当前位置:   article > 正文

我的第一篇文章——stm32的ADC+DMA+滤波算法_32常用的滤波算法

32常用的滤波算法

一 工程目的

利用stm32的ADC1外设实现双通道循环测量电压

(1)外设配置

1.GPIO
2.ADC
3.DMA

(2)源码

头文件

#ifndef __ADC_H
#define __ADC_H
#include “sys.h”

#define N 20//adc保存数组行
#define M 2//列

void adc_Init(void);
u16 Get_Adc(ADC_TypeDef* ADCx,u8 ch);
u16 Get_Adc_Average(ADC_TypeDef* ADCx,u8 ch,u8 times);
void adc_filter(u16 index[N][M]);

#endif

主文件

#include “adc.h”
#include “delay.h”
#include “LED.h”

volatile u16 adc_convert[N][M]; //ADC存放数值
volatile u16 After_Filter[M];//滤波后数组

void adc_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct;
ADC_InitTypeDef  ADC_InitStruct;
DMA_InitTypeDef	DMA_InitStruct;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1, ENABLE);	 //使能PA端口时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
		
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_1;				 
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN; 		 
GPIO_Init(GPIOA, &GPIO_InitStruct);					 //根据设定参数初始化GPIOA.0.1

DMA_DeInit(DMA1_Channel1);
DMA_InitStruct.DMA_MemoryBaseAddr = (u32) adc_convert;
DMA_InitStruct.DMA_PeripheralBaseAddr = (u32) &ADC1->DR;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC ;
DMA_InitStruct.DMA_BufferSize = M*N;//根据adc采集通道数量变化
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  //数据宽度为16位
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;  //工作在循环模式,buffer写满,自动回初始地址开始传输
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_Init(DMA1_Channel1, &DMA_InitStruct);  //根据DMA_InitStruct中指定的参数初始化DMA的通道
DMA_Cmd(DMA1_Channel1, ENABLE);

ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值//复位ADC1,同时设置ADC1分频因子
ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//ADC数据右对齐
ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//转换由软件而不是外部触发启动
ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;//ADC工作模式:ADC1和ADC2工作在独立模式
ADC_InitStruct.ADC_ScanConvMode=ENABLE;//扫描模式
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;//连续转换 
ADC_InitStruct.ADC_NbrOfChannel = M;
ADC_Init(ADC1,&ADC_InitStruct);//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
	
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_13Cycles5 );
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_13Cycles5 );


ADC_DMACmd(ADC1,ENABLE);//adc_dma使能
ADC_Cmd(ADC1, ENABLE);	//使能指定的ADC1



ADC_ResetCalibration(ADC1);	//使能复位校准
while(ADC_GetResetCalibrationStatus(ADC1));	//等待复位校准结束
ADC_StartCalibration(ADC1);	 //开启AD校准
while(ADC_GetCalibrationStatus(ADC1));	 //等待校准结束
	
ADC_SoftwareStartConvCmd(ADC1, ENABLE);	//这句话一定要有,就算这里不写,主函数也要写,否者开不了adc
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

}
//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(ADC_TypeDef* ADCx,u8 ch)
{
//设置指定ADC的规则组通道,一个序列,采样时间
ADC_RegularChannelConfig(ADCx, ch, 1, ADC_SampleTime_13Cycles5 ); //ADC1,ADC通道,采样时间为13.5周期

ADC_SoftwareStartConvCmd(ADCx, ENABLE);		//使能指定的ADC1的软件转换启动功能	
 
while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC ));//等待转换结束

return ADC_GetConversionValue(ADCx);	//返回最近一次ADC1规则组的转换结果
  • 1
  • 2
  • 3
  • 4
  • 5

}

u16 Get_Adc_Average(ADC_TypeDef* ADCx,u8 ch,u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ADCx,ch);
delay_ms(5);
}
return temp_val/times;
}

void adc_filter(u16 index[N][M])//202的中值平均滤波算法
{
/软件滤波模块
/
u16 filter_temp;
u8 i,j,k,flag=1;

for(k=0;k<M;k++)
{	
	for(i=0;i<N && flag;i++)//冒泡排序法
		{	
					for(j=0;j<N-1-i;j++)
					{
						flag=0;
					if(index[j][k]>=index[j+1][k])
						{
							filter_temp = index[j][k];
							index[j][k] = index[j+1][k];
							index[j+1][k] = filter_temp;
							flag=1;
						}
					}	
		}
		After_Filter[k]=(index[(N/2)+1][k]+index[(N/2)][k])/2;
}		
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

}

二 调试过程遇到的问题

1 如果打开中断

使用了ADC开了DMA中断,主函数会被频繁打断,除非你主函数不想执行功能,否者你就别打开DMA传输完成中断。

2 无法打开ADC

程序中adc读数始终不正常,经过软件仿真,一步一步执行,发现是ADC没有读数据,进一步发现,并没正常打开ADC,通过软件打开ADC要加下面这句话。
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //这句话一定要有,就算这里不写,主函数也要写,否者开不了adc

3 变量无法赋值

MDK这个软件会故意优化,你要定义volatile(谷歌翻译为易变)型变量。具体情况百度

三 参考资料

https://blog.csdn.net/i792439187/article/details/8825397
https://blog.csdn.net/TanTrey/article/details/82992605
正点原子例程

四 写在最后

这篇文章主要写一些我在使用ADC过程遇到的问题,希望给看到的各位提供到帮助

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/236610
推荐阅读
相关标签
  

闽ICP备14008679号