本程序用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頁一起燒入單片機。
單片機源程序如下:
- /****************************
- 本示例在Keil開發環境下請選擇STC15系列芯片型號進行編譯
- 本例程MCU的工作頻率為24MHz, 工作電壓3~5V均可.
- 使用MCU自帶的比較器進行ADC轉換, 并通過串口輸出結果.
- 比較器配置為P5.5做高阻正輸入, 接輸入分壓電阻, 比較器的負輸入接到內部1.25V參考電壓. P5.4配置為開漏輸出, 做反饋來平衡電荷.
- 本例程使用680K+10K分壓電阻接P5.5輸出, 用定時器0產生20us中斷查詢比較器的狀態, 從P3.6輸出反饋來做電荷平衡.
- 最高輸入電壓 = 1.25 * (1 + 680 / 10) = 85 V. 程序顯示1.25~84V, 低于1.25V返回000, 高于84V返回FFF.
- 例: 比較一次的時間間隔為10us, 量程為33200, 則做1次ADC的時間為33ms. 比較器的響應時間越短, 則完成ADC就越快.
- 由于要求每次比較時間間隔都要相等,所以用C編程最好在定時器中斷里進行, 定時器設置為自動重裝, 高優先級中斷, 其它中斷均低優先級.
- 用匯編的話, 保證比較輸出電平處理的時間要相等.
- 680K
- /| P5.5 ___
- /+|-----------o-|___|- ------- Vin
- ----< | P5.4 ___ |
- \-|-----|___|-o
- \| 10K |
- |
- ---
- --- 104
- |
- |
- ===
- GND
- ******************************/
- #include "MAIN.H"
- #include "EEPROM.C"
- /************* 本地常量聲明 **************/
- #define BandGap 122 //1246 mv
- #define ADC_SCALE *((unsigned short volatile data *)0x18)
- #define ADC_Reference *((unsigned long volatile data *)0x18)
- #define ADC_Multiple *((unsigned short volatile data *)0x1C)
- #define BGP *((unsigned short volatile data *)0x1E)
- //#define adc_value *((unsigned short volatile data *)0x38)
- #define Value_H *((unsigned char volatile data *)0x20)
- #define Value_L *((unsigned char volatile data *)0x21)
- //u8 volatile data adc_temp[2] _at_ 0x30;
- //#define BandGap *((unsigned short volatile data *)0x30)
- //#define ADC_Multiple *((unsigned short volatile data *)0x32)
- //#define ADC_SCALE *((unsigned short volatile data *)0x34)
- //#define ADC_Reference *((unsigned long volatile data *)0x34)
- u8 volatile data adc_temp[8] _at_ 0x18;
- u16 volatile data adc_value _at_ 0x20;
- //u8 volatile data Value_H _at_ 0x38;
- //u8 volatile data Value_L _at_ 0x39;
- #define CMPRES (CMPCR1 & 0x01)
- //u8 code Led_Lib[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
- u8 code Led_Count[] = {0xf7,0xfb,0xfd};
- /************* 本地變量聲明 **************/
- sbit P_ADC = P5^4; //P3.6 比較器轉IO輸出端
- sbit Press = P3^0; //P3.0 按鍵檢測IO
- u8 data BandGap_addr, adc_addr, Key, Long_Press, Disp_Count, T2_Count;
- u8 data Led_Temp[4], Led_Buf[3], Key_Press[3];
- u16 data adc; //ADC中間值, 用戶層不可見
- u16 data adc_duty; //ADC計數周期, 用戶層不可見
- //u16 data adc_value; //ADC值, 用戶層使用
- bit Show_Mode, Edit_Mode, adc_ok; //ADC結束標志, 為1則adc_value的值可用. 此標志給用戶層查詢,并且清0
- /************* 本地函數聲明 **************/
- void Get_ADCSCALE()
- {
- adc_temp[0] = 0xff;
- while(adc_temp[0] == 0xff)
- {
- adc_temp[0] = Read_EepromH(--adc_addr);
- }
- adc_temp[1] = Read_EepromL(adc_addr);
- }
- void Save_ADCSCALE()
- {
- if(++adc_addr == 0x00) Erase_Eeprom();
- Write_EepromH(adc_addr, adc_temp[0]);
- Write_EepromL(adc_addr, adc_temp[1]);
- }
- /*
- void Get_ADCSCALE()
- {
- adc_temp[0] = 0xff;
- BandGap_addr = 0x80;
- while(adc_temp[0] == 0xff)
- {
- adc_temp[0] = Read_EepromH(--BandGap_addr);
- }
- adc_temp[1] = Read_EepromH(BandGap_addr | 0x80);
- adc_temp[2] = Read_EepromL(BandGap_addr);
- adc_temp[3] = Read_EepromL(BandGap_addr | 0x80);
- }
- void Save_ADCSCALE()
- {
- if(++BandGap_addr == 0x80)
- {
- BandGap_addr = 0x00;
- Erase_Eeprom();
- }
- Write_EepromH(BandGap_addr, adc_temp[0]);
- Write_EepromH((BandGap_addr | 0x80), adc_temp[1]);
- Write_EepromL(BandGap_addr, adc_temp[2]);
- Write_EepromL((BandGap_addr | 0x80), adc_temp[3]);
- }
- void Reference_ADC()
- {
- ADC_Reference = BandGap * ADC_Multiple * 2621;
- }
- */
- void main(void)
- {
- IAP_CONTR = ENABLE_IAP;
- Get_ADCSCALE();
- // Reference_ADC();
- P1Mode = DDPP_PPPP; //P1.5~P1.0 設置為強推挽輸出(Led段碼a~f)
- P3Mode = PPDD_OOOD; //P3.7~P3.6 設置為強推挽輸出(Led段碼g、dp) P3.3~P3.1 設置為開漏輸出(Led位碼0~2) P3.0 設置為準雙向(按鍵檢測)
- P5Mode = DDHO_DDDD; //P5.5 設置為高阻輸入(adc正極輸入,電壓檢測) P5.4 設置為開漏輸出(adc電荷平衡)
- TH0 = Reload_for_Timer0 / 256; //重裝值 中斷率50KHZ, 中斷周期20us
- TL0 = Reload_for_Timer0 % 256;
- T2H = Reload_for_Timer2 / 256;
- T2L = Reload_for_Timer2 % 256; //設置波特率重裝值
- // 7 6 5 4 3 2 1 0
- // IAP_CONTR=B_1000_0001; // IAPEN SWBS SWRST CMD_FAL - WT2 WT1 WT0
- // IAP_CMD = B_0000_0001; // - - - - - - MS1 MS0 // IAP_TRIG = 5a a5
- CMPCR1 = B_1000_0000; // CMPEN CMPIF PIE NIE PIS NIS CMPOE CMPRES
- CMPCR2 = B_0000_0000; // INVCMPO DISFLT LCDTY[5:0]
- // SCON = B_0101_0000; // SM0/FE SM1 SM2 REN TB8 RB8 TI RI
- TMOD = B_0000_0000; // GATE C/T M1 M0 GATE C/T M1 M0
- TCON = B_0001_0000; // TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0
- AUXR = B_1001_0000; // T0x12 T1x12 UARTxM6 T2R T2_C/T T2x12 EXTRAM S1ST2
- IE2 = B_0000_0100; // - ET4 ET3 ES4 ES3 ET2 ESPI ES2
- IP = B_0000_0010; // PPCA PLVD PADC PS PT1 PX1 PT0 PX0
- IE = B_1000_0010; // EA ELVD EADC ES ET1 EX1 ET0 EX0
- while (1)
- {
- if(Show_Mode)
- {
- Led_Buf[0] = Led_Lib(adc_temp[0] >> 4);
- Led_Buf[1] = Led_Lib(adc_temp[0] & 0x0f);
- Led_Buf[2] = Led_Lib(adc_temp[1] >> 4);
- }
- else
- {
- if(adc_ok) //等待ADC結束
- {
-
- Led_Temp[1] = Hex2BCD(Value_H);
- Led_Temp[0] = Led_Temp[1] >> 4;
- Led_Temp[1] |= 0xf0;
- Led_Temp[3] = Hex2BCD(Value_L);
- Led_Temp[2] = Led_Temp[3] >> 4;
- Led_Temp[3] &= 0x0f;
- if(adc_value > 999)
- {
- if(adc_value > 8400)
- {
- Led_Buf[0] = 0x71;
- Led_Buf[1] = 0x71;
- Led_Buf[2] = 0x71;
- }
- else
- {
- Led_Buf[0] = Led_Lib(Led_Temp[0]);
- Led_Buf[1] = Led_Lib(Led_Temp[1]);
- Led_Buf[2] = Led_Lib(Led_Temp[2]);
- }
- }
- else
- {
- if(adc_value > 125)
- {
- Led_Buf[0] = Led_Lib(Led_Temp[1]);
- Led_Buf[1] = Led_Lib(Led_Temp[2]);
- Led_Buf[2] = Led_Lib(Led_Temp[3]);
- }
- else
- {
- Led_Buf[0] = 0x3f;
- Led_Buf[1] = 0x3f;
- Led_Buf[2] = 0x3f;
- }
- }
- if(Edit_Mode) Led_Buf[2] |= 0x80;
- adc_ok = 0; //清除ADC已結束標志
- }
- }
- if(Key != 0x00)
- {
- switch(Key)
- {
- case 0x01:
- if(Edit_Mode) ADC_SCALE -= 16;
- if(Show_Mode) ADC_Multiple -= 1;
- break;
- case 0x02:
- if(Edit_Mode) ADC_SCALE += 16;
- if(Show_Mode) ADC_Multiple += 1;
- break;
- case 0x11:
- if(!Show_Mode)
- {
- if(Edit_Mode)
- {
- Save_ADCSCALE();
- Edit_Mode = 0;
- }
- else Edit_Mode = 1;
- }
- break;
- case 0x12:
- if(!Edit_Mode) Show_Mode = ~Show_Mode;
- break;
- default:
- break;
- }
- Key = 0x00;
- }
- }
- }
- //==================== Timer0 中斷函數 (電壓檢測) ===============
- void Timer0_Routine() interrupt 1 using 1
- {
- if(CMPRES)
- {
- P_ADC = 0;
- adc++; //如比較結果為1,則adc計數加1
- }
- else P_ADC = 1;
- if(--adc_duty == 0) //ADC周期-1, 到0則ADC結束
- {
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
51hei.png (8.87 KB, 下載次數: 58)
下載附件
2021-10-7 03:08 上傳
所有代碼51hei附件下載:
STC15W201S簡易電壓表(開漏).7z
(508.42 KB, 下載次數: 56)
2021-10-7 03:10 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|