STM32F103C8-ADC_DMA电压采集,采样平均值,最大值,最小值

ADC.c

#include "stm32f10x.h"
#include "adc.h"

#define ADC1_DR_Address    ((uint32_t)0x4001244C)   //ADC_DR(ADC规则数据寄存器),偏移量=0x4c  ADC1(0x40012400-0x400127ff)

uint16_t ADC_Buf[16];
void ADC_DMA_Init(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div8);
	
	/* DMA1 channel1 configuration */
	DMA_DeInit(DMA1_Channel1);//选择DMA的通道1
							  //设定从ADC外设的数据寄存器(ADC1_DR_Address)转移到内存(ADCConcertedValue)
							  //每次传输大小16位,使用DMA循环传输模式
	
	/* 用以定义指定 DMA 通道的 DMA 缓存的大小,单位为数据单位 */
	DMA_InitStructure.DMA_BufferSize = 16;
	/* 规定了外设是作为数据传输的目的地还是来源 */
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//外设作为数据传输的来源
	/* 使能 DMA 通道的内存到内存传输 */
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//DMA 通道 x 没有设置为内存到内存传输
	/* 该参数用以定义 DMA 内存基地址 */
	DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_Buf;//目标地址
	/* 设定了外设数据宽度 */
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//数据宽度为 16 位
	/*  用来设定内存地址寄存器递增与否 */
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址增加,多组adc时,使能,数据传输时,内存增加
	/* 设置了 DMA 的工作模式 */
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//工作在循环缓存模式
	/* 该参数用以定义 DMA 外设基地址 */
	DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
	/* 设定了外设数据宽度 */
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//数据宽度为 16 位
	/* 用来设定外设地址寄存器递增与否 */
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址寄存器不变
	/* 设定 DMA 通道 x 的软件优先级 */
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;//DMA 通道 x 拥有高优先级
	/* 初始化 DMA 的通道 x */
	DMA_Init(DMA1_Channel1,&DMA_InitStructure);
	/* 使能或者失能指定的通道 */
	DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA
	
	/* ADC1 初始化*/
	/* 指定是否在中执行转换连续模式或单一模式 */
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//连续转换
	/* 指定是否在中执行转换扫描(多通道)或单通道(单通道)模式 */
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;//多通道
	/* 将ADC配置为在独立或双模 */
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立
	/* 规定了 ADC 数据向左边对齐还是向右边对齐 */
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐
	/* 定义了使用外部触发来启动规则通道的模数转换 */
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//无外部触发
	/* 规定了顺序进行规则转换的 ADC 通道的数目。这个数目的取值范围是 1 到 16 */
	ADC_InitStructure.ADC_NbrOfChannel = 16;
	/* 根据 ADC_InitStruct 中指定的参数初始化外设 ADCx 的寄存器 */
	ADC_Init(ADC1,&ADC_InitStructure);
	
	/* 设置指定 ADC 的规则组通道,设置它们的转化顺序和采样时间 */
	ADC_RegularChannelConfig(ADC1,ADC_Channel_0 ,1,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_1 ,2,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_2 ,3,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_3 ,4,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_4 ,5,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_5 ,6,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_6 ,7,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_7 ,8,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_8 ,9,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_9 ,10,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_10,11,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_11,12,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_12,13,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_13,14,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_14,15,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_15,16,ADC_SampleTime_239Cycles5);
	
	/* 使能ADC_DMA */
	ADC_DMACmd(ADC1, ENABLE);

	/* 使能ADC */
	ADC_Cmd(ADC1, ENABLE);

	/* 使能ADC1的复位校准寄存器  */   
	ADC_ResetCalibration(ADC1);
	/* 等待校准完成 */
	/* ADC_GetResetCalibrationStatus//获取 ADC 重置校准寄存器的状态 */
	while(ADC_GetResetCalibrationStatus(ADC1));

	/* 使能ADC1的开始校准寄存器 */
	ADC_StartCalibration(ADC1);
	/* 等待完成 */
	/* ADC_GetCalibrationStatus//获取指定 ADC 的校准状态 */
	while(ADC_GetCalibrationStatus(ADC1));
	
	/* 使用软件触发,由于没有采用外部触发 */ 
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

/* 采样平均值 */
uint32_t Read_ADC_DMA_number(uint16_t buf,uint8_t count)
{
	uint16_t MIN_AD = 0x0fff,MAX_AD = 0;
	uint16_t num;
	uint8_t t;
	uint32_t number;
	for(t=0;t<count;t++)
	{
		num = buf;
		MIN_AD = ADC_MIN(MIN_AD,num);
		MAX_AD = ADC_MAX(MAX_AD,num);
		number+=num;
	}
	number = (number-MIN_AD-MAX_AD)/(count-2);
	return number;
}

//最大最小值
void Read_ADC_DMA_number_MAX_MIN(uint16_t buf,uint32_t number_count)
{
	uint16_t  MinAD = 0x0fff,MaxAd = 0;
	uint16_t  num =0;
	uint32_t t;
	for(t = 0; t < number_count; t++) 
	{
		num = system_t.adc.buf_t.buf[buf];
		MaxAd = ADC_MAX(MaxAd,num);
		MinAD = ADC_MIN(MinAD,num);
	}
	
	system_t.adc.numerical_value_max = MaxAd;//自定义全局变量,请自行添加
	system_t.adc.numerical_value_min = MinAD;//自定义全局变量,请自行添加
}

ADC.h

#ifndef _ADC_H_
#define _ADC_H_
#include "stm32f10x.h"

void ADC_DMA_Init(void);

#define ADC_MAX(x, y)   ((x) > (y) ? (x) : (y))
#define ADC_MIN(x, y)   ((x) < (y) ? (x) : (y))

uint32_t Read_ADC_DMA_number(uint16_t buf,uint8_t count);
uint32_t Read_ADC_DMA_number_MAX_MIN(uint16_t buf,uint32_t number_count);

#endif

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32微控制器的ADC(Analog-to-Digital Converter)支持中断采集模式,可以用于实时监测模拟信号并计算平均值,通常通过以下步骤实现: 1. **配置ADC模块**:首先,在初始化阶段,你需要设置ADC的工作模式、通道选择、采样时间、转换速率等,并开启中断。 ```c ADC_InitTypeDef ADC_InitStructure; ADC中断处理函数 pointer ADC_IRQHandler; // 初始化ADC ADC_InitStructure.ADC_Mode = ADC_ContinuousConvMode; // 连续转换模式 ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 非扫描模式 ADC_InitStructure.ADC_Resolution = ADC_12b Resolution; // 12位分辨率 ADC_InitStructure.ADC_DMAAccessMode = DISABLE; // 如果不需要DMA,则关闭 ADC_InitStructure.ADC pData = NULL; // 数据缓冲区指针 HAL_ADC_Init(&hadc1, &ADC_InitStructure); ``` 2. **配置中断**:然后,需要启用ADC中断,例如,当转换完成时触发中断。 ```c __HAL_ADC_ENABLE_IT(&hadc1, ADC_IT_EOC); // 开启结束标志(EOC)中断 NVIC_EnableIRQ(ADC_IRQn); // 启动ADC中断服务请求 ``` 3. **中断服务函数**:`ADC_IRQHandler` 函数会在每个转换完成后被调用,这时你可以读取转换结果并更新平均值。 ```c void ADC_IRQHandler(void) { if (__HAL_ADC_GET_FLAG(&hadc1, ADC_FLAG_EOC) != RESET) { uint16_t sample = HAL_ADC_GetValue(&hadc1); // 获取当前转换值 average += sample; // 更新平均值 average /= NUM_SAMPLES; // 如果有滤波需求,这里除以样本数 __HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_EOC); // 清除中断标志 } } ``` 4. **启动转换**:每次中断发生后,你需要再次启动ADC的转换,以便获取下一次的样本值。 ```c HAL_ADC_Start(&hadc1); // 开始新一次的转换 ``` 5. **控制周期和滤波**:为了得到平滑的滤波效果,可以设置一定的采集周期(例如100ms),在这个周期内收集足够多的样本再计算平均值。 注意:以上代码仅作示例,实际应用中需根据具体的STM32型号和库文件进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值