AT32F423 的 ADC 支持过采样,可以对1个通道连续采样多次,直接输出连续采样的平均值。这样可以省去软件做平均。
配合 DMA,周期触发采样,就可以得到对应通道的周期采样的平均值。
本测评采集3个通道,ADC_IN0、内部温度传感器、内部参考电压。
步骤:
1、配置过程
2、代码编写
main.c
int main(void)
{
/* add user code begin 1 */
uint32_t start_tick;
/* add user code end 1 */
/* add a necessary delay to ensure that Vdd is higher than the operating
voltage of battery powered domain (2.57V) when the battery powered
domain is powered on for the first time and being operated. */
wk_wait_for_power_stable();
/* system clock config. */
wk_system_clock_config();
/* config periph clock. */
wk_periph_clock_config();
/* nvic config. */
wk_nvic_config();
/* init dma1 channel1 */
wk_dma1_channel1_init();
/* config dma channel transfer parameter */
/* user need to modify parameters memory_base_addr and buffer_size */
wk_dma_channel_config(DMA1_CHANNEL1, (uint32_t)&ADC1->odt, (uint32_t)adc_val, 3);
dma_channel_enable(DMA1_CHANNEL1, TRUE);
/* init usart1 function. */
wk_usart1_init();
/* init adc1 function. */
wk_adc1_init();
/* add user code begin 2 */
sys_init();
printf("The demo is started!\n");
start_tick = sys_get_tick();
dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
adc_interrupt_enable(ADC1, ADC_OCCO_INT, TRUE);
adc_interrupt_enable(ADC1, ADC_OCCE_INT, TRUE);
adc_ordinary_software_trigger_enable(ADC1, TRUE);
/* add user code end 2 */
while(1)
{
/* add user code begin 3 */
if (adc_val_update) {
adc_val_update = 0;
#define calculate_volt(val) (val * 3.3 / 4095)
#define calculate_temperature(val) \
((calculate_volt(val) - 1.29f) * 1000 / 4.26f + 25)
printf("temperature sensor value = %f ℃\n",
calculate_temperature(adc_val[0]));
printf("vintrv value = %f V\n", calculate_volt(adc_val[1]));
printf("ADC_IN0 value = %f V\n\n", calculate_volt(adc_val[2]));
}
if (sys_get_tick() - start_tick >= 1000) {
start_tick = sys_get_tick();
dma_flag_clear(DMA1_FDT1_FLAG);
dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
wk_dma_channel_config(DMA1_CHANNEL1, (uint32_t)&ADC1->odt, (uint32_t)adc_val, 3);
dma_channel_enable(DMA1_CHANNEL1, TRUE);
adc_dma_mode_enable(ADC1, TRUE);
adc_ordinary_software_trigger_enable(ADC1, TRUE);
printf("ADC overflow count = %d\n\n", adc_overflow_cnt);
}
/* add user code end 3 */
}
}
中断函数
void DMA1_Channel1_IRQHandler(void)
{
/* add user code begin DMA1_Channel1_IRQ 0 */
if(dma_flag_get(DMA1_FDT1_FLAG)) {
adc_val_update = 1;
adc_dma_mode_enable(ADC1, FALSE);
dma_channel_enable(DMA1_CHANNEL1, FALSE);
dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, FALSE);
}
/* add user code end DMA1_Channel1_IRQ 0 */
/* add user code begin DMA1_Channel1_IRQ 1 */
/* add user code end DMA1_Channel1_IRQ 1 */
}
void ADC1_IRQHandler(void)
{
/* add user code begin ADC1_IRQ 0 */
if(adc_flag_get(ADC1, ADC_OCCO_FLAG) != RESET)
{
adc_flag_clear(ADC1, ADC_OCCO_FLAG);
adc_overflow_cnt++;
}
if(adc_flag_get(ADC1, ADC_OCCE_FLAG) != RESET)
{
adc_flag_clear(ADC1, ADC_OCCE_FLAG);
}
/* add user code end ADC1_IRQ 0 */
/* add user code begin ADC1_IRQ 1 */
/* add user code end ADC1_IRQ 1 */
}
3、测试
测试中遇到的问题:
1、DMA 使用过程中有开关通道和中断操作,当关必 DMA 通道后,再打开 DMA 通道时,必须要重新使能 ADC 的 DMA,
adc_dma_mode_enable(ADC1, TRUE);
否则,不会触发 DMA 传输。2、内部温度传感器采到的温度值,和 ADC_IN0 的电压相关,ADC_IN0 电压越高,采到的温度越高,猜测可能和通道切换过程有关。不过,内部参考电压不受这些影响。
|