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.c
的void 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模块的初始化函数