找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5526|回复: 15
收起左侧

关于ADC0832采集电压的范围

[复制链接]
ID:549426 发表于 2020-11-10 20:15 | 显示全部楼层 |阅读模式
如果采集的电压不在0-5V,电压是-1v-3v,这种程序应该怎么写,或者这个电压在0-1v这个程序又该怎么写,谢谢!
回复

使用道具 举报

ID:213173 发表于 2020-11-11 07:51 | 显示全部楼层
如果采集的电压不在0~VCC范围,假设是±1.5V,可以通过双电源运放转换到0~VCC。采集到的ADC数据通过运算就可以显示正负值。
回复

使用道具 举报

ID:549426 发表于 2020-11-12 23:23 | 显示全部楼层
wulin 发表于 2020-11-11 07:51
如果采集的电压不在0~VCC范围,假设是±1.5V,可以通过双电源运放转换到0~VCC。采集到的ADC数据通过运算就 ...

现在在做一个PM2.5检测系统,目前在网上查询到的很多都是用夏普模块做的,现在我手上拿到的模块,初始无尘电压是0.2v,而夏普的电压是0.9v,看了别人的算法是:
            DUST=Error_Correct(ADC_Get,10);
            DUST_Value=(DUST/256.0)*5;//转化成电压值
            DUST_Value=(DUST_Value*0.17-0.1)*1000;//固体悬浮颗粒浓度计
里面这个算法公式电压值乘0.17在减0.1是怎么来的,如果我要换成自己手里的模块,公式应该怎么变换,谢谢
回复

使用道具 举报

ID:549426 发表于 2020-11-12 23:29 | 显示全部楼层
wulin 发表于 2020-11-11 07:51
如果采集的电压不在0~VCC范围,假设是±1.5V,可以通过双电源运放转换到0~VCC。采集到的ADC数据通过运算就 ...

https://kdocs.cn/l/srCscYPuHbqz?f=111
[文档] GP2Y1010AU_设计参考指南及原理.pdf
https://kdocs.cn/l/sqjSGUZ0Y7jH?f=111
[文档] SS-关于日本友穗(株)DSH02灰尘传感器规格书-20160506.pdf
这是我拿到的模块和夏普模块,如果要修改浓度算法,该怎么修改,谢谢!
回复

使用道具 举报

ID:128695 发表于 2020-11-12 23:34 | 显示全部楼层
如果有正负电压,一般需要通过模拟电路如运放加法器抬升到正电压进行检测,如果是0~1V这种小电压为了保证精度可以通过运放放大到adc满量程范围,如对精度要求不高也可以只利用adc的1/5范围进行采集
回复

使用道具 举报

ID:549426 发表于 2020-11-12 23:42 | 显示全部楼层
dreamtek 发表于 2020-11-12 23:34
如果有正负电压,一般需要通过模拟电路如运放加法器抬升到正电压进行检测,如果是0~1V这种小电压为了保证精 ...

我现在有个传感器输出是0.2-3.5v这种用你说的办法写程序的时候怎么写
回复

使用道具 举报

ID:213173 发表于 2020-11-13 06:25 | 显示全部楼层
ybsuse 发表于 2020-11-12 23:23
现在在做一个PM2.5检测系统,目前在网上查询到的很多都是用夏普模块做的,现在我手上拿到的模块,初始无 ...

ADC采样和显示测量结果是两回事。传感器的输出电压范围远小于ADC采样电压范围会明显影响采样精度。通常在传感器与ADC之间加入运算放大器,以使两者适用电压变化范围接近。ADC转换结果不能直接表示实际值,需要通过换算才能得到实际值。如果传感器的输出电压与样本浓度呈正线性关系,那么按比例换算非常简单;如果是呈非线性关系,就很难用简单公式来计算。通常是根据传感器制造商提供的资料制作数据表(数组),用查表法将ADC转换结果与数据表比对,从而得到实际值用于显示或其它用途。楼主所问上述算法公式中电压值乘0.17再减0.1是怎么来的。0.17明显是比值,0.1应该是修正值。
回复

使用道具 举报

ID:549426 发表于 2020-11-13 15:24 | 显示全部楼层
wulin 发表于 2020-11-13 06:25
ADC采样和显示测量结果是两回事。传感器的输出电压范围远小于ADC采样电压范围会明显影响采样精度。通常在 ...

夏普模块,前段基本是线性变化,后面拿到这个模块,厂家文档上面没有具体的参考数据,能帮忙看下么?
回复

使用道具 举报

ID:213173 发表于 2020-11-13 20:36 | 显示全部楼层
ybsuse 发表于 2020-11-13 15:24
夏普模块,前段基本是线性变化,后面拿到这个模块,厂家文档上面没有具体的参考数据,能帮忙看下么?

根据上述两个文件基本可以考虑使用内置10~12位ADC和EEPROM的单片机。ADC0832是8位ADC,分辨率不高。由于传感器有效测量范围基本呈线性变化,不必加前置运算放大器,EEPROM用于校准记录无尘电压,作为修正值。计算浓度也简单得多。
回复

使用道具 举报

ID:213173 发表于 2020-11-13 21:08 | 显示全部楼层
ybsuse 发表于 2020-11-13 15:24
夏普模块,前段基本是线性变化,后面拿到这个模块,厂家文档上面没有具体的参考数据,能帮忙看下么?

原厂资料下载https://www.waveshare.net/wiki/Dust_Sensor
回复

使用道具 举报

ID:549426 发表于 2020-11-14 00:49 | 显示全部楼层
wulin 发表于 2020-11-13 20:36
根据上述两个文件基本可以考虑使用内置10~12位ADC和EEPROM的单片机。ADC0832是8位ADC,分辨率不高。由于 ...

目前要求用ST89C52、ADC0832来做,因为实验室现成的配件。对于精度到不是一定要求多高,本来就是练手,通过项目来学习。
回复

使用道具 举报

ID:843349 发表于 2020-11-14 05:30 | 显示全部楼层
加法器试一下呢?
回复

使用道具 举报

ID:549426 发表于 2020-11-17 14:55 | 显示全部楼层
  1. #include <reg52.h>
  2. #include <intrins.h>
  3. #define uint unsigned int
  4. #define uchar unsigned char //宏定义
  5. sbit RS=P1^6;//液晶接口
  6. sbit EN=P1^7;

  7. sbit LED = P2^0;//粉尘传感器控制接口

  8. sbit ADCS = P3^7;//AD0832接口
  9. sbit ADCLK =P3^5;
  10. sbit ADDI = P3^6;
  11. sbit ADDO = P3^6;                  

  12. sbit SET= P1^1;//按键接口
  13. sbit ADD= P1^2;
  14. sbit DEC= P1^3;

  15. sbit BEEP=P2^1;//蜂鸣器接口

  16. uchar set_st;
  17. uchar tab[5];
  18. uint DUST_SET=150; //固体颗粒的阈值

  19. //bit shanshuo_st; //闪烁间隔标志
  20. bit beep_st; //蜂鸣器间隔标志
  21. uchar x=4; //计数器
  22. //定义标识
  23. uchar FlagStart = 0;
  24. float DUST_Value;
  25. uint DUST;
  26. uchar num=0;
  27. uchar mm;
  28. uchar abc;
  29. uchar ADC_Get[10]={0}; //定义AD采样数组
  30. uchar str[5]={0};

  31. /*****初始化定时器0*****/
  32. void InitTimer(void)
  33. {
  34.         TMOD = 0x01;
  35.         TL0 = (65536-10000)/256; //定时10ms
  36.         TH0 = (65536-10000)%256;
  37.         TR0 = 1;
  38.         ET0 = 1;
  39.         EA = 1;
  40. }
  41. /*************************lcd1602程序**************************/
  42. void delay1ms(uint ms)//延时1毫秒
  43. {
  44.     uint i,j;
  45.         for(i=0;i<ms;i++)
  46.         for(j=0;j<100;j++);
  47. }

  48. void wr_com(uchar com)//写指令//
  49. {
  50.     delay1ms(1);
  51.         RS=0;
  52. //        RW=0;
  53.         EN=0;
  54.         P0=com;
  55.         delay1ms(1);
  56.         EN=1;
  57.         delay1ms(1);
  58.         EN=0;
  59. }
  60. void wr_dat(uchar dat)//写数据//
  61. {
  62.     delay1ms(1);;
  63.         RS=1;
  64. //        RW=0;
  65.         EN=0;
  66.         P0=dat;
  67.         delay1ms(1);
  68.         EN=1;
  69.         delay1ms(1);
  70.         EN=0;
  71. }
  72. /*****************************液晶初始化
  73. *********************************************/
  74. void lcd_init()//初始化设置//
  75. {
  76.         delay1ms(15);
  77.         wr_com(0x38);
  78.         delay1ms(5);
  79.         wr_com(0x01);
  80.         delay1ms(5);
  81.         wr_com(0x06);
  82.         delay1ms(5);
  83.         wr_com(0x0c);
  84.         delay1ms(5);

  85.         wr_com(0x80);
  86.         wr_dat('P');//
  87.         wr_com(0x81);
  88.         wr_dat('M');//:
  89.         wr_com(0x82);
  90.         wr_dat('2');//
  91.         wr_com(0x83);
  92.         wr_dat('.');//:
  93.         wr_com(0x84);
  94.         wr_dat('5');//:
  95.         wr_com(0x85);
  96.         wr_dat(':');


  97.         wr_com(0x8b);
  98.         wr_dat('m');
  99.         wr_com(0x8c);
  100.         wr_dat('g');
  101.         wr_com(0x8d);
  102.         wr_dat('/');
  103.         wr_com(0x8e);
  104.         wr_dat('m');
  105.         wr_com(0x8f);
  106.         wr_dat('3');
  107.         


  108. /////////////////////////////////////

  109.         wr_com(0xc0);
  110.         wr_dat('A');
  111.         wr_com(0xc1);
  112.         wr_dat('l');
  113.         wr_com(0xc2);
  114.         wr_dat('a');
  115.         wr_com(0xc3);
  116.         wr_dat('r');
  117.         wr_com(0xc4);
  118.         wr_dat('m');
  119.         wr_com(0xc5);
  120.         wr_dat(':');

  121.         wr_com(0xcb);
  122.         wr_dat('m');
  123.         wr_com(0xcc);
  124.         wr_dat('g');
  125.         wr_com(0xcd);
  126.         wr_dat('/');
  127.         wr_com(0xce);
  128.         wr_dat('m');
  129.         wr_com(0xcf);
  130.         wr_dat('3');
  131. }
  132. /*****************显示函数******************************/
  133. void disp(unsigned int Data)//PM2.5值显示
  134. {
  135.         uint Temp;
  136.         Temp=Data%10000;
  137.         str[0]=Temp/1000+0x30; //千位
  138.         Temp%=1000;
  139.         str[1]='.';
  140.         str[2]=Temp/100+0x30; //百位
  141.         Temp%=100;
  142.         str[3]=Temp/10+0x30; //十位
  143.         str[4]=Temp%10+0x30; //个位
  144.         wr_com(0x86);
  145.         wr_dat(str[0]);
  146.         wr_com(0x87);
  147.         wr_dat(str[1]);
  148.         wr_com(0x88);
  149.         wr_dat(str[2]);
  150.         wr_com(0x89);
  151.         wr_dat(str[3]);
  152.         wr_com(0x8a);
  153.         wr_dat(str[4]);

  154. }
  155. /************************报警值显示************************************/
  156. void baojing()
  157. {
  158.         wr_com(0xc6);
  159.         wr_dat(tab[0]+0x30);
  160.         wr_com(0xc7);
  161.         wr_dat(tab[1]);
  162.         wr_com(0xc8);
  163.         wr_dat(tab[2]+0x30);
  164.         wr_com(0xc9);
  165.         wr_dat(tab[3]+0x30);
  166.         wr_com(0xca);
  167.         wr_dat(tab[4]+0x30);
  168. }
  169. /*****延时子程序*****/
  170. void Delay(uint num)
  171. {
  172. while( --num );
  173. }
  174. /**************************按键检测
  175. *******************************************/
  176. void checkkey()
  177. {
  178.         if(SET==0)
  179.         {
  180.         Delay(2000);
  181.         do{}while(SET==0);
  182.         set_st++;
  183.         if(set_st>1)set_st=0;
  184.         }
  185.         if(set_st==0)
  186.         {
  187.         }
  188.         else if(set_st==1)
  189.         {
  190.         if(DEC==0)
  191.         {
  192.         Delay(2000);
  193.         do{}while(DEC==0);
  194.         if(DUST_SET>0)DUST_SET--;
  195.         if(DUST_SET==0)DUST_SET=0;
  196.         }
  197.         if(ADD==0)
  198.         {
  199.         Delay(2000);
  200.         do{}while(ADD==0);
  201.         DUST_SET++;
  202.         if(DUST_SET>800)DUST_SET=800;
  203.         }
  204.         }
  205.         tab[0]=DUST_SET/1000;
  206.         tab[1]='.';
  207.         tab[2]=DUST_SET%1000/100;
  208.         tab[3]=DUST_SET%100/10;
  209.         tab[4]=DUST_SET%10;
  210. }
  211. /*****报警子程序*****/
  212. void Alarm()
  213. {
  214.         if(x>=10){beep_st=~beep_st;x=0;}
  215.         if(DUST>DUST_SET&&beep_st==1)BEEP=0;
  216.         else BEEP=1;
  217. //        if(DUST>0&&DUST<100){LED2=0;LED3=1;LED4=1;}
  218. //        if(DUST>=10&&DUST<300){LED2=1;LED3=0;LED4=1;}
  219. //        if(DUST>=300){LED2=1;LED3=1;LED4=0;}
  220.         }
  221. /**************************AD0832转换程序
  222. ***********************************************/
  223. uchar ADC0832(bit mode,bit channel) //AD转换,返回结果
  224. {
  225.         uchar i,dat,ndat;
  226.         ADCS = 0;//拉低CS端
  227.         _nop_();
  228.         _nop_();
  229.         ADDI = 1; //第1个下降沿为高电平
  230.         ADCLK = 1;//拉高CLK端
  231.         _nop_();
  232.         _nop_();
  233.         ADCLK = 0;//拉低CLK端,形成下降沿1
  234.         _nop_();
  235.         _nop_();
  236.         ADDI = mode; //低电平为差分模式,高电平为单通道模式。
  237.         ADCLK = 1;//拉高CLK端
  238.         _nop_();
  239.         _nop_();
  240.         ADCLK = 0;//拉低CLK端,形成下降沿2
  241.         _nop_();
  242.         _nop_();
  243.         ADDI = channel; //低电平为CH0,高电平为CH1
  244.         ADCLK = 1;//拉高CLK端
  245.         _nop_();
  246.         _nop_();
  247.         ADCLK = 0;//拉低CLK端,形成下降沿3
  248.         ADDI = 1;//控制命令结束(经试验必需)
  249.         dat = 0;
  250.         //下面开始读取转换后的数据,从最高位开始依次输出(D7~D0)
  251.         for(i = 0;i < 8;i++)
  252.         {
  253.         dat <<= 1;
  254.         ADCLK=1;//拉高时钟端
  255.         _nop_();
  256.         _nop_();
  257.         ADCLK=0;//拉低时钟端形成一次时钟脉冲
  258.         _nop_();
  259.         _nop_();
  260.         dat |= ADDO;
  261.         }
  262.         ndat = 0; //记录D0
  263.         if(ADDO == 1)
  264.         ndat |= 0x80;
  265.         //下面开始继续读取反序的数据(从D1到D7)
  266.         for(i = 0;i < 7;i++)
  267.         {
  268.         ndat >>= 1;
  269.         ADCLK = 1;//拉高时钟端
  270.         _nop_();
  271.         _nop_();
  272.         ADCLK=0;//拉低时钟端形成一次时钟脉冲
  273.         _nop_();
  274.         _nop_();
  275.         if(ADDO==1)
  276.         ndat |= 0x80;
  277.         }
  278.         ADCS=1;//拉高CS端,结束转换
  279.         ADCLK=0;//拉低CLK端
  280.         ADDI=1;//拉高数据端,回到初始状态
  281.         if(dat==ndat)
  282.         return(dat);
  283.         else
  284.         return 0;
  285. }
  286. /*****定时器0中断服务程序*****/
  287. void timer0(void) interrupt 1
  288. {
  289.         uint j;
  290.         TL0 = (65536-10000)/256; //定时10ms
  291.         TH0 = (65536-10000)%256;
  292.         LED=1; //开启传感器的LED
  293.         x++;
  294.         for (j=0;j<30;j++); //0.28ms //延时0.28ms
  295.         abc=ADC0832(1,0); //开启ADC采集
  296.         FlagStart=1;
  297.         TR0 = 0; //先关闭定时器0
  298.         EA = 0;
  299.         LED=0;//关闭传感器LED
  300. }
  301. //中值滤波
  302. //算法:先进行排序,然后将数组的中间值作为当前值返回。
  303. uchar Error_Correct(uchar *str,uchar num)
  304. {
  305.         unsigned char i=0;
  306.         unsigned char j=0;
  307.         unsigned char Temp=0;
  308.         //排序
  309.         for(i=0;i<num-1;i++)
  310.         {
  311.         for(j=i+1;j<num;j++)
  312.         {
  313.            if(str[i]<str[j])
  314.                 {
  315.                 Temp=str[i];
  316.                 str[i]=str[j];
  317.                 str[j]=Temp;
  318.                 }
  319.         }
  320. }

  321.         //去除误差,取中间值
  322.         return str[num/2];
  323. }
  324. /*****主函数*****/
  325. void main(void)
  326. {
  327.         InitTimer(); //初始化定时器
  328.         BEEP=1;
  329.         lcd_init();//初始化显示
  330.         delay1ms(500);
  331.         while(1)
  332.         {

  333.          checkkey();//按键检测
  334.         if(set_st==0)
  335.         {
  336.                 //wr_com(0x0c);
  337.                 if(FlagStart==1) //1次数据采集完成
  338.                 {
  339.                 num++;
  340.                 ADC_Get[num]=abc;
  341.                 if(num>9)
  342.                 {
  343.                 num=0;
  344. //                DUST=Error_Correct(ADC_Get,10); //求取10次AD采样的值
  345. //                DUST_Value=(DUST/256.0)*5000; //转化成电压值MV
  346. //                DUST_Value=DUST_Value*0.17-100; //固体悬浮颗粒浓度计算 Y=0.17*X-0.1 X--采样电压V
  347.         
  348.                 DUST=Error_Correct(ADC_Get,10);
  349.             DUST_Value=(DUST/256.0)*5;//转化成电压值
  350.             DUST_Value=(DUST_Value*0.17-0.1)*1000;//固体悬浮颗粒浓度计
  351.         
  352.                 if(DUST_Value<0) DUST_Value=0;
  353.                 if(DUST_Value>760) DUST_Value=760; //限位
  354.                 DUST=(uint)DUST_Value;
  355.                 }
  356.                 TL0 = (65536-10000)/256;
  357.                 TH0 = (65536-10000)%256;
  358.                 TR0 = 1; //开启定时器0
  359.                 EA = 1;
  360.                 FlagStart=0;
  361.                 }
  362.                 Alarm(); //报警检测
  363.         }
  364.         disp(DUST);//显示粉尘浓度值
  365.         baojing();//显示报警值

  366.                 if(set_st==1)//报警值闪动
  367.                 {
  368.                 wr_com(0xca);
  369.                 wr_com(0x0d);
  370.                 delay1ms(150);
  371.                 }
  372.         }
  373. }
复制代码

这是别人做好的夏普的程序,其中关于ADC采集回来的结果转换为灰尘浓度,不明白她的公式怎么来的,难道是按照给的那个图像,算出直线的方程,但是我我试了下也不是。
回复

使用道具 举报

ID:213173 发表于 2020-11-20 10:53 | 显示全部楼层
ybsuse 发表于 2020-11-17 14:55
这是别人做好的夏普的程序,其中关于ADC采集回来的结果转换为灰尘浓度,不明白她的公式怎么来的,难道 ...

P2.5.zip (112.16 KB, 下载次数: 7)
回复

使用道具 举报

ID:549426 发表于 2020-11-23 17:36 | 显示全部楼层
回复

使用道具 举报

ID:213173 发表于 2020-11-26 07:32 | 显示全部楼层

无标题.jpg

Dust Sensor 灰尘传感器 用户手册.pdf (659.61 KB, 下载次数: 4)
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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