赞
踩
利用stm32的ADC1外设实现双通道循环测量电压
1.GPIO
2.ADC
3.DMA
#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
}
//获得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规则组的转换结果
}
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; }
}
使用了ADC开了DMA中断,主函数会被频繁打断,除非你主函数不想执行功能,否者你就别打开DMA传输完成中断。
程序中adc读数始终不正常,经过软件仿真,一步一步执行,发现是ADC没有读数据,进一步发现,并没正常打开ADC,通过软件打开ADC要加下面这句话。
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //这句话一定要有,就算这里不写,主函数也要写,否者开不了adc
MDK这个软件会故意优化,你要定义volatile(谷歌翻译为易变)型变量。具体情况百度
https://blog.csdn.net/i792439187/article/details/8825397
https://blog.csdn.net/TanTrey/article/details/82992605
正点原子例程
这篇文章主要写一些我在使用ADC过程遇到的问题,希望给看到的各位提供到帮助
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。