AT32F403A/STM32F103 采用DMA方式多路ADC采集

AT32F403A/STM32F103 采用DMA方式多路ADC采集

` 提示:采用DMA方式进行ADC采样,用到端口PA0到PA3, PC0到PC3,共8路ADC同时进行采样,用定时器控制100ms刷新一次采样结果并通过串口打印出来,带软件滤波和电压转换,串口初始化这里就不作介绍了


前言

stm32f103有多路12位ADC,外部参考电压一般使用3.3V, 理论上STM32F103是在CPU频率为56MHz时,ADC的最大采样转换频率达到1MHz。但是当CPU频率为72MHz时,ADC的最大采样转换频率变为854.7kHz,即1.17us,比1MHz慢。而AT32F403A主频可达240MHZ, 3组2M采样速率12位A/D转换器(21通道)
最小采样周期为1.5个周期+12.5周期=14周期。
最大采样频率为:12MHZ/14周期=851.142KHZ≈851KHZ
也就是1s可以采样851K个数据,这个采样率已经可以满足很多应用需要了。


在这里插入图片描述其中PA0~PA3 分别对应ADC_CHANNEL_0到ADC_CHANNEL_3
在这里插入图片描述
其中PC0~PC3 分别对应ADC_CHANNEL_10到ADC_CHANNEL_13

1. 头文件 adc.h

代码使用的是 AT32F403A_407_Firmware_Library_V2.0.8版本库进行编写,也可以通过JLINK烧录到STM32F103上使用:


#ifndef __ADC_H
#define __ADC_H




#include "sys.h"



#define	FIRL_N	8
#define	AD_NUM   8


/**
  * @brief tmr channel select type
  */
typedef enum
{
  AD_INPUT                   = 0x00, /*!< ad channel select channel 1 */
  DAT_INPUT                  = 0x01, /*!< ad channel select channel 1 complementary */
} Sysctrl_Input_select_type;


extern __IO uint32_t dma1_trans_complete_flag;
extern __IO uint16_t vmor_flag_index;
extern __IO uint16_t 	ADValue[FIRL_N][AD_NUM];
void Get_ADValue(u16* value);
void App_MutiAdcCfg(void);
void PilotAnalogToBuf(uint8_t *rptr, uint8_t *wptr,uint16_t *buf,uint8_t cnt);


extern __IO double  fatualvot[AD_NUM];
#endif

2. 源文件adc.c

程序配置了PA0到PA3, PC0到PC3 八路ADC进行采集,采用DMA方式进行存储,ADValue[FIRL_N][AD_NUM] 用来存放ADC转换结果,也是DMA的目标地址,每完成一次转换,DMA将数据依次存放到数组

#include "adc.h"
#include "at32f403a_407_board.h"

__IO uint16_t 	ADValue[FIRL_N][AD_NUM];
__IO uint16_t		ADValFilter[AD_NUM];
__IO uint32_t dma1_trans_complete_flag = 0;

static void adc_gpio_config(void);
static void dma_config(void);
static void adc_config(void);

/**
  * @brief  gpio configuration.
  * @param  none
  * @retval none
  */
static void adc_gpio_config(void)
{
  gpio_init_type gpio_initstructure;
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);

  gpio_default_para_init(&gpio_initstructure);
  gpio_initstructure.gpio_mode = GPIO_MODE_ANALOG;
  gpio_initstructure.gpio_pins = GPIO_PINS_0 | GPIO_PINS_1 | GPIO_PINS_2 | GPIO_PINS_3;
  gpio_init(GPIOA, &gpio_initstructure);

   gpio_initstructure.gpio_mode = GPIO_MODE_ANALOG;
  gpio_initstructure.gpio_pins = GPIO_PINS_0 | GPIO_PINS_1 | GPIO_PINS_2 | GPIO_PINS_3;
  gpio_init(GPIOC, &gpio_initstructure);
}

/**
  * @brief  dma configuration.
  * @param  none
  * @retval none
  */
static void dma_config(void)
{
  dma_init_type dma_init_struct;
  crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
//  nvic_irq_enable(DMA1_Channel1_IRQn, 0, 0);
  dma_reset(DMA1_CHANNEL1);
  dma_default_para_init(&dma_init_struct);
  dma_init_struct.buffer_size = FIRL_N*AD_NUM;
  dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
  dma_init_struct.memory_base_addr = (uint32_t)ADValue;
  dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;
  dma_init_struct.memory_inc_enable = TRUE;
  dma_init_struct.peripheral_base_addr = (uint32_t)&(ADC1->odt);
  dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;
  dma_init_struct.peripheral_inc_enable = FALSE;
  dma_init_struct.priority = DMA_PRIORITY_HIGH;
  dma_init_struct.loop_mode_enable = TRUE;
  dma_init(DMA1_CHANNEL1, &dma_init_struct);

//  dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
  dma_channel_enable(DMA1_CHANNEL1, TRUE);
}

/**
  * @brief  adc configuration.
  * @param  none
  * @retval none
  */
static void adc_config(void)
{
  adc_base_config_type adc_base_struct;
  crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE);
  crm_adc_clock_div_set(CRM_ADC_DIV_6);

  /* select combine mode */
  adc_combine_mode_select(ADC_INDEPENDENT_MODE);
  adc_base_default_para_init(&adc_base_struct);
  adc_base_struct.sequence_mode = TRUE;
  adc_base_struct.repeat_mode = TRUE;
  adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;
  adc_base_struct.ordinary_channel_length = AD_NUM;
  adc_base_config(ADC1, &adc_base_struct);
  adc_ordinary_channel_set(ADC1, ADC_CHANNEL_0, 1, ADC_SAMPLETIME_239_5);
  adc_ordinary_channel_set(ADC1, ADC_CHANNEL_1, 2, ADC_SAMPLETIME_239_5);
  adc_ordinary_channel_set(ADC1, ADC_CHANNEL_2, 3, ADC_SAMPLETIME_239_5);
  adc_ordinary_channel_set(ADC1, ADC_CHANNEL_3, 4, ADC_SAMPLETIME_239_5);
    
  adc_ordinary_channel_set(ADC1, ADC_CHANNEL_10, 5, ADC_SAMPLETIME_239_5);
  adc_ordinary_channel_set(ADC1, ADC_CHANNEL_11, 6, ADC_SAMPLETIME_239_5);
  adc_ordinary_channel_set(ADC1, ADC_CHANNEL_12, 7, ADC_SAMPLETIME_239_5);
  adc_ordinary_channel_set(ADC1, ADC_CHANNEL_13, 8, ADC_SAMPLETIME_239_5);
  adc_ordinary_conversion_trigger_set(ADC1, ADC12_ORDINARY_TRIG_SOFTWARE, TRUE);
  adc_dma_mode_enable(ADC1, TRUE);

  adc_enable(ADC1, TRUE);
  adc_calibration_init(ADC1);
  while(adc_calibration_init_status_get(ADC1));
  adc_calibration_start(ADC1);
  while(adc_calibration_status_get(ADC1));
}

void App_MutiAdcCfg(void)
{
    adc_gpio_config();
    dma_config();
    adc_config();
   
}

3. 软件滤波程序

void Get_ADValue(u16* value)
{
	u8 i,chnl;
    
    for (i=0;i<AD_NUM;i++)
	{
		ADValFilter[i]=0;
	}	
	
    for(chnl=0; chnl<AD_NUM; chnl++)
    {
        for(i=0;i<FIRL_N;i++)
        {
            ADValFilter[chnl]+=ADValue[i][chnl];
        }
        ADValFilter[chnl]>>=3;
        if(ADValFilter[chnl]<9)ADValFilter[chnl] = 9;
        ADValFilter[chnl] -= 9;
        *value++ = ADValFilter[chnl];
    }    
}

4. 主函数main.c

/**
  **************************************************************************
  * @file     main.c
  * @version  v2.0.8
  * @date     2022-04-02
  * @brief    main program
  **************************************************************************
  *                       Copyright notice & Disclaimer
  *
  * The software Board Support Package (BSP) that is made available to
  * download from Artery official website is the copyrighted work of Artery.
  * Artery authorizes customers to use, copy, and distribute the BSP
  * software and its related documentation for the purpose of design and
  * development in conjunction with Artery microcontrollers. Use of the
  * software is governed by this copyright notice and the following disclaimer.
  *
  * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
  * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
  * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
  * STATUTORY
#define	AD_SCALE	  2.400f     //0到4096对应外部输入电压0到10v(0~10000)

uint8_t timer100ms_updateflag = 0;
/**
  * @brief  this function handles timer1 overflow handler.
  * @param  none
  * @retval none
  */
void TMR1_OVF_TMR10_IRQHandler(void)
{
  if(tmr_flag_get(TMR1, TMR_OVF_FLAG) != RESET)
  {
        /* add user code... */
        timer100ms_updateflag = 1;
        tmr_flag_clear(TMR1, TMR_OVF_FLAG);
   }
}

crm_clocks_freq_type crm_clocks_freq_struct = {0};
void TIM1_TimeBaseInit(void)
{
    /* get system clock */
    crm_clocks_freq_get(&crm_clocks_freq_struct);
     /* enable tmr1 clock */
    crm_periph_clock_enable(CRM_TMR1_PERIPH_CLOCK, TRUE);

    /* tmr1 configuration */
    /* time base configuration */
    tmr_base_init(TMR1, 999, (crm_clocks_freq_struct.ahb_freq / 10000) - 1);
    tmr_cnt_dir_set(TMR1, TMR_COUNT_UP);

    /* overflow interrupt enable */
    tmr_interrupt_enable(TMR1, TMR_OVF_INT, TRUE);

    /* tmr1 overflow interrupt nvic init */
    nvic_irq_enable(TMR1_OVF_TMR10_IRQn, 1, 0);

    /* enable tmr1 */
    tmr_counter_enable(TMR1, TRUE);
//    clkout_config();
}


__IO double  fatualvot[AD_NUM];  
int  main(void)
{
    u32 chnl;
	u16 ADvolt[AD_NUM];
    system_clock_config();
    nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);   
    TIM1_TimeBaseInit();   
	App_MutiAdcCfg();
    adc_ordinary_software_trigger_enable(ADC1, TRUE);
    
    while(1)
    {
    	if (timer100ms_updateflag) 
        {
            timer100ms_updateflag = 0;
     		Get_ADValue(ADvolt);
	        for (chnl=0; chnl<AD_NUM; chnl++)
	        {
	            fatualvot[chnl] = AD_SCALE * ADvolt[chnl];
	            printf("vtmp[%d]=%d\r\n", chnl,(u16)fatualvot[chnl]);
	        }
        }
	}
}

  • 2
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

章鱼哥嵌入式开发

坚持不易,你们的鼓励是我的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值