打印
[其他产品]

PIC16F877A单片机 (ADC)

[复制链接]
564|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gwsan|  楼主 | 2022-6-23 15:51 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
1 基本原理1.1 ADC基本原理

根据微芯的ADC手册,ADC可以分为单端ADC和差分ADC。

1.1.1 单端ADC

单端ADC的输出范围是[0,2^n-1]。



根据标黄的这句话,就可以得知,如果电压高于参考电压,ADC的输出结果仍然为全1,如果电压低于0V,ADC的输出结果为全零。

1.1.2 差分ADC

差分ADC的输出范围一般为[-2 ^ (n-1) , 2^(n-1)-1]。编码一般采用补码,最高位表示符号位。


1.2 PIC16F877A单片机的ADC模式






2 实现原码


/*---------------------------------函数功能:-------------------------------------

将模拟输入变成数字输出AD的转换以及AD转换完成后产生一个AD中断

RA0为模拟电压输入,RD口为AD量化输出

编程思路:参考手册的P131  To do an A/D Conversion, follow these steps

----------------------------------------------------------------------------*/



#include<pic.h>// 调用PIC16f87XA单片机的头文件


//#include"delay.h"//调用延时子函数的头文件




__CONFIG(0xFF32);//芯片配置字,看门狗关,上电延时开,掉电检测关,低压编程关

//__CONFIG(HS&WDTDIS&LVPDIS);




/*-----------宏定义--------------*/

#define  uint  unsigned int

#define  uchar unsigned char


uint  ADbuf=0;                                                // 缓存AD转换结果



/*-----------子函数声明--------------*/




/*-----------主函数--------------*/

void main()

{

        // The corresponding data direction register is TRISA.

        // Setting  a TRISA bit (= 1) will make the corresponding PORTA pi an input.

        // Clearing a TRISA bit (= 0) will make the corresponding PORTA pin an output.


        // 解释为什么需要TRISA0=1? After the A/D module has been configured as desired,

        // the selected channel must be acquired before the conversion is started.

        // The analog input channels must have their corresponding TRIS bits selected as inputs.

        TRISA0=1;                                        // RA0口为输入口,电压输入口       

        TRISE0=0;                                        // AD中断对应的LED灯的数据方向为输出

        // 用来显示AD转换结果(10bit,对应10个LED)

        TRISC7=0;

        TRISC6=0;       

        TRISD=0x00;                                       




        // 1 = Port pin is > VIH,即高电平  ;  0 = Port pin is < VIL,即低电平

        RA0=0;                                                // 要不要这行语句没有影响,因为该端口是输入端口

        RE0=0;                                                // LED灯的初值为灭

        // AD转换结果(10bit)对应的led灯初值为灭

        RC7=0;                                               

        RC6=0;

        RD=0x00;                               





        while(1)                                        // 死循环,单片机初始化后,就一直运行这个死循环

        {

                /****************AD初始化****************/

                // The ADCON1 register, configures the functions of the port pins.

                //ADCON1=0x0e;                        //RA0为AD输入口.   ADFM=1,转换后数据右移

                //下面几条语句等价于上面一条语句

                ADFM=1;                                        // AD Result Format Select bit.  0 = Left justified.  1 = Right justified       

                ADCS2=0;                                // AD Conversion Clock Select bit. // ADCS1=0; ADCS0=1;(ADCON0配置这两位)   FOSC/8

                PCFG3=1;PCFG2=1;PCFG1=1;PCFG0=0; //AD Port Configuration Control bits.  1110 D D D D D D D A




                //ADIE=0;                                //禁止AD中断

                //AD中断使能

                ADIE=1;

                ADIF=0;                                        // Clear ADIF bit

                PEIE=1;                                        // 允许外设中断

                GIE=1;                                        // 总中断允许


       


                /******************启动一次AD转换*******************/

                // The ADCON0 register, controls the operation of the A/D module.       

                //ADCON0=0x01;//选择AN0通道准备AD转换,启动AD模块

                //下面几条语句等价于上面一条语句

                ADCS1=0;ADCS0=0;                // AD Conversion Clock Select bits    FOSC/8

                CHS2=0;CHS1=0;CHS0=0;        // Analog Channel Select bits。  000 = Channel 0 (AN0)   

                  GO_DONE=0;                                // AD Conversion Status bit。为什么叫用GO_DONE看一下pic.h头文件,该文件在HT-PIC\include目录下  

                ADON=1;                                        //模数转换器使能位。 1 = A/D converter module is powered up

               

         



                asm("NOP");                                //延时,让模拟电压稳定

                asm("NOP");

                asm("NOP");

                asm("NOP");

                asm("NOP");


               


                // When ADON = 1时,GO_DONE=1: AD conversion in progress set this bit(GO_DONE=1), starts the AD conversion.

                // it is automatically cleared by hardware when the AD conversion is complete

                GO_DONE=1;                                //开始进行AD转换   GO/DONE: A/D Conversion Status bit

                while(GO_DONE) continue;//等待AD转换结束,AD转换完成后,GO_DONE自动由1变成0




                // The conversion of an analog input signal results in a corresponding 10-bit digital number.

                // The ADRESH(高8位):ADRESL(低8位) registers contain the 10-bit result of the AD conversion.

                // When the AD conversion is complete, the result is loaded into this AD Result register pair,

                // the GO/DONE bit is cleared and the A/D interrupt flag bit ADIF is set

                ADbuf=ADRESH*256+ADRESL;//转换结果一共有10bit。由于2^10为1024,所以这是一个4位数  0-1023

                //ADbuf=ADRESL;


                // 将一个4位数用10位的LED灯显示出来  RC7 RC6 RD7...RD0

                RC7= ADbuf/512;

                RC6=(ADbuf-RC7*512)/256;

                RD7=(ADbuf-RC7*512-RC6*256)/128;

                RD6=(ADbuf-RC7*512-RC6*256-RD7*128)/64;

                RD5=(ADbuf-RC7*512-RC6*256-RD7*128-RD6*64)/32;

                RD4=(ADbuf-RC7*512-RC6*256-RD7*128-RD6*64-RD5*32)/16;

                RD3=(ADbuf-RC7*512-RC6*256-RD7*128-RD6*64-RD5*32-RD4*16)/8;

                RD2=(ADbuf-RC7*512-RC6*256-RD7*128-RD6*64-RD5*32-RD4*16-RD3*8)/4;

                RD1=(ADbuf-RC7*512-RC6*256-RD7*128-RD6*64-RD5*32-RD4*16-RD3*8-RD2*4)/2;

                RD0= ADbuf%2;

        }

       

}





/*************中断服务程序***************/

void interrupt ISR(void)//PIC单片机的所有中断都是这样一个入口

{

        // When the AD conversion is complete, the A/D interrupt flag bit ADIF is set.

        if(ADIF==1)                                        // 需要进一步判断是否为外部中断的溢出中断标志位   

        {

                // The interrupt flag bit(s) must be cleared in software before

                // re-enabling interrupts to avoid recursive interrupts

                //溢出中断标志位清零     如果ADIF出现上升沿,则产生中断,所以中断发生之后要清零。

                ADIF=0;                       


               


                // 执行中断处理程序,执行中断产生时想要执行的功能

                RE0=1;                                // 外部中断发生时,LED灯亮


        }

}



3 protues仿真结果特别要注意ADFM位的选择,左对齐还是右对齐。这会影响ADbuf=ADRESH*256+ADRESL;这条语句对不对。




4 一般的ADC的首位都是符号位,为什么PIC单片机没有符号位,如何解释?

以下结论仅适用于单端ADC。



如上图所示,这是在PIC16F1513的数据手册找到的模拟信号到数字信号的转化图。根据芯片手册可知,该芯片的ADC转换结果一共有10bit。

从这幅图可以看出,最大值为3FFh(0011_1111_1111),最小值为00h。也就是说,如果有符号位,那么符号位肯定在这10bit内。现在看VREF-(负参考电压)这里,它的转换结果为00h。它最小可以接地,即0V,如下图所示。结论:如果电压小于0V,那么相当于会当成0V来被量化,AD量化结果还是为00h。


下面这几幅图是PIC16F877a的AD转换仿真图,这款芯片的转化结果也是10bit,所设置的VREF+(正参考电压)为VDD(+5v),负参考电压为地(0V)。




论:PIC单片机的ADC转换机理应该是这样的,小于负参考电压的模拟输入电压的量化结果为全0,大于正参考电压的模拟输入电压的量化结果为全1。



使用特权

评论回复
沙发
yiyigirl2014| | 2022-6-24 21:36 | 只看该作者
这个型号很老了,好像不支持MCC配置。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

68

主题

3427

帖子

1

粉丝