找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5696|回复: 3
收起左侧

PCF8591数字电压表试验-Proteus仿真51单片机开发板平台

[复制链接]
ID:223055 发表于 2017-8-2 02:39 | 显示全部楼层 |阅读模式
自己做的一个仿真的单片机开发板,有完整的试验步骤和仿真工程文件提供.
板子上带扩展ROM空间(i^2c 24c02)、adc(PCF8591芯片数字电压表)、dac(信号发生器)、矩形按键(计算器),四个任务通过独立按键进行切换

下面是数字电压表部分的的单片机源程序
完整代码和仿真工程文件请下载http://www.51hei.com/bbs/dpj-91558-1.html
单片机PCF8591驱动(1602液晶显示)部分源程序预览:
  1. #include<reg52.h>    //包含单片机寄存器的头文件
  2. #include <intrins.h>
  3. #define ulong unsigned long
  4. #define uchar unsigned char
  5. #define uint unsigned int
  6. #define LCD1602_PORT P0                  //用LED1602_PORT表示P2总线接口
  7. #define  PCF8591 0x90    //PCF8591 地址
  8. #define  NOP()   _nop_()   /* 定义空指令 */
  9. #define  _Nop()  _nop_()   /*定义空指令*/

  10. // 位定义
  11. sbit SCL=P2^1;       //I2C  时钟
  12. sbit SDA=P2^0;       //I2C  数据
  13. sbit LCD1602_RS = P2^6;          //定义1602液晶显示屏的数据/命令选择端,数据/命令(H/L)
  14. sbit LCD1602_RW = P2^5;          //定义1602液晶显示屏的读/写选择端,读/写(H/L)
  15. sbit LCD1602_EN = P2^7;          //定义1602液晶显示屏的使能端
  16. bit ack;                 /*应答标志位*/
  17. sbit key=P3^3;

  18. // 变量定义
  19. uchar AD_CHANNEL;
  20. ulong xdata  LedOut[8];          //单片机内部存取器
  21. ulong  v,a,ss;
  22. uchar date;

  23. // 函数申明
  24. extern bit ack;                //起动总线函数
  25. extern void Start_I2c();        //结束总线函数  
  26. extern void Stop_I2c();                //应答子函数
  27. extern void Ack_I2c(bit a);                //字节数据发送函数
  28. extern void  SendByte(uchar  c);        //有子地址发送多字节数据函数               
  29. extern bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no) ;        //无子地址发送多字节数据函数   
  30. extern bit ISendStrExt(uchar sla,uchar *s,uchar no);        //无子地址读字节数据函数               
  31. extern uchar RcvByte();

  32. void LCD1602_delay_ms(uint n);
  33. void LCD1602_write_com(uchar com);
  34. void LCD1602_write_data(ulong dat);
  35. void LCD1602_write_word(uchar *s);
  36. void Init_LCD1602();

  37. bit ISendByte(uchar sla,uchar c);
  38. uchar IRcvByte(uchar sla);

  39. //MS延时函数(12M晶振下测试)
  40. void delay_ms(uint n)        
  41. {
  42.         unsigned int  i,j;
  43.         for(i=0;i<n;i++)
  44.                 for(j=0;j<123;j++);
  45. }

  46. //写指令
  47. void LCD1602_write_com(uchar com)
  48. {
  49.         LCD1602_RS = 0;                 //1602液晶显示屏的数据/命令选择端置0,数据/命令(H/L),此时选择写命令操作
  50.         delay_ms(1);
  51.         LCD1602_EN = 1;                 //使能,也就是打开液晶接收数据命令的通道
  52.         LCD1602_PORT = com;         //把命令送给P2口
  53.         delay_ms(1);
  54.         LCD1602_EN = 0;
  55. }

  56. //写数据
  57. void LCD1602_write_data(ulong dat)
  58. {
  59.         LCD1602_RS = 1;                 //1602液晶显示屏的数据/命令选择端置0,数据/命令(H/L),此时选择写数据操作
  60.         delay_ms(1);        
  61.         LCD1602_PORT = dat;         //把数据送给P2口
  62.         LCD1602_EN = 1;
  63.         delay_ms(1);
  64.         LCD1602_EN = 0;
  65. }

  66. //连续写字符
  67. void LCD1602_write_word(uchar *s)
  68. {
  69.         while(*s>0)
  70.         {
  71.                 LCD1602_write_data(*s);
  72.                 s++;
  73.         }
  74. }

  75. //1602初始化函数
  76. void Init_LCD1602()                                       
  77. {
  78.         LCD1602_EN = 0;
  79.         LCD1602_RW = 0;                                                //设置为写状态
  80.         LCD1602_write_com(0x38);                        //显示模式设定
  81.         LCD1602_write_com(0x0c);                        //开关显示、光标有无设置、光标闪烁设置
  82.         LCD1602_write_com(0x06);                        //写一个字符后指针加一
  83.         LCD1602_write_com(0x01);                        //清屏指令
  84. }
  85. /*******************************************************************
  86.                      起动总线函数               
  87. 函数原型: void  Start_I2c();  
  88. 功能:     启动I2C总线,即发送I2C起始条件.  
  89. ********************************************************************/
  90. void Start_I2c()
  91. {
  92.   SDA=1;         /*发送起始条件的数据信号*/
  93.   _Nop();
  94.   SCL=1;
  95.   _Nop();        /*起始条件建立时间大于4.7us,延时*/
  96.   _Nop();
  97.   _Nop();
  98.   _Nop();
  99.   _Nop();   
  100.   SDA=0;         /*发送起始信号*/
  101.   _Nop();        /* 起始条件锁定时间大于4μs*/
  102.   _Nop();
  103.   _Nop();
  104.   _Nop();
  105.   _Nop();      
  106.   SCL=0;       /*钳住I2C总线,准备发送或接收数据 */
  107.   _Nop();
  108.   _Nop();
  109. }

  110. /*******************************************************************
  111.                       结束总线函数               
  112. 函数原型: void  Stop_I2c();  
  113. 功能:     结束I2C总线,即发送I2C结束条件.  
  114. ********************************************************************/
  115. void Stop_I2c()
  116. {
  117.   SDA=0;      /*发送结束条件的数据信号*/
  118.   _Nop();       /*发送结束条件的时钟信号*/
  119.   SCL=1;      /*结束条件建立时间大于4μs*/
  120.   _Nop();
  121.   _Nop();
  122.   _Nop();
  123.   _Nop();
  124.   _Nop();
  125.   SDA=1;      /*发送I2C总线结束信号*/
  126.   _Nop();
  127.   _Nop();
  128.   _Nop();
  129.   _Nop();
  130. }

  131. /*******************************************************************
  132.                  字节数据发送函数               
  133. 函数原型: void  SendByte(UCHAR c);
  134. 功能:     将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
  135.           此状态位进行操作.(不应答或非应答都使ack=0)     
  136.            发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
  137. ********************************************************************/
  138. void  SendByte(uchar  c)
  139. {
  140. uchar  BitCnt;

  141. for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8位*/
  142.     {
  143.      if((c<<BitCnt)&0x80)SDA=1;   /*判断发送位*/
  144.        else  SDA=0;               
  145.      _Nop();
  146.      SCL=1;               /*置时钟线为高,通知被控器开始接收数据位*/
  147.       _Nop();
  148.       _Nop();             /*保证时钟高电平周期大于4μs*/
  149.       _Nop();
  150.       _Nop();
  151.       _Nop();         
  152.      SCL=0;
  153.     }
  154.    
  155.     _Nop();
  156.     _Nop();
  157.     SDA=1;                /*8位发送完后释放数据线,准备接收应答位*/
  158.     _Nop();
  159.     _Nop();   
  160.     SCL=1;
  161.     _Nop();
  162.     _Nop();
  163.     _Nop();
  164.     if(SDA==1)ack=0;     
  165.        else ack=1;        /*判断是否接收到应答信号*/
  166.     SCL=0;
  167.     _Nop();
  168.     _Nop();
  169. }

  170. /*******************************************************************
  171.                  字节数据接收函数               
  172. 函数原型: UCHAR  RcvByte();
  173. 功能:        用来接收从器件传来的数据,并判断总线错误(不发应答信号),
  174.           发完后请用应答函数应答从机。  
  175. ********************************************************************/   
  176. uchar   RcvByte()
  177. {
  178.   uchar  retc;
  179.   uchar  BitCnt;
  180.   
  181.   retc=0;
  182.   SDA=1;                     /*置数据线为输入方式*/
  183.   for(BitCnt=0;BitCnt<8;BitCnt++)
  184.       {
  185.         _Nop();           
  186.         SCL=0;                  /*置时钟线为低,准备接收数据位*/
  187.         _Nop();
  188.         _Nop();                 /*时钟低电平周期大于4.7μs*/
  189.         _Nop();
  190.         _Nop();
  191.         _Nop();
  192.         SCL=1;                  /*置时钟线为高使数据线上数据有效*/
  193.         _Nop();
  194.         _Nop();
  195.         retc=retc<<1;
  196.         if(SDA==1)retc=retc+1;  /*读数据位,接收的数据位放入retc中 */
  197.         _Nop();
  198.         _Nop();
  199.       }
  200.   SCL=0;   
  201.   _Nop();
  202.   _Nop();
  203.   return(retc);
  204. }

  205. /********************************************************************
  206.                      应答子函数
  207. 函数原型:  void Ack_I2c(bit a);
  208. 功能:      主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
  209. ********************************************************************/
  210. void Ack_I2c(bit a)
  211. {
  212.   if(a==0)SDA=0;              /*在此发出应答或非应答信号 */
  213.   else SDA=1;
  214.   _Nop();
  215.   _Nop();
  216.   _Nop();      
  217.   SCL=1;
  218.   _Nop();
  219.   _Nop();                    /*时钟低电平周期大于4μs*/
  220.   _Nop();
  221.   _Nop();
  222.   _Nop();  
  223.   SCL=0;                     /*清时钟线,钳住I2C总线以便继续接收*/
  224.   _Nop();
  225.   _Nop();   
  226. }


  227. /*******************************************************************
  228. ADC发送字节[命令]数据函数               
  229. *******************************************************************/
  230. bit ISendByte(uchar sla,uchar c)
  231. {
  232.    Start_I2c();              //启动总线
  233.    SendByte(sla);            //发送器件地址
  234.    if(ack==0)return(0);
  235.    SendByte(c);              //发送数据
  236.    if(ack==0)return(0);
  237.    Stop_I2c();               //结束总线
  238.    return(1);
  239. }

  240. /*******************************************************************
  241. ADC读字节数据函数               
  242. *******************************************************************/
  243. uchar IRcvByte(uchar sla)
  244. {  
  245.    uchar c;
  246.    Start_I2c();          //启动总线
  247.    SendByte(sla+1);      //发送器件地址
  248.    if(ack==0)return(0);
  249.    c=RcvByte();          //读取数据0
  250.    Ack_I2c(1);           //发送非就答位
  251.    Stop_I2c();           //结束总线
  252.    return(c);
  253. }

  254. //        字符显示函数
  255. void Display()
  256. {
  257.         LCD1602_write_com(0x80);                        //指针设置,指向1602液晶第一行第一列
  258.     LCD1602_write_word("Voltage: ");
  259.         LCD1602_write_com(0x80+0x0e);                        //指针设置,指向1602液晶第一行第一列
  260.     LCD1602_write_word(" V");
  261. }

  262. //实时电压显示函数
  263. void Display_Voltage()
  264. {
  265.         ss=(v*a);
  266. //        ss=((ss*6)/100);
  267.         ss=((ss*6)/239.6);
  268.         LCD1602_write_com(0x80+0x09);        //1602液晶屏命令操作,表示起始显示位置为第二行第7列        
  269.         LCD1602_write_data(ss%10000000/1000000 + 0x30);
  270.         LCD1602_write_data(ss%1000000/100000 + 0x30);
  271.         LCD1602_write_data('.');
  272.         LCD1602_write_data(ss%100000/10000 + 0x30);
  273.         LCD1602_write_data(ss%10000/1000 + 0x30);
  274. //        LCD1602_write_data(ss%1000/100 + 0x30);
  275. //        LCD1602_write_data('.');
  276. //        LCD1602_write_data(ss%100/10 + 0x30);
  277. //        LCD1602_write_data(ss%10/1 + 0x30);
  278. }
  279. //******************************************************************/
  280. void dianyabiao()
  281. {  
  282.     Init_LCD1602(); //初始化LCD1602
  283.     Display();
  284.         a=50000000/255;
  285.                 while(key)
  286.         {
  287.                 ISendByte(PCF8591,0x41);
  288.                 v=IRcvByte(PCF8591);         
  289.                 Display_Voltage();                 
  290.         }         
  291. }


复制代码



回复

使用道具 举报

ID:255077 发表于 2018-11-5 12:20 | 显示全部楼层
非常好的东西
回复

使用道具 举报

ID:442274 发表于 2019-3-6 09:45 | 显示全部楼层
没有提供下载啊
回复

使用道具 举报

ID:183056 发表于 2019-8-24 11:31 | 显示全部楼层
下载成功,测试通过。感谢楼主!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表