在实际开发中,AD,DA用的相当多,这一节,我们写一个程序,将采集到的电压数值显示在数码管上,程序如下:
/*******************************************************************************
  • * 文件名: ADC转换器使用
  • * 描  述: 电池电压
  • * 功  能:中断方式 11.059200MHZ
  • * 作  者:大核桃
  • * 版本号:1.0.1(2017.05.23)
  • *******************************************************************************/
  • #include "stc15w.h"//头文件
  • #include "intrins.h"
  • /*******************************************************************************
  • * 文件名: 重定义
  • * 描  述:   
  • * 功  能:
  • * 作  者:大核桃
  • * 版本号:1.0.1(2017.05.23)
  • *******************************************************************************/
  • typedef unsigned char uint8;
  • typedef unsigned int  uint16;
  • typedef unsigned long uint32;
  • #define ADC_POWER   0x80            //ADC电源控制位
  • #define ADC_FLAG    0x10            //ADC完成标志
  • #define ADC_START   0x08            //ADC起始控制位
  • #define ADC_SPEEDLL 0x00            //540个时钟
  • /*******************************************************************************
  • * 文件名:全局变量定义区域
  • * 描  述:
  • * 功  能:
  • * 作  者:大核桃
  • * 版本号:1.0.1(2015.03.03)
  • *******************************************************************************/
  • uint8 val,ch;
  • uint16 temp;
  • /*******************************************************************************
  • * 文件名:共阳数码管真值表
  • * 描  述:
  • * 功  能:
  • * 作  者:大核桃
  • * 版本号:1.0.1(2015.03.03)
  • *******************************************************************************/
  • code uint8 LedChar[] = {
  •         0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
  •         0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff,0xc1
  • };
  • /*******************************************************************************
  • * 文件名:单独位定义
  • * 描  述:   
  • * 功  能:
  • * 作  者:大核桃
  • * 版本号:1.0.1(2017.05.23)
  • *******************************************************************************/
  • sbit LED0 = P1^0;//第1组LED
  • sbit LED1 = P1^1;//第2组LED
  • sbit LED2 = P1^2;//第3组LED                                 
  • sbit LED3 = P1^3;//第4组LED
  • sbit LED4 = P1^4;//第5组LED
  • sbit LED5 = P3^2;//第6组LED
  • sbit LED6 = P0^0;//第7组LED
  • sbit LED7 = P0^1;//第8组LED
  • sbit LEDS1 = P3^3;//数码管1
  • sbit LEDS2 = P3^4;//数码管2
  • sbit LEDS3 = P3^6;//数码管3
  • sbit LEDS4 = P3^7;//数码管4
  • /*******************************************************************************
  • * 文件名:函数前置声明
  • * 描  述:   
  • * 功  能:
  • * 作  者:大核桃
  • * 版本号:1.0.1(2017.05.23)
  • *******************************************************************************/
  • void Mcu_Port_Init();
  • void LedScan();
  • void Delay500ms(); //24MHZ
  • void Time0_Init();//定时器0
  • void InitADC(void);
  • /*******************************************************************************
  • * 文件名
  • * 描  述: 主函数  
  • * 功  能:入口
  • * 作  者:大核桃
  • * 版本号:1.0.1(2017.05.23)
  • *******************************************************************************/
  • void main(void)
  • {                                       
  •         Mcu_Port_Init();//IO上电初始化
  •         Time0_Init();
  •         InitADC();
  •         while(1);
  • }
  • /*******************************************************************************
  • * 文件名:void LedScan()
  • * 描  述: LED刷新
  • * 功  能:
  • * 作  者:大核桃
  • * 版本号:1.0.1(2017.05.23)
  • *******************************************************************************/
  • void LedScan()
  • {
  •         static uint8 i = 0;
  •         P2 = 0Xff;
  •         switch(i)
  •         {
  •                 case 0: LEDS4 = 0;LEDS1 = 1;P2 = 0x7f & LedChar[16];i++;break;
  •                 case 1: LEDS1 = 0;LEDS2 = 1;P2 = LedChar[val / 10 % 10];i++;break;
  •                 case 2: LEDS2 = 0;LEDS3 = 1;P2 = LedChar[val % 10];i++;break;
  •                 case 3: LEDS3 = 0;LEDS4 = 1;P2 = LedChar[17];i = 0;break;
  •                 default:break;
  •         }
  • }
  • /*******************************************************************************
  • * 文件名:void InitADC(void)
  • * 描  述: //初始化 AD 转换
  • * 功  能:
  • * 作  者:大核桃
  • * 版本号:1.0.1(2015.03.03)
  • *******************************************************************************/
  • void InitADC(void)
  • {
  •         P1ASF = 0xE0; //设置 P1 口为模拟口
  •         ADC_RES = 0; //清除结果寄存器
  •         CLK_DIV |= 0x20; //ADRJ 为 1,ADC_RES 存放高两位结果,ADC_RESL 存放低 8 位结果
  •     //ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START;
  •         ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START;                    //ADC上电并延时
  • }
  • /*******************************************************************************
  • * 文件名:void adc_isr() interrupt 5 using 1
  • * 描  述: 中断服务程序
  • * 功  能:
  • * 作  者:大核桃
  • * 版本号:1.0.1(2015.03.03)
  • *******************************************************************************/
  • void adc_isr() interrupt 5 using 1
  • {
  •         EADC = 1; //允许ADC转换中断
  •         ET0 = 0;  //关闭定时器0中断
  •         ADC_CONTR &= !ADC_FLAG; //清除ADC中断标志
  •         temp = ADC_RES;
  •         temp <<= 8;
  •         temp |= ADC_RESL;
  •         ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START | 5;
  •         EADC = 0;//关闭ADC转换
  •         ET0 = 1;  //打开定时器0中断        
  • }
  • /*******************************************************************************
  • * 文件名:void VoltageCheckRefresh()
  • * 描  述: 电压检测
  • * 功  能:
  • * 作  者:大核桃
  • * 版本号:1.0.1(2015.03.03)
  • *******************************************************************************/
  • void VoltageCheckRefresh()
  • {
  •         val = (uint8)((temp)* 2 * 10 * 3.3 / 1023);                        
  • }
  • /*******************************************************************************
  • * 文件名:void Time0_Init()
  • * 描  述: 定时器0初始化
  • * 功  能:10毫秒@11.0592MHz
  • * 作  者:大核桃
  • * 版本号:1.0.1(2017.05.23)
  • *******************************************************************************/
  • void Time0_Init(void)
  • {
  •         AUXR &= 0x7F;                //定时器时钟12T模式
  •         TMOD &= 0xF0;                //设置定时器模式
  •         TMOD |= 0X01;      //确保不干扰其他配置
  •         TH0 = (65536 - 1000) / 256;                //设置定时初值
  •         TL0 = (65536 - 1000) % 256;                //设置定时初值
  •         ET0 = 1;
  •         TR0 = 1;                //定时器0开始计时
  •         EA = 1;               
  • }
  • /*******************************************************************************
  • * 文件名:
  • * 描  述: 中断函数
  • * 功  能:1毫秒@11.0592MHz
  • * 作  者:大核桃
  • * 版本号:1.0.1(2017.05.23)
  • *******************************************************************************/
  • void ET0_IRQHandler() interrupt 1
  • {
  •         static uint8 tmr5ms = 0;
  •         TH0 = (65536 - 1000) / 256;                //设置定时初值
  •         TL0 = (65536 - 1000) % 256;                //设置定时初值
  •         EADC = 0; //不允许ADC转换中断
  •         tmr5ms++;
  •         if(tmr5ms >= 5)
  •         {
  •                 tmr5ms = 0; //定时器5MS溢出一次
  •                 VoltageCheckRefresh();
  •         }
  •         LedScan();
  •         EADC = 1; //允许ADC转换中断
  •                         
  • }
  • /*******************************************************************************
  • * 文件名:void Mcu_Port_Init()
  • * 描  述: io初始化
  • * 功  能:
  • * 作  者:大核桃
  • * 版本号:1.0.1(2017.05.23)
  • *******************************************************************************/
  • void Mcu_Port_Init()
  • {
  •         IE = 0xa8;//允许AD转换
  •         //将P0口低二位配置为推挽输出
  •         //234567位配置位高阻输入
  •         P0M1 = 0xFC;//1111 1100
  •         P0M0 = 0X03;//0000 0011
  •         //P0 = 0X01;//第6个
  •         //P0 = 0X02;//第7个
  •         //高3位配置高阻输入,用作模拟口
  •         //其他配置推挽输出,驱动LED
  •         P1M1 = 0xE0;//1110 0000
  •         P1M0 = 0X1F;//0001 1111
  •         //P2口配置准双向口
  •         P2M1 = 0X00;
  •         P2M0 = 0X00;
  •         P2 = 0Xff; //上电为1111 1111
  • //        //P54,P55口为推挽输出
  •         P5M1 = 0X00;
  •         P5M0 = 0X00;
  •         P5 = 0xFF;
  •         //P37,P36,3.2,P3.3 P3.4口为推挽输出
  •         P3M1 = 0X00;
  •         P3M0 = 0XFC;
  •         P3 = 0X23; //0010 0111//第5个LED端口
  •         
  •         LED0 = 0;//第1组LED,如果使能请置为1
  •         LED1 = 0;
  •         LED2 = 0;
  •         LED3 = 0;
  •         LED4 = 0;
  •         LED5 = 0;
  •         LED6 = 0;
  •         LED7 = 0;        
  • }
  • /*******************************************************************************
  • * 文件名:void Delay500ms()                //@11.0592MHz
  • * 描  述:Y5内核延时
  • * 功  能:
  • * 作  者:大核桃
  • * 版本号:1.0.1(2017.05.23)
  • *******************************************************************************/
  • void Delay500ms()                //@11.0592MHz
  • {
  •         unsigned char i, j, k;
  •         _nop_();
  •         _nop_();
  •         i = 22;
  •         j = 3;
  •         k = 227;
  •         do
  •         {
  •                 do
  •                 {
  •                         while (--k);
  •                 } while (--j);
  •         } while (--i);
  • }
  • 复制代码

    在数码管上显示的数值如下图所示,注意这是测试的锂电池的电压:
    image.png

    实际万用表测量的结果是4.01V,数码管显示的结果跟万用表的结果相差0.01V,我们用的ADC是10位的分辨率,参考电压是3.3V,那么一个LSB是3.3/1024 = 0.00322265625,那么0.01V,差不多3个LSB,考虑到我们的参考电压也是有少许误差存在的,所以这个结果还是比较合理的,如果使用独立的参考电压,误差应该会更小。

    image.png