
第十九章 AT32F403A基于V2库 adc采集
国产MCU 雅特力 AT32F403A基于V2库的adc轮询采集
目录
概述
本文主要是使用AT32F403A开发板,基于V2库实现adc采集电压的功能。
串口工具使用的Atlink-ez自带的串口功能。
工程建立、调试工具配置在前面章节有详细介绍。
硬件
硬件方面使用的是参考官方AT32F437 SURF板子而设计的一个AT32F403A开发板,板子上的芯片是AT32F403AVGT7的型号,开发板上面还板载了一个atlink-ez的仿真器,atlink-ez除了可以在线仿真和下载之外还有一个串口的功能,硬件上是通过跳线帽接到了MCU的串口1,pa9/10上面。
如下图是开发板pcb图,以及硬件资源。(左边上角的就是atlink-ez,用usb线接到pc即可):
如下是实物图:
本功能是使用ad采集可变电阻的电压值,相关原理图如下:
ADC
ADC也就是模数转换,把外部电路的电压转换成具体的数值,在根据参考电压就可以计算出外部电路的实际电压值。
AT32F403A有三个12bit的ADC转换器,ADC的工作时钟最高是28M,采样率最高可达 2MSPS,多达 18 个通道源可进行采样及转换,其中最后两个通道是连接到了内部电压和内部温度传感器,其他的16个通道都是对外的。
如上图,PA1是ADC123_IN1,ADC123是指的ADC的三个转换器,PA1可以使用ADC1转换器,也可以使用ADC2转换器,也可以使用ADC3转换器,IN1指的是通道1。
AT32系列的ADC供电要求是2.6V到3.6V ,ADC输入范围是VREF- ≤ VIN ≤ VREF+,VREF+也就是参考电压,这个引脚是100pin才有的引脚,小于100pin的是内部连接到vcc上,在电压方面最高必须是3.6v,大于这个值的都会对adc转换器产生影响,导致所有的adc的采用都是不对的。
软件
初始化
本文使用ADC1的通道10来转换电压,也就是PC0,IO要设置为模拟输入模式,无上下拉。
开启ADC1的时钟,设置ADC分频系数,ADC123都是挂载在apb2总线下面,所以ADC的工作时钟是apb2总线的时钟除以ADC的分频系数,当系统时钟为240M,apb2为120M时钟,那么ADC的分频系数最小是六分频,也就是20M的工作时钟,因为AT32F403A的ADC的工作时钟最高是28M。
ADC转换时间
ADC转换时需要时间的,转换时间计算方式如下图:
采样时间由下面函数设置:图中设置的是239.5周期。
接上面的我们设置的ADC的工作时钟20M,那么周期就是0.05us,转换时间就是239.5+12.5个周期,即252*0.05=12.6us,一次完整的转换时间就是12.6us。
ADC参数结构体如下:
typedef struct
{
confirm_state sequence_mode; /*!< adc sequence mode */
confirm_state repeat_mode; /*!< adc repeat mode */
adc_data_align_type data_align; /*!< adc data alignment */
uint8_t ordinary_channel_length; /*!< adc ordinary channel sequence length*/
} adc_base_config_type;
sequence_mode:顺序转换模式
repeat_mode:重复转换模式
data_align:adc数据对齐
ordinary_channel_length:普通通道数
设置ADC工作模式位独立模式,这里我们只是转换1个通道,并且不需要重复转换,所以前面两个参数都不使能,数据一般是设置右对齐,普通通道的数量为1,开启软件触发方式,使能ADC,最后在校准下adc,初始化就完成了。后续需要转换时,设置通道并调用软件触发即可进行ad的采集。
需要注意的是AT32使用adc的时候,所使用的IO口不能悬空。当需要精度比较高的时候就对输入内阻要求内阻要小,所以当没有速度需求的时候尽量降低ADC工作时钟,加大采样时间,同时使用多次采样并去掉第一个值和最后一个值然后求平均的方式。
初始化代码
/*
*adc 轮询采样
*ADC1-CH10 (PC0)
*软件触发
*普通通道转换
*
*/
void adc_loop_init(void)
{
gpio_init_type gpio_initstructure;
adc_base_config_type adc_base_struct;
crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE); //开启gpioc时钟
crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE); //开启ADC1时钟
crm_adc_clock_div_set(CRM_ADC_DIV_6); //时钟六分频。
gpio_default_para_init(&gpio_initstructure);
gpio_initstructure.gpio_mode = GPIO_MODE_ANALOG; //模拟输入模式
gpio_initstructure.gpio_pins = GPIO_PINS_0 ; //PC0
gpio_init(GPIOC, &gpio_initstructure);
adc_combine_mode_select(ADC_INDEPENDENT_MODE); //设置adc工作模式,独立模式
adc_base_default_para_init(&adc_base_struct);
adc_base_struct.sequence_mode = FALSE; //关闭序列模式
adc_base_struct.repeat_mode = FALSE; //关闭重复模式
adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT; //数据右对齐
adc_base_struct.ordinary_channel_length = 1; //通道数为1
adc_base_config(ADC1, &adc_base_struct); //初始化参数
adc_ordinary_conversion_trigger_set(ADC1, ADC12_ORDINARY_TRIG_SOFTWARE, TRUE); //普通通道触发设置为软件触发
adc_enable(ADC1, TRUE); //使能ADC1
adc_calibration_init(ADC1); //初始化校准
while(adc_calibration_init_status_get(ADC1)); //初始化校准完毕
adc_calibration_start(ADC1); //开始校准
while(adc_calibration_status_get(ADC1)); //校准完毕
}
采样代码
/*
*获得ADC值
*adc_channel:要获取的通道
*
*/
u16 get_adcval(adc_channel_select_type adc_channel)
{
adc_ordinary_channel_set(ADC1, adc_channel, 1, ADC_SAMPLETIME_239_5); //ADC1,ADC通道,序列号1,采样时间为239.5周期
adc_ordinary_software_trigger_enable(ADC1, TRUE); //使能指定的ADC1的软件转换启动功能
while(!adc_flag_get(ADC1, ADC_CCE_FLAG )); //等待转换结束
return adc_ordinary_conversion_data_get(ADC1); //返回最近一次ADC1普通通道的转换结果
}
取平均值
/*
*获取adc平均值
*adc_channel:要获取的通道
*times:总次数
*去掉第一和最后一个数据再取平均值。
*/
u16 get_adcval_average(adc_channel_select_type adc_channel,u8 times)
{
u16 adc_val[100];
u32 adc_valsum=0;
u8 cut;
for(cut=0;cut<times;cut++) //多次获取adc的值
{
adc_val[cut]=get_adcval(adc_channel);
delay_ms(5);
}
for(cut=1;cut<times-1;cut++) //去掉第一次和最后一次的值
{
adc_valsum+=adc_val[cut];
}
return adc_valsum/(times-2); //返回平均值
}
测试
测试代码
通过每3秒采集12次通道1的值并且去掉第一个值和最后一个值取然后平均值。硬件上通过手动来调节可变电阻。
测试结果
手动调节可变电阻的时候,ad采集的值也在对应的变化,测试通过。
电压的计算:采样得到的值*参考电压/4096(2的12次方)
最后
有问题的可以加QQ群技术交流,同时相关代码上传到QQ群中。
更多推荐
所有评论(0)