From 8dade4f9a009fe69a81d4c9d34e5999dc1853f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A7=D0=B5=D1=80?= =?UTF-8?q?=D1=82=D0=BA=D0=BE=D0=B2?= Date: Thu, 28 Sep 2023 14:26:24 +0000 Subject: [PATCH] =?UTF-8?q?=D0=97=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=B8?= =?UTF-8?q?=D0=BB(=D0=B0)=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B=20=D0=B2=20''?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lcdpcf8574.cpp | 316 ++++++++++++++++++++++++++++++++++++++++++++++ lcdpcf8574.h | 110 ++++++++++++++++ pcf8574.cpp | 115 +++++++++++++++++ pcf8574.h | 21 +++ sketch_sep19a.ino | 83 ++++++++++++ 5 files changed, 645 insertions(+) create mode 100644 lcdpcf8574.cpp create mode 100644 lcdpcf8574.h create mode 100644 pcf8574.cpp create mode 100644 pcf8574.h create mode 100644 sketch_sep19a.ino diff --git a/lcdpcf8574.cpp b/lcdpcf8574.cpp new file mode 100644 index 0000000..e0829c3 --- /dev/null +++ b/lcdpcf8574.cpp @@ -0,0 +1,316 @@ +#include "MyLCD.h" + +// задержеки через асемблер +#define lcd_e_delay() __asm__ __volatile__( "rjmp 1f\n 1:" ); +#define lcd_e_toggle() toggle_e() + + +volatile uint8_t dataport = 0; + +static void toggle_e(void); + +// сама реализация задержек +static inline void _delayFourCycles(unsigned int __count) +{ + if ( __count == 0 ) + __asm__ __volatile__( "rjmp 1f\n 1:" ); + else + __asm__ __volatile__ ( + "1: sbiw %0,1" "\n\t" + "brne 1b" + : "=w" (__count) + : "0" (__count) + ); +} + +// тупа оборачиваем функцию в макрос +#define delay(us) _delayFourCycles( ( ( 1*(F_CPU/4000) )*us)/1000 ) + +// переключение пина для начала записи команды +static void toggle_e(void) +{ + pcf8574_setoutputpinhigh(LCD_PCF8574_DEVICEID, LCD_E_PIN); + lcd_e_delay(); + pcf8574_setoutputpinlow(LCD_PCF8574_DEVICEID, LCD_E_PIN); +} + + +// отправка байта для контроллера LCD +static void lcd_write(uint8_t data,uint8_t rs) +{ + if (rs) //отправка данных (RS=1, RW=0) + dataport |= _BV(LCD_RS_PIN); + else // отпрака инструкций(RS=0, RW=0) + dataport &= ~_BV(LCD_RS_PIN); + dataport &= ~_BV(LCD_RW_PIN); + pcf8574_setoutput(LCD_PCF8574_DEVICEID, dataport); + + // отправка старшего полубайта + dataport &= ~_BV(LCD_DATA3_PIN); + dataport &= ~_BV(LCD_DATA2_PIN); + dataport &= ~_BV(LCD_DATA1_PIN); + dataport &= ~_BV(LCD_DATA0_PIN); + if(data & 0x80) dataport |= _BV(LCD_DATA3_PIN); + if(data & 0x40) dataport |= _BV(LCD_DATA2_PIN); + if(data & 0x20) dataport |= _BV(LCD_DATA1_PIN); + if(data & 0x10) dataport |= _BV(LCD_DATA0_PIN); + pcf8574_setoutput(LCD_PCF8574_DEVICEID, dataport); + lcd_e_toggle(); + + // отправка младшего полубайта + dataport &= ~_BV(LCD_DATA3_PIN); + dataport &= ~_BV(LCD_DATA2_PIN); + dataport &= ~_BV(LCD_DATA1_PIN); + dataport &= ~_BV(LCD_DATA0_PIN); + if(data & 0x08) dataport |= _BV(LCD_DATA3_PIN); + if(data & 0x04) dataport |= _BV(LCD_DATA2_PIN); + if(data & 0x02) dataport |= _BV(LCD_DATA1_PIN); + if(data & 0x01) dataport |= _BV(LCD_DATA0_PIN); + pcf8574_setoutput(LCD_PCF8574_DEVICEID, dataport); + lcd_e_toggle(); + + // завершаем передачу + dataport |= _BV(LCD_DATA0_PIN); + dataport |= _BV(LCD_DATA1_PIN); + dataport |= _BV(LCD_DATA2_PIN); + dataport |= _BV(LCD_DATA3_PIN); + pcf8574_setoutput(LCD_PCF8574_DEVICEID, dataport); +} + +// чтение байта +static uint8_t lcd_read(uint8_t rs) +{ + uint8_t data; + + if (rs) // запись данных (RS=1, RW=0) + dataport |= _BV(LCD_RS_PIN); + else // запись инструкций (RS=0, RW=0) + dataport &= ~_BV(LCD_RS_PIN); + dataport |= _BV(LCD_RW_PIN); + pcf8574_setoutput(LCD_PCF8574_DEVICEID, dataport); + + pcf8574_setoutputpinhigh(LCD_PCF8574_DEVICEID, LCD_E_PIN); + lcd_e_delay(); + // чтение страшего полубайта + data = pcf8574_getoutputpin(LCD_PCF8574_DEVICEID, LCD_DATA0_PIN) << 4; + pcf8574_setoutputpinlow(LCD_PCF8574_DEVICEID, LCD_E_PIN); + + lcd_e_delay(); + + pcf8574_setoutputpinhigh(LCD_PCF8574_DEVICEID, LCD_E_PIN); + lcd_e_delay(); + // чтение младшего полубайта + data |= pcf8574_getoutputpin(LCD_PCF8574_DEVICEID, LCD_DATA0_PIN) &0x0F; + pcf8574_setoutputpinlow(LCD_PCF8574_DEVICEID, LCD_E_PIN); + + return data; +} + +// ждем пока ЖК освободится +static uint8_t lcd_waitbusy(void) + +{ + register uint8_t c; + + // ждем + while ( (c=lcd_read(0)) & (1<= LCD_START_LINE2) && (pos < LCD_START_LINE4) ) + addressCounter = LCD_START_LINE3; + else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE2) ) + addressCounter = LCD_START_LINE4; + else + addressCounter = LCD_START_LINE1; +#endif + lcd_command((1<>4; + dataport |= _BV(LCD_DATA0_PIN); // _BV(LCD_FUNCTION_8BIT)>>4; + pcf8574_setoutput(LCD_PCF8574_DEVICEID, dataport); + + // дрючим дисплей чтобы он начал работать + lcd_e_toggle(); + delay(4992); + lcd_e_toggle(); + delay(64); + lcd_e_toggle(); + delay(64); + + // переходим в 4 битный режим + dataport &= ~_BV(LCD_DATA0_PIN); + pcf8574_setoutput(LCD_PCF8574_DEVICEID, dataport); + lcd_e_toggle(); + delay(64); + + + lcd_command(LCD_FUNCTION_DEFAULT); // настраиваем кол-во строк + lcd_command(LCD_DISP_OFF); // вырубаем дисплей + lcd_clrscr(); // чистим экран + lcd_command(LCD_MODE_DEFAULT); // запускаемся в стандартном режиме + lcd_command(dispAttr); // отправляем настройки +} diff --git a/lcdpcf8574.h b/lcdpcf8574.h new file mode 100644 index 0000000..b9059de --- /dev/null +++ b/lcdpcf8574.h @@ -0,0 +1,110 @@ +#ifndef LCD_H +#define LCD_H + +#define LCD_PCF8574_INIT 1 // pcf + +#define LCD_PCF8574_DEVICEID 0 //id - +#define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES + +// : / , / +#define LCD_ENTRY_DEC 0x04 // , +#define LCD_ENTRY_DEC_SHIFT 0x05 // , +#define LCD_ENTRY_INC_ 0x06 // , . +#define LCD_ENTRY_INC_SHIFT 0x07 // , + +// / , / , +#define LCD_DISP_OFF 0x08 // +#define LCD_DISP_ON 0x0C // , +#define LCD_DISP_ON_BLINK 0x0D // , , +#define LCD_DISP_ON_CURSOR 0x0E // , +#define LCD_DISP_ON_CURSOR_BLINK 0x0F // , , + +// / +#define LCD_MOVE_CURSOR_LEFT 0x10 // +#define LCD_MOVE_CURSOR_RIGHT 0x14 // +#define LCD_MOVE_DISP_LEFT 0x18 // +#define LCD_MOVE_DISP_RIGHT 0x1C // + +// : +#define LCD_FUNCTION_4BIT_1LINE 0x20 // 4- , , 5x7 +#define LCD_FUNCTION_4BIT_2LINES 0x28 // 4- , , 5x7 +#define LCD_FUNCTION_8BIT_1LINE 0x30 // 8- , , 5x7 +#define LCD_FUNCTION_8BIT_2LINES 0x38 // 8- , , 5x7 + +#define LCD_LINES 2 // - +#define LCD_DISP_LENGTH 16 // - +#define LCD_LINE_LENGTH 0x40 // +#define LCD_START_LINE1 0x00 // DDRM 1 +#define LCD_START_LINE2 0x40 // DDRM 2 +#define LCD_WRAP_LINES 1 // + + + +#define LCD_DATA0_PIN 4 // +#define LCD_DATA1_PIN 5 // +#define LCD_DATA2_PIN 6 // +#define LCD_DATA3_PIN 7 // +#define LCD_RS_PIN 0 // RS +#define LCD_RW_PIN 1 // RW +#define LCD_E_PIN 2 // +#define LCD_LED_PIN 3 // + + +// HD44780U. +#define LCD_CLR 0 // +#define LCD_HOME 1 // +#define LCD_ENTRY_MODE 2 // +#define LCD_ENTRY_INC 1 // +#define LCD_ENTRY_SHIFT 0 // +#define LCD_ON 3 // +#define LCD_ON_DISPLAY 2 // +#define LCD_ON_CURSOR 1 // +#define LCD_ON_BLINK 0 // +#define LCD_MOVE 4 // +#define LCD_MOVE_DISP 3 // +#define LCD_MOVE_RIGHT 2 // +#define LCD_FUNCTION 5 // +#define LCD_FUNCTION_8BIT 4 // 8 +#define LCD_FUNCTION_2LINES 3 // +#define LCD_FUNCTION_10DOTS 2 // +#define LCD_CGRAM 6 // CG RAM +#define LCD_DDRAM 7 // DD RAM +#define LCD_BUSY 7 // + +// +#define LCD_MODE_DEFAULT ((1<= 0 && deviceid < PCF8574_MAXDEVICES)) { + data = pcf8574_pinstatus[deviceid]; + } + return data; +} + +// получаем статус пинов вывода +int8_t pcf8574_getoutputpin(uint8_t deviceid, uint8_t pin) { + int8_t data = -1; + if((deviceid >= 0 && deviceid < PCF8574_MAXDEVICES) && (pin >= 0 && pin < PCF8574_MAXPINS)) { + data = pcf8574_pinstatus[deviceid]; + data = (data >> pin) & 0b00000001; + } + return data; +} + +// настройка вывода +int8_t pcf8574_setoutput(uint8_t deviceid, uint8_t data) { + if((deviceid >= 0 && deviceid < PCF8574_MAXDEVICES)) { + pcf8574_pinstatus[deviceid] = data; + i2c_start(((PCF8574_ADDRBASE+deviceid)<<1) | I2C_WRITE); + i2c_write(data); + i2c_stop(); + return 0; + } + return -1; +} + +// установить выходные контакты, заменить фактический статус устройства из pinstart для i2c +int8_t pcf8574_setoutputpins(uint8_t deviceid, uint8_t pinstart, uint8_t pinlength, int8_t data) { + if((deviceid >= 0 && deviceid < PCF8574_MAXDEVICES) && (pinstart - pinlength + 1 >= 0 && pinstart - pinlength + 1 >= 0 && pinstart < PCF8574_MAXPINS && pinstart > 0 && pinlength > 0)) { + uint8_t b = 0; + b = pcf8574_pinstatus[deviceid]; + uint8_t mask = ((1 << pinlength) - 1) << (pinstart - pinlength + 1); + data <<= (pinstart - pinlength + 1); + data &= mask; + b &= ~(mask); + b |= data; + pcf8574_pinstatus[deviceid] = b; + //рестартим + i2c_start(((PCF8574_ADDRBASE+deviceid)<<1) | I2C_WRITE); + i2c_write(b); + i2c_stop(); + return 0; + } + return -1; +} + +// настройка пинов вывода +int8_t pcf8574_setoutputpin(uint8_t deviceid, uint8_t pin, uint8_t data) { + if((deviceid >= 0 && deviceid < PCF8574_MAXDEVICES) && (pin >= 0 && pin < PCF8574_MAXPINS)) { + uint8_t b = 0; + b = pcf8574_pinstatus[deviceid]; + b = (data != 0) ? (b | (1 << pin)) : (b & ~(1 << pin)); + pcf8574_pinstatus[deviceid] = b; + //рестартим + i2c_start(((PCF8574_ADDRBASE+deviceid)<<1) | I2C_WRITE); + i2c_write(b); + i2c_stop(); + return 0; + } + return -1; +} + +// установка высокого уровня на выходных пинах +int8_t pcf8574_setoutputpinhigh(uint8_t deviceid, uint8_t pin) { + return pcf8574_setoutputpin(deviceid, pin, 1); +} + +// установка низкого уровня на выходных пинах +int8_t pcf8574_setoutputpinlow(uint8_t deviceid, uint8_t pin) { + return pcf8574_setoutputpin(deviceid, pin, 0); +} + +// получение входных данных +int8_t pcf8574_getinput(uint8_t deviceid) { + int8_t data = -1; + if((deviceid >= 0 && deviceid < PCF8574_MAXDEVICES)) { + i2c_start(((PCF8574_ADDRBASE+deviceid)<<1) | I2C_READ); + data = ~i2c_readNak(); + i2c_stop(); + } + return data; +} + +// получение входного контакта (высокий или низкий) +int8_t pcf8574_getinputpin(uint8_t deviceid, uint8_t pin) { + int8_t data = -1; + if((deviceid >= 0 && deviceid < PCF8574_MAXDEVICES) && (pin >= 0 && pin < PCF8574_MAXPINS)) { + data = pcf8574_getinput(deviceid); + if(data != -1) { + data = (data >> pin) & 0b00000001; + } + } + return data; +} \ No newline at end of file diff --git a/pcf8574.h b/pcf8574.h new file mode 100644 index 0000000..34a9439 --- /dev/null +++ b/pcf8574.h @@ -0,0 +1,21 @@ +#ifndef PCF8574_H_ +#define PCF8574_H_ + +#define PCF8574_ADDRBASE (0x27) // - + +#define PCF8574_I2CINIT 1 // i2c + +#define PCF8574_MAXDEVICES 1 // - +#define PCF8574_MAXPINS 8 // - + +void pcf8574_init(); +int8_t pcf8574_getoutput(uint8_t deviceid); +int8_t pcf8574_getoutputpin(uint8_t deviceid, uint8_t pin); +int8_t pcf8574_setoutput(uint8_t deviceid, uint8_t data); +int8_t pcf8574_setoutputpins(uint8_t deviceid, uint8_t pinstart, uint8_t pinlength, int8_t data); +int8_t pcf8574_setoutputpin(uint8_t deviceid, uint8_t pin, uint8_t data); +int8_t pcf8574_setoutputpinhigh(uint8_t deviceid, uint8_t pin); +int8_t pcf8574_setoutputpinlow(uint8_t deviceid, uint8_t pin); +int8_t pcf8574_getinput(uint8_t deviceid); +int8_t pcf8574_getinputpin(uint8_t deviceid, uint8_t pin); +#endif diff --git a/sketch_sep19a.ino b/sketch_sep19a.ino new file mode 100644 index 0000000..2816b91 --- /dev/null +++ b/sketch_sep19a.ino @@ -0,0 +1,83 @@ +#include "MyLCD.h" + +struct DisplayData { + char topLine[64]; + int value1; + int value2; + int value3; +}; + +struct TextCounter { + unsigned long startTime; + int incrementValue; +}; + +TextCounter textCounter; + +void setup() { + lcd_init(LCD_DISP_ON_BLINK); // инициализация дисплея + lcd_home(); // домой курсор + lcd_led(0); // вкл подсветки + textCounter.startTime = millis(); // Запоминаем время запуска программы +} + +void loop() { + unsigned long currentTime = millis(); // Текущее время + // Проверяем, прошло ли 500 мс с момента последнего увеличения incrementValue + if (currentTime - textCounter.startTime >= 500) { + textCounter.incrementValue++; // Увеличиваем incrementValue на 1 + textCounter.startTime = currentTime; // Обновляем время + } + + DisplayData displayData; + strncpy(displayData.topLine, "we are responsible for those who have been tame ", sizeof(displayData.topLine) - 1); + displayData.topLine[sizeof(displayData.topLine) - 1] = '\0'; + displayData.value1 = 500; + displayData.value2 = 800; + displayData.value3 = 855; + + // Буферы для заполнения данных + char buffer1[17]; + char buffer2[17]; + + // Заполнение буфера 1 + fillBuffer1(displayData.topLine, buffer1, sizeof(buffer1), textCounter.incrementValue); + + // Заполнение буфера 2 + fillBuffer2(displayData.value1, displayData.value2, displayData.value3, buffer2, sizeof(buffer2)); + + // Создание массива для вывода на дисплей + char displayArray[32]; + strncpy(displayArray, buffer1, 16); // Копирование первых 16 символов из buffer1 в displayArray + strncpy(displayArray + 16, buffer2, 16); // Копирование первых 16 символов из buffer2 в displayArray, начиная с позиции 16 + + // Вывод данных на экран + lcd_gotoxy(0, 0); + lcd_puts(displayArray); + + lcd_gotoxy(0, 1); + lcd_puts(displayArray + 16); // Вывод второй половины displayArray +} + +void fillBuffer1(const char* source, char* buffer, size_t bufferSize, int incrementValue) { + int startIndex = incrementValue % strlen(source); // Определяем начальный индекс на основе incrementValue + int endIndex = startIndex + 16; + + if (endIndex > strlen(source)) { + // Если endIndex превышает длину строки source, переносим его на начало строки + endIndex = endIndex - strlen(source); + + // Копируем символы с конца строки source + strncpy(buffer, source + startIndex, strlen(source) - startIndex); + + // Копируем оставшиеся символы с начала строки source + strncat(buffer, source, endIndex); + } else { + strncpy(buffer, source + startIndex, endIndex - startIndex); + } + buffer[endIndex - startIndex] = '\0'; // Установка нулевого символа в конце буфера +} + +void fillBuffer2(int value1, int value2, int value3, char* buffer, size_t bufferSize) { + snprintf(buffer, bufferSize, "%d.%d.%d", value1, value2, value3); +}