久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4649|回復: 5
打印 上一主題 下一主題
收起左側

分享一個用單片機比較器做電壓表的程序

  [復制鏈接]
跳轉到指定樓層
樓主
本程序用STC15W201S單片機。16引腳共14IO,  共連接 一個 3位 8段共陰數碼管,兩個按鍵,以及680K+10K電阻分壓連接比較器測量外部電壓。
其中,P10~P15 + P36,P37 分別通過1K電阻連接數碼管 段選 ,P31~P33 直接接數碼管共陰位選,P5.4,P5.5 操縱比較器測量電壓,P3.0, 接兩個按鍵,分別連接P3.1 P3.2 共陰位選引腳。可以說用光單片機所有IO.

電壓比較通過TO定時器 實現,T2定時器負責按鍵檢測和數碼管顯示。按鍵主要是為了校正阻值的誤差所造成的電壓失準。校正后自動保存Eeprom. 初始數值已經存在隨壓縮包的bin文件中,燒錄文件時,應通過Eeprom頁一起燒入單片機。

單片機源程序如下:
  1. /****************************
  2. 本示例在Keil開發環境下請選擇STC15系列芯片型號進行編譯

  3. 本例程MCU的工作頻率為24MHz,  工作電壓3~5V均可.

  4. 使用MCU自帶的比較器進行ADC轉換, 并通過串口輸出結果.

  5. 比較器配置為P5.5做高阻正輸入, 接輸入分壓電阻, 比較器的負輸入接到內部1.25V參考電壓. P5.4配置為開漏輸出, 做反饋來平衡電荷.

  6. 本例程使用680K+10K分壓電阻接P5.5輸出, 用定時器0產生20us中斷查詢比較器的狀態, 從P3.6輸出反饋來做電荷平衡.

  7. 最高輸入電壓 = 1.25 * (1 + 680 / 10) = 85 V.  程序顯示1.25~84V, 低于1.25V返回000, 高于84V返回FFF.

  8. 例: 比較一次的時間間隔為10us, 量程為33200, 則做1次ADC的時間為33ms. 比較器的響應時間越短, 則完成ADC就越快.

  9. 由于要求每次比較時間間隔都要相等,所以用C編程最好在定時器中斷里進行, 定時器設置為自動重裝, 高優先級中斷, 其它中斷均低優先級.

  10. 用匯編的話, 保證比較輸出電平處理的時間要相等.



  11.                                          680K
  12.                             /| P5.5         ___
  13.                            /+|-----------o-|___|- ------- Vin
  14.                       ----<  | P5.4 ___  |
  15.                            \-|-----|___|-o
  16.                             \|      10K  |
  17.                                          |
  18.                                         ---
  19.                                         ---  104
  20.                                          |  
  21.                                          |
  22.                                         ===
  23.                                         GND

  24. ******************************/
  25. #include        "MAIN.H"
  26. #include        "EEPROM.C"
  27. /*************        本地常量聲明        **************/
  28. #define                BandGap                122        //1246 mv
  29. #define                ADC_SCALE        *((unsigned short volatile data *)0x18)
  30. #define                ADC_Reference        *((unsigned long volatile data *)0x18)
  31. #define                ADC_Multiple        *((unsigned short volatile data *)0x1C)
  32. #define                BGP                *((unsigned short volatile data *)0x1E)
  33. //#define                adc_value        *((unsigned short volatile data *)0x38)
  34. #define                Value_H                *((unsigned char volatile data *)0x20)
  35. #define                Value_L                *((unsigned char volatile data *)0x21)
  36. //u8 volatile data        adc_temp[2] _at_ 0x30;
  37. //#define                BandGap                *((unsigned short volatile data *)0x30)
  38. //#define                ADC_Multiple        *((unsigned short volatile data *)0x32)
  39. //#define                ADC_SCALE        *((unsigned short volatile data *)0x34)
  40. //#define                ADC_Reference        *((unsigned long volatile data *)0x34)
  41. u8 volatile data        adc_temp[8] _at_ 0x18;
  42. u16 volatile data        adc_value _at_ 0x20;
  43. //u8 volatile data        Value_H _at_ 0x38;
  44. //u8 volatile data        Value_L _at_ 0x39;
  45. #define                CMPRES                (CMPCR1 & 0x01)
  46. //u8 code Led_Lib[]        = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
  47. u8 code Led_Count[]        = {0xf7,0xfb,0xfd};

  48. /*************        本地變量聲明        **************/
  49. sbit P_ADC        = P5^4;                //P3.6 比較器轉IO輸出端
  50. sbit Press        = P3^0;                //P3.0 按鍵檢測IO
  51. u8        data        BandGap_addr, adc_addr, Key, Long_Press, Disp_Count, T2_Count;
  52. u8        data        Led_Temp[4], Led_Buf[3], Key_Press[3];
  53. u16        data        adc;                        //ADC中間值, 用戶層不可見
  54. u16        data        adc_duty;                //ADC計數周期, 用戶層不可見
  55. //u16        data        adc_value;                //ADC值, 用戶層使用
  56. bit        Show_Mode, Edit_Mode, adc_ok;                        //ADC結束標志, 為1則adc_value的值可用. 此標志給用戶層查詢,并且清0

  57. /*************        本地函數聲明        **************/
  58. void Get_ADCSCALE()
  59. {
  60.         adc_temp[0] = 0xff;
  61.         while(adc_temp[0] == 0xff)
  62.         {
  63.                 adc_temp[0] = Read_EepromH(--adc_addr);
  64.         }
  65.         adc_temp[1] = Read_EepromL(adc_addr);
  66. }

  67. void Save_ADCSCALE()
  68. {
  69.         if(++adc_addr == 0x00)        Erase_Eeprom();
  70.         Write_EepromH(adc_addr, adc_temp[0]);
  71.         Write_EepromL(adc_addr, adc_temp[1]);
  72. }

  73. /*
  74. void Get_ADCSCALE()
  75. {
  76.         adc_temp[0]        = 0xff;
  77.         BandGap_addr        = 0x80;
  78.         while(adc_temp[0] == 0xff)
  79.         {
  80.                 adc_temp[0] = Read_EepromH(--BandGap_addr);
  81.         }
  82.         adc_temp[1] = Read_EepromH(BandGap_addr | 0x80);
  83.         adc_temp[2] = Read_EepromL(BandGap_addr);
  84.         adc_temp[3] = Read_EepromL(BandGap_addr | 0x80);
  85. }

  86. void Save_ADCSCALE()
  87. {
  88.         if(++BandGap_addr == 0x80)
  89.         {
  90.                 BandGap_addr        = 0x00;
  91.                 Erase_Eeprom();
  92.         }
  93.         Write_EepromH(BandGap_addr, adc_temp[0]);
  94.         Write_EepromH((BandGap_addr | 0x80), adc_temp[1]);
  95.         Write_EepromL(BandGap_addr, adc_temp[2]);
  96.         Write_EepromL((BandGap_addr | 0x80), adc_temp[3]);
  97. }

  98. void Reference_ADC()
  99. {
  100.         ADC_Reference = BandGap        * ADC_Multiple * 2621;
  101. }
  102. */

  103. void main(void)
  104. {
  105.         IAP_CONTR = ENABLE_IAP;
  106.         Get_ADCSCALE();
  107. //        Reference_ADC();        
  108.         P1Mode        = DDPP_PPPP;        //P1.5~P1.0  設置為強推挽輸出(Led段碼a~f)
  109.         P3Mode        = PPDD_OOOD;        //P3.7~P3.6  設置為強推挽輸出(Led段碼g、dp)  P3.3~P3.1  設置為開漏輸出(Led位碼0~2)  P3.0  設置為準雙向(按鍵檢測)
  110.         P5Mode        = DDHO_DDDD;        //P5.5  設置為高阻輸入(adc正極輸入,電壓檢測)  P5.4  設置為開漏輸出(adc電荷平衡)

  111.         TH0 = Reload_for_Timer0 / 256;        //重裝值  中斷率50KHZ, 中斷周期20us
  112.         TL0 = Reload_for_Timer0 % 256;

  113.         T2H = Reload_for_Timer2 / 256;
  114.         T2L = Reload_for_Timer2 % 256;   //設置波特率重裝值

  115.                                 //        7        6        5        4        3        2        1        0
  116. //        IAP_CONTR=B_1000_0001;        //        IAPEN        SWBS        SWRST        CMD_FAL        -        WT2        WT1        WT0
  117. //        IAP_CMD        = B_0000_0001;        //        -        -        -        -        -        -        MS1        MS0        // IAP_TRIG = 5a a5
  118.         CMPCR1        = B_1000_0000;        //        CMPEN        CMPIF        PIE        NIE        PIS        NIS        CMPOE        CMPRES
  119.         CMPCR2        = B_0000_0000;        //        INVCMPO        DISFLT        LCDTY[5:0]

  120. //        SCON        = B_0101_0000;        //        SM0/FE        SM1        SM2        REN        TB8        RB8        TI        RI
  121.         TMOD        = B_0000_0000;        //        GATE        C/T        M1        M0        GATE        C/T        M1        M0
  122.         TCON        = B_0001_0000;        //        TF1        TR1        TF0        TR0        IE1        IT1        IE0        IT0
  123.         AUXR        = B_1001_0000;        //        T0x12        T1x12        UARTxM6        T2R        T2_C/T        T2x12        EXTRAM        S1ST2
  124.         IE2        = B_0000_0100;        //        -        ET4        ET3        ES4        ES3        ET2        ESPI        ES2
  125.         IP        = B_0000_0010;        //        PPCA        PLVD        PADC        PS        PT1        PX1        PT0        PX0
  126.         IE        = B_1000_0010;        //        EA        ELVD        EADC        ES        ET1        EX1        ET0        EX0

  127.         while (1)
  128.         {
  129.                 if(Show_Mode)
  130.                 {
  131.                         Led_Buf[0]        = Led_Lib(adc_temp[0] >> 4);
  132.                         Led_Buf[1]        = Led_Lib(adc_temp[0] & 0x0f);
  133.                         Led_Buf[2]        = Led_Lib(adc_temp[1] >> 4);
  134.                 }
  135.                 else
  136.                 {
  137.                         if(adc_ok)                //等待ADC結束
  138.                         {
  139.                                 
  140.                                 Led_Temp[1]        = Hex2BCD(Value_H);
  141.                                 Led_Temp[0]        = Led_Temp[1] >> 4;
  142.                                 Led_Temp[1]        |= 0xf0;
  143.                                 Led_Temp[3]        = Hex2BCD(Value_L);
  144.                                 Led_Temp[2]        = Led_Temp[3] >> 4;
  145.                                 Led_Temp[3]        &= 0x0f;
  146.                                 if(adc_value > 999)
  147.                                 {
  148.                                         if(adc_value > 8400)
  149.                                         {
  150.                                                 Led_Buf[0]        = 0x71;
  151.                                                 Led_Buf[1]        = 0x71;
  152.                                                 Led_Buf[2]        = 0x71;
  153.                                         }
  154.                                         else
  155.                                         {
  156.                                                 Led_Buf[0]        = Led_Lib(Led_Temp[0]);
  157.                                                 Led_Buf[1]        = Led_Lib(Led_Temp[1]);
  158.                                                 Led_Buf[2]        = Led_Lib(Led_Temp[2]);
  159.                                         }
  160.                                 }
  161.                                 else
  162.                                 {
  163.                                         if(adc_value > 125)
  164.                                         {
  165.                                                 Led_Buf[0]        = Led_Lib(Led_Temp[1]);
  166.                                                 Led_Buf[1]        = Led_Lib(Led_Temp[2]);
  167.                                                 Led_Buf[2]        = Led_Lib(Led_Temp[3]);
  168.                                         }
  169.                                         else
  170.                                         {
  171.                                                 Led_Buf[0]        = 0x3f;
  172.                                                 Led_Buf[1]        = 0x3f;
  173.                                                 Led_Buf[2]        = 0x3f;
  174.                                         }
  175.                                 }
  176.                                 if(Edit_Mode)        Led_Buf[2] |= 0x80;
  177.                                 adc_ok = 0;                                //清除ADC已結束標志
  178.                         }
  179.                 }
  180.                 if(Key != 0x00)
  181.                 {
  182.                         switch(Key)
  183.                         {
  184.                                 case 0x01:
  185.                                         if(Edit_Mode)        ADC_SCALE -= 16;
  186.                                         if(Show_Mode)        ADC_Multiple -= 1;
  187.                                 break;
  188.                                 case 0x02:
  189.                                         if(Edit_Mode)        ADC_SCALE += 16;
  190.                                         if(Show_Mode)        ADC_Multiple += 1;
  191.                                 break;
  192.                                 case 0x11:
  193.                                         if(!Show_Mode)
  194.                                         {
  195.                                                 if(Edit_Mode)
  196.                                                 {
  197.                                                         Save_ADCSCALE();
  198.                                                         Edit_Mode = 0;
  199.                                                 }
  200.                                                 else        Edit_Mode = 1;
  201.                                         }
  202.                                 break;
  203.                                 case 0x12:
  204.                                         if(!Edit_Mode)        Show_Mode        = ~Show_Mode;
  205.                                 break;
  206.                                 default:
  207.                                 break;
  208.                         }
  209.                         Key = 0x00;
  210.                 }
  211.         }
  212. }

  213. //====================        Timer0        中斷函數 (電壓檢測)        ===============
  214. void Timer0_Routine()        interrupt 1        using 1
  215. {
  216.         if(CMPRES)
  217.         {
  218.                 P_ADC        = 0;
  219.                 adc++;                        //如比較結果為1,則adc計數加1
  220.         }
  221.         else        P_ADC        = 1;
  222.         if(--adc_duty == 0)                        //ADC周期-1, 到0則ADC結束
  223.         {
  224. ……………………

  225. …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼

所有代碼51hei附件下載:
STC15W201S簡易電壓表(開漏).7z (508.42 KB, 下載次數: 56)

評分

參與人數 1黑幣 +80 收起 理由
admin + 80 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏11 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:1108581 發表于 2024-1-9 22:48 | 只看該作者
大佬牛逼,能寫這么多代碼,學習學習
回復

使用道具 舉報

板凳
ID:1064915 發表于 2024-1-12 08:43 | 只看該作者
STC15W201S系列單片機引腳圖:


回復

使用道具 舉報

地板
ID:1064915 發表于 2024-1-12 16:10 | 只看該作者

MCU的工作頻率為22.1184MHz.
使用MCU自帶的比較器進行ADC轉換, 并通過串口輸出結果. 用定時器0產生10us中斷查詢比較器的狀態.
使用比較器做ADC, 原理圖如下.
做ADC的原理是基于電荷平衡的計數式ADC.
電壓從Vin輸入, 通過100K+104濾波, 進入比較器的P5.5正輸入端, 經過比較器的比較, 將結果輸出到P1.5再通過100K+104濾波后送比較器P5.4負輸入端,跟輸入電壓平衡.
設置兩個變量: 計數周期(量程)adc_duty 和 比較結果高電平的計數值 adc, adc嚴格比例于輸入電壓.
ADC的基準就是P1.5的高電平. 如果高電平準確,比較器的放大倍數足夠大,則ADC結果會很準確.
當比較結果為高電平,則P1.5輸出1, 并且adc+1.
當比較結果為低電平,則P1.5輸出0.
每一次比較都判斷計數周期是否完成,完成則adc里的值就是ADC結果.
電荷平衡計數式ADC的性能類似數字萬用表用的雙積分ADC, 當計數周期為20ms的倍數時,具有很強的抗工頻干擾能力,很好的線性和精度.
原理可以參考ADD3501(3 1/2位數字萬用表)或ADD3701(3 3/4位數字萬用表), 也可以參考AD7740 VFC電路.
例: 比較一次的時間間隔為10us, 量程為10000, 則做1次ADC的時間為100ms. 比較器的響應時間越短, 則完成ADC就越快.
由于要求每次比較時間間隔都要相等,所以用C編程最好在定時器中斷里進行, 定時器設置為自動重裝, 高優先級中斷, 其它中斷均低優先級.
用匯編的話, 保證比較輸出電平處理的時間要相等.
回復

使用道具 舉報

5#
ID:1109333 發表于 2024-1-15 20:51 | 只看該作者
看似簡單,其實很復雜!
回復

使用道具 舉報

6#
ID:200118 發表于 2024-1-19 16:25 | 只看該作者
分享電路圖就更好
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 国产日韩精品一区二区三区 | 久久综合成人精品亚洲另类欧美 | 91中文字幕在线 | 亚洲成人精选 | 亚洲精品一区av在线播放 | 亚洲人成在线观看 | 日韩av啪啪网站大全免费观看 | 91天堂 | 成人福利 | 日韩精品一区二区三区高清免费 | 在线激情视频 | 日韩成人免费视频 | 国产做爰 | 国产乱码久久久久久一区二区 | 国产一区中文字幕 | 亚洲性爰 | 欧美一级片免费看 | 日韩在线免费视频 | 欧美不卡在线 | 国产精品一区在线播放 | 九一在线观看 | 日本黄色片免费在线观看 | 久久99精品视频 | 日本免费一区二区三区四区 | 国产一区不卡 | 国产精品久久久久久久岛一牛影视 | 亚洲 欧美 激情 另类 校园 | 99re在线视频| 365夜爽爽欧美性午夜免费视频 | 久久久久国产 | 亚洲h在线观看 | 91婷婷韩国欧美一区二区 | 亚洲国产精品99久久久久久久久 | 91欧美精品成人综合在线观看 | 天天综合日日夜夜 | 久久夜色精品国产 | 天堂视频中文在线 | 日韩一区二区三区在线播放 | 狠狠狠干| 人人鲁人人莫人人爱精品 | 麻豆国产一区二区三区四区 |