基于STM32F4:多通道ADC采集,采用DMA的形式,亲测有效

基于STM32F4:多通道ADC采集,采⽤DMA的形式,亲测有效基于STM32F4的多通道ADC采集
单⽚机源程序如下:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "fliter.h"
#include "adc.h"
#include "oled.h"
extern u8 AD_Flag;//AD转换完成标志位
extern u16  ADC_ConvertedValue[NOFCHANEL];//⽤于存放ADC的转换值
实物卡extern float ADC_Final_DisplayValue[NOFCHANEL];//⽤于存放最终显⽰值
extern u16 ADC_filter_Value[NOFCHANEL];
int main()
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
delay_init(168);//初始化延时函数
uart_init(115200);//初始化串⼝波特率为115200
ADC_X_Init();//ADC初始化
LED_Init();//LED灯初始化
蜂窝不粘锅OLED_Init();//OLED初始化
/************⼀开始的显⽰*************/
OLED_ShowCHinese(12,0,0,1);//输
OLED_ShowCHinese(24,0,1,1);//⼊
OLED_ShowCHinese(36,0,4,1);//电
OLED_ShowCHinese(48,0,5,1);//压
OLED_ShowCHinese(60,0,10,1);//:
OLED_ShowCHinese(12,12,2,1);//输
OLED_ShowCHinese(24,12,3,1);//出
OLED_ShowCHinese(36,12,6,1);//电
OLED_ShowCHinese(48,12,7,1);//流
OLED_ShowCHinese(60,12,10,1);//:
OLED_ShowString(12,24,"DAC:",12);
OLED_Refresh_Gram();//更新显⽰到OLED
while(1)
{
AD_Flag=AD_voltage;  ADC_filter_Value[0]=middleValueFilter();
AD_Flag=AD_current;  ADC_filter_Value[1]=middleValueFilter();
AD_Flag=AD_DAC;                ADC_filter_Value[2]=middleValueFilter();
ADC_Final_DisplayValue[0]=(double) ADC_filter_Value[0]/4096*3.3*6;//电压检测
ADC_Final_DisplayValue[1]=(double) ADC_filter_Value[1]/4096*3.3;//电流检测
ADC_Final_DisplayValue[2]=(double) ADC_filter_Value[2]/4096*3.3;//DAC检测
OLED_ShowFloatNum_12(72,0,ADC_Final_DisplayValue[0],2,12);
OLED_ShowFloatNum_12(72,12,ADC_Final_DisplayValue[1],2,12);
OLED_ShowFloatNum_12(72,24,ADC_Final_DisplayValue[2],2,12);
OLED_Refresh_Gram();//更新显⽰到OLED
delay_ms(500);
}
}
#include "usart.h"
#include "adc.h"
#include "delay.h"
#include "fliter.h"
#include "led.h"
extern u8 AD_Flag;//AD转换完成标志位
extern u16  ADC_ConvertedValue[NOFCHANEL];//⽤于存放ADC的转换值
extern float ADC_Final_DisplayValue[NOFCHANEL];//⽤于存放最终显⽰值
u16 ADC_filter_Value[NOFCHANEL];
extern u16 ADC_ConvertedValue[NOFCHANEL];
// 软件延时
void Delay_ruan(__IO uint32_t nCount)
{
for(; nCount !=0; nCount--);
}
//中位值滤波
//⽅法:连续采样N次(N取奇数)把N次采样值按⼤⼩排列取中间值为本次有效值
/
/优点:能有效克服因偶然因素引起的波动⼲扰;对温度、液位等变化缓慢的被测参数有良好的滤波效果
//缺点:对流量,速度等快速变化的参数不宜
#define N 30
u16 middleValueFilter()//会获取30个ADC转换值,然后取中间的⼀个作为本次采样周期的输出值
{
u16 value_buf[N];
u16 i,j,k,temp;
人脸识别医疗for( i =0; i < N;++i)
{
value_buf[i]=getValue();
}
for(j =0; j < N-1;++j)
{
for(k =0; k < N-j-1;++k)
{
//从⼩到⼤排序,冒泡法排序
if(value_buf[k]> value_buf[k+1])
{
temp = value_buf[k];
value_buf[k]= value_buf[k+1];
value_buf[k+1]= temp;
}
}
}
return value_buf[(N-1)/2];
}
/*******************获得ADC转换的值*******************/
u16 getValue()
{
Delay_ruan(5);//软件延时⼀下再获取ADC的值,但是这个时间怎么确定呢?
if(AD_Flag==AD_voltage)//获取ADC电压的值
{
return ADC_ConvertedValue[0];//因为ADC1的数据数据寄存器地址连接到了ADC_ConvertedValue数组上,所以ADC1采集到的值会传输到数组中,
}
if(AD_Flag==AD_current)//获取ADC采集电流的值
{
return ADC_ConvertedValue[1];
}
if(AD_Flag==AD_DAC)//获取DAC的值
{
return ADC_ConvertedValue[2];
}
}
//**************疑问*************//
/
/ADC1⽤了两个通道,我怎么知道什么时候电流或者电压的值存放到数组⾥?是否存到了对应的位置?
//因为存储地址是连续的,所以ADC采集获得的值会根据顺序存⼊到数组中
#include "adc.h"
#include "delay.h"
u8    AD_Flag;//AD转换完成标志位
u16  ADC_ConvertedValue[NOFCHANEL]={0};//⽤于存放ADC的转换值
float ADC_Final_DisplayValue[NOFCHANEL];//⽤于存放最终显⽰值
/*********************IO⼝复⽤为ADC******************/
void ADC_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;//结构体定义
/*=====================通道1======================*/
/********** 使能 GPIO 时钟****/
RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK1,ENABLE);
/********配置 IO************/
GPIO_InitStructure.GPIO_Pin =  ADC_GPIO_PIN1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//引脚复⽤时,作为ADC或者DAC,不能选复⽤,必须选模拟输⼊,其他的都是复⽤                GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
/*******初始化IO⼝*********/
GPIO_Init(ADC_GPIO_PORT1,&GPIO_InitStructure);
/*=====================通道2======================*/
/********** 使能 GPIO 时钟****/
RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK2,ENABLE);
/********配置 IO************/
GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//引脚复⽤时,作为ADC或者DAC,不能选复⽤,必须选模拟输⼊,其他的都是复⽤                GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
/*******初始化IO⼝*********/
GPIO_Init(ADC_GPIO_PORT2,&GPIO_InitStructure);
/*=====================通道3=======================*/
/********** 使能 GPIO 时钟****/
RCC_AHB1PeriphClockCmd( ADC_GPIO_CLK3,ENABLE);hxi
/********配置 IO************/
GPIO_InitStructure.GPIO_Pin =ADC_GPIO_PIN3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//引脚复⽤时,作为ADC或者DAC,不能选复⽤,必须选模拟输⼊,其他的都是复⽤
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
/*******初始化IO⼝*********/
GPIO_Init(ADC_GPIO_PORT3,&GPIO_InitStructure);
}
/***********配置ADC和DMA*************/
void ADC_Mode_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;// DMA初始化结构体
ADC_InitTypeDef ADC_InitStructure;// ADC初始化结构体
ADC_CommonInitTypeDef ADC_CommonInitStructure;
/*-------------------DMA Iint 结构体参数初始化---------------------*/
/************开启DMA时钟*************************/
RCC_AHB1PeriphClockCmd(DMAX_CLK, ENABLE);
// 外设基址为:ADC 数据寄存器地址
DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)&ADC_X->DR;//外设的数据寄存器地址怎么确定,(u32)&name->DR(name为外设名)// 存储器地址,实际上就是⼀个内部SRAM的变量
DMA_InitStructure.DMA_Memory0BaseAddr =(u32)ADC_ConvertedValue;//存放ADC转换值的数组地址(可以理解为存放ADC转换值的寄存器与这个数组直接连接在⼀起)
// 数据传输⽅向为外设到存储器
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//确定⽅向很重要
// 缓冲区⼤⼩为,指⼀次传输的数据量
DMA_InitStructure.DMA_BufferSize = NOFCHANEL;//存放ADC转换值的数组的数据量
// 外设寄存器只有⼀个,地址不⽤递增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
// 存储器地址固定(这⾥明明写的是增加,为什么还说固定,是错误了么)钢钙板
餐具包装
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//(这⾥应该是增加,因为要把多个数据存到⼀个数组⾥,地址应该是变化的)// // 外设数据⼤⼩为半字,即两个字节
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//这⾥指的是⼀个数据的⼤⼩,STM32是32位的,所以⼀个字是32位,半字是16位
//        存储器数据⼤⼩也为半字,跟外设数据⼤⼩相同
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//外设数据⼤⼩是不是要和存储器数据⼤⼩相同?是的// 循环传输模式(ADC要不断采集数据,所以要循环模式)
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
/
/ DMA 传输通道优先级为⾼,当使⽤⼀个DMA通道时,优先级设置不影响
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
// 禁⽌DMA FIFO        ,使⽤直连模式
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
// FIFO ⼤⼩,FIFO模式禁⽌时,这个不⽤配置
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
// 选择 DMA 通道,通道存在于流中
DMA_InitStructure.DMA_Channel =DMA_Channel__x;
//初始化DMA流,流相当于⼀个⼤的管道,管道⾥⾯有很多通道
DMA_Init(DMA_Stream__x,&DMA_InitStructure);
/****使能DMA流*********/
DMA_Cmd(DMA_Stream__x, ENABLE);
/*-------------ADC_X 初始化------------------*/
/***************使能ADC时钟*****************************/
RCC_APB2PeriphClockCmd(ADC_CLK_ENABLE, ENABLE);
/*-------------------ADC Common 结构体参数初始化---------------*/
// 独⽴ADC模式
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
// 时钟为fpclk x分频
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
/
/ 禁⽌DMA直接访问模式
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
// 采样时间间隔
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;
//初始化ADC Common 结构体
ADC_CommonInit(&ADC_CommonInitStructure);
/* -------------------ADC Init 结构体参数初始化-----------------*/
// ADC 分辨率
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
// 扫描模式,多通道采集需要
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
/
/ 连续转换
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
//禁⽌外部边沿触发
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
//外部触发通道,本例⼦使⽤软件触发,此值随便赋值即可
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
//数据右对齐
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
//转换通道NOFCHANEL个
ADC_InitStructure.ADC_NbrOfConversion = NOFCHANEL;
/******ADC 结构体初始化*********/
ADC_Init(ADC_X,&ADC_InitStructure);
/*----------------配置 ADC 通道转换顺序和采样时间周期-----------------*/
// 配置 ADC 通道转换顺序和采样时间周期
ADC_RegularChannelConfig(ADC_X,ADC_CHANNEL1,1, ADC_SampleTime_56Cycles);//ADC通道1引脚是GPIOB_Pin_0 ADC_RegularChannelConfig(ADC_X,ADC_CHANNEL2,2, ADC_SampleTime_56Cycles);//ADC通道2引脚是GPIOB_Pin_1 ADC_RegularChannelConfig(ADC_X,ADC_CHANNEL3,3, ADC_SampleTime_56Cycles);//ADC通道3引脚是GPIOA_Pin_6 // 使能DMA请求 after last transfer (Single-ADC mode)
ADC_DMARequestAfterLastTransferCmd(ADC_X, ENABLE);
/*************使能ADC DMA*************/
ADC_DMACmd(ADC_X, ENABLE);
/*************使能ADC******************/
ADC_Cmd(ADC_X, ENABLE);
//开始adc转换,软件触发
ADC_SoftwareStartConv(ADC_X);
}
void ADC_X_Init(void)
{
ADC_GPIO_Config();
ADC_Mode_Config();
}
STM32⼯程下载:

本文发布于:2024-09-23 05:21:30,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/2/190753.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:转换   通道   数据   地址   数组   变化
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议