标题: 单片机加个PCF8574模块,实现IIC方式驱动LCD1602 [打印本页]

作者: lmn2005    时间: 2019-3-4 18:51
标题: 单片机加个PCF8574模块,实现IIC方式驱动LCD1602
PCF8574模块使实现IIC驱动LCD1602成为现实。

下图是PCF8574模块与1602的连接电路图:

实物接法如下:
想要使用PCF8574模块来实现IIC驱动LCD1602,首先非常必要弄清楚IIC的时序、PCF8574设备地址、四线控制LCD1602方法。
下面是两个重要的h文件。通过修改这两个h文件中的部分代码(接线有所不同)即可移植到你的程序中去。

单片机源程序如下:
  1. void delay1(uchar x)
  2. {
  3.         uchar a,b;
  4.         for(a=x;a>0;a--)
  5.          for(b=200;b>0;b--);
  6. }

  7. void write_com(uchar com)                //写命令函数
  8. {        uchar com1,com2;
  9.         com1=com|0x0f;
  10.         write_add(com1&0xfc);
  11.         delay1(2);
  12.     write_add(com1&0xf8);
  13.         com2=com<<4;
  14.         com2=com2|0x0f;
  15.         write_add(com2&0xfc);
  16.         delay1(2);
  17.     write_add(com2&0xf8);
  18.        
  19. }

  20. void write_date(uchar date)                //写数据函数
  21. {
  22.         uchar date1,date2;
  23.         date1=date|0x0f;
  24.         write_add(date1&0xfd);
  25.         delay1(2);
  26.         write_add(date1&0xf9);
  27.         date2=date<<4;
  28.         date2=date2|0x0f;
  29.         write_add(date2&0xfd);
  30.         delay1(2);
  31.         write_add(date2&0xf9);
  32.                
  33. }

  34. void init_lcd()                                        //初始化函数
  35. {                                                                                                 
  36.         write_com(0x33); //显示模式设置
  37.         delayms(6);
  38.         write_com(0x32); //显示模式设置
  39.         delayms(6);
  40.         write_com(0x28); //4位总线,双行显示,显示5×7的点阵字符
  41.         delayms(6);
  42.         write_com(0x01); //清屏
  43.         delayms(6);
  44.         write_com(0x06); //字符进入模式:屏幕不动,字符后移
  45.         delayms(6);
  46.         write_com(0x0c); //显示开,关光标
  47.         //write_LCD_Command(0x0f); //显示开,开光标,光标闪烁
  48.         delayms(6);
  49. }

  50. //显示字符串:第x行第y列显示什么内容
  51. void ShowString(unsigned char x,unsigned char y,unsigned char *str)
  52. {
  53.        
  54.         if(x == 1)
  55.         {
  56.                 write_com(0x80 | y-1);
  57.         }
  58.         if(x == 2)
  59.         {
  60.                 write_com(0xc0 | y-1);
  61.         }
  62.         //输出字符串
  63.        
  64.         while(*str!='\0')
  65.         {
  66.                 write_date(*str);
  67.                 str++;
  68.         }

  69. }
复制代码

所有资料51hei提供下载:
PCF8574 LCD1602_4.rar (685 Bytes, 下载次数: 658)
PCF8574.rar (536 Bytes, 下载次数: 444)

作者: lmn2005    时间: 2019-3-5 10:28
补个实物连接图:

作者: w402333815    时间: 2019-4-19 17:26
看到里面的内容了,一个函数一个压缩包
作者: at366    时间: 2019-6-23 17:09
谢谢分享,不好一点就是分成两包
作者: bhjyqjs    时间: 2019-6-24 08:17
谢谢楼主分享,但实际中毫无意义。淘宝上IIC方式驱动的LCD1602屏就8元多,比这个模块贵不了多少。好用多了!
作者: ldshen00    时间: 2019-7-9 22:05
void delay1(uchar x)
{
        uchar a,b;
        for(a=x;a>0;a--)
         for(b=200;b>0;b--);
}

void write_com(uchar com)                //写命令函数
{        uchar com1,com2;
        com1=com|0x0f;
        write_add(com1&0xfc);
        delay1(2);
    write_add(com1&0xf8);
        com2=com<<4;
        com2=com2|0x0f;
        write_add(com2&0xfc);
        delay1(2);
    write_add(com2&0xf8);
       
}

void write_date(uchar date)                //写数据函数
{
        uchar date1,date2;
        date1=date|0x0f;
        write_add(date1&0xfd);
        delay1(2);
        write_add(date1&0xf9);
        date2=date<<4;
        date2=date2|0x0f;
        write_add(date2&0xfd);
        delay1(2);
        write_add(date2&0xf9);
               
}

void init_lcd()                                        //初始化函数
{                                                                                                 
        write_com(0x33); //显示模式设置
        delayms(6);
        write_com(0x32); //显示模式设置
        delayms(6);
        write_com(0x28); //4位总线,双行显示,显示5×7的点阵字符
        delayms(6);
        write_com(0x01); //清屏
        delayms(6);
        write_com(0x06); //字符进入模式:屏幕不动,字符后移
        delayms(6);
        write_com(0x0c); //显示开,关光标
        //write_LCD_Command(0x0f); //显示开,开光标,光标闪烁
        delayms(6);
}

//显示字符串:第x行第y列显示什么内容
void ShowString(unsigned char x,unsigned char y,unsigned char *str)
{
       
        if(x == 1)
        {
                write_com(0x80 | y-1);
        }
        if(x == 2)
        {
                write_com(0xc0 | y-1);
        }
        //输出字符串
       
        while(*str!='\0')
        {
                write_date(*str);
                str++;
        }

}
这就是 高级货
作者: ampere53060083    时间: 2019-7-10 03:12
厲害 高手
作者: 鹏博士PBs    时间: 2019-7-10 09:18
I2C通讯啊
作者: zxy2266    时间: 2019-7-30 11:40
正要做这个,软件很好
作者: jiajuntao    时间: 2019-10-20 21:41
能驱动就好,麻烦能告诉下,哪句是PCF8574地址句。
作者: xlmttkl    时间: 2019-12-1 19:25
write_add函数没有啊
作者: 哇哦恩    时间: 2019-12-12 21:10
淘宝店家给的例程是arduino的,直接调用现成的库,也是醉了,到论坛里来看看有没有能用的程序
作者: ytzmoonunit    时间: 2019-12-26 17:34
这段代码可行吗,有人成功吗?
里面的 write_byte 有疑问
作者: ytzmoonunit    时间: 2019-12-26 17:51
我测试成功了,感谢楼主!
分享下经验:如果是8574 写入的地址是0X27<<1 ,如果是8574A,写入的地址是0X3F<<1
(write_add 里面指代的是8574A)
iic的sart,stop,ack 。。。 都是通用的

作者: LEI365    时间: 2020-1-10 13:16
先看看,正在用这个模块。
作者: LEI365    时间: 2020-1-20 09:34
有现成的,懒得自己写协议转换程序了。
作者: lyl44    时间: 2020-2-28 14:53
bhjyqjs 发表于 2019-6-24 08:17
谢谢楼主分享,但实际中毫无意义。淘宝上IIC方式驱动的LCD1602屏就8元多,比这个模块贵不了多少。好用多了 ...

那个宝上买的就是这个东西的成品。
作者: minjunshuyi    时间: 2020-3-5 21:32
2个文件都需要?
作者: lmn2005    时间: 2020-3-25 08:11
jiajuntao 发表于 2019-10-20 21:41
能驱动就好,麻烦能告诉下,哪句是PCF8574地址句。

void write_iic(uchar date1)//写入数据到IO    中的
      write_byte(0x7e); //8574A地址,写数据

uchar read_iic()//向IO读取数据  中的
      write_byte(0x7f); //8574A地址,写数据
作者: a461624201    时间: 2020-4-1 00:51
确实不错,void write_add(uchar date1)//写入数据到IO
{
        start();
//        write_byte(0x7e); 0X3F<<1   0x7e 8574A芯片
        write_byte(0x4e); //bin(0x27<<1) 0x4e 8574 芯片
        respons();
        write_byte(date1);
        respons();
        stop();
}
作者: 1233423asd    时间: 2020-4-6 10:55
真好用感谢感谢
作者: 罗程峰8200    时间: 2020-4-20 21:14
真好,要啥来啥,我都怀疑我被监控了,谢谢
作者: yy1956029281    时间: 2020-5-10 14:27
这个是只需要该pcf8574的地址然后直接运行就可以了吗
作者: hunterfox    时间: 2020-5-14 16:34
STC12C5A60S2 打死也调试不出来。疯了
作者: rsbook    时间: 2020-5-22 14:46
刚买子这个模块测试下
作者: bresya    时间: 2020-6-4 20:09
ytzmoonunit 发表于 2019-12-26 17:51
我测试成功了,感谢楼主!
分享下经验:如果是8574 写入的地址是0X27

还好你提醒,要不然我怎么都调试不通。
作者: 欣语宝贝    时间: 2020-7-30 19:40
1602  老是搞不定   不知道哪里问题
作者: JasonW    时间: 2020-8-19 17:01
感谢楼主分享,现在就试一下
作者: ag26259    时间: 2021-1-16 21:21
感谢楼主分享,刚入了这转接板,现在就试一下
作者: cx301    时间: 2021-2-16 22:09
借用楼主程序,用STC15W408单片机测试了一下,现把完整的测试工程文件分享一下

PCF8574+1602.rar

28.43 KB, 下载次数: 80, 下载积分: 黑币 -5


作者: wwh2382    时间: 2021-2-17 16:03
请问pcf8574+1602可以用proteus仿真吗?
作者: tomsmiss123    时间: 2021-4-28 12:21
正在看这个,但是没有点亮,在找找看是啥原因

作者: 天下倒数第一    时间: 2021-4-28 12:29
谢谢,51hei真好用
作者: Capta1nY    时间: 2021-6-30 16:42
hunterfox 发表于 2020-5-14 16:34
STC12C5A60S2 打死也调试不出来。疯了

老哥,我也用的60s2,同样调不出来,你知道什么问题了吗
作者: Capta1nY    时间: 2021-6-30 16:43
tomsmiss123 发表于 2021-4-28 12:21
正在看这个,但是没有点亮,在找找看是啥原因

找到原因了么,我也是没有输出显示
作者: Capta1nY    时间: 2021-6-30 16:46
请教一下,我也用的这个模块,单片机用的stc12C5A60S2, lcd是1602A,用您的程序调试,没用结果,地址我改的0x27,不过换了其他的也没用
作者: zmc419    时间: 2021-7-2 23:23
谢谢楼主,有用
作者: 828    时间: 2021-12-20 14:12
不是SCL对应15,SDA对应14吗
作者: kmsj    时间: 2022-9-5 13:03
非常感谢楼主的无私奉献!按照楼主的程序,稍加修改,立即成功!
之前用一片CD4094成功驱动LCD1602,这次我只要把8574驱动I/O口的试验做成功就可以了。



拆掉洞洞板之前做试验的两片74HC595,留下LED和电阻,加上8574,我用的是双列直插PCF8574P,经过试验发现,PCF8574P的I/O口驱动能力较弱,通过1K电阻驱动LED,亮度只有一点点,远远达不到CD4094和74HC595的驱动能力,估计驱动LCD1602问题不大,毕竟PCF8574P的I/O口是双向I/O口。之所以用PCF8574P,是因为PCF8574P才一块多钱一片,需要注意的是,PCF8574P 13脚INT不能直接接VCC,必须通过电阻才能接VCC,否则芯片发烫!!!
单片机用的是STC8H1K08,PCF8574P双列直插的写地址是0x40,STC8H1K08用的IRC是1.2M,注释掉所有的delay( ),程序运行照样正常,经过试验,IRC为5M,程序正常,IRC为6M,程序不正常, delay( )替换成一个_nop_ ( ) 应该就可以了,那么IRC为12M,估计要替换两个到三个nop,程序才能正常。另外,应答部分的程序代码没有完全看懂,等以后用到的时候再慢慢研究和改进了。


作者: puqiong233    时间: 2022-10-28 01:19
hunterfox 发表于 2020-5-14 16:34
STC12C5A60S2 打死也调试不出来。疯了

我也是,请问调试出来了么
作者: jokerking    时间: 2023-3-21 15:32
没有人试STC89C51的吗
孩子pcf8574为什么地址设置的0x27也不行
#include <reg52.h>
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int

//#define                        L1                0x80            // 第一行写入地址
//#define                        L2                0xc0            // 第二行写入地址
        
sbit SCL = P2^1;
sbit SDA = P2^0;

uchar woder[]={"wangzijie"};

//char ADDR = 0x4E;    // PCF8574  T  模块的地址码
//char ADDR = 0x7e;    // PCF8574   AT  模块的地址码
char ADDR = 0x27;    // PCF8574   AT  模块的地址码


//***************************** 延时 y  ms ***********************************************


void delay1(int y)   //
{
         ;
        while(y--)
        {
        unsigned char a,b,c;
        for(c=1;c>0;c--)
        for(b=142;b>0;b--)
        for(a=2;a>0;a--);
        }
}






//******************************** IIC 串口开始 ********************************************


void IIC_start(void)
{
        SDA=1;
        _nop_();
        SCL=1;
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        SDA=0;
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        SCL=0;
}




//********************************** IIC 串口写1个字节 ******************************************


void IIC_writeByte(char temp)
{
        char i;
        for(i=0;i<8;i++)
        {
                SDA=(bit)(temp & 0x80) ;   // 根据规定1602的数据最高位必须为  1  
                temp <<=1;
                _nop_();
                _nop_();
                SCL=1;
                _nop_();
                _nop_();
                _nop_();
                _nop_();
                _nop_();
                SCL=0;
        }
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        SDA=1;
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        SCL=1;
        _nop_();
        _nop_();
        _nop_();
        while(SDA);
        _nop_();
        SCL=0;
}




//******************************** 1602写命令 ********************************************


void LCD_write_command(char comm)
{
        char tmp;
        IIC_start();          // 串口开始
        IIC_writeByte(ADDR);  // 先选PCF 8574T 的地址  (应该是相当于选中的意思吧)
        
        tmp = comm & 0xF0;    // 与0xf0 应该是取第四位的意思吧
        tmp |= 0x0C;         //保留高4位为指令的高四位,低四位为   RS = 0, RW = 0, EN = 1  
        IIC_writeByte(tmp);  //从串口送出
        delay1(20);
        tmp &= 0xFB;        //Make EN = 0
        IIC_writeByte(tmp);
        
        tmp = (comm & 0x0F) << 4 ;  //将指令的低四位 送到高位置保存
        tmp |= 0x0C;        //RS = 0, RW = 0, EN = 1
        IIC_writeByte(tmp);
        delay1(20);
        tmp &= 0xFB; // Make EN = 0
        IIC_writeByte(tmp);
        
}
//******************************** 1602写数据 ********************************************


void LCD_write_data(char data1)
{
        char tmp;
        IIC_start();
        IIC_writeByte(ADDR);   // 先选PCF8574T 的地址  (应该是相当于选中的意思吧)
        
        tmp = data1 & 0xF0;
        tmp |= 0x0D; //RS = 0, RW = 0, EN = 1
        IIC_writeByte(tmp);
        delay1(20);
        tmp &= 0xFB; //Make EN = 0
        IIC_writeByte(tmp);
        
        tmp = (data1 & 0x0F) << 4 ;
        tmp |= 0x0D; //RS = 0, RW = 0, EN = 1
        IIC_writeByte(tmp);
        delay1(20);
        tmp &= 0xFB ; // Make EN = 0
        IIC_writeByte(tmp);
}


//******************************** 1602初始化 ********************************************


void Init_Lcd(void)
{
        LCD_write_command(0x33); //将8位总线转为4位总线
        delay1(50) ;
        LCD_write_command(0x32); //
        delay1(50) ;
        LCD_write_command(0x28); // 4位数据线0x28,显示2行,5*7点阵字符  !如果是0x38  则为8位数据线,显示2行,5*7点阵字符
        delay1(50) ;
        LCD_write_command(0x0C); // 开显示,关闭光标,不闪烁
        delay1(50) ;  
        LCD_write_command(0x06); // 设定输入方式,增量不位移
        delay1(50) ;
        LCD_write_command(0x01); // 清屏
        delay1(50) ;
//                LCD_write_command(0x80);  //设置数据指针起点
//                delay1(50) ;
}








//*************************************** 在指定位置显示字符串 *************************************


void Write_LCD(int x, int y, char *str)
{
        char addr;
        if( x < 0)
        {
                x = 0;
        }
        if(x > 15)
        {
                x = 15;
        }
        if(y<0)
        {
                y = 0;
        }
        if(y > 1)
        {
                y = 1;
        }
        
        addr = 0x80 + 0x40 * y + x;   // Move cursor  移动光标
        LCD_write_command(addr);
        while (*str)
        {
                LCD_write_data(*str++);
        }
}


//-------------------------------------------- 显示字符串的函数 ----------------------------------------------------


void LCD_write_word(unsigned char *s)                  //显示字符串的函数
{
        while(*s>0)
        {
                LCD_write_data(*s);
                s++;
        }
}

void main()
{               
        uchar i;
        Init_Lcd();
//        for(i=0;i<9;i++)
//        {
        Write_LCD(0,0,(uchar *)woder[i]);
        LCD_write_word((uchar *)woder[i]);
//        }
        while(1);                               
}


//********************************* 指定位置显示一个字符*******************************************


/*
void Print_Char (unsigned char line,unsigned char num,unsigned char date)
{
                LCD_write_command(line+num);
                LCD_write_data(date);
}


*/




//按指定位置显示一个字符(针对1602液晶)-用在温度显示


//void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
//{
//Y &= 0x1;
//X &= 0xF;                 //限制X不能大于15,Y不能大于1
//if (Y) X |= 0x40;        //当要显示第二行时地址码+0x40;
//X |= 0x80;               // 算出指令码
//LCD_write_command(X);    //这里不检测忙信号,发送地址码
//LCD_write_data(DData);
//}

看看代码呜呜呜@
作者: 15031773670    时间: 2023-4-8 11:21
cx301 发表于 2021-2-16 22:09
借用楼主程序,用STC15W408单片机测试了一下,现把完整的测试工程文件分享一下

等我有分了来下载一下。终于看到了。谢谢分享希望好用。
作者: 15031773670    时间: 2023-4-8 17:37
lmn2005 发表于 2019-3-5 10:28
补个实物连接图:

我用的和这个是一样的。您的代码看不懂。用的204S用下面的408AS的也是不行。程序改了。端口也改了。希望得到回复
作者: su27smk    时间: 2023-7-30 10:58
试了一下,可以用




欢迎光临 (http://www.51hei.com/bbs/) Powered by Discuz! X3.1