ejsanyo
Active member
Предлагаю делиться здесь своими наработками.
Начнём с простого: библиотека для текстового LCD-экрана, совместимого с HD44780, или как их довольно часто называют, "1602". Впрочем, при небольшой модификации, её можно приспособить и для других разрешений, вроде 20x4. Она используется, конечно же, в этом изделии, а вообще, в той или иной форме много где у меня.
В данном случае, прикрутил я экран на порт P1 через двунаправленный преобразователь уровней, но вот, например, мой коллега просто сажает экран сразу на 3,3В выходы, и у него и так всё работает. Кроме того, бывают экраны и с нативным 3,3В питанием. Такие точно есть у МЭЛТ-а, например.
Линии P1.0...P1.3 передают данные, P1.4...P1.7 - управление. И ещё бит остаётся, которым через ключ можно, например, подёргать подсветкой. Так что, вначале, настроим их:
Также не забудте настроить таймер ядра, он нам понадобится:
После чего можно будет сделать:
И пользоваться остальными функциями. А вот и библиотека:
Конечно, чтобы печатать на экране float-ы, придётся использовать последнюю версию xprintf!
Как известно, HD44780 в дополнение ко встроенному шрифту позволяет загрузить до 8 пользовательских символов. Это, в частности, позволяет хотя бы частично русифицировать какой-нибудь дешёвый дисплей с Алиэкспресса, который изначально умеет говорить только по английски и покетайски японски. Для этого у нас есть функция LCD_upload(). Вот пример такой "частичной русификации":
Начнём с простого: библиотека для текстового LCD-экрана, совместимого с HD44780, или как их довольно часто называют, "1602". Впрочем, при небольшой модификации, её можно приспособить и для других разрешений, вроде 20x4. Она используется, конечно же, в этом изделии, а вообще, в той или иной форме много где у меня.
В данном случае, прикрутил я экран на порт P1 через двунаправленный преобразователь уровней, но вот, например, мой коллега просто сажает экран сразу на 3,3В выходы, и у него и так всё работает. Кроме того, бывают экраны и с нативным 3,3В питанием. Такие точно есть у МЭЛТ-а, например.
Линии P1.0...P1.3 передают данные, P1.4...P1.7 - управление. И ещё бит остаётся, которым через ключ можно, например, подёргать подсветкой. Так что, вначале, настроим их:
C:
//main.c
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3; //ноги данных для LCD-экрана
GPIO_InitStruct.Mode = HAL_GPIO_MODE_GPIO_INPUT;
GPIO_InitStruct.Pull = HAL_GPIO_PULL_UP;
GPIO_InitStruct.DS = HAL_GPIO_DS_8MA;
HAL_GPIO_Init(GPIO_1, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7; //ноги управления для LCD-экрана
GPIO_InitStruct.Mode = HAL_GPIO_MODE_GPIO_OUTPUT;
GPIO_InitStruct.Pull = HAL_GPIO_PULL_NONE;
GPIO_InitStruct.DS = HAL_GPIO_DS_8MA;
HAL_GPIO_Init(GPIO_1, &GPIO_InitStruct);
C:
//main.c
//чтобы работать с функциями delay
SCR1_TIMER_HandleTypeDef hscr1_timer;
hscr1_timer.Instance = SCR1_TIMER;
hscr1_timer.ClockSource = SCR1_TIMER_CLKSRC_INTERNAL;
hscr1_timer.Divider = 0; //без деления частоты
HAL_SCR1_Timer_Init(&hscr1_timer);
C:
//main.c
LCD_init();
C:
/*
LCD.c
Библиотека для работы с ЖК-дисплеем
на HD44780-совместимом контроллере
в 4-битном режиме
*/
#include "mik32_hal_gpio.h"
#include "xprintf.h"
#include "mik32_hal_scr1_timer.h"
#include "LCD.h"
//#include "LCD_Rus.h"
#define __NOP() __asm volatile ("ADDI x0, x0, 0")
#define wait_busy() while (LCD_busy() == GPIO_PIN_HIGH) __NOP()
//чтобы выбирать регистр команд или данных в контроллере LCD
typedef enum
{
COMMAND_REG,
DATA_REG
} LCD_reg;
extern SCR1_TIMER_HandleTypeDef hscr1_timer;
//буфер для вывода цифр текстом
uint8_t PrintBuf[xmax + 1];
//софтовая задержка на несколько команд
void nano_delay(void)
{
__NOP();
__NOP();
__NOP();
__NOP();
__NOP();
__NOP();
__NOP();
}
//записывает полубайт по 4-битному интерфейсу
void LCD_write_4bit(uint8_t dat)
{
uint32_t tmp;
tmp = data_port->OUTPUT & 0xFFFFFFF0;
data_port->OUTPUT = tmp | (dat & 0x0F);
data_port->DIRECTION_OUT = 0x0F; //временно делаем ноги выходами
HAL_GPIO_WritePin(control_port, E_port, GPIO_PIN_HIGH);
nano_delay();
HAL_GPIO_WritePin(control_port, E_port, GPIO_PIN_LOW);
nano_delay();
data_port->DIRECTION_IN = 0x0F;
}
//записывает байт в интерфейс
//второй параметр = регистр команд / регистр данных
void LCD_write(uint8_t dat, LCD_reg reg)
{
if (reg == DATA_REG)
HAL_GPIO_WritePin(control_port, RS_port, GPIO_PIN_HIGH);
else
HAL_GPIO_WritePin(control_port, RS_port, GPIO_PIN_LOW);
HAL_GPIO_WritePin(control_port, RW_port, GPIO_PIN_LOW);
LCD_write_4bit(dat >> 4);
LCD_write_4bit(dat);
}
//читаем состояние бита занятости
GPIO_PinState LCD_busy(void)
{
GPIO_PinState tmp;
HAL_GPIO_WritePin(control_port, RS_port, GPIO_PIN_LOW);
HAL_GPIO_WritePin(control_port, RW_port, GPIO_PIN_HIGH);
HAL_GPIO_WritePin(control_port, E_port, GPIO_PIN_HIGH);
nano_delay();
tmp = HAL_GPIO_ReadPin(data_port, ready_pin);
HAL_GPIO_WritePin(control_port, E_port, GPIO_PIN_LOW);
nano_delay();
HAL_GPIO_WritePin(control_port, E_port, GPIO_PIN_HIGH);
nano_delay();
HAL_GPIO_WritePin(control_port, E_port, GPIO_PIN_LOW);
nano_delay();
return tmp;
}
//полная очистка экрана
void LCD_clear(void)
{
LCD_write(0x01, COMMAND_REG);
wait_busy();
}
//поставить курсор в определённую позицию
void LCD_goto(uint8_t x, uint8_t y)
{
if ((x <= xmax) & (y <= ymax))
{
switch (y)
{
case 1:
x += 0x40;
break;
case 2:
x += 0x14;
break;
case 3:
x += 0x54;
break;
}
x |= 0x80; //дополняем до команды
LCD_write(x, COMMAND_REG);
wait_busy();
}
}
//вывести один символ
void LCD_putchar(uint8_t dat)
{
if (dat == '\n')
LCD_goto(0, 1);
else
{
LCD_write(dat, DATA_REG);
wait_busy();
}
}
//вывести строку символов
//заканчивающуюся "нуль-терминатором"
void LCD_puts(uint8_t *s)
{
while (*s)
{
LCD_putchar(*s);
s++;
}
}
//вывести 32-битную переменную на экран
//в 16-ричном виде
void LCD_puthex(uint32_t a)
{
xsprintf(PrintBuf, "0x%08X", a);
LCD_puts(PrintBuf);
}
//вывести float на экран
void LCD_putfloat(float a)
{
xsprintf(PrintBuf, "%7.3f", a);
LCD_puts(PrintBuf);
}
//загружает из массива юзерские символы в CGRAM
//длина массива должна быть 64 байта!
void LCD_upload(const uint8_t *UserChars)
{
uint8_t i;
//устанавливаем указатель на начало CGRAM
LCD_write(0x40, COMMAND_REG);
wait_busy();
//заливаем массив
for (i = 0; i < 0x40; i++)
{
LCD_write(*UserChars, DATA_REG);
wait_busy();
UserChars++;
}
}
//начальные настройки ног контроллера и режима дисплея
void LCD_init(void)
{
//выставляем ноги в изначальные состояния
HAL_GPIO_WritePin(control_port, RS_port, GPIO_PIN_LOW);
HAL_GPIO_WritePin(control_port, RW_port, GPIO_PIN_LOW);
HAL_GPIO_WritePin(control_port, E_port, GPIO_PIN_LOW);
HAL_DelayMs(&hscr1_timer, 20);
//настраиваем разрядность интерфейса
LCD_write_4bit(0x03);
HAL_DelayMs(&hscr1_timer, 1);
LCD_write_4bit(0x03);
HAL_DelayMs(&hscr1_timer, 1);
LCD_write_4bit(0x03);
HAL_DelayMs(&hscr1_timer, 1);
LCD_write_4bit(0x02);
HAL_DelayMs(&hscr1_timer, 1);
LCD_write(0x28, COMMAND_REG);
wait_busy();
//настройка параметров
LCD_write(0x06, COMMAND_REG);
wait_busy();
/*
//заливаем юзерские символы
LCD_upload(__cgram);
*/
//чистим экран
LCD_clear();
//вкл. дисплей
LCD_write(0x0C, COMMAND_REG);
wait_busy();
}
//Вкл/выкл подсветку
void LCD_BL(uint8_t a)
{
if (a)
HAL_GPIO_WritePin(control_port, BL_port, GPIO_PIN_HIGH);
else
HAL_GPIO_WritePin(control_port, BL_port, GPIO_PIN_LOW);
}
C:
//LCD.h
//ноги для ЖК дисплея
#define RS_port GPIO_PIN_4
#define RW_port GPIO_PIN_5
#define E_port GPIO_PIN_6
#define data_port GPIO_1
#define control_port GPIO_1
#define ready_pin GPIO_PIN_3
//подсветка
#define BL_port GPIO_PIN_7
//максимальные позиции курсора
#define xmax 15
#define ymax 1
void LCD_init(void);
void LCD_clear(void);
void LCD_goto(uint8_t x, uint8_t y);
void LCD_putchar(uint8_t dat);
void LCD_puts(uint8_t *s);
void LCD_puthex(uint32_t a);
void LCD_putfloat(float a);
void LCD_BL(uint8_t a);
Как известно, HD44780 в дополнение ко встроенному шрифту позволяет загрузить до 8 пользовательских символов. Это, в частности, позволяет хотя бы частично русифицировать какой-нибудь дешёвый дисплей с Алиэкспресса, который изначально умеет говорить только по английски и по
C:
//LCD_Rus.h
const uint8_t __cgram[]=
{
0x1F, 0x10, 0x1E, 0x11, 0x11, 0x11, 0x1E, 0x00, //Char 0x08 'Б'
0x06, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x1F, 0x11, //Char 0x09 'Д'
0x15, 0x15, 0x15, 0x0E, 0x15, 0x15, 0x15, 0x00, //Char 0x0A 'Ж'
0x11, 0x11, 0x13, 0x15, 0x19, 0x11, 0x11, 0x00, //Char 0x0B 'И'
0x07, 0x09, 0x09, 0x09, 0x09, 0x09, 0x11, 0x00, //Char 0x0C 'Л'
0x1F, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, //Char 0x0D 'П'
0x11, 0x11, 0x11, 0x19, 0x15, 0x15, 0x19, 0x00, //Char 0x0E 'Ы'
0x0F, 0x11, 0x11, 0x0F, 0x05, 0x09, 0x11, 0x00, //Char 0x0F 'Я'
};
Последнее редактирование: