[AT32F403/403A]

AT32F403A下ADC+DMA采集电压值

[复制链接]
1421|8
手机看帖
扫描二维码
随时随地手机跟帖
hejun96|  楼主 | 2021-4-14 11:25 | 显示全部楼层 |阅读模式
本帖最后由 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[SAMPLE_CHANNEL_NUM*SAMPLE_COUNT];
volatile uint16_t ADC_ConvertedValue;///[SAMPLE_CHANNEL_NUM*SAMPLE_COUNT];
static u16 nDmaMenLen;//保存DMA每次数据传送的长度

///__IO uint16_t ADC_ConvertedValue[50];

__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[count];
        
        }
        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学习,支持雅特力

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

55

帖子

2

粉丝