打印
[AT32F403/403A]

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

[复制链接]
734|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2023-7-24 17:28 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
AD, ADC, DM, DMA
前言
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=0;
        }       
       
    for(chnl=0; chnl<AD_NUM; chnl++)
    {
        for(i=0;i<FIRL_N;i++)
        {
            ADValFilter[chnl]+=ADValue[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]);
                }
        }
        }
}
————————————————
版权声明:本文为CSDN博主「章鱼哥嵌入式开发」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/shufawangzhang/article/details/124923691

使用特权

评论回复
评论
xu@xupt 2023-9-17 08:43 回复TA
很好的资源,学习啦~~ 
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1747

主题

15155

帖子

10

粉丝