找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4473|回复: 2
收起左侧

单片机+PCF8591 4通道AD采集源程序与原理图

[复制链接]
ID:210139 发表于 2020-5-17 13:22 | 显示全部楼层 |阅读模式
这是一个把PCF8591-4个通道都开启的AD采集,OLED12864显示.单片机:STC15W408AS
通道1:光敏电阻--光照强度0-100(自己定义的),根据采集的AD值转换成光照梯度
通道2:热敏电阻--NTC,通过采集出来的AD值转换成温度值。
通道3,4:通过电位器采集电源电压

这段时间在用PCF8591AD采集模块,发送只采集一个通道时,AD采集是正常的,但是当把4个通道都开启时,就要出错,通过查资料才发送一些问题。关于PCF8591说明,自己用8591作AD采集时,当只用一个通道时,
都能采集出正常的AD值,但是把4个通道都开启时,就会出错,通过查资料得知,PCF8591,发送AD转转指令时,
得到的是上一次的AD值,如果设置通道号自动增加的话,当发送采集通道2AD值的指令时,实际读取的AD值时
通道1的AD值,所以要重复发送同一通道的AD采集指令,保证采集到的AD值是要采集用到的AD值。

OLED12864显示4个通道

OLED12864显示4个通道

PCB

PCB

单片机源程序如下:
  1. /******************************************************************************************
  2.         PCF8591-4通道AD采集,OLED12864显示
  3. 通道1:光敏电阻--光照强度0-100(自己定义的),根据采集的AD值转换成光照梯度
  4. 通道2:热敏电阻--NTC,通过采集出来的AD值转换成温度值。
  5. 通道3,4:通过电位器采集电源电压
  6.         关于PCF8591说明,自己用8591作AD采集时,当只用一个通道时,都能采集出正常的AD值,但是把4
  7. 个通道都开启时,就会出错,通过查资料得知,PCF8591,发送AD转转指令时,得到的是上一次的AD值,
  8. 如果设置通道号自动增加的话,当发送采集通道2AD值的指令时,实际读取的AD值时通道1的AD值,所以
  9. 要重复发送同一通道的AD采集指令,保证采集到的AD值是要采集用到的AD值
  10. ******************************************************************************************/
  11. #include "OLED.h"
  12. #include "PCF8591.h"
  13. #include "math.h"

  14. float Vin;        //采集的电压
  15. float Rt;        //电阻阻值
  16. float temper;

  17. u8 TableBuff1[]="000CD";
  18. u8 TableBuff2[]="000.0C";
  19. u8 TableBuff3[]="0.00V";

  20. void Time0_Init(u8 T0XMS,u8 Mode)
  21. {
  22.         u16 T0_xMS;         //定时器T0的初值变量,现定义10ms 的初值,注意要与FOSC统一单位标准
  23.         if(Mode == 0)        TMOD &= 0xF0;                //设置定时器模式0        16位自动重转        
  24.         if(Mode == 1)        {TMOD&= 0XF0;TMOD|=0X01;}
  25.         if(Mode == 2)        {TMOD&= 0XF0;TMOD|=0X02;}
  26.         if(Mode == 3)        {TMOD&= 0XF0;TMOD|=0X03;}
  27. //=====装载初值               
  28. #ifdef T0_1T        //1T模式
  29.         T0_xMS =(65536-T0XMS*FOSC/1000);        //FOSC的定义在 STC8.H中
  30. #else                        //12T模式
  31.         T0_xMS =(65536-T0XMS*FOSC/12/1000);
  32. #endif

  33.         TL0 = T0_xMS;
  34.         TH0 = T0_xMS >> 8;
  35.         TR0 = 1;
  36.         ET0 = 1;
  37.         EA  = 1;        
  38. }

  39. u8 AD_CH=1;

  40. void main()
  41. {
  42.         u16 value;
  43.         u16 valuet;
  44.         u16 temp=123;
  45.         IIC_int();
  46.         Time0_Init(20,0);
  47.         OLED_Init();
  48.         Write_GB16X16(0,0,"CH0:");
  49.         Write_GB16X16(2,0,"CH1:");
  50.         Write_GB16X16(4,0,"CH2:");
  51.         Write_GB16X16(6,0,"CH3:");
  52.         while(1)
  53.         {
  54.                 switch(AD_CH)
  55.                 {
  56.                         case 0:        //光明电阻
  57.                                         value=ReadPCF_Dat(0X40);        //这事获得的AD值是通道4的AD值
  58.                                         value=ReadPCF_Dat(0X40);        //多采集几次,保证是通道0的AD值
  59.                                         value=ReadPCF_Dat(0X40);
  60.                                         value=ReadPCF_Dat(0X40);
  61.                                         value = 100-(value*100.0/255.0);
  62.                                        
  63.                                         TableBuff1[0] = value%1000/100 +0X30;
  64.                                         TableBuff1[1] = value%100/10 +0X30;
  65.                                         TableBuff1[2] = value%10 +0X30;
  66.                                         Write_GB16X16(0,4,TableBuff1);
  67.                                         break;
  68.                         case 1:        //热敏电阻
  69.                                         value=ReadPCF_Dat(0X41);
  70.                                         value=ReadPCF_Dat(0X41);
  71.                                         value=ReadPCF_Dat(0X41);
  72.                                         value=ReadPCF_Dat(0X41);
  73.                                         Vin = ( 5*value )/255.0;
  74.                                         Rt = 10*Vin/(5-Vin);
  75.                                        
  76.                                         temper = ( (3950 *298.15)/( (298.15 * log (Rt / 10)) + 3950 )  )-273.15;
  77.                                         valuet = temper*10;
  78.                                        
  79.                                         TableBuff2[0] = valuet%10000/1000 +0X30;
  80.                                         TableBuff2[1] = valuet%1000/100 +0X30;
  81.                                         TableBuff2[2] = valuet%100/10 +0X30;
  82.                                        
  83.                                         TableBuff2[4] = valuet%10 +0X30;
  84.                                        
  85.                                         Write_GB16X16(2,4,TableBuff2);
  86.                                         break;
  87.                         case 2:        //测电压
  88.                                         value=ReadPCF_Dat(0X42);
  89.                                         value=ReadPCF_Dat(0X42);
  90.                                         value=ReadPCF_Dat(0X42);
  91.                                         value=ReadPCF_Dat(0X42);
  92.                                         value = 500.0*value/255.0;
  93.                                         TableBuff3[0] = value%1000/100 +0X30;
  94.                                         TableBuff3[2] = value%100/10 +0X30;
  95.                                         TableBuff3[3] = value%10 +0X30;
  96.                                         Write_GB16X16(4,4,TableBuff3);
  97.                                         break;
  98.                         case 3:        //测电压
  99.                                         value=ReadPCF_Dat(0X43);
  100.                                         value=ReadPCF_Dat(0X43);
  101.                                         value=ReadPCF_Dat(0X43);
  102.                                         value=ReadPCF_Dat(0X43);
  103.                                         value = 500.0*value/255.0;
  104.                                         TableBuff3[0] = value%1000/100 +0X30;
  105.                                         TableBuff3[2] = value%100/10 +0X30;
  106.                                         TableBuff3[3] = value%10 +0X30;
  107.                                         Write_GB16X16(6,4,TableBuff3);
  108.                                         break;
  109.                 }        
  110.         }
  111. }

  112. u8 a=0;
  113. void Time0() interrupt 1
  114. {
  115.         a++;
  116.         if(a>25)
  117.         {
  118.                 a=0;
  119.                 AD_CH++;
  120.                 if(AD_CH>3)AD_CH=0;                //通过定时器改变要采集的通道
  121.         }
  122. }
复制代码
  1. #include "PCF8591.h"
  2. #include "intrins.h"

  3. bit Ack;        //应答标志

  4. void Delay_IIC(u8 t)
  5. {
  6.         while(t--)
  7.         {
  8.                 _nop_();_nop_();
  9.                 _nop_();_nop_();
  10.         }
  11. }

  12. void IIC_Start()
  13. {
  14.         PCFSDA = 1;
  15.         Delay_IIC(4);
  16.         PCFSCL = 1;
  17.         Delay_IIC(4);
  18.         PCFSDA = 0;
  19.         Delay_IIC(4);
  20.         PCFSCL = 0;
  21.         Delay_IIC(2);
  22. }

  23. void IIC_Stop()
  24. {
  25.         PCFSCL = 0;
  26.         Delay_IIC(2);
  27.         PCFSDA = 0;
  28.         Delay_IIC(4);
  29.         PCFSCL = 1;
  30.         Delay_IIC(4);
  31.         PCFSDA = 1;
  32.         Delay_IIC(4);
  33. }

  34. u8 Wait_Ack()
  35. {
  36.         u8 errtimr=255;
  37.         
  38.         PCFSCL = 0;
  39.         PCFSDA = 1;
  40.         Delay_IIC(2);
  41.         PCFSCL = 1;
  42.         while(PCFSDA)
  43.         {
  44.                 errtimr--;
  45.                 if(!errtimr)
  46.                 {
  47.                         PCFSCL = 0;
  48.                         return 0;
  49.                 }
  50.         }
  51.         PCFSCL = 0;
  52.         return 1;        
  53. }

  54. void IIC_int()
  55. {
  56.         PCFSCL=1;
  57.         PCFSDA=1;
  58. }

  59. void IICSend_Byte(u8 Byte)
  60. {
  61.         u8 i;
  62.         for(i=0;i<8;i++)
  63.         {
  64.                 PCFSDA = Byte&0X80;
  65.                 Delay_IIC(1);
  66.                 PCFSCL = 1;
  67.                 Delay_IIC(4);
  68.                 Byte <<=1;
  69.                 PCFSCL = 0;
  70.                 Delay_IIC(2);
  71.         }
  72. }

  73. u8 IICRece_Byte()
  74. {
  75.         u8 i;
  76.         u8 Dat;
  77.         for(i=0;i<8;i++)
  78.         {
  79.                 PCFSCL = 1;
  80.                 Delay_IIC(4);
  81.                 Dat = (Dat<<1) | PCFSDA;
  82.                 PCFSCL = 0;
  83.                 Delay_IIC(4);
  84.         }
  85.         return Dat;
  86. }

  87. /******单片机机应答PCF8591*********/
  88. void Ack_IIc(bit a)
  89. {
  90.         PCFSDA = a;
  91.         PCFSCL = 0;
  92.         Delay_IIC(4);
  93.         PCFSCL = 1;
  94.         Delay_IIC(4);
  95.         PCFSCL = 0;
  96.         Delay_IIC(4);
  97. }

  98. /******读取PCF8591寄存器数据************/
  99. u8 ReadPCF_Dat(u8 control)
  100. {
  101.         u8 Dat;
  102.         IIC_Start();
  103.         IICSend_Byte(PCFADD);        //写
  104.         Wait_Ack();
  105.         IICSend_Byte(control);
  106.         Wait_Ack();
  107.         
  108.         IIC_Start();                                //起始信号
  109.         IICSend_Byte(PCFADD +1);        //器件地址        读
  110.         Wait_Ack();
  111.         Dat =IICRece_Byte();        //读取数据
  112.         Ack_IIc(1);                                //发送非应答位        
  113.         IIC_Stop();                                //停止信号
  114.         return Dat;
  115. }

  116. /*************DA转换***************
  117. Add:器件地址
  118. c:控制字节
  119. value:发送DAC的数值
  120. ***********************************/
  121. void PCF_DAC(u8 Add, u8 c, u8 value)
  122. {
  123.         IIC_Start();
  124.         IICSend_Byte(Add);        //写
  125.         Wait_Ack();
  126.         IICSend_Byte(c);
  127.         Wait_Ack();
  128.         IICSend_Byte(value);        //第三个字节数据存储到DAC数据寄存器
  129.         Wait_Ack();
  130.         IIC_Stop();        
  131. }









复制代码
  1. #include "OLED.h"
  2. #include "Font.h"

  3. void Delay_OLED(u16 t)
  4. {
  5.         u16 i,j;
  6.         for(i=t;i>0;i--)
  7.                 for(j=500;j>0;j--);
  8. }

  9. /***********向SSD1306写一字节数据***********
  10. Dat:要写入的数据/命令
  11. Cmd:数据/命令标志 0,表示命令;1,表示数据;
  12. ********************************************/
  13. void Write_OLED_Byte(u8 Dat,u8 Cmd)
  14. {
  15.         u8 i;
  16.         OLED_CS = 0;
  17.         OLED_DC        =Cmd;
  18.         for(i=0;i<8;i++)
  19.         {
  20.                 OLED_SCL = 0;
  21.                 OLED_SDA = Dat&0X80;
  22.                 OLED_SCL = 1;
  23.                 Dat<<=1;
  24.         }
  25.         OLED_CS = 1;
  26. }

  27. /*********设置显示坐标*********/
  28. void OLED_Set_PoS(u8 page,u8 column)
  29. {
  30.         Write_OLED_Byte(0XB0+page,OLED_CMD);
  31.         Write_OLED_Byte( ((column&0XF0)>>4)|0X10,OLED_CMD);
  32.         Write_OLED_Byte( column&0X0F,OLED_CMD);
  33. }

  34. ////开启OLED显示   
  35. //void OLED_Display_On(void)
  36. //{
  37. //        Write_OLED_Byte(0X8D,OLED_CMD);  //SET DCDC命令
  38. //        Write_OLED_Byte(0X14,OLED_CMD);  //DCDC ON
  39. //        Write_OLED_Byte(0XAF,OLED_CMD);  //DISPLAY ON
  40. //}


  41. ////关闭OLED显示     
  42. //void OLED_Display_Off(void)
  43. //{
  44. //        Write_OLED_Byte(0X8D,OLED_CMD);  //SET DCDC命令
  45. //        Write_OLED_Byte(0X10,OLED_CMD);  //DCDC OFF
  46. //        Write_OLED_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
  47. //}

  48. /************操作整个屏幕************
  49. Input: Ins=0        清除整个屏幕
  50.            Ins=0XFF        全部显示整个屏幕
  51. *************************************/
  52. void OLED_Screen_All(u8 Ins)
  53. {
  54.         u8 page,seg;
  55.         for(page=0;page<8;page++)
  56.         {
  57.                 OLED_Set_PoS(page,0);
  58.                 for(seg=0;seg<128;seg++)
  59.                 Write_OLED_Byte(Ins,OLED_DAT);
  60.         }
  61. }

  62. ///*********OLED初始化***********/
  63. //void OOLED_INIT()
  64. //{
  65. ////--复位
  66. //        OLED_RST = 1;
  67. //        Delay_OLED(200);
  68. //        OLED_RST = 0;
  69. //        Delay_OLED(200);
  70. //        OLED_RST = 1;
  71. //        Delay_OLED(20);        
  72. ////--指令初始化        
  73. //}

  74. /*********OLED初始化***********/
  75. void OLED_Init()
  76. {
  77.         OLED_RST = 1;
  78.         Delay_OLED(200);  
  79.         OLED_RST = 0;
  80.         Delay_OLED(200);
  81.         OLED_RST = 1;
  82.         Delay_OLED(20);
  83. //--地址设置
  84.         Write_OLED_Byte(0X20,OLED_CMD);        //设置寻址模式
  85.         Write_OLED_Byte(0X02,OLED_CMD);        //0X00--水平寻址;0X01--垂直寻址;0X02--页面寻址
  86. //--硬件设置
  87.         //显示方向-引脚向上为正方向
  88.         Write_OLED_Byte(0XA1,OLED_CMD);        //段寻址,add0-->seg0
  89.         Write_OLED_Byte(0XC8,OLED_CMD);        //com扫描方向,com0-com63
  90.         //引脚在下为正方向
  91.         //Write_OLED_Byte(0XA0,OLED_CMD);        //段寻址,add127-->seg0
  92.         //Write_OLED_Byte(0XC0,OLED_CMD);        //com扫描方向,com63-com0
  93.         Write_OLED_Byte(0X8D,OLED_CMD);        //电荷泵设置
  94.         Write_OLED_Byte(0X14,OLED_CMD);        //REST=0X10,        0X14才能显示内容
  95. //--基本命令
  96.         Write_OLED_Byte(0X81,OLED_CMD);        //设置对比度
  97.         Write_OLED_Byte(0XCF,OLED_CMD);        //0X00-0XFF,与数值成正比        RES=0X7F
  98.         Write_OLED_Byte(0XA4,OLED_CMD);        //整体显示开启,可用来测试液晶是否显示正常
  99.                                                                         //0XA4跟随RAM内容,0XA5不跟随RAM的内容,一直是白屏全部显示。
  100.         Write_OLED_Byte(0XA6,OLED_CMD);        //设置正显0XA6,反显0XA7
  101.         Write_OLED_Byte(0XAF,OLED_CMD);        //0XAE显示关,0XAF显示开
  102. //---清屏
  103.         OLED_Screen_All(0);                        
  104. }

  105. /**************清除N个8*16区域**********/
  106. //void Clear8X16(u8 page, u8 column ,u8 N)
  107. //{
  108. //        u8 i,j,k;
  109. //        column*=8;
  110. //        for(k=0;k<N;k++)
  111. //        {
  112. //                for(i=0;i<2;i++)
  113. //                {
  114. //                        OLED_Set_PoS(page+i,column+k*8);
  115. //                        for(j=8;j>0;j--)
  116. //                                Write_OLED_Byte(0X00,OLED_DAT);
  117. //                }
  118. //        }
  119. //}

  120. /*****************在(16行/2页)*Wide列区域写数据****************
  121. Input:        
  122.         *Buff@点阵数据        Num@字符个数,Wide@字体宽度
  123.         Wide=8时,为写8*16的数据,字母,符号
  124.         Wide=16时,为写宋体2号汉字
  125. **************************************************************/
  126. void Write_16xWide(u8 page,u8 column ,u8 *Buff,u8 Num,u8 Wide)
  127. {
  128.         u8 i,j,k;
  129.         for(k=0;k<Num;k++)
  130.         {
  131.                 for(i=0;i<2;i++)
  132.                 {
  133.                         OLED_Set_PoS(page+i,column+k*8);
  134.                         for(j=Wide;j>0;j--)
  135.                         {
  136.                                 Write_OLED_Byte(*Buff,OLED_DAT);
  137.                                 Buff++;
  138.                         }
  139.                 }
  140.         }
  141. }

  142. /**************写宋体12号汉字 16*Wide ***********
  143. Input:        page@页                column@列        *CH@字符串
  144.         可以显示汉字,数字,字母,符号
  145.         page:0 2 4 6        column:0~15
  146. ************************************************/
  147. void Write_GB16X16(u8 page,u8 column ,u8 *CH)
  148. {
  149.         u8 a,k;
  150.         if( (*CH>=0X20) && (*CH<=0X7E) )        column=column;
  151.         else column*=8;
  152.         while( *CH != '\0')
  153.         {
  154.                 if( (*CH>=0X20) && (*CH<=0X7E) )        //数字,字母,符号        一行16个
  155.                 {
  156.                         k=*CH-0X20;
  157.                         for(a=0;a<2;a++)
  158.                         {
  159.                                 Write_16xWide(page,column*8, &ASCII_8X16[k][0],1,8);
  160.                         }
  161.                         CH+=1;
  162.                         column+=1;
  163.                 }        
  164.                 else        //汉字,一行 8个
  165.                 {
  166.                         for(a=0;a<FontNum;a++)
  167.                         {
  168.                                 if( (*CH == GB12Hanzi[a].Index[0]) && (*(CH+1)==GB12Hanzi[a].Index[1]) )
  169.                                         Write_16xWide(page,column,&GB12Hanzi[a].Msk[0],1,16);
  170.                         }
  171.                         CH+=2;
  172.                         column+=16;
  173.                 }
  174.         }
  175. }


复制代码

51hei.png

全部资料51hei下载地址:
PCF8591.zip (1.37 MB, 下载次数: 74)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:920644 发表于 2021-6-15 15:25 | 显示全部楼层
学这个东西好难啊,仔细看看
回复

使用道具 举报

ID:230742 发表于 2021-6-18 00:54 | 显示全部楼层
感谢分享。有8591模块,一直不会用。正好学一下。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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