| Ваш IP: 100.26.179.251 | Online(45) - гости: 8, боты: 37 | Загрузка сервера: 0.34 ::::::::::::

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 байт.

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

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

Случайные статьи

  • TDA8924 — двух канальный усилитель мощности звуковой частоты класса D

    TDA8924 — двух канальный усилитель мощности звуковой частоты класса D

    TDA8924 — двух канальный усилитель мощности звуковой частоты класса D. Номинальная выходная мощность усилителя 120 Вт на канал. Микросхема TDA8924 поставляется в корпусе HSOP24 с малым внутренним радиатором и не требует внешнего радиатора. Напряжение питания микросхемы от ± 12,5 В до ± 30 В. КПД усилителя более 90%. Сопротивление нагрузки 2 Ом. Размер …Подробнее...
  • Двухтональный звонок

    Двухтональный звонок

    Двухтональный звонок содержит управляющий генератор на элементах D1.1 — D1.3 микросхемы К155ЛА, который вырабатывает управляющие импульсы, частота которых зависит от емкости С1 и сопротивления R1. При указанных на схеме элементах частота переключения генератора примерно 0,7…0,8 Гц. Импульсы управляющего генератора подаются на генератор тона и поочередно подключают их к усилителю звуковой …Подробнее...
  • УСТРОЙСТВО ПЛАВНОГО ПЕРЕКЛЮЧЕНИЯ ЕЛОЧНОЙ ГИРЛЯНДЫ

    Устройство предназначено для плавного переключения, сетевой елочной гирлянды с частотой 0,2…2 Гц. Яркость свечения ламп можно регулировать. Устройство рассчитано на подключение гирлянды напряжением 220 В, мощностью не более 100 Вт. Принципиальная схема устройства переключения изображена на рисунке. Частотой переключения управляет мультивибратор, собранный на элементах DD1.3, DD1.4. Сдвиг момента открывания тиристора …Подробнее...
  • Малогабаритная АС

    В статье описана АС объемом 12л. Выбор закрытого акустического оформления для НЧ головки обусловлен там, что АС рассчитаны на воспроизведение классических и традиционных джазовых музыкальных произведений. В этих жанрах исполнения АС закрытого типа звучат лучше. Так же малые габариты АС обладают малой неравномерностью АЧХ. Для малогабаритной АС была выбрана НЧ …Подробнее...
  • Мостовой двухтактный усилитель мощностью 25Вт

    Мостовой двухтактный усилитель мощностью 25Вт

    Входной каскад на лампе Л1.1 построен по схеме с общим катодом и особенностей не имеет. Его назначение это обеспечить необходимый уровень чувствительности. При входном сигнале не менее 4 В входной каскад можно исключить. Фазоинвертор построен на лампе Л2 и представляет собой балансный смеситель. Фазоинвертор обладает большим усилением и симметричностью разделенного …Подробнее...