PIC单片机-AD转换

编写程序,使用数码管显示ADC测量得到的电压值。电压值由1位整数和1位小数构成。例如若当前AN0通道上的电压为6V,则数码管应显示3.6。

#include <htc.h>
#include <math.h>

#define uint8 unsigned char
#define uint16 unsigned int

__CONFIG(FOSC_HS &WDTE_OFF &BOREN_OFF &PWRTE_OFF &LVP_OFF); //设置配置位
//WDTE_OFF:disable watchdog timer       看门狗禁止
//LVP_OFF:low voltage programming disabled  低电压编程禁止
//FOSC_HS:high speed crystal/resonator  4M以上晶振选择HS高速
//PWRTDIS:disable power up timer
//BOREN_OFF:disable brown out reset
/***************************定义全局变量***************************************/

uint8 disp[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90}; //共阳数码管段码表
uint16 AD_Result;   //ADC转换结果变量
uint16 count;
long AD_Result_temp;

/***************************声明函数*******************************************/

void ADC_Init(void);
void Time2_Init(void);
void DelayUS(uint8 delay);
void LED_Display(uint8 chosebit, uint8 wdata);

/*******************************************************************************
* 函 数 名: DelayUS(uint8 delay)
* 函数功能: 微秒延时   for 20MHZ
* 入口参数: delay
* 返    回: 无
*******************************************************************************/

void DelayUS(uint8 delay)
{
    while(--delay);
}

/******************************************************************************
* 函 数 名: ADC_Init(void)
* 函数功能: ADC初始化
* 入口参数: 无
* 返    回: 无
*******************************************************************************/
void ADC_Init(void)
{
    TRISA0 = 1;     //模拟通道0设置为输入
    ADCON1 = 0x8E;  //10001110  Vref+ = VDD Vref- = VSS
    ADCON0 = 0x01;  //选择通道0,使能AD
    ADIF = 0;       //中断标志清零
    ADIE = 1;       //ADC中断使能
}

/*******************************************************************************
* 函 数 名: Time2_Init(void)
* 函数功能: 定时器2初始化
* 入口参数: 无
* 返    回: 无
*******************************************************************************/

void Time2_Init(void)
{
    T2CON = 0x01;   //postscale 1:1 prescale 1:4
    PR2 = 250;      //匹配寄存器   1*4*250*200ns = 200us
    TMR2IF = 0;         //定时器2中断标志位清零
    GIE = 1;            //开总中断
    PEIE = 1;           //开外设中断
    TMR2IE = 1;         //开定时器中断
}

/*******************************************************************************
* 函 数 名: LED_Display(uint8 chosebit,uint8 wdata)
* 函数功能: 单个数码管显示
* 入口参数: chosebit选择字位,wdata字型
* 返    回: 无
*******************************************************************************/

void LED_Display(uint8 chosebit, uint8 wdata)
{
    if((chosebit < 0) || (chosebit > 4))
        return;
    ADCON1 = 0x8E;  //10001110  RA0位模拟输入
    TRISA &= 0x01;
    TRISE &= 0xEF;      //配置PORTD为普通IO口,对PORTD的操作务必加上这句
    TRISD = 0x00;       //数据线配置为输出
    PORTA = (PORTA & 0xE3) | ((chosebit + 3) << 2); //RA2:RA3:RA4:011 选通第一位 100选通第二位 101选通第三位 110选通第四位
    PORTD = wdata;  //送显示数字的断码
    DelayUS(100);       //延时
    PORTD = 0xFF;       //关闭显示
}

/******************************************************************************
* 函 数 名: mian(void)
* 函数功能: 对模拟通道0进行采样,并显示,再采样,再显示
* 入口参数: 无
* 返    回: 无
*******************************************************************************/

void main(void)
{
    long temp;
    ADC_Init();     //ADC初始化
    Time2_Init();   //定时器2初始化
    GIE = 1;        //总中断使能
    PEIE = 1;       //外设中断设能
    GO = 1;         //启动ADC转换
    TMR2ON = 1;     //启动定时器2计时
    while(1)
    {
        temp = AD_Result_temp;
        temp /= 10;
        LED_Display(2, disp[temp % 10]);    //显示十分位
        temp /= 10;
        LED_Display(1, disp[temp % 10] & 0x7F); //显示个位
    }
}

/******************************************************************************
* 函 数 名: interrupt PIC_Init(void)
* 函数功能: 中断函数
* 入口参数: 无
* 返    回: 无
*******************************************************************************/

void interrupt PIC_Init(void)
{
    if(ADIF == 1)
    {
        ADIE = 0;   //关AD中断
        ADIF = 0;                       //AD中断标志清零
        AD_Result = ADRESL & 0x00FF;    //读取ADC采样结果
        AD_Result |= ADRESH << 8 ;
        AD_Result_temp = AD_Result * 50;    //5V为VDD电压,根据不同的电压作修改
        AD_Result_temp = AD_Result_temp * 10 / 1023;    //再放大10倍,方便计算显示
        ADIE = 1;   //开启AD中断
    }

    if(TMR2IF == 1)
    {
        TMR2IE = 0;     //关定时器0中断
        TMR2IF = 0;     //清标志位
        count++;        //计数值加1
        if(count >= 500)    //200us*500 = 100ms,即0.1s启动采样一次
        {
            count = 0;
            GO = 1;     //启动ADC转换
        }
        TMR2 = 0x00;
        TMR2IE = 1;     //开中断
    }
}