你可以參考這個
- /*---------------------------------------------------------------------*/
- /* --- STC MCU International Limited ----------------------------------*/
- /* --- STC 1T Series MCU Demo Programme -------------------------------*/
- /* --- Mobile: (86)13922805190 ----------------------------------------*/
- /* --- Fax: 86-0513-55012956,55012947,55012969 ------------------------*/
- /* --- Tel: 86-0513-55012928,55012929,55012966 ------------------------*/
- /* --- QQ: 800003751 -------------------------------------------------*/
- /* 如果要在程序中使用此代碼,請在程序中注明使用了宏晶科技的資料及程序 */
- /*---------------------------------------------------------------------*/
- /****************************
- 本示例在Keil開發(fā)環(huán)境下請選擇Intel的8052芯片型號進行編譯
- 本例程MCU的工作頻率為22.1184MHz.
- 使用MCU自帶的比較器進行ADC轉(zhuǎn)換, 并通過串口輸出結(jié)果. 用定時器0產(chǎn)生10us中斷查詢比較器的狀態(tài).
- 使用比較器做ADC, 原理圖如下.
- 做ADC的原理是基于電荷平衡的計數(shù)式ADC.
- 電壓從Vin輸入, 通過100K+104濾波, 進入比較器的P5.5正輸入端, 經(jīng)過比較器的比較, 將結(jié)果輸出到P1.5再通過100K+104濾波后送比較器P5.4負輸入端,跟輸入電壓平衡.
- 設(shè)置兩個變量: 計數(shù)周期(量程)adc_duty 和 比較結(jié)果高電平的計數(shù)值 adc, adc嚴格比例于輸入電壓.
- ADC的基準就是P1.5的高電平. 如果高電平準確,比較器的放大倍數(shù)足夠大,則ADC結(jié)果會很準確.
- 當比較結(jié)果為高電平,則P1.5輸出1, 并且adc+1.
- 當比較結(jié)果為低電平,則P1.5輸出0.
- 每一次比較都判斷計數(shù)周期是否完成,完成則adc里的值就是ADC結(jié)果.
- 電荷平衡計數(shù)式ADC的性能類似數(shù)字萬用表用的雙積分ADC, 當計數(shù)周期為20ms的倍數(shù)時,具有很強的抗工頻干擾能力,很好的線性和精度.
- 原理可以參考ADD3501(3 1/2位數(shù)字萬用表)或ADD3701(3 3/4位數(shù)字萬用表), 也可以參考AD7740 VFC電路.
- 例: 比較一次的時間間隔為10us, 量程為10000, 則做1次ADC的時間為100ms. 比較器的響應(yīng)時間越短, 則完成ADC就越快.
- 由于要求每次比較時間間隔都要相等,所以用C編程最好在定時器中斷里進行, 定時器設(shè)置為自動重裝, 高優(yōu)先級中斷, 其它中斷均低優(yōu)先級.
- 用匯編的話, 保證比較輸出電平處理的時間要相等.
- 100K
- /| P5.5 ___
- P1.2 /+|---------o-|___|- ------- Vin
- .----< | P5.4 |
- | \-|---. |
- | \| | |
- | | |
- | ___ | |
- '---|___|---o |
- 100K | |
- --- ---
- --- ---
- 104 | | 104
- | |
- === ===
- GND GND
- ******************************/
- #define MAIN_Fosc 22118400L //定義主時鐘
- #define BaudRate1 9600ul //定義波特率
- #define ADC_SCALE 50000 //ADC滿量程, 根據(jù)需要設(shè)置
- #include "STC15Fxxxx.H"
- /************* 本地常量聲明 **************/
- //CMPCR1
- #define CMPEN 0x80 //1: 允許比較器, 0: 禁止,關(guān)閉比較器電源
- #define CMPIF 0x40 //比較器中斷標志, 包括上升沿或下降沿中斷, 軟件清0
- #define PIE 0x20 //1: 比較結(jié)果由0變1, 產(chǎn)生上升沿中斷
- #define NIE 0x10 //1: 比較結(jié)果由1變0, 產(chǎn)生下降沿中斷
- #define PIS 0x08 //輸入正極性選擇, 0: 選擇內(nèi)部P5.5做正輸入, 1: 由ADCIS[2:0]所選擇的ADC輸入端做正輸入.
- #define NIS 0x04 //輸入負極性選擇, 0: 選擇內(nèi)部BandGap電壓BGv做負輸入, 1: 選擇外部P5.4做輸入.
- #define CMPOE 0x02 //1: 允許比較結(jié)果輸出到P1.2, 0: 禁止.
- #define CMPRES 0x01 //比較結(jié)果, 1: CMP+電平高于CMP-, 0: CMP+電平低于CMP-, 只讀
- //CMPCR2
- #define INVCMPO 0x80 //1: 比較器輸出取反, 0: 不取反
- #define DISFLT 0x40 //1: 關(guān)閉0.1uF濾波, 0: 允許
- #define LCDTY 0x00 //0~63, 比較結(jié)果變化延時周期數(shù)
- #define TIM_16BitAutoReload 0
- #define TIM_16Bit 1
- #define TIM_8BitAutoReload 2
- #define TIM_16BitAutoReloadNoMask 3
- #define Pin0 0x01 //IO引腳 Px.0
- #define Pin1 0x02 //IO引腳 Px.1
- #define Pin2 0x04 //IO引腳 Px.2
- #define Pin3 0x08 //IO引腳 Px.3
- #define Pin4 0x10 //IO引腳 Px.4
- #define Pin5 0x20 //IO引腳 Px.5
- #define Pin6 0x40 //IO引腳 Px.6
- #define Pin7 0x80 //IO引腳 Px.7
- #define PinAll 0xFF //IO所有引腳
- /************* 本地變量聲明 **************/
- //sbit P_ADC = P1^2; //P1.2 比較器轉(zhuǎn)IO輸出端
- sbit P_ADC = P1^4; //P1.2 比較器轉(zhuǎn)IO輸出端
- u16 adc; //ADC中間值, 用戶層不可見
- u16 adc_duty; //ADC計數(shù)周期, 用戶層不可見
- u16 adc_value; //ADC值, 用戶層使用
- bit adc_ok; //ADC結(jié)束標志, 為1則adc_value的值可用. 此標志給用戶層查詢,并且清0
- /************* 本地函數(shù)聲明 **************/
- void TxString(u8 *puts);
- void main(void)
- {
- u8 i;
- u8 tmp[5];
- //IO口初始化
- // P1n_push_pull(Pin2); //P1.2設(shè)置為push-pull output
- P1n_push_pull(Pin4); //P1.2設(shè)置為push-pull output
- P5n_pure_input(Pin4+Pin5); //P5.4 P5.5設(shè)置為高阻輸入
- //比較器初始化
- CMPCR1 = 0;
- CMPCR2 = 20; //比較結(jié)果變化延時周期數(shù), 0~63
- CMPCR1 |= CMPEN; //允許比較器 ENABLE,DISABLE
- // CMPCR1 |= PIE; //允許上升沿中斷 ENABLE,DISABLE
- // CMPCR1 |= NIE; //允許下降沿中斷 ENABLE,DISABLE
- // CMPCR1 |= PIS; //輸入正極性選擇, 0: 選擇內(nèi)部P5.5做正輸入, 1: 由ADCIS[2:0]所選擇的ADC輸入端做正輸入.
- CMPCR1 |= NIS; //輸入負極性選擇, 0: 選擇內(nèi)部BandGap電壓BGv做負輸入, 1: 選擇外部P5.4做輸入
- // CMPCR1 |= CMPOE; //允許比較結(jié)果輸出到P1.2, ENABLE,DISABLE
- // CMPCR2 |= INVCMPO; //比較器輸出取反, ENABLE,DISABLE
- CMPCR2 |= DISFLT; //內(nèi)部0.1uF濾波, ENABLE,DISABLE
- //定時器0 初始化
- TMOD &= ~0x0f;
- Timer0_16bitAutoReload(); //設(shè)置為16位自動重裝模式
- Timer0_1T(); //設(shè)置為1T模式
- ET0 = 1; //允許中斷
- PT0 = 1; //高優(yōu)先級中斷
- TH0 = (u8)((65536 - MAIN_Fosc / 100000ul)>>8); //重裝值 100KHZ, 10us, 65536 - (MAIN_Fosc)/100000
- TL0 = (u8)( 65536 - MAIN_Fosc / 100000ul);
- TR0 = 1; //開始運行
- //串口1初始化
- S1_USE_P30P31(); //UART1 使用P30 P31口 默認
- // S1_USE_P36P37(); //UART1 使用P36 P37口
- // S1_USE_P16P17(); //UART1 使用P16 P17口
- S1_8bit(); //8位數(shù)據(jù),波特率可變
- S1_RX_Enable(); //允許接收
- S1_TXD_RXD_OPEN(); //將TXD與RXD連接中繼斷開 默認
- S1_BRT_UseTimer2(); //使用Timer2做波特率發(fā)生器
- ES = 0; //禁止中斷, 使用查詢發(fā)送
- Timer2_1T(); //Timer2 1T模式, 固定為16位自動重裝
- T2L = (65536 - (MAIN_Fosc/4/BaudRate1)); //設(shè)置波特率重裝值
- T2H = (65536 - (MAIN_Fosc/4/BaudRate1))>>8;
- Timer2_Run(); //允許定時器2計數(shù)
- EA = 1; //允許全局中斷
- TxString("\r\n使用比較器做ADC例子\r\n"); //SUART1發(fā)送一個字符串
-
- while (1)
- {
- if(adc_ok) //等待ADC結(jié)束
- {
- adc_ok = 0; //清除ADC已結(jié)束標志
- TxString("ADC = "); //轉(zhuǎn)十進制
- tmp[0] = adc_value / 10000 + '0';
- tmp[1] = adc_value % 10000 / 1000 + '0';
- tmp[2] = adc_value % 1000 / 100 + '0';
- tmp[3] = adc_value % 100 / 10 + '0';
- tmp[4] = adc_value % 10 + '0';
- for(i=0; i<4; i++) //消無效0
- {
- if(tmp[i] != '0') break;
- tmp[i] = ' ';
- }
- for(i=0; i<5; i++) //發(fā)串口
- {
- TI = 0;
- SBUF = tmp[i];
- while(!TI);
- TI = 0;
- }
- TxString("\r\n");
- }
- }
- }
- void TxString(u8 *puts) //發(fā)送一個字符串
- {
- for (; *puts != 0; puts++) //遇到停止符0結(jié)束
- {
- TI = 0;
- SBUF = *puts;
- while(!TI);
- TI = 0;
- }
- }
- /********************* Timer0中斷函數(shù)************************/
- void timer0_int (void) interrupt TIMER0_VECTOR
- {
- if((CMPCR1 & CMPRES) == 0) P_ADC = 0; //比較器輸出高電平
- else //P_ADC輸出低電平, 給負輸入端做反饋.
- {
- P_ADC = 1; //P_ADC輸出高電平, 給負輸入端做反饋.
- adc ++; //ADC計數(shù)+1
- }
- if(--adc_duty == 0) //ADC周期-1, 到0則ADC結(jié)束
- {
- adc_duty = ADC_SCALE; //周期計數(shù)賦初值
- adc_value = adc; //保存ADC值
- adc = 0; //清除ADC值
- adc_ok = 1; //標志ADC已結(jié)束
- }
- }
復(fù)制代碼 |