2.1. ADC

Overview

以 AC638N 为例,提供 ADC 应用示例、工程配置、API 介绍和常见问题。

2.1.1. 应用示例

  • 具体的 ADC 源代码详见 sdk/bsp/AC638N/src/adc.c

  • adc.c 中参考示例如下:

    #include "asm/adc_api.h"
    
    static u16 _vbg_val = 0;
    static void user_adc_cbfun(u8 ch, u16 adc_val)
    {
        u32 tmp_vol = adc_value_to_voltage(_vbg_val, adc_val);
        printf("ch = %d, adc = %d  -->  %d mv\n", ch, adc_val, tmp_vol);
    }
    
    void adc_test(void)
    {
        printf("*****************  adc test  ***************\n\r");
        adc_init();
    
        u32 adc_io = IO_PORTA_03;
        gpio_set_die(adc_io, 0);        //将io设为模拟功能
        //浮空输入
        gpio_set_direction(adc_io, 1);  //方向设为输入
        gpio_set_pull_up(adc_io, 0);    //关上拉10K
        gpio_set_pull_down(adc_io, 0);  //关下拉10K
    
        adc_io = IO_PORTC_04;
        gpio_set_die(adc_io, 0);        //将io设为模拟功能
        //浮空输入
        gpio_set_direction(adc_io, 1);  //方向设为输入
        gpio_set_pull_up(adc_io, 0);    //关上拉10K
        gpio_set_pull_down(adc_io, 0);  //关下拉10K
    
        u16 adc_val = 0;
        u16 io_vol = 0;
        extern void wdt_clr();
        while (1) {
            wdt_clr();
            delay(1000000);
            _vbg_val = adc_get_value(AD_CH_LDOREF);
            adc_val = adc_get_value(AD_CH_VBAT);
            io_vol = adc_get_voltage(AD_CH_VBAT);
            adc_get_value_by_isr(AD_CH_VBAT, user_adc_cbfun);
            printf("adc_val = %d  >>>  %d mv\n", adc_val, io_vol*4);
            printf("adc_val = %d\n", adc_val);
        }
    }
    

2.1.2. 工程配置

  • sdk/apps/main.c 中函数 user_main() 添加如下工程代码:

    int user_main()
    {
        extern void adc_test(void);
        adc_test();
    }
    
  • 编译下载后,在开发板的 PA3 和 PC4 分别接电压信号,会打印对应引脚的 AD 值和电压值

2.1.3. 常见问题

  • ADC 初始化函数在 board_demo.cvoid board_init() 函数中已经声明调用

  • 添加测量通道之后,需延时操作,不能马上去读取ADC值。

  • 10Bit ADC(A/D转换器),其时钟最大不可超过2MHz。

  • 电压测量范围是0~3.3V,测量精度为0~0.0032V。

  • 使用 adc_get_voltage() 函数时,若数据不对,芯片需要经过杰理烧写器trim校准才行。

  • 没有trim过ADC电压校准,可以根据对应的计算公式进行电压校准调准。每个芯片都存在差异,不确保每次都是正确的。

    Note

    1.进入bsp/AC638N/src/adc.c文件。

    2.找到对应的函数u32 adc_get_voltage(u32 ch),通过串口打印把adc_vbg、adc_res、adc_trim、tmp1的值打印出来。

    3.根据最后返回值的公式adc_res * tmp / adc_vbg,反推算出需要的tmp值。

    例如:现在输入电压是1400mv,但是采样等到的电压值是1100mv,需要调整。通过打印得到的adc_res和adc_vbg的值分别是426和256,则据公式

    426*tmp/256 = 1400

    得到tmp要为841。

    4.根据公式tmp = (adc_trim & BIT(7)) ? center - tmp1 * TRIM_MV : center + tmp1 * TRIM_MV,反推出要修改的center值。

    例如:打印出来的adc_trim是256对应的二进制是1111 1111,adc_trim & BIT(7)为1走的是减法公式center - tmp1 * TRIM_MV,打印出来的tmp1为31,则据公式

    center - 31 * 3 = 841

    得到center CENTER0值要修改为934。

    #define     CENTER0 934
    #define         TRIM_MV 3
    u32 adc_get_voltage(u32 ch)
    {
        u32 adc_vbg = adc_get_value(AD_CH_LDOREF);
        u32 adc_res = adc_get_value(ch);
        u32 adc_trim = get_vbg_trim();
        printf("adc_vbg =%d\n",adc_vbg);
        printf("adc_res =%d\n",adc_res);
        printf("adc_trim =%d\n",adc_trim);
        u32 tmp, tmp1, center;
    
        tmp1 = (adc_trim & 0x7f) >> 2;
        printf("tmp1 =%d\n",tmp1);
        center = CENTER0;
        printf("center =%d\n",center);
        tmp = (adc_trim & BIT(7)) ? center - tmp1 * TRIM_MV : center + tmp1 * TRIM_MV;
        printf("tmp =%d\n",tmp);
        return adc_res * tmp / adc_vbg;
    }
    

2.1.4. API参考

ADC常用相关API介绍,具体软件代码见 sdk/bsp/AC638N/src/adc.c

Functions

void adc_get_value_by_isr(u32 ch, void (*cbfun)(u8, u16))

采用异步的方式采值,使能采值后就走,不死等,通过注册中断回调函数,等一下转换结束会起中断,中断里执行回调函数

Parameters:
  • ch – : ADC通道号

  • cbfun – : 注册的中断回调函数

u32 adc_get_value(u32 ch)

采用等待的方式采值,直到转换结束,才出来,即死等

Parameters:

ch – : ADC通道号

Returns:

当前通道的AD值

u32 adc_value_to_voltage(u32 adc_vbg, u32 adc_ch_val)

换算电压的公式函数

Parameters:
  • adc_vbg – : 基准通道的AD值, 即AD_CH_LDOREF

  • adc_ch_val – : 当前通道的AD值

Returns:

当前通道的电压值,单位mv

u32 adc_get_voltage(u32 ch)

获取通道的电压值

Parameters:

ch – : ADC通道号

Returns:

当前通道的电压值,单位mv

void adc_init(void)

adc模块的初始化函数