In articolul Afisaj cu cristale lichide KTM-S1201 am realizat, dupa ce mi-am dat seama cum se comanda, un ceas cu reglaj din encoder, avand si un temometu si higrometru cu datele ofertie de la un DHT22 (AM2302). De data asta, am modificat putin programul sa am un ceas cu reglaj din 2 (3 butoane), un termometru cu date oferite de un senzor DS18B20 si un voltmetru de curent continuu pana la 20V. Afisajul a fost primit de la dl. Baricz János si dansul voia si aceasta a doua versiune de ceas, asa ca mi-am facut timp sa revad programul (sketch-ul) initial si sa-l (re)inteleg.
Schema de conectare a afisajului nu difera de schema anterioara, doar am scos encoderul punand butoane fara retinere (2 pentru MENIU si PLUS sau MINUS, respectiv 3 pentru MENIU, PLUS si MINUS), am scos senzorul de temperatura si umiditate DHT22 (AM2302) si am pus un senzor digital de temperatura DS18B20, apoi am adaugat un divizor rezistiv pentru a putea masura tensiunea continua pana la 20V.
De data trecuta am realizat o placuta adaptoare ce are semireglabilul de contrast pe ea, schema ei fiind
Ceasul este indicat cu ora, minute si secunde, apoi este indicata temperatura si tensiunea, ca si la ceasul anterior:
Dupa ce am pus ceasul la teste, am constatat ca modul de afisare la temperaturii este deranjant datorita literei C foarte mici, am rescris partea de afisare a acesteai, in sensul ca pentru temperaturi pozitive, mai mari de 10 grade Celsius, am scos semnul de plus, iar la cele sub -10 grade Celsius, care sunt extrem de rare in casa 😇 am lasat C-ul ingust.
Acum modurile de afisare ale temperaturii sunt:
- temperaturi mai mari de 10 grade Celsius
- temperaturi pozitive mai mici de 10 grade Celsius
- temperaturi negativa mai mari de -10 grade Celsius
se vede modul de afisare (timpul de afisare normal al ceasului e mai scurt, iar pentru temperatura si umiditate mai lung, decat la functionarea normala), dar am refacut filmarile si am si timpii normali;
- ceas matriceal cu alarma, termometru si higrometru (3a)
Dupa ce am rezolvat aprinderea (relativ) usoara a virgulei, am scris un programior (sketch) pentru a arata aleator ora si apoi o temperatura si cu cifra dupa virgula, dupa cum se vede si in filmuletele;
- test 2 functionare afisaj lcd cu 6 cifre (HT1621)
Programul pentru prima versiune este HT1621_test.ino, iar cel optimizat este HT1621_test4.ino.
Primul program prezinta cateva secunde ora 23:45, cu clipirea secundelor:
apoi temperatura de 17 grade Celsius:
Cel de-al doilea alege aleator ora si minutele ceasului, indicand-o cateva secunde, pastrandu-se partea de animatie la semnul dintre secunde:
apoi alege aleator o temperatura, ce poate fi negativa sau pozitiva:
Afisajul alfanumeric cu 20 coloane si 4 randuri este similar cu cel "clasic" cu 16 coloane si 2 randuri, de aceea pentru modul de comanda clasic schema de conectare este identica cu cea prezentata in articolul Arduino si un afisaj LCD clasic (16 caractere si 2 randuri)
In mare, trebuie modificata linia de initializare a afisajului din lcd.begin(16,2); // initialize the lcd in lcd.begin(20,4); // initialize the lcd si scrierea pe randurile 0, 1, 2 si 3 (pe cel cu 2 randuri se scrie doar pe 0 si 1). Alt mod de conectare al acestui afisaj, este acela in care se foloste protocolul de comunicatie i2c, care utilizeaza 4 fire (2 de comanda si 2 de alimentare). Se foloseste un modul de adaptare, cum e cel prezentat in articolul Interfata i2c la LCD pentru Arduino, schema de conectare fiind identica:
Marked "Arduino-IIC-LCD GY-LCD-V1" Sketch-ul meu e foarte putin modificat, fiind:
/* YourDuino.com Example Software Sketch 20 character 4 line I2C Display Backpack Interface labelled "LCM1602 IIC A0 A1 A2"terry@yourduino.com *//*-----( Import needed libraries )-----*/
#include <Wire.h> // Comes with Arduino IDE// Get the LCD I2C Library here: // https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads// Move any other LCD libraries to another folder or delete them// See Library "Docs" folder for possible commands etc.
#include <LiquidCrystal_I2C.h>
/*-----( Declare Constants )-----*///none/*-----( Declare objects )-----*/// set the LCD address to 0x27 for a 20 chars 4 line display// Set the pins on the I2C chip used for LCD connections:// addr, en,rw,rs,d4,d5,d6,d7,bl,blpolLiquidCrystal_I2C lcd(0x20, 4, 5, 6, 0, 1, 2, 3, 7, NEGATIVE); // Set the LCD I2C address/*-----( Declare Variables )-----*///nonevoidsetup() /*----( SETUP: RUNS ONCE )----*/
{
Serial.begin(9600); // Used to type in characters
lcd.begin(20,4); // initialize the lcd for 20 chars 4 lines// NOTE: Cursor Position: CHAR, LINE) start at 0 /* lcd.setCursor(3,0); //Start at character 4 on line 0 lcd.print("Hello, world!"); delay(1000); lcd.setCursor(2,1); lcd.print("From YourDuino"); delay(1000); lcd.setCursor(0,2); lcd.print("20 by 4 Line Display"); lcd.setCursor(0,3); delay(2000); lcd.print("http://YourDuino.com"); delay(8000);*/
lcd.setCursor(1,0); //Start at character 4 on line 0
lcd.print("niq_ro test a 20x4");
delay(1000);
lcd.setCursor(2,1);
lcd.print("alphanumeric LCD");
delay(1000);
lcd.setCursor(1,2);
lcd.print("yellow background");
lcd.setCursor(2,3);
delay(500);
lcd.print("www.tehnic.go.ro");
delay(8000);
}/*--(end setup )---*/voidloop() /*----( LOOP: RUNS CONSTANTLY )----*/
{
}
}/* --(end main loop )-- *//* ( THE END ) */
In articolul anterior, prezentasem cum am de gand sa fac un indicator pentru temperatura exterioara (cu DS18B20), temperatura si umiditatea din masina cu DHT11 si masurarea tensiunii bateriei. Pe ecran, informatiile se prezinta asa:
Schema exacta este:
Are o mica modificare, in sensul ca rezistenta de 15k din prima schema am realizat-o din 2, una de 10k si una de 4k7. Am facut un film, numit indicator date mediu - masina in care am simulat toate situatiile, care am crezut eu ca pot exista, ca valori:
Cand tensiunea de pe baterie este sub 10V, valoarea apare cu intermitenta.. la fel si la temepratura interioara cand temperatura e sub 00C apare un zero cu intermitenta. Fiind "baiat bun" postez si sketch-ul folosit la teste:
/*original sketch by niq_ro (Nicu FLORICA) from http://nicuflorica.blogspot.comprogram original scris de mine (niq_ro) versiunea 1.0..............................................................*/
#include <LiquidCrystal.h>
// folosesc libraria pentru afisaje LCD simpleLiquidCrystal lcd(7, 6, 5, 4, 3, 2);
// indic modul de legare, vezi mai jos:/* ------------------- | LCD | Arduino | ------------------- LCD RS pin to digital pin 7 | RS | D7 | LCD Enable pin to digital pin 6 | E | D6 | LCD D4 pin to digital pin 5 | D4 | D5 | LCD D5 pin to digital pin 4 | D5 | D4 | LCD D6 pin to digital pin 3 | D6 | D3 | LCD D7 pin to digital pin 2 | D7 | D2 | LCD R/W pin to ground | R/W | GND | -------------------*/// http://arduino.cc/en/Reference/LiquidCrystalCreateCharbyte grad[8] = {
B01100,
B10010,
B10010,
B01100,
B00000,
B00000,
B00000,
};
// variables float R1, R2, R3; // rezsistors in voltage divisorfloat k1; // adjustment for divisorfloat u1, u11, u12; // for voltageint ti; // temperature inside of car;// dataint VPin = A0; // voltage pinint DHTPin = A1; // data pin from DHT11//int DSPin = 10; // // for DHT11 sensor
#include "DHT.h"
#define DHTPIN A1 // what pin we're connected to
#define DHTTYPE DHT11 // DHT 11
DHT dht(DHTPIN, DHTTYPE);
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 10 on the Arduino
#define ONE_WIRE_BUS 10
#define TEMPERATURE_PRECISION 9
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature. DallasTemperature sensors(&oneWire);
// arrays to hold device addressesDeviceAddress outsideThermometer;
voidsetup() {
R1 = 4.7; // R1 = 4k7
R2 = 10; // R2 = 10k
R3 = 4.7; // R3 = 4k7
k1 = 1/1.033;
lcd.createChar(0, grad);
lcd.begin(16, 2); // set up the LCD's number of columns and rows: // initialing the DHT11 sensor;
dht.begin();
lcd.clear(); // clear the screen
lcd.setCursor(1, 0); // put cursor at colon 2 and row 0 = left/up
lcd.print("indicator bord"); // print a text
lcd.setCursor(2, 1); // put cursor at colon 0 and row 0 = left/down
lcd.print("1.0 by niq_ro"); // print a textdelay (2000);
lcd.clear(); // clear the screen// Start up the DS18B20 sensor
sensors.begin();
// adress for ds sensor // DeviceAddress outsideThermometer = { 0x28, 0xAC, 0x7A, 0xD4, 0x04, 0x00, 0x00, 0x7E };// DeviceAddress outsideThermometer = { 0x28, 0xAC, 0x7A, 0xD4, 0x4, 0x0, 0x0, 0x7E };// set the resolution to 9..12 bit
sensors.setResolution(outsideThermometer, TEMPERATURE_PRECISION);
} // END void setupvoidloop(){
u1 = analogRead(VPin);
u11 = k1*5.0*u1/1023*(R1+R2+R3)/R1;
u12 = u11 + 0.05;
//u12=11.4; // for test// u12=7.5; //for test;if (u12<10.0)
{
lcd.setCursor(12, 0);
lcd.print(u12,1);
lcd.print("V");
delay(500);
lcd.setCursor(12, 0);
lcd.print(" ");
}
else
{
lcd.setCursor(11, 0);
lcd.print(u12,1);
lcd.print("V");
delay(500);
}
// DHT11 partint h = dht.readHumidity();
int ti = dht.readTemperature();
lcd.setCursor(0, 1);
lcd.print("int:");
//ti=0; // for test;//ti=7; // for test;//ti=29; // for test;if (ti<1) {
lcd.setCursor(5, 1);
lcd.print(" 0");
lcd.write(byte(0));
lcd.print("C");
delay(500);
lcd.setCursor(5, 1);
lcd.print(" ");
}
elseif (ti>=9) {
lcd.setCursor(4, 1);
lcd.print("+");
lcd.print(ti);
lcd.write(byte(0));
lcd.print("C");
}
else//if (ti>=1 || ti<10)
{
lcd.setCursor(5, 1);
lcd.print("+");
lcd.print(ti);
lcd.write(byte(0));
lcd.print("C");
}
lcd.setCursor(11, 1);
lcd.print(h);
lcd.print("%um");
// DeviceAddress outsideThermometer = { 0x28, 0xAC, 0x7A, 0xD4, 0x4, 0x0, 0x0, 0x7E };
sensors.requestTemperatures();
float te = sensors.getTempC(outsideThermometer);
// printTemperature(DeviceAddress outsideThermometer);delay(300);
//te=-24;//te=-2;//te=-0.4;// te=0;//te=0.3;//te=5;//te=17;//te=17.6;
lcd.setCursor(0, 0);
lcd.print("ext:");
if (te<-10) {
lcd.setCursor(4, 0);
lcd.print(te,0);
lcd.write(byte(0));
lcd.print("C ");
}
elseif (te>-10 || te<0) {
lcd.setCursor(5, 0);
lcd.print(te,0);
lcd.write(byte(0));
lcd.print("C ");
}
elseif (te=0) {
lcd.setCursor(5, 0);
lcd.print("=0");
lcd.write(byte(0));
lcd.print("C ");
}
if (te>0)
{
lcd.setCursor(5, 0);
lcd.print("+");
lcd.print(te,0);
lcd.write(byte(0));
lcd.print("C ");
}
if (te>=10) {
lcd.setCursor(4, 0);
lcd.print("+");
lcd.print(te,0);
lcd.write(byte(0));
lcd.print("C ");
}
}
Urmeaza transferarea proiectului pe un cablaj pentru a fi montat pe masina... schema de conectare la masina ar fi:
23.03.2014 Am facut si mica modificare, rezultandu-mi:
24.03.2014 Deoarece am reusit "performanta" de a strica 2 placi Arduino (partea de interfata USB + microcontroler ATmega328P-PU) din cauza consumului mare pe ramura de 5V, recomand utilizarea unui stabilizator extern pentru 5V...
Din dorinta de a putea vedea temperaturile de la distanta cat mai mare pe un afisaj alfanumeric cu 16 coloane si 2 randuri, LCD16x2 sau 1602, am folosit caractere mari (util 3 coloane + un spatiu, pe ambele randuri), dupa cum am prezentat in articolul anterior, Caractere mari pe afisaj de 2 randuri si 16 coloane si... Arduino (2):
Dupa acesta comparatie, pot spune ca e mai avantajos din punct de vedere economic sa folosim un afisaj LED, cat si al consumului, deoarece comanda la cel LED e multiplexata, deci se aprinde pe rand doar o cifra/simbol, iar la cel LCD e LED-ul de fundal plus consum afisaj.. dar partea importanta e aceea de vizibilitate, care este tot in favoarea afisajului clasic, tip LED.
In prima parte am prezentat modul de conectare al afisajului de Nokia 3410 si cum am reusit sa-l folosesc la rezolutia maxima de 95x65 (fata de cea a celui de Nokia 3310 cu 84x48). Deoarece libraria grafica pe care am folosit-o, si anume u8glib
are prezentat si un manual de utilizare in care se prezinta si comenzile, m-am gandit sa refac prezentarea grafica a unui secundar de ceas, cum am facut cu afisajul de Nokia 3310, vezi articolul Afisajul folosit la telefoanele Nokia 5110/3310 si Arduino (IV), folosind si placa Arduino facuta de Nelu, ca si afisajul e de la el si poate se inteleg mai bine:
Pentru a intelege libraria, am studiat si, am folosit, comenzi sau parti din exemplele care vin cu libraria, dar si ce e in manual:
// prima prezentare grafica
u8g.firstPage(); // pregateste partea graficado {
subrutina(); // "munceste" in subrutina, unde e mesajul de intampinare
} while( u8g.nextPage() ); // pana se termina acea parte graficadelay(5000); // asteapta 5 secunde sa faca altceva (si sa pastreze imaginea pe ecran)
Grafica dintr-o pagina (ecran) se comanda din programul principal cu comenzile prezentate mai sus, iar un subrutina propriu-zisa, poate fi:
void subrutina(void) {
// folosesesc un anume font
u8g.setFont(u8g_font_unifont);
//u8g.setFont(u8g_font_osb21); // sau alt font
u8g.drawStr( 3, 22, "Salut Nicu!"); // la coordonatele cu x=3 si y=22 scriu mesajul// pictez un chenar
u8g.drawFrame(1,1,93,63);
// u8g.setFont(u8g_font_unifont); // font mai maricel (nefolosit) u8g.setFont(u8g_font_6x13); // font mai mititel
u8g.drawStr( 3, 40, "afisez mesaj pe");
u8g.drawStr( 6, 50, "ecran de Nokia");
u8g.drawStr( 40, 60, "3410");
}
Despre cum se face un cadru, vedeti comanda drawFrame
iar despre cum scriu un text, vedeti comanda drawStr
Partea grafica a fost ok, chiar si afisarea de texte de diverse marimi, dar am vrut sa afisez secundele corespunzatoare pozitiei secundarului si a trebuit sa folosesc corespondenta caracterelor ASCII:
Eu am folosit o varianta care merge ok, adica am aflat cifra de la zeci si cea de la unitati si am adunat la ele pe 48...iar inainte am desenat un cerc si secundarul.. pentru fiecare secunda transmit variabila unghi si "chem" subrutina numita subrutina2
void subrutina2(uint8_t unghi) {
// desenez cercul principal
u8g.drawCircle(xcenter,ycenter,raza);
// for (unghi=0; unghi<60; unghi+=1);float x1=sin(6*unghi*2*3.14/360);
float y1=cos(6*unghi*2*3.14/360);
u8g.drawLine(xcenter, ycenter, xcenter+raza*x1, ycenter-raza*y1);
// folosesc un font mititel
u8g.setFont(u8g_font_6x13);
if (unghi <15 || unghi>45)
{ u8g.drawStr(30, 50, "niq_ro"); }
else
{ u8g.drawStr(30, 20, "niq_ro");
}
char s[2] = " ";
if (unghi<10)
{
// see http://www.asciitable.com/
s[0]=unghi+48; // transform cifrele in caractere ASCII
u8g.drawStr(10, 10, s);
}
else
{
s[0]=int(unghi/10)+48;
u8g.drawStr(4, 10, s);
}
s[0]=unghi-10*int(unghi/10)+48;
u8g.drawStr(10, 10, s);
}
/*// original sketch by niq_ro from http://nicuflorica.blogspot.com for analog clock using u8glib library// version 1m5 - 2013.10.22, Craiova - Romania >>> Before compiling: Please remove comment from the constructor of the >>> connected graphics display (see below). Universal 8bit Graphics Library, http://code.google.com/p/u8glib/ Copyright (c) 2012, olikraus@gmail.com All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
#include "U8glib.h"// ecran de Nokia 3410
U8GLIB_PCF8812 u8g(13, 11, 10, 9, 8); // SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9, Reset = 8int xmax=94; // lungime maxima pe axa xint ymax=64; // lungime maximape axa yint xcenter=xmax/2; // centrul ecranului pe axa xint ycenter=ymax/2; // centrul ecranului pe axa yint raza=ymax/2-2; // raza cerculuiint unghi=0;
//int ji=0;void subrutina(void) {
// graphic commands to redraw the complete screen should be placed here
u8g.setFont(u8g_font_unifont);
//u8g.setFont(u8g_font_osb21);
u8g.drawStr( 3, 22, "Salut Nicu!");
// pictez un chenar
u8g.drawFrame(1,1,93,63);
// u8g.setFont(u8g_font_unifont);
u8g.setFont(u8g_font_6x13);
u8g.drawStr( 3, 40, "afisez mesaj pe");
u8g.drawStr( 6, 50, "ecran de Nokia");
u8g.drawStr( 40, 60, "3410");
}
void subrutina1(void) {
// desenez cercul principal
u8g.drawCircle(xcenter,ycenter,raza);
/* // un font si mai mic u8g.setFont(u8g_font_4x6); u8g.drawStr(40, 60, "3410"); */// trag o linie din centrul cercului la cifra 0/12
u8g.drawLine(xcenter, ycenter, xcenter, ycenter-raza);
// delay(500);
u8g.drawLine(xcenter, ycenter, xcenter+raza, ycenter);
// delay(500);
u8g.drawLine(xcenter, ycenter, xcenter, raza+ycenter);
// delay(500);
u8g.drawLine(xcenter, ycenter, xcenter-raza, ycenter);
// delay(500);
}
void subrutina2(uint8_t unghi) {
// desenez cercul principal
u8g.drawCircle(xcenter,ycenter,raza);
// for (unghi=0; unghi<60; unghi+=1);float x1=sin(6*unghi*2*3.14/360);
float y1=cos(6*unghi*2*3.14/360);
u8g.drawLine(xcenter, ycenter, xcenter+raza*x1, ycenter-raza*y1);
// folosesc un font mititel
u8g.setFont(u8g_font_6x13);
if (unghi <15 || unghi>45)
{ u8g.drawStr(30, 50, "niq_ro"); }
else
{ u8g.drawStr(30, 20, "niq_ro");
}
char s[2] = " ";
if (unghi<10)
{
// see http://www.asciitable.com/
s[0]=unghi+48; // transform cifrele in caractere ASCII
u8g.drawStr(10, 10, s);
}
else
{
s[0]=int(unghi/10)+48;
u8g.drawStr(4, 10, s);
}
s[0]=unghi-10*int(unghi/10)+48;
u8g.drawStr(10, 10, s);
}
void subrutina3(void) {
// pun font si apoi scriu mesaj de sfarsit...// u8g.setFont(u8g_font_gdr25);
u8g.setFont(u8g_font_unifont);
u8g.drawStr(20, 30, "Sfarsit!");
}
voidsetup(void) {
// flip screen, if required// u8g.setRot180();// set SPI backup if required//u8g.setHardwareBackup(u8g_backup_avr_spi);// assign default color valueif ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
u8g.setColorIndex(255); // white
}
elseif ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
u8g.setColorIndex(3); // max intensity
}
elseif ( u8g.getMode() == U8G_MODE_BW ) {
u8g.setColorIndex(1); // pixel on
}
elseif ( u8g.getMode() == U8G_MODE_HICOLOR ) {
u8g.setHiColorByRGB(255,255,255);
}
}
u8g_uint_t xx=0;
voidloop(void) {
// picture loop
u8g.firstPage();
do {
subrutina(); // unde e mesajul de intampinare
} while( u8g.nextPage() );
delay(5000);
// a doua reprezentare grafica
u8g.firstPage();
do {
subrutina1(); // unde desenez ceva pana ma prind cum se face
} while( u8g.nextPage() );
delay(5000);
// rebuild the picture after some delaydelay(150);
// fac ceasu' cu secundarfor (xx = 0; xx < 60; xx++) // aici ar fi secundele
{
u8g.firstPage(); // incepere parte de graficado { // face asta pana termina ce e in subrutina de desenat
subrutina2(xx); // munceste la ce e in subrutina2
} while( u8g.nextPage() ); // pana o terminadelay(1000); // sta o secunda
}
xx=0; // readuce cronometrul la zerodelay(2000); // sta 2 secunde// a treia reprezentare grafica
u8g.firstPage();
do {
subrutina3(); // unde scriu ca s-a terminat demonstratia...
} while( u8g.nextPage() );
delay(10000); // sta 10 secunde