#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wiringPi.h>
// 定义LCD1602的相关指令
#define LCD_CMD_CLEAR_DISPLAY 0x01
#define LCD_CMD_RETURN_HOME 0x02
#define LCD_CMD_FUNCTION_SET 0x20
#define LCD_CMD_DISPLAY_CONTROL 0x08
#define LCD_CMD_ENTRY_MODE_SET 0x04
#define LCD_CMD_SET_CGRAM_ADDR 0x40
#define LCD_CMD_SET_DDRAM_ADDR 0x80
// 定义LCD1602的相关地址
#define LCD_ADDR_COMMAND 0x00
#define LCD_ADDR_DATA 0x01
// 定义GPIO口的编号
#define PIN_RS 0
#define PIN_RW 1
#define PIN_E 2
#define PIN_D4 3
#define PIN_D5 4
#define PIN_D6 5
#define PIN_D7 6
// 函数声明
void lcd_send_cmd(unsigned char cmd);
void lcd_send_data(unsigned char data);
void lcd_init();
void lcd_display_preset_character();
void lcd_display_custom_character();
int main() {
// 初始化wiringPi库
wiringPiSetup();
// 设置GPIO口的模式为输出
pinMode(PIN_RS, OUTPUT);
pinMode(PIN_RW, OUTPUT);
pinMode(PIN_E, OUTPUT);
pinMode(PIN_D4, OUTPUT);
pinMode(PIN_D5, OUTPUT);
pinMode(PIN_D6, OUTPUT);
pinMode(PIN_D7, OUTPUT);
lcd_init();
lcd_display_preset_character();
lcd_display_custom_character();
return 0;
}
// 发送命令到LCD1602
void lcd_send_cmd(unsigned char cmd) {
digitalWrite(PIN_RS, 0); // 设置RS为0,表示发送的是命令
digitalWrite(PIN_RW, 0); // 设置RW为0,表示写入数据
// 发送高4位数据
digitalWrite(PIN_D4, (cmd >> 4) & 0x01);
digitalWrite(PIN_D5, (cmd >> 5) & 0x01);
digitalWrite(PIN_D6, (cmd >> 6) & 0x01);
digitalWrite(PIN_D7, (cmd >> 7) & 0x01);
// 拉高E,使LCD1602读取数据
digitalWrite(PIN_E, 1);
delayMicroseconds(1);
// 拉低E,完成一次数据传输
digitalWrite(PIN_E, 0);
delayMicroseconds(1);
// 发送低4位数据
digitalWrite(PIN_D4, cmd & 0x01);
digitalWrite(PIN_D5, (cmd >> 1) & 0x01);
digitalWrite(PIN_D6, (cmd >> 2) & 0x01);
digitalWrite(PIN_D7, (cmd >> 3) & 0x01);
// 拉高E,使LCD1602读取数据
digitalWrite(PIN_E, 1);
delayMicroseconds(1);
// 拉低E,完成一次数据传输
digitalWrite(PIN_E, 0);
delayMicroseconds(1);
}
// 发送数据到LCD1602
void lcd_send_data(unsigned char data) {
digitalWrite(PIN_RS, 1); // 设置RS为1,表示发送的是数据
digitalWrite(PIN_RW, 0); // 设置RW为0,表示写入数据
// 发送高4位数据
digitalWrite(PIN_D4, (data >> 4) & 0x01);
digitalWrite(PIN_D5, (data >> 5) & 0x01);
digitalWrite(PIN_D6, (data >> 6) & 0x01);
digitalWrite(PIN_D7, (data >> 7) & 0x01);
// 拉高E,使LCD1602读取数据
digitalWrite(PIN_E, 1);
delayMicroseconds(1);
// 拉低E,完成一次数据传输
digitalWrite(PIN_E, 0);
delayMicroseconds(1);
// 发送低4位数据
digitalWrite(PIN_D4, data & 0x01);
digitalWrite(PIN_D5, (data >> 1) & 0x01);
digitalWrite(PIN_D6, (data >> 2) & 0x01);
digitalWrite(PIN_D7, (data >> 3) & 0x01);
// 拉高E,使LCD1602读取数据
digitalWrite(PIN_E, 1);
delayMicroseconds(1);
// 拉低E,完成一次数据传输
digitalWrite(PIN_E, 0);
delayMicroseconds(1);
}
// 初始化LCD1602
void lcd_init() {
delay(50); // 等待LCD1602上电稳定
// 发送初始化指令到LCD1602
lcd_send_cmd(0x30);
delay(5);
lcd_send_cmd(0x30);
delay(1);
lcd_send_cmd(0x30);
delay(1);
// 设置显示模式为2行,5x8点阵
lcd_send_cmd(LCD_CMD_FUNCTION_SET | 0x08);
delay(1);
// 设置光标不闪烁,不显示
lcd_send_cmd(LCD_CMD_DISPLAY_CONTROL | 0x04);
delay(1);
// 设置文字从左向右滚动
lcd_send_cmd(LCD_CMD_ENTRY_MODE_SET | 0x02);
delay(1);
// 清屏
lcd_send_cmd(LCD_CMD_CLEAR_DISPLAY);
delay(2);
}
// 显示预设字符
void lcd_display_preset_character() {
// 设置DDRAM地址为0x00,即第一行第一列
lcd_send_cmd(LCD_CMD_SET_DDRAM_ADDR | 0x00);
// 显示预设字符的代码
// 例如,显示ASCII码为65的字符'A'
lcd_send_data(65);
}
// 显示自定义字符
void lcd_display_custom_character() {
// 设置DDRAM地址为0x40,即第二行第一列
lcd_send_cmd(LCD_CMD_SET_DDRAM_ADDR | 0x40);
// 定义自定义字符模式
unsigned char custom_character[8] = {
0b00000,
0b01010,
0b00100,
0b11111,
0b00100,
0b00100,
0b00100,
0b00000
};
// 将自定义字符模式写入CGRAM
lcd_send_cmd(LCD_CMD_SET_CGRAM_ADDR);
for (int i = 0; i < 8; i++) {
lcd_send_data(custom_character[i]);
}
// 设置DDRAM地址为0x41,即第二行第二列
lcd_send_cmd(LCD_CMD_SET_DDRAM_ADDR | 0x41);
// 显示自定义字符
lcd_send_data(0x00); // 使用CGRAM中的第一个自定义字符
// 可以继续设置其他位置的自定义字符
// ...
}
在LCD1602中,预设字符是存储在CGROM(Character Generator ROM)中的,每个字符占用5x8的像素点阵。当我们调用lcd_send_data(65)时,实际上是将ASCII码为65的字符'A'的对应编码(即CGROM中的地址)发送给LCD1602。
LCD1602的内部控制器会根据这个编码从CGROM中读取对应的像素点阵,并在屏幕上显示出来。因此,预设字符的显示是由LCD1602的内部控制器完成的,而不是由我们的代码直接控制的。
对于自定义字符,LCD1602的内部控制器并不会直接从CGRAM中读取字符的像素点阵。相反,我们需要通过将自定义字符的编码(即CGRAM中的地址)发送给LCD1602,让它在屏幕上显示出来。
具体来说,当我们调用lcd_send_data(0x00)时,实际上是将CGRAM中的第一个自定义字符的对应编码发送给LCD1602。LCD1602的内部控制器会根据这个编码从CGRAM中读取对应的像素点阵,并在屏幕上显示出来。
在上面的代码示例中,我们通过调用lcd_send_cmd(LCD_CMD_SET_CGRAM_ADDR)将CGRAM的地址设置为写入模式,然后通过循环将自定义字符的像素数据写入CGRAM。最后,我们调用lcd_send_data(0x00)来显示CGRAM中的第一个自定义字符。
需要注意的是,LCD1602的CGRAM共有8个字符的存储空间,每个字符占用5x8的像素点阵。因此,我们可以定义最多8个不同的自定义字符,并通过设置不同的CGRAM地址来显示它们。