#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
/* Получаем устройство PCF8574 напрямую по метке из devicetree */
static const struct device *pcf_dev = DEVICE_DT_GET(DT_NODELABEL(pcf8574));
/* Маски для управления ножками согласно вашей распиновке */
#define LCD_RS (1 << 0) // Port 0
#define LCD_RW (1 << 1) // Port 1
#define LCD_E (1 << 2) // Port 2
#define LCD_BL (1 << 3) // Port 3 (Backlight)
#define LCD_DATA_MASK 0xF0 // Port 4-7 (D4-D7)
/* Глобальная переменная состояния подсветки */
static uint8_t backlight_state = LCD_BL;
/* Функция передачи 4 бит (полубайта) */
void lcd_send_nibble(uint8_t nibble, uint8_t rs_flag)
{
// Формируем байт: старшие 4 бита - данные, младшие - управление и подсветка
uint8_t port_val = (nibble << 4) | rs_flag | backlight_state;
// RW всегда держим в 0 (режим записи)
port_val &= ~LCD_RW;
// 1. Выставляем данные и RS, линию E держим в 0
gpio_port_set_masked_raw(pcf_dev, 0xFF, port_val);
k_busy_wait(1);
// 2. Импульс Enable (E = 1) для фиксации данных дисплеем
gpio_port_set_masked_raw(pcf_dev, 0xFF, port_val | LCD_E);
k_busy_wait(1); // Длина импульса строба > 450 нс
// 3. Сброс Enable (E = 0)
gpio_port_set_masked_raw(pcf_dev, 0xFF, port_val);
k_busy_wait(50); // Пауза для обработки команды дисплеем
}
/* Функция передачи полноценного байта (по 4 бита) */
void lcd_send_byte(uint8_t value, uint8_t rs_flag)
{
lcd_send_nibble(value >> 4, rs_flag); // Старший полубайт
lcd_send_nibble(value & 0x0F, rs_flag); // Младший полубайт
}
void lcd_command(uint8_t cmd) { lcd_send_byte(cmd, 0); }
void lcd_data(uint8_t data) { lcd_send_byte(data, LCD_RS); }
/* Функция инициализации дисплея 1602A в 4-битном режиме */
void lcd_init(void)
{
k_msleep(50); // Ждем стабилизации питания дисплея после включения
// Перевод контроллера HD44780 в 4-битный режим (особая процедура)
lcd_send_nibble(0x03, 0);
k_msleep(5);
lcd_send_nibble(0x03, 0);
k_busy_wait(150);
lcd_send_nibble(0x03, 0);
k_busy_wait(150);
lcd_send_nibble(0x02, 0); // Окончательный переход на 4 бита
k_msleep(2);
// Настройка параметров дисплея
lcd_command(0x28); // 4-битный режим, 2 строки, шрифт 5x8
lcd_command(0x0C); // Включить дисплей, курсор выключен, мигание выключено
lcd_command(0x06); // Автоинкремент курсора при печати
lcd_command(0x01); // Очистка дисплея
k_msleep(2); // Длинная пауза после очистки
}
/* Функция позиционирования курсора */
void lcd_set_cursor(uint8_t col, uint8_t row)
{
uint8_t row_offsets[] = {0x00, 0x40};
lcd_command(0x80 | (col + row_offsets[row]));
}
/* Функция печати строки */
void lcd_print(const char *str)
{
while (*str) {
lcd_data(*str++);
}
}