hejun96 发表于 2021-4-14 11:25

AT32F403A下ADC+DMA采集电压值

本帖最后由 hejun96 于 2021-6-11 09:37 编辑

#ifndef __BSP_ADC_H_
#define __BSP_ADC_H_


#ifdef __cplusplus
extern "C" {
#endif


typedef struct
{
      void (*Config)(void);
      void (*Handler) (void);
      
      volatile uint16_t usValue;
      float fVoltage;
}adc_t;



static void AdcDmaConfig(void);
static void ADCxGPIOConfig(void);
static void ADCxModeConfig(void);
void adcConfig(void);
u16 GetAdc(u8 ch);
u16 GetAdcAverage(u8 ch,u8 times);



static void Voltage_ADC_Filter(void);
float Get_VoltageValue(void);
//ADC Temperature Sensor

void TemperatureadcConfig(void);
u16 GetTemperatureAdc(u8 ch);
u16 GetTemperatureAverage(void);
u16 GetTemperatureAdcAverage(u8 ch,u8 times);
short GetTemperatureValue(void);

extern adc_t Adc;

#ifdef __cplusplus
}
#endif


#endif
#申请原创#

AT32F403A下ADC+DMA采集电压值
<div class="blockcode"><blockquote>/* Includes -------------------------------------------------*/
#include "includes.h"


/* Private define -------------------------------------------*/
//DMA
/*采集的通道数*/
#define SAMPLE_CHANNEL_NUM                        (1)//ֻ只需要1个DMA通道///(5)

/*一次采集的次数*/
#define SAMPLE_COUNT                                          (10)
#define ADC1_DR_ADDRESS                           ((uint32_t)0x4001244C)
//ADC
//ADC_GPIO宏定义
#define ADC_GPIO_APBxClockFUN                        RCC_APB2PeriphClockCmd
#define ADC_GPIO_CLK                                        RCC_APB2Periph_GPIOA
#define ADC_PORT                                                GPIOA
#define ADC_PIN                                                      GPIO_Pin_11
//ADC编号选择
#define ADC_APBxClock_FUN                              RCC_APB2PeriphClockCmd
#define ADC_x                                                      ADC1
#define ADC_CLk                                                      RCC_APB2Periph_ADC1
#define ADC_CHANNEL                                                      
#define ADC_IRQ                                                      ADC1_2_IRQn
#define ADC_IRQHandler                                        ADC1_2_IRQHnadler


#define ADCx                        ADC1
#define ADC_CHLx                ADC_Channel_10
#define ADC_DMA_CHANNEL      DMA1_Channel1

/* Private variables ----------------------------------------*/

static unsigned int mmi_adc_timer;

/*采集存放的AD值ֵ ADC1转换的电压值通过MDA方式传到SRAM*/
///static volatile u16 ADC_ConvertedValue;
volatile uint16_t ADC_ConvertedValue;///;
static u16 nDmaMenLen;//保存DMA每次数据传送的长度

///__IO uint16_t ADC_ConvertedValue;

__IO uint16_t After_filter;//用来存放求平均值之后的结果

/* Private function prototypes ------------------------------*/
static void adcConfig(void);
static void adcHandler(void);
static u16 GetAdc(u8 ch);
static u16 getAdcAverage(u8 ch,u8 times);
/* Public variables -----------------------------------------*/


adc_t Adc =
{
      adcConfig,
      adcHandler,
      
      0,
      0.0,
};

//PA1-Voltage ADC
static void ADCxGPIOConfig(void)
{
      /*
      GPIO_InitType GPIO_InitStructure;
      //1.配置ADC_IO引脚模式,模拟输入
      
      GPIO_InitStructure.GPIO_Pins = ADC_DET_PIN;//ADC对应PA1口
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_ANALOG;//模拟输入
      GPIO_Init(ADC_DET_PORT,&GPIO_InitStructure);
      */
      GPIOC->CTRLL &= 0XFFFFFFF0;//先获取该bit位
      GPIOC->CTRLL |= 0X00000000;//设置bit位
      
}


static void AdcDmaConfig(void)
{
      
      DMA_InitType DMA_InitStructure;
      // 配置 DMA 初始化结构体
      // 外设基址为:ADC 数据寄存器地址
      
      //使能DMA1通道1
      DMA_Reset(ADC_DMA_CHANNEL);
      
      //外设地址
      DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_ADDRESS;
      
      // 存储器地址
      DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&Adc.usValue;
      
      // 数据源来自外设
      DMA_InitStructure.DMA_Direction = DMA_DIR_PERIPHERALSRC;
      
      // 缓冲区大小,应该等于数据目的地的大小
      DMA_InitStructure.DMA_BufferSize = SAMPLE_CHANNEL_NUM*SAMPLE_COUNT;//
      
      // 外设寄存器只有一个,地址不用递增
      DMA_InitStructure.DMA_PeripheralInc = DMA_PERIPHERALINC_DISABLE;

      //存储器地址固定
      DMA_InitStructure.DMA_MemoryInc = DMA_MEMORYINC_DISABLE;
      
      // 外设数据大小为半字,即两个字节
      DMA_InitStructure.DMA_PeripheralDataWidth = DMA_PERIPHERALDATAWIDTH_HALFWORD;
      
      // 内存数据大小也为半字,跟外设数据大小相同
      DMA_InitStructure.DMA_MemoryDataWidth = DMA_MEMORYDATAWIDTH_HALFWORD;
      
      //循环传输模式
      DMA_InitStructure.DMA_Mode = DMA_MODE_CIRCULAR;      
      
      // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
      ///DMA_InitStructure.DMA_Priority = DMA_Priority_High;
      
      // 禁止存储器到存储器模式,因为是从外设到存储器
      DMA_InitStructure.DMA_MTOM = DMA_MEMTOMEM_DISABLE;
      
      // 初始化DMA
      DMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure);
      
      // 使能 DMA 通道
      DMA_ChannelEnable(ADC_DMA_CHANNEL , ENABLE);
}
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DmaChannelx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量
static void DmaConfig(DMA_Channel_Type* DMA_CHANNELx,u32 cpar,u32 cmar,u16 cndtr)
{
      GeneralTimer.Timer4DelayNms(5);//等待DMA时钟稳定
      DMA_CHANNELx->CPBA=cpar;                  //DMA1 外设地址
      DMA_CHANNELx->CMBA=(u32)cmar;         //DMA1,存储器地址
      nDmaMenLen=cndtr;            //保存DMA传输数据量
      DMA_CHANNELx->TCNT=cndtr;            //DMA1,传输数据量
      DMA_CHANNELx->CHCTRL=0X00000000;      //复位
      DMA_CHANNELx->CHCTRL|=1<<4;                  //从存储器读
      DMA_CHANNELx->CHCTRL|=0<<5;                  //普通模式
      DMA_CHANNELx->CHCTRL|=0<<6;               //外设地址非增量模式
      DMA_CHANNELx->CHCTRL|=1<<7;                  //存储器增量模式
      DMA_CHANNELx->CHCTRL|=0<<8;                  //外设数据宽度为8位
      DMA_CHANNELx->CHCTRL|=0<<10;               //存储器数据宽度8位
      ///DMA_CHANNELx->CHCTRL|=1<<12;               //中等优先级
      DMA_CHANNELx->CHCTRL|=0<<14;               //非存储器到存储器模式               
}
//ADC2没有DMA,故使用DMA1
static void ADCxModeConfig(void)
{      
      
      ADC_InitType ADC_InitStructure;
      //1.打开ADC_IO接口时钟
      AdcDmaConfig();

      ///ADC_Reset(ADCx);
      
      //只使用一个ADC,属于单模式
      ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
      ADC_InitStructure.ADC_ScanMode = DISABLE;//一次是否需要同时转换多个ADC通道,不需要则设置DISABLE,反之ENABLE
      ADC_InitStructure.ADC_ContinuousMode = ENABLE;//连续转换
      ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
      ADC_InitStructure.ADC_ExternalTrig = ADC_ExternalTrig_None;
      ADC_InitStructure.ADC_NumOfChannel = SAMPLE_CHANNEL_NUM;//单通道采集
      ADC_Init(ADCx,&ADC_InitStructure);
      
      RCC_ADCCLKConfig(RCC_APB2CLK_Div4);//AT32F403A ADC频率不超过28MHz,72/6 = 12MHz
      
      //配置 ADC 通道转换顺序为1,第一个转换,采样时间为239.5个时钟周期
      ADC_RegularChannelConfig(ADCx,ADC_CHLx,1,ADC_SampleTime_239_5);
      //使能ADC1的DMA搬运功能
      ADC_DMACtrl(ADCx,ENABLE);
      
      ADC_Ctrl(ADCx, ENABLE);      //使能指定的ADC1
      /*
      //GD32F103这里适当加延时
      GeneralTimer.Timer4DelayNms(1);//1ms延时
      */
      ADC_RstCalibration(ADCx);      //使能复位校准
         
      while(ADC_GetResetCalibrationStatus(ADCx));      //等待复位校准结束
      
      ADC_StartCalibration(ADCx);         //开启AD校准
      
      while(ADC_GetCalibrationStatus(ADCx));         //等待校准结束
      /*
      //GD32F103这里适当延时
      GeneralTimer.Timer4DelayNms(1);//1ms延时
      */
      //由于没有采用外部触发,所以使用软件触发ADC转换
      ADC_SoftwareStartConvCtrl(ADCx,ENABLE);
}

static void adcConfig(void)
{
      ADCxGPIOConfig();
      ADCxModeConfig();
}


/*****************************************
Function:GetAdc
Description:
Calls:
Called By:
Table Accessed:
Table Update:
Input:
Output:
Return:ADC_GetConversionValue(ADC1);
Others:

******************************************/
static u16 GetAdc(u8 ch)
{
      //设置指定ADC的规则组通道,一个序列,采样时间
      ADC_RegularChannelConfig(ADCx,ch,1,ADC_SampleTime_239_5);
      
      ADC_SoftwareStartConvCtrl(ADCx,ENABLE);
      
      while(!ADC_GetFlagStatus(ADCx,ADC_FLAG_EC));
      return ADC_GetConversionValue(ADCx);      
}

/*
*@brief:获取ADC的平均值
*@function:u16 GetAdcAverage
*@param:u8 ch,u8 times
*@retval:AdcAverageValue/times
*/


static u16 getAdcAverage(u8 ch,u8 times)
{
      u32 AdcAverageValue=0;
      u8 t;
      for(t=0;t<times;t++)
      {
                AdcAverageValue+=GetAdc(ch);
                GeneralTimer.Timer4DelayNms(5);
      }
      return AdcAverageValue/times;
}

static float getVoltageValue(void)
{
      /*
      Adc.usAdcValue = getAdcAverage(ADC_CHLx,10);//PC0-AD_IN10采集10次
      Adc.fVoltage = (float)Adc.usAdcValue*(3.3/(1000/1470) / 4095);//adcValue =(3.3V/(1000KΩ/(1000+470)KΩ))/4095 分压电阻(R1/R1+R2)
      */
         
      Adc.fVoltage = (float) Adc.usValue*(3.3/(1000/1470) / 4095);
      return Adc.fVoltage;///return Adc.fVoltage;
}

static void adcHandler(void)
{
      //ADC任务写在这里
      float fVoltageValue;
      fVoltageValue = getVoltageValue();
      
      if(Adc.usValue < 2955)//DC 在3.5V以下进入休眠模式 Adc.usAdcValue < (3.5V * 4095 * 1000 / 1470 /3.3)
      {
                Led.Mode = LED_BLINK;
      }
      else
      {
                Led.Mode = LED_LIGHTING;
      }
      
}


/*
//求平均值函数
static void Voltage_ADC_Filter(void)
{
      int sum = 0;
      uint8_t count;
      
      for(count=0;count<50;count++)
      {
                sum += ADC_ConvertedValue;
      
      }
      After_filter = sum/50;
}

float Get_VoltageValue(void)
{
      float Value;
      Voltage_ADC_Filter();
      
      Value = (float)After_filter*(float)3.3/4096;
      return Value;
}

*/
由于使用了AT32F403A的DMA,getAdcAverage这个函数就不需要了@21小跑堂

两只袜子 发表于 2021-4-14 15:17

很棒的

huquanz711 发表于 2021-4-15 07:21

不错,感谢楼主的分享。

duckfans 发表于 2021-4-17 23:46

学习了,感谢分享

天意无罪 发表于 2021-4-18 14:21

建议楼主不要一来就是粘贴代码啊,好歹还是写点介绍性的文字啊。

zhengshuai888 发表于 2021-4-18 14:36

ST得代码应该不能直接拿来用把

muyichuan2012 发表于 2021-4-18 15:21

本帖最后由 muyichuan2012 于 2021-5-6 09:09 编辑

这是基于at32 bsp开发的代码。

lidi911 发表于 2021-4-18 18:43

谢谢楼主的分享,刚好在搞ADC这块。

hejun96 发表于 2021-4-22 11:51

muyichuan2012 发表于 2021-4-18 15:21
这是应该是基于at32 bsp开发的代码。

是的,看bsp学习,支持雅特力
页: [1]
查看完整版本: AT32F403A下ADC+DMA采集电压值