ATtiny13 + LCD1602_I2C (Arduino)

Микроконтроллер ATtiny13 предназначен для создания простых проектов, так как обладает небольшой Flash памятью (1 кБ), имеет всего 8 выводов, 2 из которых питание. Так же микроконтроллер ATtiny13 имеет очень низкую цену. Но тем не менее микроконтроллер может работать с различными датчиками и индикаторами. На этой странице будет рассмотрен пример подключения дисплей LCD1602 оснащенным модулем на PCF8574, который позволяет подключить символьный дисплей 1602 к микроконтроллеру ATtiny13 всего по двум проводам SDA и SCL (I2C).

Модуль на базе PCF8574 имеет такое же расположение выводов как и выводы LCD1602, поэтому модуль нужно просто впаять в контактные отверстия дисплея LCD1602.

 

Схема подключения

Модуль на PCF8574 питается от постоянного напряжения 5В, управляется при помощи шины I2C на максимальной частоте шины в 100 кГц. Группа перемычек PJ1…JP3 позволяет менять адрес I2C (0х27 по умолчанию).

Для запуска экрана LCD1602_I2C соберите следующую схему:

Как прошить ATtiny13 через Arduino IDE можно узнать в  http://rcl-radio.ru/?p=98729

Перед прошивкой в Arduino IDE выберите 9,6 MHz internal и EEPROM not retained 

#define ADDR    0x27
#define SDA 3 // PB3
#define SCL 4 // PB4
#define RS      0
#define E       2
#define LED     3
 
byte led_b,h[8];
 
void setup() {
    i2c_write(led_b |= (1<<LED));// включаем подсветку
    lcdInit();
}
 
void loop() {
   lcdCurs(0,3);
   lcdString("ATtiny__13");
   lcdCurs(1,3);
   lcdLong(1234567890);  
}
 
void lcdSend(bool rs, byte data) {
    if(rs==0){led_b |= (1<<RS);} else {led_b &= ~(1<<RS);}//RS
 
    del();
    if(((data >> 7) & 1) ==1){i2c_write(led_b |= (1<<7));} else {i2c_write(led_b &= ~(1<<7));}
    if(((data >> 6) & 1) ==1){i2c_write(led_b |= (1<<6));} else {i2c_write(led_b &= ~(1<<6));}
    if(((data >> 5) & 1) ==1){i2c_write(led_b |= (1<<5));} else {i2c_write(led_b &= ~(1<<5));}
    if(((data >> 4) & 1) ==1){i2c_write(led_b |= (1<<4));} else {i2c_write(led_b &= ~(1<<4));}
    e_pin();
    if(((data >> 3) & 1) ==1){i2c_write(led_b |= (1<<7));} else {i2c_write(led_b &= ~(1<<7));}
    if(((data >> 2) & 1) ==1){i2c_write(led_b |= (1<<6));} else {i2c_write(led_b &= ~(1<<6));}
    if(((data >> 1) & 1) ==1){i2c_write(led_b |= (1<<5));} else {i2c_write(led_b &= ~(1<<5));}
    if(((data >> 0) & 1) ==1){i2c_write(led_b |= (1<<4));} else {i2c_write(led_b &= ~(1<<4));}
    e_pin();
}
 
void lcdInit(){ 
    del();
    lcd(0x03);delayMicroseconds(4500);
    lcd(0x03);delayMicroseconds(4500);
    lcd(0x03);delayMicroseconds(200);
 
    lcd(0b00000010);del();
    lcd(0b00001100);del();
    lcdClear();
  } 
 
void lcdClear(){lcd(0b00000001);} 
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(){delayMicroseconds(1000);}
void e_pin(){i2c_write(led_b |= (1<<E));del();i2c_write(led_b &= ~(1<<E));}
 
 
void lcdCurs(byte str, byte mesto){
  if(str==0){lcd(0b10000000+mesto);}
  if(str==1){lcd(0b11000000+mesto);}
  }  
 
void lcdLong(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, то выводить ноль
  }  
 
bool i2c_read_bit() {
    bool i2c_bit = 1;        
    DDRB &= ~(1 << SDA);            
    delayMicroseconds(10); 
    DDRB &= ~(1 << SCL);                
    if((PINB >> SDA) & 1) i2c_bit=0;                            
    delayMicroseconds(10);  
    DDRB |= (1 << SCL);              
    return i2c_bit;  
}
 
byte i2c_write_byte(byte data){
    for (byte i=0; i<8; i++){i2c_write_bit((data&0x80)==0);data<<=1;}    
    return i2c_read_bit(); 
}
 
void i2c_write_bit(byte b){
    delayMicroseconds(5);
    if(b){DDRB |= (1 << SDA);}else{DDRB &= ~(1 << SDA);}
    delayMicroseconds(5);
    DDRB &= ~(1 << SCL);       
    delayMicroseconds(10);
    DDRB |= (1 << SCL);
}
 
void i2c_start(){
     delayMicroseconds(10);  
     DDRB &= ~(1 << SDA); DDRB &= ~(1 << SCL); 
     delayMicroseconds(10); 
     DDRB |= (1 << SDA);  PORTB &= ~(1 << SDA);
     delayMicroseconds(10); 
     DDRB |= (1 << SCL);  PORTB &= ~(1 << SCL);   
     delayMicroseconds(10);
}
 
void i2c_stop()  {
     DDRB |= (1 << SDA);            
     delayMicroseconds(10);
     DDRB &= ~(1 << SCL);               
     delayMicroseconds(10); 
     DDRB &= ~(1 << SDA);             
}
 
void i2c_write(byte lcd){
     i2c_start();
     i2c_write_byte(ADDR<<1);
     i2c_write_byte(lcd);
     i2c_stop();
  }

Скетч использует 840 байт (82%) памяти устройства. Всего доступно 1024 байт.
Глобальные переменные используют 13 байт (20%) динамической памяти, оставляя 51 байт для локальных переменных. Максимум: 64 байт.

Для вывода строки String используется функция lcdString(), для вывода числа long используйте функцию lcdLong(), для char используйте lcdChar().

Очистка экрана lcdClear(). Позиция курсора lcdCurs(0,1) , 0 — номер строки, 1 — положение знакоместа.

Далее показаны примеры использования датчика температуры DS18B20, а так же простые часы на основе часов реального времен DS1307 (DS3231).

#define ADDR    0x27
#define SDA 3 // PB3
#define SCL 4 // PB4
#define OUT 0 // PB0
#define RS      0
#define E       2
#define LED     3
 
byte led_b;
int t;
 
void setup() {
    i2c_write(led_b |= (1<<LED));// включаем подсветку
    lcdInit();
}
 
void loop() {
   t = read_temp();
   lcdCurs(0,3);
   lcdChar(84);lcdChar(69);lcdChar(77);lcdChar(80);
   lcdCurs(1,3); 
   lcdChar(t/100 +'0');
   lcdChar(t/10%10 +'0');
   lcdChar(46);
   lcdChar(t%10 +'0');
   lcdChar(32);lcdChar(67);
   delay(1000);
}
 
void lcdSend(bool rs, byte data) {
    if(rs==0){led_b |= (1<<RS);} else {led_b &= ~(1<<RS);}//RS
 
    delay(1);
    if(((data >> 7) & 1) ==1){i2c_write(led_b |= (1<<7));} else {i2c_write(led_b &= ~(1<<7));}
    if(((data >> 6) & 1) ==1){i2c_write(led_b |= (1<<6));} else {i2c_write(led_b &= ~(1<<6));}
    if(((data >> 5) & 1) ==1){i2c_write(led_b |= (1<<5));} else {i2c_write(led_b &= ~(1<<5));}
    if(((data >> 4) & 1) ==1){i2c_write(led_b |= (1<<4));} else {i2c_write(led_b &= ~(1<<4));}
    e_pin();
    if(((data >> 3) & 1) ==1){i2c_write(led_b |= (1<<7));} else {i2c_write(led_b &= ~(1<<7));}
    if(((data >> 2) & 1) ==1){i2c_write(led_b |= (1<<6));} else {i2c_write(led_b &= ~(1<<6));}
    if(((data >> 1) & 1) ==1){i2c_write(led_b |= (1<<5));} else {i2c_write(led_b &= ~(1<<5));}
    if(((data >> 0) & 1) ==1){i2c_write(led_b |= (1<<4));} else {i2c_write(led_b &= ~(1<<4));}
    e_pin();
}
 
void lcdInit(){ 
    lcd(0x03);delay(5);
    lcd(0x03);delay(5);
    lcd(0x03);delayMicroseconds(200);
    lcd(0b00000010);delay(5);
    lcd(0b00001100);delay(5);
    lcdClear();
  } 
 
void lcdClear(){lcd(0b00000001);} 
void lcd(uint8_t sett) {lcdSend(true, sett);}
void lcdChar(const char chr) {lcdSend(false, (uint8_t)chr);}
void e_pin(){i2c_write(led_b |= (1<<E));delay(1);i2c_write(led_b &= ~(1<<E));}
 
 
void lcdCurs(byte str, byte mesto){
  if(str==0){lcd(0b10000000+mesto);}
  if(str==1){lcd(0b11000000+mesto);}
  }  
 
///// i2c /////////////
 
bool i2c_read_bit() {
    bool i2c_bit = 1;        
    DDRB &= ~(1 << SDA);            
    delayMicroseconds(10); 
    DDRB &= ~(1 << SCL);                
    if((PINB >> SDA) & 1) i2c_bit=0;                            
    delayMicroseconds(10);  
    DDRB |= (1 << SCL);              
    return i2c_bit;  
}
 
byte i2c_write_byte(byte data){
    for (byte i=0; i<8; i++){i2c_write_bit((data&0x80)==0);data<<=1;}    
    return i2c_read_bit(); 
}
 
void i2c_write_bit(byte b){
    delayMicroseconds(5);
    if(b){DDRB |= (1 << SDA);}else{DDRB &= ~(1 << SDA);}
    delayMicroseconds(5);
    DDRB &= ~(1 << SCL);       
    delayMicroseconds(10);
    DDRB |= (1 << SCL);
}
 
void i2c_start(){
     delayMicroseconds(10);  
     DDRB &= ~(1 << SDA); DDRB &= ~(1 << SCL); 
     delayMicroseconds(10); 
     DDRB |= (1 << SDA);  PORTB &= ~(1 << SDA);
     delayMicroseconds(10); 
     DDRB |= (1 << SCL);  PORTB &= ~(1 << SCL);   
     delayMicroseconds(10);
}
 
void i2c_stop()  {
     DDRB |= (1 << SDA);            
     delayMicroseconds(10);
     DDRB &= ~(1 << SCL);               
     delayMicroseconds(10); 
     DDRB &= ~(1 << SDA);             
}
 
void i2c_write(byte lcd){
     i2c_start();
     i2c_write_byte(ADDR<<1);
     i2c_write_byte(lcd);
     i2c_stop();
  }   
 
//////// ds18b20 /////////////
 
// reset
uint8_t therm_reset(){
    uint8_t i;
    PORTB &= ~(1 << OUT);
    DDRB |= (1 << OUT);
    delayMicroseconds(480);  
    DDRB &= ~(1 << OUT);
    delayMicroseconds(60);
    i=((PINB >> OUT) & 1);
    delayMicroseconds(420);
    return i;
}
// write bit
void therm_write_bit(uint8_t bit){
    PORTB &= ~(1 << OUT);
    DDRB |= (1 << OUT);
    delayMicroseconds(1);
    if(bit) DDRB &= ~(1 << OUT);
    delayMicroseconds(60);
    DDRB &= ~(1 << OUT);
}
// read bit
uint8_t therm_read_bit(void){
    uint8_t bit=0;
    PORTB &= ~(1 << OUT);
    DDRB |= (1 << OUT);
    delayMicroseconds(1);
    DDRB &= ~(1 << OUT);
    delayMicroseconds(14);
    if(PINB & (1 << OUT)) bit=1;
    delayMicroseconds(45);
    return bit;
}
 
// read byte
uint8_t therm_read_byte(void){
    uint8_t i=8, n=0;
    while(i--){n>>=1;n|=(therm_read_bit()<<7);}
    return n;
}
 
// write byte
void therm_write_byte(uint8_t byte){
    uint8_t i=8;
    while(i--){therm_write_bit(byte&1);byte >>= 1;
    }
}
// read temp
int read_temp(){
    uint8_t 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 (int)temper;
}

Скетч использует 946 байт (92%) памяти устройства. Всего доступно 1024 байт.
Глобальные переменные используют 3 байт (4%) динамической памяти, оставляя 61 байт для локальных переменных. Максимум: 64 байт.

#define ADDR    0x27
#define ADDR_T  0b1101000
#define SDA 3 // PB3
#define SCL 4 // PB4
#define RS      0
#define E       2
#define LED     3
 
byte led_b,init_t;
 
 
void setup() {
    lcdInit();
    i2c_write(led_b |= (1<<LED));// включаем подсветку
  //   set_time(21,2,5,11,15,47,0);// год 00-99, ДН 1-7 (1=ВС), месяц 1-12, дата 1-31, час 0-23, минуты 0-59, секунды 0-59
   delay(500);
}
 
void loop() {
   byte sec =  (ds_read(0) & 0x0F) + (((ds_read(0) & 0x70) >> 4) * 10);
   byte min =  (ds_read(1) & 0x0F) + (((ds_read(1) & 0x70) >> 4) * 10);
   byte hour = ((ds_read(2) & 0x0F) + ((ds_read(2) & 0x70) >> 4) * 10);
   byte datat = ((ds_read(4) & 0x0F) + ((ds_read(4) & 0x70) >> 4) * 10);
   byte mont = ((ds_read(5) & 0x0F) + ((ds_read(5) & 0x70) >> 4) * 10);
   byte year = ((ds_read(6) & 0x0F) + ((ds_read(6) & 0x70) >> 4) * 10);
   lcdCurs(0,4);
   lcdChar(hour/10+'0');lcdChar(hour%10+'0');lcdChar(58);
   lcdChar(min/10+'0');lcdChar(min%10+'0');lcdChar(58);
   lcdChar(sec/10+'0');lcdChar(sec%10+'0');
   lcdCurs(1,4); 
   lcdChar(datat/10+'0');lcdChar(datat%10+'0');lcdChar(45);
   lcdChar(mont/10+'0');lcdChar(mont%10+'0');lcdChar(45);
   lcdChar(year/10+'0');lcdChar(year%10+'0');
   delay(200);
}
 
void lcdSend(bool rs, byte data) {
    if(rs==0){led_b |= (1<<RS);} else {led_b &= ~(1<<RS);}//RS
 
    delay(1);
    if(((data >> 7) & 1) ==1){i2c_write(led_b |= (1<<7));} else {i2c_write(led_b &= ~(1<<7));}
    if(((data >> 6) & 1) ==1){i2c_write(led_b |= (1<<6));} else {i2c_write(led_b &= ~(1<<6));}
    if(((data >> 5) & 1) ==1){i2c_write(led_b |= (1<<5));} else {i2c_write(led_b &= ~(1<<5));}
    if(((data >> 4) & 1) ==1){i2c_write(led_b |= (1<<4));} else {i2c_write(led_b &= ~(1<<4));}
    e_pin();
    if(((data >> 3) & 1) ==1){i2c_write(led_b |= (1<<7));} else {i2c_write(led_b &= ~(1<<7));}
    if(((data >> 2) & 1) ==1){i2c_write(led_b |= (1<<6));} else {i2c_write(led_b &= ~(1<<6));}
    if(((data >> 1) & 1) ==1){i2c_write(led_b |= (1<<5));} else {i2c_write(led_b &= ~(1<<5));}
    if(((data >> 0) & 1) ==1){i2c_write(led_b |= (1<<4));} else {i2c_write(led_b &= ~(1<<4));}
    e_pin();
}
 
void lcdInit(){ 
    lcd(0x03);delay(5);
    lcd(0x03);delay(5);
    lcd(0x03);delayMicroseconds(200);
    lcd(0b00000010);delay(5);
    lcd(0b00001100);delay(5);
    lcdClear();
  } 
 
void lcdClear(){lcd(0b00000001);} 
void lcd(uint8_t sett) {lcdSend(true, sett);}
void lcdChar(const char chr) {lcdSend(false, (uint8_t)chr);}
void e_pin(){i2c_write(led_b |= (1<<E));delay(1);i2c_write(led_b &= ~(1<<E));}
 
 
void lcdCurs(byte str, byte mesto){
  if(str==0){lcd(0b10000000+mesto);}
  if(str==1){lcd(0b11000000+mesto);}
  }  
 
 
///// i2c /////////////
 
bool i2c_read_bit() {
    bool i2c_bit = 1;        
    DDRB &= ~(1 << SDA);            
  //  delayMicroseconds(10); 
    DDRB &= ~(1 << SCL);                
    if((PINB >> SDA) & 1) i2c_bit=0;                            
  //  delayMicroseconds(10);  
    DDRB |= (1 << SCL);              
    return i2c_bit;  
}
 
byte i2c_write_byte(byte data){
    for (byte i=0; i<8; i++){i2c_write_bit((data&0x80)==0);data<<=1;}    
    return i2c_read_bit(); 
}
 
byte i2c_read_byte(byte a){
    byte i, data=0;                
    for(i=0; i<8; i++){if (!i2c_read_bit()) data++;if(i!=7) data<<=1;}        
    i2c_write_bit(a);return data;  
}
 
void i2c_write_bit(byte b){
    delayMicroseconds(5);
    if(b){DDRB |= (1 << SDA);}else{DDRB &= ~(1 << SDA);}
    delayMicroseconds(5);
    DDRB &= ~(1 << SCL);       
    delayMicroseconds(10);
    DDRB |= (1 << SCL);
}
 
void i2c_start(){
     DDRB &= ~(1 << SDA); DDRB &= ~(1 << SCL);
     DDRB |= (1 << SDA);  PORTB &= ~(1 << SDA);
     DDRB |= (1 << SCL);  PORTB &= ~(1 << SCL);
}
 
void i2c_stop()  {
     DDRB |= (1 << SDA);           
     DDRB &= ~(1 << SCL);            
     DDRB &= ~(1 << SDA);           
}
 
void i2c_write(byte lcd){
     i2c_start();
     i2c_write_byte(ADDR<<1);
     i2c_write_byte(lcd);
     i2c_stop();
  }   
 
void ds_write(byte reg, byte data){
     i2c_start();
     i2c_write_byte(ADDR_T<<1);
     i2c_write_byte(reg);
     i2c_write_byte(data);
     i2c_stop();
  }  
 
byte ds_read(byte reg){
     byte dat=0;
     i2c_start();
     i2c_write_byte(ADDR_T<<1);
     i2c_write_byte(reg);
     i2c_start(); 
     i2c_write_byte((ADDR_T<<1)|1); 
     dat = i2c_read_byte(0);
     i2c_stop();
     return dat;
  }
 
void set_time(byte years, byte days, byte monts, byte datas, byte hours ,byte minute, byte second){
    ds_write(0x00,(second/10<<4)+second%10);
    ds_write(0x01,(minute/10<<4)+minute%10);
    ds_write(0x02,(hours/10<<4)+hours%10);
    ds_write(0x03,days);
    ds_write(0x04,(datas/10<<4)+datas%10);
    ds_write(0x05,(monts/10<<4)+monts%10);
    ds_write(0x06,(years/10<<4)+years%10);
  }

Скетч использует 950 байт (92%) памяти устройства. Всего доступно 1024 байт.
Глобальные переменные используют 1 байт (1%) динамической памяти, оставляя 63 байт для локальных переменных. Максимум: 64 байт.

Comments

  1. Привет. Повторил проект attiny13 lcd1602 измеритель температуры.
    Как бы от центровать значение температуры по центру экрана. А то в данный момент значения смещены в левую сторону.

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

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