| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <linux/i2c-dev.h>
- #include "lcd_2002a08f.h"
- static int i2c_fd = -1;
- static uint8_t i2c_addr;
- /* 延时函数 - 数据手册建议指令间延时1ms以上 */
- static void lcd_delay_ms(int ms)
- {
- usleep(ms * 1000);
- }
- /* I2C写数据 */
- static int i2c_write(uint8_t *data, int len)
- {
- if (i2c_fd < 0) {
- return -1;
- }
-
- if (write(i2c_fd, data, len) != len) {
- perror("I2C write failed");
- return -1;
- }
- return 0;
- }
- /* 发送指令到LCD - 根据数据手册第7-8页的两线串行通讯格式 */
- static int lcd_send_command(uint8_t cmd)
- {
- uint8_t buf[3];
-
- /* 控制字节: Co=0, RS=0 (指令) */
- buf[0] = LCD_CONTROL_BYTE; /* 0x00 */
- buf[1] = cmd;
-
- if (i2c_write(buf, 2) < 0) {
- return -1;
- }
-
- lcd_delay_ms(2); /* 指令执行时间,数据手册建议1ms以上 */
- return 0;
- }
- /* 发送数据到LCD */
- static int lcd_send_data(uint8_t data)
- {
- uint8_t buf[3];
-
- /* 控制字节: Co=0, RS=1 (数据) */
- buf[0] = LCD_DATA_BYTE; /* 0x40 */
- buf[1] = data;
-
- if (i2c_write(buf, 2) < 0) {
- return -1;
- }
-
- lcd_delay_ms(1);
- return 0;
- }
- /* 初始化LCD - 根据数据手册的初始化流程 */
- int lcd_init(const char *i2c_bus, uint8_t addr)
- {
- i2c_addr = addr;
-
- /* 打开I2C设备 */
- i2c_fd = open(i2c_bus, O_RDWR);
- if (i2c_fd < 0) {
- perror("Failed to open I2C bus");
- return -1;
- }
-
- /* 设置I2C从机地址 */
- if (ioctl(i2c_fd, I2C_SLAVE, i2c_addr) < 0) {
- perror("Failed to set I2C address");
- close(i2c_fd);
- i2c_fd = -1;
- return -1;
- }
-
- /* 初始化延时 - 上电后需要等待 */
- lcd_delay_ms(50);
-
- /* 功能设置: 2行显示,5x7点阵 */
- /* 指令码: 0010 NFxx, N=1(2行), F=0(5x7) -> 0x28 */
- lcd_send_command(LCD_FUNCTION_SET | LCD_2LINE | LCD_5x8DOTS);
- lcd_delay_ms(5);
-
- /* 显示开/关控制: 显示开,光标关,闪烁关 */
- /* 指令码: 0000 1DCB, D=1, C=0, B=0 -> 0x0C */
- lcd_send_command(LCD_DISPLAY_CONTROL | LCD_DISPLAY_ON | LCD_CURSOR_OFF | LCD_BLINK_OFF);
-
- /* 清显示 */
- lcd_clear();
-
- /* 设置输入模式: 光标右移,显示不移位 */
- /* 指令码: 0000 01IS, I/D=1, S=0 -> 0x06 */
- lcd_send_command(LCD_ENTRY_MODE_SET | LCD_ENTRY_RIGHT | LCD_ENTRY_SHIFT_OFF);
-
- return 0;
- }
- /* 关闭LCD */
- void lcd_close(void)
- {
- if (i2c_fd >= 0) {
- /* 关闭显示 */
- lcd_send_command(LCD_DISPLAY_CONTROL | LCD_DISPLAY_OFF);
- close(i2c_fd);
- i2c_fd = -1;
- }
- }
- /* 清显示 - 指令码0x01 */
- int lcd_clear(void)
- {
- int ret = lcd_send_command(LCD_CLEAR_DISPLAY);
- lcd_delay_ms(2); /* 清显示需要1.52ms */
- return ret;
- }
- /* 归位 - 指令码0x02 */
- int lcd_home(void)
- {
- int ret = lcd_send_command(LCD_RETURN_HOME);
- lcd_delay_ms(2); /* 归位需要1.52ms */
- return ret;
- }
- /* 显示控制 */
- int lcd_display_control(uint8_t display, uint8_t cursor, uint8_t blink)
- {
- uint8_t cmd = LCD_DISPLAY_CONTROL | display | cursor | blink;
- return lcd_send_command(cmd);
- }
- /* 设置输入模式 */
- int lcd_entry_mode(uint8_t id, uint8_t shift)
- {
- uint8_t cmd = LCD_ENTRY_MODE_SET | id | shift;
- return lcd_send_command(cmd);
- }
- /* 设置光标位置 - 根据数据手册第16页DDRAM地址 */
- int lcd_set_cursor(uint8_t col, uint8_t row)
- {
- uint8_t addr;
-
- if (col >= LCD_COLS || row >= LCD_ROWS) {
- return -1;
- }
-
- /* 计算DDRAM地址 */
- if (row == 0) {
- addr = LCD_LINE1_ADDR + col; /* 第一行: 0x00-0x27 */
- } else {
- addr = LCD_LINE2_ADDR + col; /* 第二行: 0x40-0x67 */
- }
-
- return lcd_send_command(LCD_SET_DDRAM_ADDR | addr);
- }
- /* 写单个字符 */
- int lcd_write_char(char c)
- {
- return lcd_send_data((uint8_t)c);
- }
- /* 写字符串 */
- int lcd_write_string(const char *str)
- {
- while (*str) {
- if (lcd_write_char(*str++) < 0) {
- return -1;
- }
- }
- return 0;
- }
- /* 写入自定义字符到CGRAM - 根据数据手册第12页 */
- /* num: 0-7 (最多8个自定义字符) */
- /* data: 5x8点阵数据,8字节(每行5位有效) */
- int lcd_write_custom_char(uint8_t num, uint8_t *data)
- {
- uint8_t addr;
- int i;
-
- if (num > 7) {
- return -1;
- }
-
- /* 设置CGRAM地址 - 每个字符占8字节 */
- /* CGRAM地址: 0x01 ACG5-ACG0, 字符0地址=0x00, 字符1地址=0x08, ... */
- addr = num * 8;
- lcd_send_command(LCD_SET_CGRAM_ADDR | addr);
-
- /* 写入8行点阵数据 */
- for (i = 0; i < 8; i++) {
- /* 数据D4-D0有效,D7-D5必须为0 */
- lcd_send_data(data[i] & 0x1F);
- }
-
- return 0;
- }
- /* 显示自定义字符 */
- int lcd_show_custom_char(uint8_t num)
- {
- if (num > 7) {
- return -1;
- }
- /* 自定义字符的字符码为0x00-0x07 */
- return lcd_write_char(num);
- }
- /* 移位显示 */
- int lcd_shift_display(uint8_t direction)
- {
- uint8_t cmd = LCD_CURSOR_SHIFT | LCD_DISPLAY_MOVE | direction;
- return lcd_send_command(cmd);
- }
- /* 移位光标 */
- int lcd_shift_cursor(uint8_t direction)
- {
- uint8_t cmd = LCD_CURSOR_SHIFT | LCD_CURSOR_MOVE | direction;
- return lcd_send_command(cmd);
- }
- /* 使用DDRAM地址设置清除行 - 更高效 */
- int lcd_clear_line_fast(uint8_t row)
- {
- uint8_t addr;
- int i;
-
- if (row >= LCD_ROWS) {
- return -1;
- }
-
- /* 计算起始地址 */
- addr = (row == 0) ? LCD_LINE1_ADDR : LCD_LINE2_ADDR;
-
- /* 设置DDRAM地址 */
- lcd_send_command(LCD_SET_DDRAM_ADDR | addr);
-
- /* 连续写入20个空格(空位字符码0x20) */
- for (i = 0; i < LCD_COLS; i++) {
- lcd_send_data(0x20); /* 空格字符 */
- }
-
- return 0;
- }
|