找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 22892|回復(fù): 35
打印 上一主題 下一主題
收起左側(cè)

51單片機入門經(jīng)驗分享7-更加實用的ADC轉(zhuǎn)換程序

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:74187 發(fā)表于 2018-10-13 09:22 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
                              更加實用的ADC轉(zhuǎn)換程序


    來接著繼續(xù)分享單片機的一些學(xué)習(xí)經(jīng)歷,上一次,我們寫了一個測試電壓的程序,但是這樣的程序是不實用的,所以我們這一節(jié),來介紹個比較實用的程序,還是測電池電壓,然后我們解釋一下這個代碼,這一節(jié)狠狠狠重要。。。
     先把代碼獻(xiàn)上,然后我們再來分析
  1. /*******************************************************************************
  2. * 文件名: ADC轉(zhuǎn)換器使用
  3. * 描  述: 電池電壓
  4. * 功  能:中斷方式
  5. * 作  者:大核桃
  6. * 版本號:1.0.1(2017.05.23)
  7. *******************************************************************************/
  8. #include "stc15w.h"//頭文件
  9. #include "intrins.h"



  10. /*******************************************************************************
  11. * 文件名: 重定義
  12. * 描  述:   
  13. * 功  能:
  14. * 作  者:大核桃
  15. * 版本號:1.0.1(2017.05.23)
  16. *******************************************************************************/
  17. typedef unsigned char uint8;
  18. typedef unsigned int  uint16;
  19. typedef unsigned long uint32;

  20. #define ADC_POWER   0x80            //ADC電源控制位
  21. #define ADC_FLAG    0x10            //ADC完成標(biāo)志
  22. #define ADC_START   0x08            //ADC起始控制位
  23. #define ADC_SPEEDLL 0x00            //540個時鐘
  24. //#define ADC_SPEEDL  0x20            //360個時鐘
  25. //#define ADC_SPEEDH  0x40            //180個時鐘
  26. //#define ADC_SPEEDHH 0x60            //90個時鐘

  27. /*******************************************************************************
  28. * 文件名:全局變量定義區(qū)域
  29. * 描  述:
  30. * 功  能:
  31. * 作  者:大核桃
  32. * 版本號:1.0.1(2015.03.03)
  33. *******************************************************************************/
  34. uint8 val,ch;
  35. uint16 temp;
  36. bit flag_ad2 = 0;//電壓采集完成標(biāo)志
  37. bit flag_coll1 = 0;//數(shù)據(jù)采集間隔
  38. uint16 Adresult_val = 0;//采集的AD數(shù)值xx
  39. uint8 ad_count = 0; //采集AD的次數(shù)計數(shù)器

  40. /*******************************************************************************
  41. * 文件名:共陽數(shù)碼管真值表
  42. * 描  述:
  43. * 功  能:
  44. * 作  者:大核桃
  45. * 版本號:1.0.1(2015.03.03)
  46. *******************************************************************************/
  47. code uint8 LedChar[] = {
  48.         0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
  49.         0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff,0xc1
  50. };

  51. /*******************************************************************************
  52. * 文件名:單獨位定義
  53. * 描  述:   
  54. * 功  能:
  55. * 作  者:大核桃
  56. * 版本號:1.0.1(2017.05.23)
  57. *******************************************************************************/
  58. sbit LED0 = P1^0;//第1組LED
  59. sbit LED1 = P1^1;//第2組LED
  60. sbit LED2 = P1^2;//第3組LED                                 
  61. sbit LED3 = P1^3;//第4組LED
  62. sbit LED4 = P1^4;//第5組LED
  63. sbit LED5 = P3^2;//第6組LED
  64. sbit LED6 = P0^0;//第7組LED
  65. sbit LED7 = P0^1;//第8組LED

  66. sbit LEDS1 = P3^3;//數(shù)碼管1
  67. sbit LEDS2 = P3^4;//數(shù)碼管2
  68. sbit LEDS3 = P3^6;//數(shù)碼管3
  69. sbit LEDS4 = P3^7;//數(shù)碼管4

  70. /*******************************************************************************
  71. * 文件名:函數(shù)前置聲明
  72. * 描  述:   
  73. * 功  能:
  74. * 作  者:大核桃
  75. * 版本號:1.0.1(2017.05.23)
  76. *******************************************************************************/
  77. void Mcu_Port_Init();
  78. void LedScan();
  79. void Time0_Init();//定時器0
  80. void InitADC(void);
  81. uint16 VolTage_Monitor(uint8 times); //AD轉(zhuǎn)換與查表處理程序

  82. /*******************************************************************************
  83. * 文件名
  84. * 描  述: 主函數(shù)  
  85. * 功  能:入口
  86. * 作  者:大核桃
  87. * 版本號:1.0.1(2017.05.23)
  88. *******************************************************************************/
  89. void main(void)
  90. {                                       
  91.         Mcu_Port_Init();//IO上電初始化
  92.         Time0_Init();
  93.         InitADC();

  94.         while(1)
  95.         {
  96.                 VolTage_Monitor(16);//采集16次數(shù)據(jù)
  97.         }
  98. }

  99. /*******************************************************************************
  100. * 文件名:void LedScan()
  101. * 描  述: LED刷新
  102. * 功  能:
  103. * 作  者:大核桃
  104. * 版本號:1.0.1(2017.05.23)
  105. *******************************************************************************/
  106. void LedScan()
  107. {
  108.         static uint8 i = 0;

  109.         P2 = 0Xff;
  110.         switch(i)
  111.         {
  112.                 case 0: LEDS4 = 0;LEDS1 = 1;P2 = 0x7f & LedChar[16];i++;break;
  113.                 case 1: LEDS1 = 0;LEDS2 = 1;P2 = LedChar[val / 10 % 10];i++;break;
  114.                 case 2: LEDS2 = 0;LEDS3 = 1;P2 = LedChar[val % 10];i++;break;
  115.                 case 3: LEDS3 = 0;LEDS4 = 1;P2 = LedChar[17];i = 0;break;

  116.                 default:break;
  117.         }
  118. }

  119. /*******************************************************************************
  120. * 文件名:void InitADC(void)
  121. * 描  述: //初始化 AD 轉(zhuǎn)換
  122. * 功  能:
  123. * 作  者:大核桃
  124. * 版本號:1.0.1(2015.03.03)
  125. *******************************************************************************/
  126. void InitADC(void)
  127. {
  128.         P1ASF = 0xE0; //設(shè)置 P1 口為模擬口
  129.         ADC_RES = 0; //清除結(jié)果寄存器
  130.         CLK_DIV |= 0x20; //ADRJ 為 1,ADC_RES 存放高兩位結(jié)果,ADC_RESL 存放低 8 位結(jié)果
  131.     //ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START;
  132.         ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START;                    //ADC上電并延時
  133. }

  134. /*******************************************************************************
  135. * 文件名:void adc_isr() interrupt 5 using 1
  136. * 描  述: 中斷服務(wù)程序
  137. * 功  能:
  138. * 作  者:大核桃
  139. * 版本號:1.0.1(2015.03.03)
  140. *******************************************************************************/
  141. void adc_isr() interrupt 5 using 1
  142. {
  143.         EADC = 1;//開ADC中斷

  144.         ADC_CONTR &= !ADC_FLAG; //清除ADC中斷標(biāo)志
  145.         temp = ADC_RES;
  146.         temp <<= 8;
  147.         temp |= ADC_RESL;
  148.         flag_ad2 = 1; //電壓采集完成標(biāo)志
  149.         ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START | 5;

  150.         EADC = 0;//關(guān)閉中斷               

  151. }

  152. /*******************************************************************************
  153. * 文件名:VolTage_Monitor(void);
  154. * 描  述: 電壓結(jié)果計算
  155. * 功  能:模編程塊化
  156. * 作  者:大核桃
  157. * 版本號:1.0.1(2015.03.03)
  158. *******************************************************************************/
  159. uint16 VolTage_Monitor(uint8 times) //AD轉(zhuǎn)換與查表處理程序
  160. {
  161.    if(flag_coll1) //每次采集AD的時間間隔標(biāo)志位
  162.    {
  163.                 if(ad_count < times)//連續(xù)采集16次后再把求總數(shù)據(jù)的平均值
  164.                 {
  165.                         if(flag_ad2 == 1)   //完成一次AD采樣
  166.                         {
  167.                                 flag_ad2 = 0;  //清除完成一次采樣的標(biāo)志位

  168.                                 Adresult_val = Adresult_val + temp;
  169.                                 ad_count++;
  170.                                 ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START | 5;
  171.                         }
  172.                 } //右移動一位數(shù)據(jù)就相當(dāng)于整除以2
  173.                 else  //已經(jīng)采集完16次數(shù)據(jù),這個時候把總累加數(shù)據(jù)除以16就可以求得平均值了
  174.                 {
  175.                         Adresult_val >>= 4;
  176.                         val = ((Adresult_val) * 2 * (3.3 / 1023) * 10);//放大10
  177.                         Adresult_val = 0; //AD暫存清零
  178.                         temp = 0;        //把采集AD的結(jié)果清零
  179.                         ad_count = 0;     //把采集次數(shù)重新清零
  180.                 }
  181.    }

  182.    return  val;//返回采集的電壓數(shù)值
  183. }

  184. /*******************************************************************************
  185. * 文件名:void Time0_Init()
  186. * 描  述: 定時器0初始化
  187. * 功  能:1毫秒@11.0592MHz
  188. * 作  者:大核桃
  189. * 版本號:1.0.1(2017.05.23)
  190. *******************************************************************************/
  191. void Time0_Init(void)
  192. {
  193.         AUXR |= 0x80;   //定時器時鐘1T模式
  194.         TMOD &= 0xF0;        //設(shè)置定時器模式
  195.         TL0 = 0xCD;                //設(shè)置定時初值
  196.         TH0 = 0xD4;                //設(shè)置定時初值
  197.         ET0 = 1;
  198.         TR0 = 1;                //定時器0開始計時
  199.         EA = 1;               
  200. }
  201. /*******************************************************************************
  202. * 文件名:
  203. * 描  述: 中斷函數(shù)
  204. * 功  能:1毫秒@11.0592MHz
  205. * 作  者:大核桃
  206. * 版本號:1.0.1(2017.05.23)
  207. *******************************************************************************/
  208. void ET0_IRQHandler() interrupt 1
  209. {
  210.         static uint8 tmrcoll1 = 0;//數(shù)據(jù)采集間隔

  211.         EADC = 0;  //在定時中斷中禁止AD中斷

  212.     TL0 = 0xCD;                //設(shè)置定時初值
  213.         TH0 = 0xD4;                //設(shè)置定時初值

  214.         tmrcoll1++;//數(shù)據(jù)采集時間累加
  215.         if(tmrcoll1 >= 2) // 2 = 2ms                                                                                                                                                                           //1
  216.         {
  217.             tmrcoll1 = 0;
  218.                 flag_coll1 = 1;//數(shù)據(jù)采集間隔標(biāo)志位 2ms讀取一次數(shù)據(jù)
  219.         }

  220.         LedScan();

  221.         EADC = 1;  //在定時中斷中打開AD中斷
  222.                         
  223. }

  224. /*******************************************************************************
  225. * 文件名:void Mcu_Port_Init()
  226. * 描  述: io初始化
  227. * 功  能:
  228. * 作  者:大核桃
  229. * 版本號:1.0.1(2017.05.23)
  230. *******************************************************************************/
  231. void Mcu_Port_Init()
  232. {
  233.         IE = 0xa8;//允許AD轉(zhuǎn)換
  234.         //將P0口低二位配置為推挽輸出
  235.         //234567位配置位高阻輸入
  236.         P0M1 = 0xFC;//1111 1100
  237.         P0M0 = 0X03;//0000 0011
  238.         //P0 = 0X01;//第6個
  239.         //P0 = 0X02;//第7個
  240.         //高3位配置高阻輸入,用作模擬口
  241.         //其他配置推挽輸出,驅(qū)動LED
  242.         P1M1 = 0xE0;//1110 0000
  243.         P1M0 = 0X1F;//0001 1111
  244.         //P2口配置準(zhǔn)雙向口
  245.         P2M1 = 0X00;
  246.         P2M0 = 0X00;
  247.         P2 = 0Xff; //上電為1111 1111


  248. //        //P54,P55口為推挽輸出
  249.         P5M1 = 0X00;
  250.         P5M0 = 0X00;
  251.         P5 = 0xFF;

  252.         //P37,P36,3.2,P3.3 P3.4口為推挽輸出
  253.         P3M1 = 0X00;
  254.         P3M0 = 0XFC;
  255.         P3 = 0X23; //0010 0111//第5個LED端口
  256.         
  257.         LED0 = 0;//第1組LED,如果使能請置為1
  258.         LED1 = 0;
  259.         LED2 = 0;
  260.         LED3 = 0;
  261.         LED4 = 0;
  262.         LED5 = 0;
  263.         LED6 = 0;
  264.         LED7 = 0;        
  265. }
復(fù)制代碼


先來介紹一些基本的理論知識,不然的話,可能有些東西無法搞懂。
     關(guān)于ADC的參考電壓
因為我們的電子時鐘是鋰電池供電的,電壓是3.7V的,我們這里用了一個3.3V的穩(wěn)壓芯片662K,輸出3.3V直接作為單片機的電源,也作為ADC的參考電壓,這里我們簡化了設(shè)計,沒有用外部的參考電壓源,對于一個簡單的來說,這樣也是可以的。
     關(guān)于ADC的位數(shù)和分辨率
在這里,我們選擇ADC工作在10位方式,10位的ADC,是從0-1023,那么分辨率也就是3.3/1023 = 0.0032258064516129V,大概一個分辨率3mv左右。
     關(guān)于轉(zhuǎn)換時間和轉(zhuǎn)換速率
轉(zhuǎn)換時間和轉(zhuǎn)換速率是倒數(shù)的關(guān)系,所謂的轉(zhuǎn)換時間,指的是ADC從開始啟動,到ADC轉(zhuǎn)換完成出結(jié)果,這個時間該怎么去計算呢?我們在程序中選擇了時鐘頻率是11.0592MHZ,那么我們ADC的時鐘頻率也就是11.0592MHZ了,在程序中,我們選擇了540個時鐘周期完成一個ADC轉(zhuǎn)換,轉(zhuǎn)換速率也就是20KHZ左右,轉(zhuǎn)換時間大約是48US左右
    關(guān)于采樣頻率和采樣周期
采樣頻率和采樣周期也是互為倒數(shù)的關(guān)系,這個和上面的轉(zhuǎn)換時間,轉(zhuǎn)換速率非常容易讓人搞迷糊,關(guān)于采樣頻率,有一個采樣定理,叫奈奎斯特采樣定律,這個定律說的是,采樣頻率不能低于輸入ADC的信號的最高頻率的2倍,舉個例子,比如上面這樣的情況,我們選擇540個時鐘周期完成一次ADC轉(zhuǎn)換,那么轉(zhuǎn)換速率是20KHZ,那么也就是說,如果我們要保證信號采集的是完整的波形,那么這個輸入的信號不能超過10KHZ,你想想看,如果輸入的信號大于10KHZ,而你轉(zhuǎn)換速率是20KHZ,如果采樣頻率小于20KHZ,那么可能你還沒有完成一個完整的ADC轉(zhuǎn)換過程,或者采集的波形不是完整的,那么這樣的ADC的結(jié)果跟實際值比較會存在嚴(yán)重的失真,這樣是不被允許的。

   好了,經(jīng)過以上知識的鋪墊,再來看程序代碼就應(yīng)該比較容易懂了,在程序中,我們選擇了在ADC進(jìn)中斷前打開EADC,處理完數(shù)據(jù)后,要關(guān)閉EADC這個ADC轉(zhuǎn)換中斷使能標(biāo)志位,防止其他中斷或者任務(wù)打斷ADC的采集。我們在任務(wù)中選擇的采樣頻率是500HZ,也就是2MS啟動ADC采集依次數(shù)據(jù),連續(xù)采集16次,因為我們所采集的電壓信號的變化頻率沒有那么快速,所以,我們這里是可以這樣用的,當(dāng)啟動了一次AD轉(zhuǎn)換之后,進(jìn)行計數(shù),如果小于16次,那么一直在IF里面執(zhí)行,當(dāng)系統(tǒng)檢測到完成一個AD轉(zhuǎn)換,將AD轉(zhuǎn)換完成標(biāo)志位清零,將讀取的相關(guān)通道的ADC數(shù)值累加,繼續(xù)采集,如果采集完成了,那么進(jìn)行取平均運算,然后將結(jié)果計算出來,賦值給相關(guān)的變量就可以了,然后對相關(guān)的變量或者緩沖區(qū)清零,這樣,顯示在數(shù)碼管上的電壓結(jié)果是比較穩(wěn)定的。和前面那個例子不一樣,我們這個例子用的是STC15W單片機定時器0的1T模式,也就是說比原來快了12倍,這個移植的時候一定要注意。
   好了,今天就到這里吧,源碼奉獻(xiàn)上。
007 實用的AD轉(zhuǎn)換器的使用.rar (50.8 KB, 下載次數(shù): 259)



     



評分

參與人數(shù) 1黑幣 +3 收起 理由
tab001 + 3

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏31 分享淘帖 頂5 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:413430 發(fā)表于 2018-10-22 14:14 | 只看該作者
感謝分享
回復(fù)

使用道具 舉報

板凳
ID:416567 發(fā)表于 2018-10-28 09:27 | 只看該作者
感謝分享............
回復(fù)

使用道具 舉報

地板
ID:284702 發(fā)表于 2018-11-10 23:55 | 只看該作者
感謝分享............
回復(fù)

使用道具 舉報

5#
ID:427566 發(fā)表于 2018-11-16 10:19 | 只看該作者
謝謝大佬
回復(fù)

使用道具 舉報

6#
ID:426444 發(fā)表于 2018-11-20 15:30 來自手機 | 只看該作者
感謝,能派上用場了
回復(fù)

使用道具 舉報

7#
ID:434952 發(fā)表于 2018-11-28 16:49 | 只看該作者
感謝分享
回復(fù)

使用道具 舉報

8#
ID:116662 發(fā)表于 2018-11-28 22:06 | 只看該作者
多謝師傅知識分享,公開者大公無私,贊一個
回復(fù)

使用道具 舉報

9#
ID:435900 發(fā)表于 2018-11-29 17:17 | 只看該作者
樓主,val = ((Adresult_val) * 2 * (3.3 / 1023) * 10);//放大10 這里為什么要*2呢
回復(fù)

使用道具 舉報

10#
ID:417062 發(fā)表于 2018-12-10 08:10 | 只看該作者
厲害了額 小學(xué)生這么難的
回復(fù)

使用道具 舉報

11#
ID:76133 發(fā)表于 2018-12-24 16:01 | 只看該作者
感謝分享
回復(fù)

使用道具 舉報

12#
ID:393577 發(fā)表于 2018-12-28 09:46 | 只看該作者
仗義 發(fā)表于 2018-12-10 08:10
厲害了額 小學(xué)生這么難的

誰讓我們是從幼兒園畢業(yè)200多月的寶寶呢
回復(fù)

使用道具 舉報

13#
ID:461280 發(fā)表于 2019-1-3 20:10 | 只看該作者
厲害厲害
回復(fù)

使用道具 舉報

14#
ID:461889 發(fā)表于 2019-1-23 10:13 | 只看該作者

感謝分享
回復(fù)

使用道具 舉報

15#
ID:477934 發(fā)表于 2019-2-20 17:25 | 只看該作者
有一點用,先下了
回復(fù)

使用道具 舉報

16#
ID:485529 發(fā)表于 2019-3-6 13:46 | 只看該作者
MARK,多謝樓主分享
回復(fù)

使用道具 舉報

17#
ID:524764 發(fā)表于 2019-5-10 15:39 | 只看該作者
感謝,謝謝分享
回復(fù)

使用道具 舉報

18#
ID:404572 發(fā)表于 2019-8-22 12:52 | 只看該作者
感謝分享
回復(fù)

使用道具 舉報

19#
ID:613800 發(fā)表于 2019-10-8 22:59 | 只看該作者
感謝。分享。
回復(fù)

使用道具 舉報

20#
ID:76612 發(fā)表于 2019-11-15 10:53 | 只看該作者
感謝分享
回復(fù)

使用道具 舉報

21#
ID:626079 發(fā)表于 2019-11-22 16:59 | 只看該作者

感謝分享
回復(fù)

使用道具 舉報

22#
ID:646449 發(fā)表于 2019-12-5 09:16 | 只看該作者
哭了,這帖子太好了
回復(fù)

使用道具 舉報

23#
ID:610633 發(fā)表于 2020-2-17 15:55 | 只看該作者
為什么放大10呢?
回復(fù)

使用道具 舉報

24#
ID:294865 發(fā)表于 2020-2-27 15:49 | 只看該作者
這個注示寫的太好了,條理清楚。不懂的人都很容易看懂。
回復(fù)

使用道具 舉報

25#
ID:727207 發(fā)表于 2020-4-11 22:00 | 只看該作者

感謝分享.感謝分享.
回復(fù)

使用道具 舉報

26#
ID:736629 發(fā)表于 2020-4-24 00:32 | 只看該作者
謝謝樓主分享。。。。。。
回復(fù)

使用道具 舉報

27#
ID:305511 發(fā)表于 2020-5-14 15:56 | 只看該作者
非常感謝分享!
回復(fù)

使用道具 舉報

28#
ID:747667 發(fā)表于 2020-5-20 10:57 來自手機 | 只看該作者
謝謝分享
回復(fù)

使用道具 舉報

29#
ID:805324 發(fā)表于 2020-7-19 10:05 來自手機 | 只看該作者
LowHuang 發(fā)表于 2018-11-29 17:17
樓主,val = ((Adresult_val) * 2 * (3.3 / 1023) * 10);//放大10 這里為什么要*2呢

應(yīng)該是外圍分壓比
回復(fù)

使用道具 舉報

30#
ID:822728 發(fā)表于 2020-9-24 15:21 來自手機 | 只看該作者
我想知道怎么接線
回復(fù)

使用道具 舉報

31#
ID:824534 發(fā)表于 2020-9-29 11:14 | 只看該作者
如果有多個ADC,進(jìn)行采集,是否進(jìn)行I/o口切換,還是并行操作
回復(fù)

使用道具 舉報

32#
ID:356562 發(fā)表于 2021-2-12 08:29 | 只看該作者
正在學(xué)習(xí)STC芯片的AD,很好的資料。
回復(fù)

使用道具 舉報

33#
ID:46228 發(fā)表于 2021-4-29 22:55 來自手機 | 只看該作者
現(xiàn)在才接觸adc,做電陶爐熱電偶+lm358,溫度達(dá)到500度,關(guān)閉繼電器這樣的工程,遺憾的是,能力有限,這么長時間了,還是實現(xiàn)不了,真是絕望啊
回復(fù)

使用道具 舉報

34#
ID:976070 發(fā)表于 2021-11-17 21:57 | 只看該作者
正在學(xué)習(xí)AD轉(zhuǎn)換,很好資料。
回復(fù)

使用道具 舉報

35#
ID:1049825 發(fā)表于 2022-10-31 18:52 | 只看該作者
你他娘的是個天才,還能與大家分享,贊一個.
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表