打印
[牛人杂谈]

N76E003的ADC

[复制链接]
4303|21
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主

好多人说不知道参考电压,看这个图,就知道了,VDD嘛。
沙发
tianxj01| | 2018-7-8 11:10 | 只看该作者
本帖最后由 tianxj01 于 2018-7-8 11:12 编辑

本来用Vdd作为Vref也没什么,对比那些内置Vref绝对精度比较差的带隙基准而言,大家通过控制单一电源电压值,就可以获得不错的精确性。
可坏就坏在,这一类采用VDD作为ADC基准的芯片,他们都是单片机,单片机本质内部有复杂的高频信号在运行,导致VCC上面非常容易产生随机的,各种不可预知的波动,这对ADC来说,采样速度要求低的,可以通过多次读取平均来抵消这个影响,对于需要高采样速率的数据,就让我们不知所措了。你好歹弄另外一个AVDD,并入ADC基准,或者至少弄一个ADC基准的旁路电容引脚这样的类似硬件配置,这样我们只需要通过一个简单退偶就可以既精确控制ADC基准,又单电源解决问题。
可貌似目前该类单片机,都只是简单的和数字系统直接连接,新唐如此,ST公司的  STM8如此,48引脚的STM32也是如此。这个非常坑。

使用特权

评论回复
板凳
捉虫天师|  楼主 | 2018-7-8 12:26 | 只看该作者
      N76E003内嵌12位逐次逼近寄存器型(SAR)的模拟数字转换器(ADC)。模数转换模块负责将管脚上的模拟信号转换为12位二进制数据。N76E003支持8信道单端输入模式。内部带隙电压(band-gap voltage)为1.22V,同时也可用作内部ADC输入端。所有模拟电路复用同一组采样电路和同一组采样保持电容。该组采样保持电容为转换电路的输入端。然后转换器通过逐次逼近的方式得到有效结果并存放在ADC结果寄存器中。

使用特权

评论回复
地板
捉虫天师|  楼主 | 2018-7-8 12:31 | 只看该作者
在开始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最高时钟频率参考表
表 31‑9. 当采样时钟设置超过最大值时,采样结果数据为不可预测。
通过置ADCS位(ADCCON0.6)开启AD转换。当转换完成后,硬件会自动清除该位,同时置ADCF (ADCCON0.7)
位,如果之前ADC中断已使能,则会产生ADC中断。转换结果存放在ADCRH (高8位) 及 ADCRL (低4位)中。12
位转换结果值为

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);
    }
}


使用特权

评论回复
5
捉虫天师|  楼主 | 2018-7-8 12:34 | 只看该作者
上面的例子就是说明这个操作过程:
1,使能相应的通道,一共9个通道,0~7,带隙
2,清理中断标志位
3,启动ADC转换开关
4,等待标志位置位
5,读取转换结果的寄存器值
这样就完成了一轮一共通道的转换。

使用特权

评论回复
6
捉虫天师|  楼主 | 2018-7-8 13:05 | 只看该作者
tianxj01 发表于 2018-7-8 11:10
本来用Vdd作为Vref也没什么,对比那些内置Vref绝对精度比较差的带隙基准而言,大家通过控制单一电源电压值 ...

其实用VDD有个好处啊,比如你通过ADC和一个已知的电阻,测量另外一个电阻,不管VDD怎么波动,都是准确的。就看使用在什么场合了,如果是测电压那就要用更加可靠的电源才行,而且最好VDD单独一路。

使用特权

评论回复
7
捉虫天师|  楼主 | 2018-7-8 13:10 | 只看该作者
好多人说怕电源不稳干扰,其实官方说明了,PCB做的时候要考虑这些因素
内部及外部数字电路,可能影响采样结果的准确度。所以如果需要高精准的转换结果,请参考如下应用,以降低噪声电平干扰。
1. 模拟输入脚尽量离芯片越近越好,避免管脚附近有高速数字电路经过,并离高速数字电路越远越好。
2. 在转换过程中,将芯片进入空闲模式。
3. 如果模拟输入脚AIN在系统中同时需要切换做数字管脚,请确保在转换过程中不要做数字/模拟切换动作

使用特权

评论回复
8
捉虫天师|  楼主 | 2018-7-8 13:22 | 只看该作者
外部触发的操作可以参考上面的图。

使用特权

评论回复
9
捉虫天师|  楼主 | 2018-7-8 13:24 | 只看该作者
外部触发的,这种就是中断操作,你也可以查询操作
/******************************************************************************
* FUNCTION_PURPOSE: ADC interrupt Service Routine
******************************************************************************/
void ADC_ISR (void) interrupt 11
{
    clr_ADCF;                               //clear ADC interrupt flag
                printf ("\n Value = 0x%bx",ADCRH);
}

/******************************************************************************
The main C function.  Program execution starts
here after stack initialization.
******************************************************************************/
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


}



使用特权

评论回复
10
捉虫天师|  楼主 | 2018-7-8 13:27 | 只看该作者
采集16次的平均滤波法
                int ADCdataH[16], ADCdataL[16], ADCsumH=0, ADCsumL=0;
                unsigned char ADCavgH, ADCavgL;
                               
/******************************************************************************
The main C function.  Program execution starts
here after stack initialization.
******************************************************************************/
void main (void)
{
                int i;                       
                P05_PushPull_Mode;
                P05 = 1;
                Timer0_Delay1ms(300);
       
                P05 = 0;       
                Enable_ADC_AIN0;                                                // Enable AIN0 P1.7 as ADC input, Find in "Function_define.h" - "ADC INIT"
                ADCsumH = 0x0000;
                ADCsumL = 0x0000;
                       
                for(i=0;i<16;i++)
    {
                        clr_ADCF;
                        set_ADCS;                                                                        // ADC start trig signal
      while(ADCF == 0);
                        ADCdataH[i] = ADCRH;
                        ADCdataL[i] = ADCRL;
                }               
               
                for(i=0;i<16;i++)
    {
                        ADCsumH = ADCsumH + ADCdataH[i];
                        ADCsumL = ADCsumL + ADCdataL[i];
                }                               

                ADCavgH = ADCsumH/16;
                ADCavgL = ADCsumL/16;
                P05 = 1;
                while(1);
}

使用特权

评论回复
11
捉虫天师|  楼主 | 2018-7-8 13:30 | 只看该作者
本帖最后由 捉虫天师 于 2018-7-8 13:31 编辑

PWM触发的


void ADC_ISR (void) interrupt 11
{
    clr_ADCF;                               // Clear ADC interrupt flag
                printf ("\n Value = 0x%bx",ADCRH);                // printf display will cause delay in ADC interrupt
                P30 ^= 1;                                                                                                                                // Check the P3.0 toggle at falling edge of PWM
}



void main (void)
{
    Set_All_GPIO_Quasi_Mode;
                InitialUART0_Timer1(9600);
        
/*-------------------------------------------------
        ADC trig initial setting
        Please modify #if value to open diffent type
--------------------------------------------------*/

// By PWM falling edge
                PWM0_P12_OUTPUT_ENABLE;                                
                Enable_ADC_AIN0;                                                                                                                // Enable AIN0 P1.7 as ADC input
                PWM0_FALLINGEDGE_TRIG_ADC;

// Setting PWM value
    PWMPH = 0x07;                                                                                                                                //Setting PWM value         
    PWMPL = 0xFF;
    PWM0H = 0x02;
    PWM0L = 0xFF;
          set_LOAD;                                                                                                                                                // PWM run
    set_PWMRUN;
// Setting ADC
          set_EADC;                                                                                                                                                // Enable ADC interrupt (if use interrupt)
                EA = 1;        
                while(1);

}
      


使用特权

评论回复
12
幸福小强| | 2018-7-8 18:23 | 只看该作者
仔细把官方资料看看,就不难了。

使用特权

评论回复
13
zhuomuniao110| | 2018-7-8 22:34 | 只看该作者
除了PWM那个是怎么关联的, 其他的都看懂了。

使用特权

评论回复
14
734774645| | 2018-7-10 20:32 | 只看该作者
等我回去找个板子演练一下。

使用特权

评论回复
15
xinpian101| | 2018-7-10 22:56 | 只看该作者
这个系列的非常好用。

使用特权

评论回复
16
停车说爱枫林晚| | 2018-7-12 16:11 | 只看该作者
我不知道用串口采集的电压波动很大

使用特权

评论回复
17
停车说爱枫林晚| | 2018-7-12 16:17 | 只看该作者
不知道是不是连线造成的,等打了样品回来在测试。

使用特权

评论回复
18
zhuomuniao110| | 2018-7-12 19:26 | 只看该作者
其实这样挺好用的。

使用特权

评论回复
19
heisexingqisi| | 2018-7-14 09:55 | 只看该作者
实际用一下,就知道好用了

使用特权

评论回复
20
wahahaheihei| | 2018-7-15 22:25 | 只看该作者
用过的都说好

使用特权

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

本版积分规则

196

主题

3135

帖子

7

粉丝