本程序用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附件下载:
STC15W201S简易电压表(开漏).7z
(508.42 KB, 下载次数: 56)
|