ATtiny2313 + LCD1602 (Arduino IDE)

В различных проектах очень часто используется дисплей 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 байт.

Добавить комментарий

Войти с помощью: