[应用方案]

【转】N76E003的学习之路(ADC简单小例程篇)

[复制链接]
2210|1
手机看帖
扫描二维码
随时随地手机跟帖
Bruing|  楼主 | 2018-10-30 09:34 | 显示全部楼层 |阅读模式
N76E003内嵌12位逐次逼近寄存器型(SAR)的模拟数字转换器(ADC)。模数转换模块负责将管脚上的模拟
信号转换为12位二进制数据。N76E003支持8通道单端输入模式。内部带隙电压(band-gap voltage)为
1.22V,同时也可用作内部ADC输入端。所有模拟电路复用同一组采样电路和同一组采样保持电容。该组
采样保持电容为转换电路的输入端。然后转换器通过逐次逼近的方式得到有效结果并存放在ADC结果寄
存器中。
1318049-20180612142044736-2118922284.jpg
在开始ADC转换前,通过设置ADCEN (ADCCON1.0)位使能ADC电路,从而激活ADC电路,由于ADC
模块需要额外功耗,一旦ADC转换模块不再使用,建议清零ADCEN位关闭ADC模块电路以节省功耗。
ADC转换输入管脚需要特别配置,通过ADCHS[2:0] 来选择采样所需要的ADC通道连接到采样电路上。
同时,用户需要通过PxMn寄存器把采样所用的管脚配置为“输入高阻模式” (input-only high
impedance) 。配置后用于ADC管脚与数字输出电路将断开,但数字输入电路仍然可以工作,因此数字
输入将可能产生漏电流。所以还需要通过配置AINDIDS寄存器相应位来关闭数字输入缓冲区。如上配置
后,ADC输入脚将变成纯模拟输入电路。同样ADC采样时钟也需要认真考虑。
ADC最高时钟频率参考表
1318049-20180612153303946-335619489.jpg

表 31-9. 当采样时钟设置超过最大值时,采样结果数据为不可预测。

通过置ADCS位(ADCCON0.6)开启AD转换。当转换完成后,硬件会自动清除该位,同时置ADCF
(ADCCON0.7)位,如果之前ADC中断已使能,则会产生ADC中断。转换结果存放在ADCRH (高8位) 及
ADCRL (低4位)中。12位转换结果值为REF
内部及外部数字电路,可能影响采样结果的准确度。所以如果需要高精准的转换结果,请参考如下应
用,以降低噪声电平干扰。
1. 模拟输入脚尽量离芯片越近越好,避免管脚附近有高速数字电路经过,并离高速数字电路越远越好。
2. 在转换过程中,将芯片进入空闲模式。
3. 如果模拟输入脚AIN在系统中同时需要切换做数字管脚,请确保在转换过程中不要做数字/模拟切换动
作。
现在我们可以根据功能描述来编写程序
在开始ADC转换前,通过设置ADCEN (ADCCON1.0)位使能ADC电路,从而激活ADC电路,由于ADC
模块需要额外功耗,一旦ADC转换模块不再使用,建议清零ADCEN位关闭ADC模块电路以节省功耗。
ADC转换输入管脚需要特别配置,通过ADCHS[2:0] 来选择采样所需要的ADC通道连接到采样电路上。
同时,用户需要通过PxMn寄存器把采样所用的管脚配置为“输入高阻模式” (input-only high
impedance) 。配置后用于ADC管脚与数字输出电路将断开,但数字输入电路仍然可以工作,因此数字
输入将可能产生漏电流。所以还需要通过配置AINDIDS寄存器相应位来关闭数字输入缓冲区。如上配置
后,ADC输入脚将变成纯模拟输入电路。同样ADC采样时钟也需要认真考虑。
首先设置ADCEN(ADCCON1.0)位使能ADC电路,从而激活ADC电路
1318049-20180613094926824-1092621304.jpg
1318049-20180613094934290-138709233.jpg
由于ADC模块需要额外功耗,一旦ADC转换模块不再使用,建议清零ADCEN位关闭ADC模块电路以节省功耗。


ADC转换输入管脚需要特别配置,通过ADCHS[2:0] 来选择采样所需要的ADC通道连接到采样电路上。
同时,用户需要通过PxMn寄存器把采样所用的管脚配置为“输入高阻模式” (input-only high
impedance) 。
1318049-20180613095534184-4408152.jpg
1318049-20180613095622512-2027020189.jpg
用户需要通过PxMn寄存器把采样所用的管脚配置为“输入高阻模式” (input-only high
impedance) 。
1318049-20180613100542527-233804966.jpg

1318049-20180613101654568-1284581881.jpg
1318049-20180613101927527-301483319.jpg
配置后用于ADC管脚与数字输出电路将断开,但数字输入电路仍然可以工作,因此数字
输入将可能产生漏电流。所以还需要通过配置AINDIDS寄存器相应位来关闭数字输入缓冲区。如上配置
后,ADC输入脚将变成纯模拟输入电路。同样ADC采样时钟也需要认真考虑。
1318049-20180613102505141-2010148766.jpg

首先设置ADCEN(ADCCON1.0)位使能ADC电路,从而激活ADC电路
ADC转换输入管脚需要特别配置,通过ADCHS[2:0] 来选择采样所需要的ADC通道连接到采样电路上。
同时,用户需要通过PxMn寄存器把采样所用的管脚配置为“输入高阻模式” (input-only high
impedance) 。
配置后用于ADC管脚与数字输出电路将断开,但数字输入电路仍然可以工作,因此数字
输入将可能产生漏电流。所以还需要通过配置AINDIDS寄存器相应位来关闭数字输入缓冲区。如上配置
后,ADC输入脚将变成纯模拟输入电路。同样ADC采样时钟也需要认真考虑。
根据上述内容,程序具体如下:
Enable_ADC_AIN3; // Enable AIN0 P1.7 as ADC input, Find in "Function_define.h" - "ADC INIT"#define Enable_ADC_AIN3 ADCCON0&=0xF0;ADCCON0|=0x03;P06_Input_Mode;AINDIDS=0x00;AINDIDS|=SET_BIT3;ADCCON1|=SET_BIT0 //P06
ADCCON0&=0xF0;ADCCON0|=0x03;这部分的意思是选中引脚3 具体看上面的ADCCON0部分  //注意ADCCON0&=0xF0;这部分是一定要加的,因为在项目中必须要先清零在选择通道,如果涉及多个通道切换,每个通道一定要加上这句,否则系统只会承认上一个通道。
1318049-20180613103822776-1677655664.jpg
P06_Input_Mode;是将通道三即P06引脚设为输入高阻模式,#define P00_Input_Mode                P0M1|=SET_BIT0;P0M2&=~SET_BIT0
P0M1|=SET_BIT0;P0M2&=~SET_BIT0 这部分看上文配置即可AINDIDS=0x00;AINDIDS|=SET_BIT3;这部分意思是将第三通道数字输入功能关闭,由此三通道即P06引脚将变成纯模拟输入ADCCON1|=SET_BIT0  是将ADCEN使能位使能

也就是说Enable_ADC_AIN3;这个宏定义就是将ADC通道进行初始化
初始化完成,接下来来看应用:
通过置ADCS位(ADCCON0.6)开启AD转换。
1318049-20180613105217753-2070258274.jpg

1318049-20180613105304437-950186154.jpg
当转换完成后,硬件会自动清除该位,同时置ADCF
(ADCCON0.7)位,如果之前ADC中断已使能,则会产生ADC中断。
1318049-20180613105605048-437505056.jpg

转换结果存放在ADCRH (高8位) 及ADCRL (低4位)中。12位转换结果值为REF
1318049-20180613105901010-903106132.jpg
程序如下:
[url=][/url]
while(1)    {            clr_ADCF;            set_ADCS;                                    // ADC start trig signal            while(ADCF == 0);            printf ("\n Value = 0x%bx",ADCRH);            printf ("\n Value = 0x%bx",ADCRL);            Timer0_Delay1ms(100);    }[url=][/url]

clr_ADCF;以防万一,软件清零
#define clr_ADCF    ADCF     = 0

set_ADCS;启动AD转换#define set_ADCS ADCS = 1
while(ADCF == 0);由于其AD转换完成后置位为一,可以进行读取当前转换结果,那么这行代码的作用是等待该位置一,然后进行读数

printf ("\n Value = 0x%bx",ADCRH);            printf ("\n Value = 0x%bx",ADCRL);            Timer0_Delay1ms(100);之后进行串口打印
完整程序如下:[url=][/url]
void main (void) {        InitialUART0_Timer1(115200);         Enable_ADC_AIN3;                        // Enable AIN0 P1.7 as ADC input, Find in "Function_define.h" - "ADC INIT"        while(1)    {            clr_ADCF;            set_ADCS;                                    // ADC start trig signal      while(ADCF == 0);            printf ("\n Value = 0x%bx",ADCRH);            printf ("\n Value = 0x%bx",ADCRL);            Timer0_Delay1ms(100);    }}[url=][/url]

当然这只是一个很简单的小程序,如果涉及复杂程序,欢迎交流。
接下来 就是ADC中断部分


首先来讲讲中断使能
每一个中断源都可以通过各自的中断使能位开启或关闭,这些位在IE和EIE特殊功能寄存器SFRs中。有一个全局使能中断EA(IE.7)位,清0将关闭所有中断,置位启用已单独使能了的中断,清0不管单独的中断源,是否使能了都关闭所有中断。注意:当EA为0时有中断请求,所有中断会被挂起直到EA恢复为1,才去执行该中断。所有中断标志位可以用软件置位,也可以用软件启动中断。
注意:每一个中断产生时对应中断标志位都会被置1,不管是通过硬件还是软件。用户在中断服务程序里应该小心处理中断标志位,大多数中断标志位都是写0清除,这样可以避免递归中断请求。
1318049-20180613112322445-1748995388.jpg
中断服务
中断标志位在每个系统时钟周期都会被采样。在同一个周期内,被采样到的中断和优先级都会被解决。如果满足特定的条件硬件将执行内部产生的LCALL指令,目标地址是中断向量地址。能产生LCALL条件如下:
1. 没有相同或更高优先级中断服务程序在执行。
2.当前查询中断标志周期正好是当前执行指令的最后一个周期。
3. 当前指令不是写任何中断使能位或优先级位且也不能是中断返回指令RETI。
如果以上任何一个条件不满足,就不能产生LCALL指令。在每一个指令周期都会重新检测中断标志。当某个中断标志位被置起,但没有满足上述条件都不会被响应,即使后面满足上述条件,没有立即执行的中断仍然不会执行LCALL指令。这个中断标志生效,但没有进入中断服务程序,下一个指令周期需要重新检测中断标志。
处理器响应一个有效的中断,通过执行一个LCALL 指令将程序转移到中断入口地址。对应的中断标志根据不同的中断源在执行中断服务程序时,可能被硬件清除,也可能不被清除。硬件LCALL与软件LCALL指令相同,执行LCALL指令,保存程序计数器PC内容到堆栈,但不保存程序状态字PSW,PC指针重新装载产生中断的中断向量地址,从向量地址继续执行程序直到执行RETI指令。在执行RETI指令时,处理器弹出堆栈,将栈顶内容加载到程序计数器PC。用户必须注意堆栈的状态,如果堆栈的内容被修改,处理器不会被通知,将会从堆栈加载的地址继续执行。注,RET指令与RETI指令表现相同,但它不会通知中断控制器中断服务已经完成,致使控制器认为中断服务仍在进行。使中断不可能再产生。
中断的目的是让软件处理非常规或异步的事件。N76E003有 4个中断优先级、18个中断源。每个中断源都有独立的优先级、标志位、中断向量和使能位。另外,中断可被全局使能或关闭。当中断发生时,CPU将执行对应的中断服务子程序(ISR)。 ISR被分配到预先指定的地址如中断向量表表20-1.中断向量. 如果中断使能,当中断发生时,CPU 将根据中断源跳转到相应的中断向量地址,执行此地址处的程序,保持中断服务状态直到执行中断服务程序ISR。 一旦ISR 开始执行, 仅能被更高优先级的中断抢占。 ISR 通过指令RETI返回,该指令强迫CPU回到中断发生前所执行指令的下一条指令。
1318049-20180613112931999-1118287809.jpg
从上表可以看出,EADC是使能ADC中断的指令,所以有了下面的这行代码
#define set_EADC    EADC     = 1

可寻址指的是这个寄存器中各位值可以直接调用
如:可寻址的IE中有八位EA - ET2 ES ET1 EX1 ET0 EX0可以直接用ET2=1来操作;
不可寻址的TMOD只能用TMOD=0x00来控制其中的各位。N76E003这个寄存器是可寻址的。[url=][/url]
void main (void) {    Set_All_GPIO_Quasi_Mode;        InitialUART0_Timer1(115200);/*---------------------------------------------------------------    ADC port trig initial setting toggle P0.4 to start ADC ----------------------------------------------------------------*/        Enable_ADC_AIN0;                                                            // Enable AIN0 P1.7 as ADC pin        P04_FALLINGEDGE_TRIG_ADC;                                            // P0.4 falling edge as adc start trig signal// find ADC result in ADC interrupt    set_EADC;                                                                            // Enable ADC interrupt (if use interrupt)        EA = 1;                                                                                // Enable global interrupt//    set_ADCS;                                                                            // Trig P04 falling edge to start adc, no need set ADCS bit        while(1);                                                                            // Wait ADC interrupt}[url=][/url]

Set_All_GPIO_Quasi_Mode;将引脚设为准双向模式
Enable_ADC_AIN0; 初始化0通道set_EADC; 打开ADC中断EA = 1; 打开中断中断服务函数
void ADC_ISR (void) interrupt 11{    clr_ADCF;                               //clear ADC interrupt flag        printf ("\n Value = 0x%bx",ADCRH);}
清楚标志,并进行打印高位的数值。
先开始转换然后打开中断,然后进行配置。

小灵通2018| | 2018-10-30 10:49 | 显示全部楼层
讲的真详细MARK一下,看完了。

使用特权

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

本版积分规则

71

主题

308

帖子

1

粉丝