[通用8051核FLASH系列] 【芯圣电子HC89S105A测评报告】+PCF8591DAC

[复制链接]
2691|2
 楼主| 比神乐 发表于 2023-5-29 12:00 | 显示全部楼层 |阅读模式
本帖最后由 芯圣电子官方QQ 于 2023-7-19 16:41 编辑

今天搞了一下PCF8591,本来PCF8591既有DAC功能,又有ADC功能。
可我只搞出了DAC,ADC一直不对。
SCL接P01,SDA接P00。
代码:
  1. #define ALLOCATE_EXTERN
  2. #include "HC89S105AC8.h"
  3. #include "i2c.h"

  4. #define uint8_t unsigned char
  5. #define uint16_t  unsigned int

  6. #define PCF8591 0x90    //PCF8591 地址
  7. #define SCL P0_1             //I2C时钟控制位
  8. #define SDA P0_0        

  9. unsigned char AD_CHANNEL;

  10. unsigned char  DAC_VALUE=0;
  11. unsigned char  ADCVALUE=0;
  12. unsigned char  txBuf[]={"ADC VALUE=:   \r\n"};

  13.   // 函数申明


  14. void delay(uchar i);


  15. /***************************************************************************************
  16.   * @说明          IIC发送一个字节的数据
  17.   *        @参数        fuc_Add:存储的地址
  18.   *                        fuc_Dat:存储的数据
  19.   * @返回值 无
  20.   * @注                无
  21. ***************************************************************************************/
  22. void DACconversion(unsigned char fuc_Add, unsigned char fuc_Dat)
  23. {
  24.         IICCON &= ~0x08; //清除中断标志位

  25.         IICCON |= 0x20; //起始位发送起始信号

  26.         while ((!(IICCON & 0x08)) && (IICSTA != 0x08));
  27.         IICCON &= ~0x20;        //起始位停止起始信号
  28.         IICCON &= ~0x08;        //清除中断标志位
  29.         IICDAT = PCF8591; //写入器件地址
  30.         while (IICSTA != 0x18);
  31.         IICCON &= ~0x08;  //清除中断标志位
  32.         IICDAT = fuc_Add; //写入地址
  33.         while (IICSTA != 0x28);
  34.         IICCON &= ~0x08;  //清除中断标志位
  35.         IICDAT = fuc_Dat; //写入数据
  36.         while (IICSTA != 0x28);
  37.         IICCON &= ~0x08; //清除中断标志位
  38.         IICCON |= 0x10;         //停止位发送停止信号
  39. }

  40. unsigned char ADC(unsigned char fuc_Add)
  41. {
  42.         unsigned char fuc_Dat;
  43.         IICCON &= ~0x08; //清除中断标志位
  44.         IICCON |= 0x20;         //起始位发送起始信号
  45.         while ((!(IICCON & 0x08)) && (IICSTA != 0x08));
  46.         IICCON &= ~0x20;        //起始位停止起始信号
  47.         IICCON &= ~0x08;        //清除中断标志位
  48.         IICDAT = PCF8591; //写入器件地址
  49.         while (IICSTA != 0x18);
  50.         IICCON &= ~0x08;  //清除中断标志位
  51.         IICDAT = fuc_Add; //写入读地址
  52.         while (IICSTA != 0x28);
  53.         IICCON &= ~0x08; //清除中断标志位

  54.         IICCON |= 0x20; //起始位发送起始信号
  55.         while ((!(IICCON & 0x08)) && (IICSTA != 0x08));
  56.         IICCON &= ~0x20;                   //起始位停止起始信号
  57.         IICCON &= ~0x08;                   //清除中断标志位
  58.         IICDAT = PCF8591 | 0x01; //写入读指令
  59.         while (IICSTA != 0x40);
  60.         IICCON &= ~0x08; //清除中断标志位
  61.         while (IICSTA != 0x58);
  62.         fuc_Dat = IICDAT; //读入数据
  63.         IICCON &= ~0x08;  //清除中断标志位
  64.         IICCON |= 0x10;          //停止位发送停止信号

  65.         return fuc_Dat;
  66. }
  67. /*******************************************************************
  68. DAC 变换, 转化函数               
  69. *******************************************************************/
  70. //bit DACconversion(unsigned char sla,unsigned char c,  unsigned char Val)
  71. //{
  72. //   Start_I2c();              //启动总线
  73. //   SendByte(sla);            //发送器件地址
  74. //   if(ack==0)return(0);
  75. //   SendByte(c);              //发送控制字节
  76. //   if(ack==0)return(0);
  77. //   SendByte(Val);            //发送DAC的数值  
  78. //   if(ack==0)return(0);
  79. //   Stop_I2c();               //结束总线
  80. //   return(1);
  81. //}
  82. //
  83. ///*******************************************************************
  84. //ADC发送字节[命令]数据函数               
  85. //*******************************************************************/
  86. bit ISendByte(unsigned char sla,unsigned char c)
  87. {
  88.    Start_I2c();              //启动总线
  89.    SendByte(sla);            //发送器件地址
  90.    if(ack==0)return(0);
  91.    SendByte(c);              //发送数据
  92.    if(ack==0)return(0);
  93.    Stop_I2c();               //结束总线
  94.    return(1);
  95. }

  96. /*******************************************************************
  97. ADC读字节数据函数               
  98. *******************************************************************/
  99. unsigned char IRcvByte(unsigned char sla)
  100. {  unsigned char c;

  101.    Start_I2c();          //启动总线
  102.    SendByte(sla+1);      //发送器件地址
  103.    if(ack==0)return(0);
  104.    c=RcvByte();          //读取数据0

  105.    Ack_I2c(1);           //发送非就答位
  106.    Stop_I2c();           //结束总线
  107.    return(c);
  108. }

  109. /***************************************************************************************
  110.   * @实现效果        UART1接收到上位机发送的数据后,把接收的数据再次发送给上位机
  111.   * @注意                波特率1200,8位数据,无校验位               
  112. ***************************************************************************************/
  113. void main(void)
  114. {
  115.         uint8_t bai,shi,ge;
  116.         uint16_t i;
  117. /********************************系统初始化*******************************************/               
  118.         WDTCCR = 0x00;                           //关闭看门狗
  119.                                                            //本例程为方便测试关闭看门狗,实际使用中,建议客户打开看门狗,详见WDT复位例程
  120.         CLKCON = 0x02;                           //选择内部高频RC为系统时钟,Fosc=32MHz
  121.         CLKDIV = 0x02;                           //Fosc 2分频得到Fper,Fper=16MHz        
  122. /**********************************IO配置初始化**************************************/        
  123.     P2M2 = P2M2&0x0F|0x20;                //P25设置为上拉输入
  124.     P2M2 = P2M2&0xF0|0x08;                //P24设置为推挽输出
  125.         P0M0 = P0M0 & 0xF0 | 0x0A;  //P00带上拉开漏输出
  126.         P0M0 = P0M0 & 0x0F | 0x80;  //P01推挽输出
  127.         SCL_MAP = 0x01;                           //SCL映射P01口
  128.         SDA_MAP = 0x00;                           //SDA映射P00口
  129.         IICCON = 0x40;                           //启动IIC模块
  130. /**********************************UART配置初始化**************************************/        
  131.     TXD_MAP = 0x14;                                                //TXD映射P24
  132.                 RXD_MAP = 0x15;                                                //RXD映射P25
  133.         
  134.         //8位数据发送,波特率1200
  135.         //波特率计算
  136.         //波特率 = 1/16 * 时钟源频率 / (65536 - 0xFCBE)
  137.         //       = 1/16 * 16000000 / 834)
  138.         //        = 1199.04(误差0.05%)

  139.         //波特率1200
  140.         //反推初值
  141.         //初值 = (65536 - (Fper / 波特率) * (1 / 16))
  142.         //           = (65536 - (16000000 / 1200) * (1 / 16))
  143.         //           = (65536 - 833.33)
  144.         //     = FCBE
  145.         

  146.     SBRTH = 0xFCBE/256;      
  147.         SBRTL = 0xFCBE%256;
  148.         SCON2 = 0x12;                                //8位UART 独立波特率,波特率可变
  149.         SCON  = 0x10;                                 //开串口接收

  150.         //IE = 0x10;                                         //使能串口中断
  151.         //EA = 1;                                                //使能总中断
  152.         while(1)
  153.         {
  154. //                if(guc_Uartflag)
  155. //                {
  156. //                        IE &=~ 0x10;                                  //失能UART1中断
  157. //                        for(guc_i= 0;guc_i<guc_Uartcnt;guc_i++)
  158. //                        {
  159. //                                SBUF = guc_Uartbuf_a[guc_i];                          //发送数据
  160. //                                while(!(SCON&0x02));
  161. //                                SCON &=~ 0x02;                        //发送中断请求中断标志位清0
  162. //                        }
  163. //                        guc_Uartflag = 0;                        //标志位置0        
  164. //                        guc_Uartcnt = 0;
  165. //                        SCON |= 0x10;                                 //使能串口中断
  166. //                        IE |= 0x10;                                      //UART1中断使能
  167. //                }
  168.                   DACconversion(0x40,DAC_VALUE);
  169.                   DAC_VALUE+=5;
  170.                   delay(200);
  171.                   //ISendByte(PCF8591,0x40);
  172.                   ADCVALUE=ADC(0x40);  //ADC0 模数转换1      光敏电阻
  173. //                  ISendByte(PCF8591,0x40);
  174. //                  ADCVALUE=IRcvByte(PCF8591);  //ADC0 模数转换1      光敏电阻
  175.                   bai=ADCVALUE/100+0x30;
  176.                   shi=ADCVALUE%100/10+0x30;
  177.                   ge=ADCVALUE%10+0x30;
  178.                   txBuf[11]=bai;
  179.                   txBuf[12]=shi;
  180.                   txBuf[13]=ge;
  181.                         for(i = 0; i < sizeof(txBuf); i++)
  182.                         {
  183.                                         SBUF = txBuf[i];                          //发送数据
  184.                                         while(!(SCON&0x02));
  185.                                         SCON &=~ 0x02;                        //发送中断请求中断标志位?
  186.                         }
  187.                         delay(200);
  188.                                         //        for(i=0;i<50000;i++);
  189.         }

  190. }

  191. /***************************************************************************************
  192.   * @说明          UART1中断服务函数
  193.   *        @参数          无
  194.   * @返回值 无
  195.   * @注                  无
  196. ***************************************************************************************/
  197. void delay(volatile uchar i)
  198. {
  199.   volatile uchar j,k;
  200.   for(j=i;j>0;j--)
  201.     for(k=125;k>0;k--);
  202. }
效果图:
8.jpg 9.jpg
有何不可0365 发表于 2024-7-31 14:45 | 显示全部楼层
在 ADC 函数中,你需要指定要读取的 ADC 通道。根据 PCF8591 的工作原理,读取 ADC 时需要首先选择 ADC 通道(如 A0、A1、A2、A3)。在你的代码中,fuc_Add 可能是选择 ADC 通道的控制字节。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

470

主题

3537

帖子

7

粉丝
快速回复 在线客服 返回列表 返回顶部