前面介绍了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); } }
显示效果如下: