找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1115|回复: 5
打印 上一主题 下一主题
收起左侧

看不懂单片机代码DA/AD这里的转化

[复制链接]
跳转到指定楼层
楼主
ID:1078938 发表于 2023-6-16 22:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
void ValueToString(unsigned char *str, unsigned char val)
{
//电压值=转换结果*2.5V/255,式中的25隐含了一位十进制小数
val = (val*25) / 255;
str[0] = (val/10) + '0'; //整数位字符
str[1] = '.'; //小数点
str[2] = (val%10) + '0'; //小数位字符
str[3] = 'V'; //电压单位
str[4] = '\0'; //结束符
}

就val = (val*25) / 255;这句看不懂,255我理解是PCF89C51模数转换器的量程,但是乘以25是什么意思了,为何又要除以255?这里的val是从I2C读取到的电压值。
我觉得是对A/D和D/A理解太模糊导致的。

整体代码如下:
  1. #include <reg52.h>

  2. bit flag300ms = 1;       //300ms定时标志
  3. unsigned char T0RH = 0;  //T0重载值的高字节
  4. unsigned char T0RL = 0;  //T0重载值的低字节

  5. void ConfigTimer0(unsigned int ms);
  6. unsigned char GetADCValue(unsigned char chn);
  7. void ValueToString(unsigned char *str, unsigned char val);
  8. extern void I2CStart();
  9. extern void I2CStop();
  10. extern unsigned char I2CReadACK();
  11. extern unsigned char I2CReadNAK();
  12. extern bit I2CWrite(unsigned char dat);
  13. extern void InitLcd1602();
  14. extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);

  15. void main()
  16. {
  17.     unsigned char val;
  18.     unsigned char str[10];
  19.    
  20.     EA = 1;            //开总中断
  21.     ConfigTimer0(10);  //配置T0定时10ms
  22.     InitLcd1602();     //初始化液晶   
  23.     LcdShowStr(0, 0, "AIN0  AIN1  AIN3");  //显示通道指示
  24.    
  25.     while (1)
  26.     {
  27.         if (flag300ms)
  28.         {
  29.             flag300ms = 0;
  30.             //显示通道0的电压
  31.             val = GetADCValue(0);     //获取ADC通道0的转换值
  32.             ValueToString(str, val);  //转为字符串格式的电压值
  33.             LcdShowStr(0, 1, str);    //显示到液晶上
  34.             //显示通道1的电压
  35.             val = GetADCValue(1);
  36.             ValueToString(str, val);
  37.             LcdShowStr(6, 1, str);
  38.             //显示通道3的电压
  39.             val = GetADCValue(3);
  40.             ValueToString(str, val);
  41.             LcdShowStr(12, 1, str);
  42.         }
  43.     }
  44. }
  45. /* 读取当前的ADC转换值,chn-ADC通道号0~3 */
  46. unsigned char GetADCValue(unsigned char chn)
  47. {
  48.     unsigned char val;
  49.    
  50.     I2CStart();
  51.     if (!I2CWrite(0x48<<1))  //寻址PCF8591,如未应答,则停止操作并返回0
  52.     {
  53.         I2CStop();
  54.         return 0;
  55.     }
  56.     I2CWrite(0x40|chn);        //写入控制字节,选择转换通道
  57.     I2CStart();
  58.     I2CWrite((0x48<<1)|0x01);  //寻址PCF8591,指定后续为读操作   
  59.     I2CReadACK();              //先空读一个字节,提供采样转换时间
  60.     val = I2CReadNAK();        //读取刚刚转换完的值
  61.     I2CStop();
  62.    
  63.     return val;
  64. }
  65. /* ADC转换值转为实际电压值的字符串形式,str-字符串指针,val-AD转换值 */
  66. void ValueToString(unsigned char *str, unsigned char val)
  67. {
  68.     //电压值=转换结果*2.5V/255,式中的25隐含了一位十进制小数
  69.     val = (val*25) / 255;
  70.     str[0] = (val/10) + '0';  //整数位字符
  71.     str[1] = '.';             //小数点
  72.     str[2] = (val%10) + '0';  //小数位字符
  73.     str[3] = 'V';             //电压单位
  74.     str[4] = '\0';            //结束符
  75. }

  76. void ConfigTimer0(unsigned int ms)
  77. {
  78.     unsigned long tmp;  //临时变量
  79.    
  80.     tmp = 11059200 / 12;      //定时器计数频率
  81.     tmp = (tmp * ms) / 1000;  //计算所需的计数值
  82.     tmp = 65536 - tmp;        //计算定时器重载值
  83.     tmp = tmp + 12;           //补偿中断响应延时造成的误差
  84.     T0RH = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节
  85.     T0RL = (unsigned char)tmp;
  86.     TMOD &= 0xF0;   //清零T0的控制位
  87.     TMOD |= 0x01;   //配置T0为模式1
  88.     TH0 = T0RH;     //加载T0重载值
  89.     TL0 = T0RL;
  90.     ET0 = 1;        //使能T0中断
  91.     TR0 = 1;        //启动T0
  92. }

  93. void InterruptTimer0() interrupt 1
  94. {
  95.     static unsigned char tmr300ms = 0;
  96.    
  97.     TH0 = T0RH;  //重新加载重载值
  98.     TL0 = T0RL;
  99.     tmr300ms++;
  100.     if (tmr300ms >= 30)  //定时300ms
  101.     {
  102.         tmr300ms = 0;
  103.         flag300ms = 1;
  104.     }
  105. }
复制代码

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:1078938 发表于 2023-6-16 22:07 | 只看该作者
51单片机的模数和数模转换,难以理解?
回复

使用道具 举报

板凳
ID:94031 发表于 2023-6-17 06:37 | 只看该作者
比如用传感器测压力,AD转换出来的内码(val)并不是我们要的压力值,要通过量程转换变成真实的压力值,这个25就是转换系数,要根据实际环境调整大小。
回复

使用道具 举报

地板
ID:466505 发表于 2023-6-17 08:50 | 只看该作者
2.5/255=V取样/val
V取样=val*2.5/255, 换成用25*val是为了避免浮点运算
回复

使用道具 举报

5#
ID:624769 发表于 2023-6-17 17:15 | 只看该作者
你已经知道,255是量程。
25则是 满量程情况下的电压值。大多基准电压都是2.5V.

你71行代码中的注释已经写的很清楚了:
//电压值=转换结果*2.5V/255,式中的25隐含了一位十进制小数
而72行的代码,就是依据71行的注释的具体实现。
回复

使用道具 举报

6#
ID:1045628 发表于 2023-6-19 14:43 | 只看该作者
这就相当于  y = kx + b
y 相当于你的电压
x 相当于获取的ADC
k 相当于25/255
b 在这里为0
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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