Микроконтроллер 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 байт.
Привет. Повторил проект attiny13 lcd1602 измеритель температуры.
Как бы от центровать значение температуры по центру экрана. А то в данный момент значения смещены в левую сторону.
Используйте функции:
lcdCurs(0,3);
lcdCurs(1,3);
аналог lcd.cursor(3,0);