前面介绍了IIC LCD1602的相关知识。这次我们就是用STC15系列的单片机来实现驱动LCD1602显示。程序中使用了单片机的两个IO口用来模拟SCL和SDA来实现IIC功能。程序中接收来自从机的ACK时,没有判断是否正常接收。对程序就不另外说明了,看注释就应该能明白。另外要说明的是,这个测试是专门为了使用芯圣HC18M003测试IIC设备做的铺垫。
/**
* IIC方式驱动LCD1602
* 使用IAP15W4K58S4
* LCD1602模块: VCC - 5V
* (PFC8547) GND
* SCL - P3.2
* SDA - P3.3
* PCF8574T LCD1602
* P7 DB7
* P6 DB6
* P5 DB5
* P4 DB4
* P3 控制背光灯
* P0 RS
* P1 RW
* P2 CS
*================================================================================
* LCD1602的操作指令 P7 P6 P5 P4 P7 P6 P5 P4 P2(CS) P1(RW) P0(RS)
* 写指令: RS=0, RW=0, CS(E)上升沿
* 写数据: RS=1, RW=0, CS(E)上升沿
*
* 显示模式设置 0 0 1 1 1 0 0 0 1 0 0 设置显示5*7点阵,8位数据接口
* 显示开关 0 0 0 0 1 D C B 1 0 0 D=1开显示,D=0关显示
* C=1显示光标,C=0关闭光标
* B=1光标闪烁,B=0光标不闪烁
* 0 0 0 0 0 1 N S N=1,读写后,自制自动加1;N=0,读写后,自制自动减1
* S=1,写一个字符,整屏左移;S=0,不左移
* 数据指针设置 80H + 地址码(0-27H(第一行),40H-67H(第二行))
*
*
*
*
* LCD1602 四线驱动方式下,一个字节数据传输2回
*
*/
#include "stc15.h"
#include "string.h"
sbit SCL=P3^2;
sbit SDA=P3^3;
void delay_ms(unsigned int ms);
void delay_10us(unsigned int i);
/**********I2C init***********/
void I2cStart(void);
void I2cStop(void);
unsigned char I2cSendByte(unsigned char dat);
void send_pfc8574Byte(unsigned char dat);
void write_lcd1602_cmd(unsigned char cmd);
void write_lcd1602_data(unsigned char dat);
void lcd_init(void);
void write_cmd(unsigned char cmd);
void write_data(unsigned char DData);
void dispaly(unsigned char X, unsigned char Y, unsigned char DData);
void dispaly_character(unsigned char X, unsigned char Y, unsigned char* Arry);
void lcd1602_write_str(unsigned char addr, unsigned char num, unsigned char *dat);
//Y为显示指针的位置,即为各行的第几个位置,X选行
//col:0-15
//row:0-1
void lcd1602_GotoXY(unsigned char row, unsigned char col);
//向LCD写入字符串
void LCD1602_Display_NoXY(unsigned char *str);
unsigned char code arry[]="successfully!";
// 读写IIC显示板的地址
#define LCD_ADDR_W 0x4E
#define LCD_ADDR_R 0x4F
// 毫秒级延时
void delay_ms(unsigned int ms) {
unsigned int i,j;
for(j=0;j<ms;j++)
for(i=0;i<1000;i++);
}
// 1o微秒单位的延时
void delay_10us(unsigned int i) {
unsigned char a,b,c;
for(c=0;c<i;c++) {
for(b=1;b>0;b--) {
for(a=2;a>0;a--);
}
}
}
// 开始信号
void I2cStart(void) {
SDA=1;
delay_10us(5);
SCL=1;
delay_10us(5);
SDA=0;
delay_10us(5);
SCL=0;
delay_10us(5);
}
// 停止信号
void I2cStop(void) {
SDA=0;
delay_10us(5);
SCL=1;
delay_10us(5);
SDA=1;
delay_10us(5);
}
// MCU模拟IIC方式发出一字节
unsigned char I2cSendByte(unsigned char dat) {
unsigned char a=0,b=0;
for(a=0;a<8;a++) {
SDA=dat>>7;
dat=dat<<1;
delay_10us(5);
SCL=1;
delay_10us(5);
SCL=0;
delay_10us(5);
}
// 等待ACK
SDA=1;
// 等待从机使ACK=0
delay_10us(5);
SCL=1;
delay_10us(5);
// 等待SDA=0
while(SDA) {
b++;
if(b>200) {
SCL=0;
delay_10us(5);
// 超时
return 0;
}
}
// 收到SDA=0
SCL=0;
delay_10us(5);
return 1;
}
// 发送一个字节给pfc8574
// 发送给LCD1602,要通过pfc8574实现,类似于74HC164那种串并转换处理
void send_pfc8574Byte(unsigned char dat) {
I2cStart();
I2cSendByte(LCD_ADDR_W); // 写器件的物理地址,读时为0x4F
I2cSendByte(dat);
I2cStop();
}
// 向LCD1602发送指令
void write_lcd1602_cmd(unsigned char cmd) {
unsigned char cmd1, cmd2;
cmd1=cmd|0x0f;
send_pfc8574Byte(cmd1 & 0xfc); // 11111100 : CS=1,RW=0, RS=0
delay_10us(1);
send_pfc8574Byte(cmd1 & 0xf8); // 11111100 : CS=0,RW=0, RS=0
cmd2=cmd<<4;
cmd2=cmd2|0x0f;
send_pfc8574Byte(cmd2 & 0xfc); // 11111100 : CS=1,RW=0, RS=0
delay_10us(1);
send_pfc8574Byte(cmd2 & 0xf8); // 11111100 : CS=0,RW=0, RS=0
}
// 向LCD1602发送数据
void write_lcd1602_data(unsigned char dat) {
unsigned char dat1, dat2;
dat1=dat|0x0f;
send_pfc8574Byte(dat1 & 0xfd); // 11111100 : CS=1,RW=0, RS=1
delay_10us(1);
send_pfc8574Byte(dat1 & 0xf9); // 11111100 : CS=0,RW=0, RS=1
dat2=dat<<4;
dat2=dat2|0x0f;
send_pfc8574Byte(dat2 & 0xfd); // 11111100 : CS=1,RW=0, RS=1
delay_10us(1);
send_pfc8574Byte(dat2 & 0xf9); // 11111100 : CS=0,RW=0, RS=1
}
// 初始化
void lcd_init(void) {
write_lcd1602_cmd(0x33); // 设置显示 4 (0x38:8)
write_lcd1602_cmd(0x32); // 设置4线控制
write_lcd1602_cmd(0x28); // 设置16*2, 5*7, 4线初始化
write_lcd1602_cmd(0x06); // 地址加1,数据不一定,地址移动
write_lcd1602_cmd(0x0C); // 不显示光标,光标不闪烁
//write_lcd1602_cmd(0x0f); // 显示光标,光标闪烁
write_lcd1602_cmd(0x01); // 清屏
write_lcd1602_cmd(0x80); // 起始地址
delay_ms(5);
}
// 使LCD1602显示字符串
void lcd1602_write_str(unsigned char addr, unsigned char num, unsigned char *dat) {
unsigned char i;
write_lcd1602_cmd(addr);
for (i=0;i<num; i++) {
write_lcd1602_data(*dat++);
}
}
//Y为显示指针的位置,即为各行的第几个位置,X选行
//col:0-15
//row:0-1
void lcd1602_GotoXY(unsigned char row, unsigned char col) {
if(row == 0)
write_lcd1602_cmd(0x80 + col);
if(row == 1)
write_lcd1602_cmd(0x80 + 0x40 + col);
}
//向LCD写入字符串
void LCD1602_Display_NoXY(unsigned char *str) {
while(*str != '\0') {
write_lcd1602_data(*str);
str++;
}
}
int main() {
// 初始化LCD1602
lcd_init();
// 循环显示固定内容,仅仅是为了测试
while(1) {
// 定位显示位置为第一行、第一列
lcd1602_GotoXY(0,0);
write_lcd1602_data('B');
// 定位显示位置为第二行、第一列
lcd1602_GotoXY(1,0);
LCD1602_Display_NoXY(arry);
delay_ms(10);
}
}显示效果如下:

我要赚赏金
