В различных проектах очень часто используется дисплей LCD1602, который может отображать ASCII символа в 2 строки (16 знаков в 1 строке) каждый символ в виде матрицы 5х7 пикселей. Для работы с дисплеем LCD1602 под управлением Arduino существуют несколько библиотек, но при использовании микроконтроллера ATtiny2313 использование библиотек не целесообразно из-за малого объема памяти (2 кБ). Следующий пример скетча не использует библиотек, что позволило оптимально использовать память ATtiny2313.
Перед загрузкой скетча рекомендую ознакомится со статьей — ATtiny2313 + Arduino IDE
// ATTINY2313 V1.25 // D4 = PB0 // D5 = PB1 // D6 = PB2 // D7 = PB3 // E = PB4 // RS = PD6 void setup() { lcdInit();} void loop() { lcdCurs(0,3); lcdString("ATtiny2313"); lcdCurs(1,0); lcdInt(12345678); lcdCurs(1,10); lcdFloat(12.36); delay(100); } /////////////////////////////////////////////////////////////////////////////////////////// void lcdSend(bool rs, byte data) { if(rs==0){PORTD |= (1 << 6);} else{PORTD &= ~(1 << 6);}//RS del(); if(((data >> 7) & 1) ==1){PORTB |= (1 << 3);}else{PORTB &= ~(1 << 3);} if(((data >> 6) & 1) ==1){PORTB |= (1 << 2);}else{PORTB &= ~(1 << 2);} if(((data >> 5) & 1) ==1){PORTB |= (1 << 1);}else{PORTB &= ~(1 << 1);} if(((data >> 4) & 1) ==1){PORTB |= (1 << 0);}else{PORTB &= ~(1 << 0);} e_pin(); if(((data >> 3) & 1) ==1){PORTB |= (1 << 3);}else{PORTB &= ~(1 << 3);} if(((data >> 2) & 1) ==1){PORTB |= (1 << 2);}else{PORTB &= ~(1 << 2);} if(((data >> 1) & 1) ==1){PORTB |= (1 << 1);}else{PORTB &= ~(1 << 1);} if(((data >> 0) & 1) ==1){PORTB |= (1 << 0);}else{PORTB &= ~(1 << 0);} e_pin(); } void lcd(uint8_t cmd) {lcdSend(true, cmd);} void lcdChar(const char chr) {lcdSend(false, (uint8_t)chr);} void lcdString(const char* str) {while(*str != '\0') {del();lcdChar(*str);str++;}} void del(){delay(5);} void e_pin(){PORTB |= (1 << 4);del();PORTB &= ~(1 << 4);} void lcdCurs(byte str, byte mesto){ if(str==0){lcd(0b10000000+mesto);} if(str==1){lcd(0b11000000+mesto);} } void lcdInit(){ DDRB |= (1 << 0) | (1 << 1)| (1 << 2) | (1 << 3) | (1 << 4); DDRD |= (1 << 6); delay(100); lcd(0x03);delayMicroseconds(4500); lcd(0x03);delayMicroseconds(4500); lcd(0x03);delayMicroseconds(200); lcd(0b00000010);del(); lcd(0b00001100);del(); lcdClear(); } void lcdInt(long int_x){ byte h[8]; long int_y=int_x; int i,i_kol; if(int_x<0){int_x=abs(int_x);lcdChar('-');} // если минус for(i_kol=0;int_x>0;i_kol++){int_x=int_x/10;} // определяем кол-во цифр в long for(i=0;i<i_kol;i++){h[i]=int_y%10; int_y=int_y/10;}// разбиваем число на отдельные цифры for(i=i_kol-1;i>=0;i--){lcdChar(h[i] +'0');} // преобразуем числа в char if(i_kol==0){lcdChar('0');} // если long = 0, то выводить ноль } void lcdClear(){lcd(0b00000001);} void lcdFloat(float fr){ long int_f = fr*100, int_y=int_f; // умножаем float на 100, чтобы получить long и выделить два знака после запятой byte h[8]; int i,i_kol; if(int_f<0){int_f=abs(int_f);lcdChar('-');} // если минус for(i_kol=0;int_f>0;i_kol++){int_f=int_f/10;} // определяем кол-во цифр в long for(i=0;i<i_kol;i++){h[i]=int_y%10; int_y=int_y/10;}// разбиваем число на отдельные цифры for(i=i_kol-1;i>=0;i--){ // преобразуем числа в char if(i_kol==2&&i==1){lcdChar('0');lcdChar('.');} // если float = 0.XX if(i_kol==1){lcdChar('0');lcdChar('.');lcdChar('0');}// если float = 0.0X if(i==1&&i_kol>2){lcdChar('.');} lcdChar(h[i] +'0');}// если float > 0 if(i_kol==0){lcdChar('0');lcdChar('.');lcdChar('0');lcdChar('0');}// если float = 0, то выводить 0.00 }
На дисплей LCD1602 выводится следующая информация:
На первую строку дисплея выводится строка String, на вторую строку выводится цифры типа long и float.
Скетч использует 1056 байт (51%) памяти устройства. Всего доступно 2048 байт.
Глобальные переменные используют 21 байт (16%) динамической памяти, оставляя 107 байт для локальных переменных. Максимум: 128 байт.
Следующий скетч написан с использованием стандартной библиотеки
#include <LiquidCrystal.h> // Добавляем необходимую библиотеку LiquidCrystal lcd(8, 13, 9, 10, 11, 12); // (RS, E, DB4, DB5, DB6, DB7) void setup(){ lcd.begin(16, 2); } void loop(){ lcd.setCursor(3, 0); lcd.print("ATtiny2313"); lcd.setCursor(0, 1); lcd.print(12345678); lcd.setCursor(10, 1); lcd.print(12.36); }
Информация выводимая на дисплей в пером и втором скетче одинаковая, но второй скетч занимает очень много места и загрузить его не удалось.
Скетч использует 2588 байт (126%) памяти устройства. Всего доступно 2048 байт.
Глобальные переменные используют 55 байт (42%) динамической памяти, оставляя 73 байт для локальных переменных. Максимум: 128 байт.
Скетч слишком большой; прочитайте http://www.arduino.cc/en/Guide/Troubleshooting#size
Ошибка компиляции для платы ATtiny2313/4313.
В первом скетче используются всего несколько основных функций:
- lcdCurs(0,3) — позиция курсора, строка 0, позиция 3
- lcdString(«ATtiny2313») — вывод строки String
- lcdInt(12345678) — вывод числа long или int (ограничение в 8 цифр)
- lcdFloat(12.36) — вывод числа float (ограничение — после запятой только 2 цифры, ограничение в 8 цифр)
- lcdClear() — очистка экрана
Скетч занимает половину памяти ATtiny2313, что дает возможность подключать к ATtiny2313 различные датчики и выводить их показания на дисплей.
Для примера использования LCD1602 с ATtiny2313 можно собрать простые часы с датчиком температуры DS18B20.
Кнопками HH и MM можно установить нужное время часов, измерение температуры происходит раз в минуту.
// ATTINY2313 V1.25 // D4 = PB0 // D5 = PB1 // D6 = PB2 // D7 = PB3 // E = PB4 // RS = PD6 // DS18B20 = PD0 // HH++ = PD4 // MM++ = PD5 int i1,hh,mm,ss,tempp; void setup() { DDRD &= ~(1 << 4); DDRD &= ~(1 << 5); PORTD |= (1 << 4) | (1 << 5); lcdInit(); cli(); TCCR1A = 0; TCCR1B = 0; OCR1A = 18750; // 0.1 s TCCR1B |= (1 << WGM12); TCCR1B |= (1 << CS11) | (1 << CS10); // 64 TIMSK |= (1 << OCIE1A); sei(); } void loop() { if(((PIND >> 5) & 1) == 0){mm++; if(mm>59){mm = 0;}} if(((PIND >> 4) & 1) == 0){hh++; if(hh>23){hh = 0;}} lcdCurs(0,1); lcdString("TIME"); lcdCurs(0,7); lcdInt(hh/10);lcdInt(hh%10);lcdString(":"); lcdInt(mm/10);lcdInt(mm%10);lcdString(":"); lcdInt(ss/10);lcdInt(ss%10); lcdCurs(1,1); if(ss==0 || ss == 30){tempp = read_temp();} lcdString("TEMPER"); lcdCurs(1,10); lcdInt(tempp/10);lcdChar('.');lcdInt(tempp%10); delay(100); } void lcdSend(bool isCommand, byte data) { if(isCommand==0){PORTD |= (1 << 6);}else{PORTD &= ~(1 << 6);}//RS del(); if(((data >> 7) & 1) ==1){PORTB |= (1 << 3);}else{PORTB &= ~(1 << 3);} if(((data >> 6) & 1) ==1){PORTB |= (1 << 2);}else{PORTB &= ~(1 << 2);} if(((data >> 5) & 1) ==1){PORTB |= (1 << 1);}else{PORTB &= ~(1 << 1);} if(((data >> 4) & 1) ==1){PORTB |= (1 << 0);}else{PORTB &= ~(1 << 0);} e_pin(); if(((data >> 3) & 1) ==1){PORTB |= (1 << 3);}else{PORTB &= ~(1 << 3);} if(((data >> 2) & 1) ==1){PORTB |= (1 << 2);}else{PORTB &= ~(1 << 2);} if(((data >> 1) & 1) ==1){PORTB |= (1 << 1);}else{PORTB &= ~(1 << 1);} if(((data >> 0) & 1) ==1){PORTB |= (1 << 0);}else{PORTB &= ~(1 << 0);} e_pin(); } void lcd(uint8_t cmd) {lcdSend(true, cmd);} void lcdChar(const char chr) {lcdSend(false, (uint8_t)chr);} void lcdString(const char* str) {while(*str != '\0') {del();lcdChar(*str);str++;}} void del(){delay(5);} void e_pin(){PORTB |= (1 << 4);del();PORTB &= ~(1 << 4);} void lcdCurs(byte str, byte mesto){ if(str==0){lcd(0b10000000+mesto);} if(str==1){lcd(0b11000000+mesto);} } void lcdInit(){ DDRB |= (1 << 0) | (1 << 1)| (1 << 2) | (1 << 3) | (1 << 4); DDRD |= (1 << 6); delay(100); lcd(0x03);delayMicroseconds(4500); lcd(0x03);delayMicroseconds(4500); lcd(0x03);delayMicroseconds(200); lcd(0b00000010);del(); lcd(0b00001100);del(); lcdClear(); } void lcdInt(long int_x){ byte h[8]; int i,i_kol; if(int_x<0){int_x=abs(int_x);lcdChar('-');} long int_y=int_x; for(i_kol=0;int_x>0;i_kol++){int_x=int_x/10;} for(i=0;i<i_kol;i++){h[i]=int_y%10; int_y=int_y/10;} for(i=i_kol-1;i>=0;i--){lcdChar(h[i] +'0');} if(i_kol==0){lcdChar('0');} } void lcdClear(){lcd(0b00000001);} void lcdFloat(float fr){ long int_f = fr*100; byte h[8]; int i,i_kol; if(int_f<0){int_f=abs(int_f);lcdChar('-');} long int_y=int_f; for(i_kol=0;int_f>0;i_kol++){int_f=int_f/10;} for(i=0;i<i_kol;i++){h[i]=int_y%10; int_y=int_y/10;} for(i=i_kol-1;i>=0;i--){ if(i_kol==2&&i==1){lcdChar('0');lcdChar('.');} if(i_kol==1){lcdChar('0');lcdChar('.');lcdChar('0');} if(i==1&&i_kol>2){lcdChar('.');} lcdChar(h[i] +'0');} if(i_kol==0){lcdChar('0');lcdChar('.');lcdChar('0');lcdChar('0');} } ISR(TIMER1_COMPA_vect){ i1++; if(i1 > 9){i1 = 0;ss++;} if(ss > 59){mm++;ss=0;} if(mm > 59){hh++;mm = 0;} if(hh > 23){hh = 0;} } /////////// 18B20 uint8_t therm_reset(){ uint8_t i2; PORTD &= ~(1 << 0); DDRD |= (1 << 0); delayMicroseconds(480); DDRD &= ~(1 << 0); delayMicroseconds(60); i2=((PIND >> 0) & 1); delayMicroseconds(420); return i2; } // write bit void therm_write_bit(uint8_t bits){ PORTD &= ~(1 << 0); DDRD |= (1 << 0); delayMicroseconds(1); if(bits) DDRD &= ~(1 << 0); delayMicroseconds(60); DDRD &= ~(1 << 0); } // read bit uint8_t therm_read_bit(void){ uint8_t bits=0; PORTD &= ~(1 << 0); DDRD |= (1 << 0); delayMicroseconds(1); DDRD &= ~(1 << 0); delayMicroseconds(14); if(PIND & (1 << 0)) bits=1; delayMicroseconds(45); return bits; } // read byte uint8_t therm_read_byte(void){ uint8_t i2=8, n2=0; while(i2--){n2>>=1;n2|=(therm_read_bit()<<7);} return n2; } // write byte void therm_write_byte(uint8_t bytes){ uint8_t i2=8; while(i2--){therm_write_bit(bytes&1);bytes >>= 1; } } // read temp int read_temp(){ byte temperature[2]; int temper; therm_reset(); therm_write_byte(0xCC); therm_write_byte(0x44); while(!therm_read_bit()); therm_reset(); therm_write_byte(0xCC); therm_write_byte(0xBE); temperature[0]=therm_read_byte(); temperature[1]=therm_read_byte(); therm_reset(); temper = (temperature[1] << 8 | (temperature[0]))*10/16; return temper; }
Скетч использует 1954 байт (95%) памяти устройства. Всего доступно 2048 байт.
Глобальные переменные используют 33 байт (25%) динамической памяти, оставляя 95 байт для локальных переменных. Максимум: 128 байт.