完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
STM32 ADC1+DMA+TIM 实现四路模拟信号采集
STM32 ADC
~~附:刚接触ADC的时候我对它的那四种模式概念比较模糊,举个例子大家应该就会清楚~~ 举例 用ADC1 规则通道的顺序为CH0,CH1,CH2,CH3, 不启动扫描模式: 在单次转换模式下: 启动ADC1,则 1.开始转换CH0(ADC_SQR的第一通道) 转换完成后停止,等待ADC的下一次启动,继续从第一步开始转换 在连续转换模式下: 启动ADC1,则 1.开始转换CH0(ADC_SQR的第一通道) 转换完成后回到第一步,继续转换 启动扫描模式下 在单次转换模式下: 启动ADC1,则 1.开始转换CH0、 2.转换完成后自动开始转换CH1 3.转换完成后自动开始转换CH2 4.转换完成后自动开始转换CH3 5.转换完成后停止,等待ADC的下一次启动下一次ADC启动后从第一步开始转换 在连续转换模式下: 启动ADC1,则 1.开始转换CH0 2.转换完成后自动开始转换CH1 3.转换完成后自动开始转换CH2 4.转换完成后自动开始转换CH3 5.转换完成后返回第一步,继续转换 总结:扫描模式决定通道个数,连续模式决定检测次数 介绍完ADC基本知识,下面我们介绍代码 实现的功能: 通过ADC1采集PA.0,PA.1,PA.2,PA.3口的电压,定时器tim3设定0.5s提取一次测量结果,通过串口打印出来 为了方便起见,我把所有初始化代码放在了一个文件里面 adc.h #ifndef __ADC_H #define __ADC_H #include "sys.h" void DMA_Config(DMA_Channel_TypeDef* DMA_Ch,u32 cpar,u32 cmar,u16 cndtr);//DMA初始化 void DMA_Enable(DMA_Channel_TypeDef* DMA_Ch); //DMA使能 void GPIOA_Init(void); //四个IO口初始化 void ADC_Config(void); //ADC初始化 void TIM_Config(u16 arr,u16 psc); //TIM时钟的初始化 #endif **adc.c** **首先配置io口 void GPIOA_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //打开io口时钟 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN; //由参考手册,设置模式为模拟输入 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStruct); //初始化PA.0口 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_1; GPIO_Init(GPIOA,&GPIO_InitStruct); //初始化PA.1口 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_2; GPIO_Init(GPIOA,&GPIO_InitStruct); //初始化PA.2口 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_3; GPIO_Init(GPIOA,&GPIO_InitStruct); //初始化PA.3口 } 配置DMA u16 Get_Number; //预留cndtr (进行一组转化后cndtr会置零) void DMA_Config(DMA_Channel_TypeDef* DMA_Ch,u32 cpar,u32 cmar,u16 cndtr) { DMA_InitTypeDef DMA_InitStruct; //由参考手册,DMA1的通道1与ADC1相连 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); //使能DMA1时钟 Get_Number=cndtr; //预留cndtr (进行一组转化后cndtr会置零) DMA_InitStruct.DMA_BufferSize=cndtr; //设置传输数据的个数 DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC; //设置方向为外设-->存储器 DMA_InitStruct.DMA_M2M=DMA_M2M_Disable; //失能存储器之间的传输 DMA_InitStruct.DMA_MemoryBaseAddr=cmar; //存储器地址 DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord; //设置存储器为半字长 DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable; //使能存储器增量 DMA_InitStruct.DMA_Mode=DMA_Mode_Circular; //循环传输 DMA_InitStruct.DMA_PeripheralBaseAddr=cpar; //外设存储寄存器地址 DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//设置外设寄存器为半字长 DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable; //失能外寄存储器增量 DMA_InitStruct.DMA_Priority=DMA_Priority_High; //设置极性为高 DMA_Init(DMA_Ch,&DMA_InitStruct); } DMA使能函数 void DMA_Enable(DMA_Channel_TypeDef* DMA_Ch) { DMA_Cmd(DMA_Ch,DISABLE); DMA_SetCurrDataCounter(DMA_Ch,Get_Number); DMA_Cmd(DMA_Ch,ENABLE); } ADC1的配置 ADC_InitTypeDef ADC_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); //打开ADC1的时钟 RCC_ADCCLKConfig(RCC_PCLK2_Div6); //分频,最高72 ADC_DeInit(ADC1); ADC_InitStruct.ADC_ContinuousConvMode=ENABLE; //连续模式 ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right; //右对齐 ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //无外部触发 ADC_InitStruct.ADC_Mode=ADC_Mode_Independent; //独立模式 ADC_InitStruct.ADC_NbrOfChannel=4; //4个通道 ADC_InitStruct.ADC_ScanConvMode=ENABLE; //扫描模式 ADC_Init(ADC1,&ADC_InitStruct); ADC_Cmd(ADC1,ENABLE); //ADC使能 ADC_DMACmd(ADC1,ENABLE); //ADC的DMA使能 ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_1Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_1Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_1Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_1Cycles5); //设置4个规则组的扫描顺序 ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)) ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); //校准 ADC_SoftwareStartConvCmd(ADC1,ENABLE); //软件触发 TIM3的配置 void TIM_Config(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //开启时钟 TIM_TimeBaseInitStruct.TIM_ClockDivision=0; TIM_TimeBaseInitStruct.TIM_Period=arr; TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInitStruct.TIM_Prescaler=psc; TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct); //TIM3的配置 NVIC_InitStruct.NVIC_IRQChannel=TIM3_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; NVIC_InitStruct.NVIC_IRQChannelSubPriority=2; //中断优先级 NVIC_Init(&NVIC_InitStruct); TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //更新中断配置 TIM_Cmd(TIM3,ENABLE); 以上就是初始化的配置,大家只需要正确调用,TIM3的更新中断中就可以读取数据啦 main.c #include "sys.h" #include "adc.h" #include "delay.h" #include "usart.h" u16 Get_Value[4]; float v0,v1,v2,v3 int main() { delay_init(); uart_init(9600); GPIOA_Init(); DMA_Config(DMA1_Channel1,(u32)& ADC1->DR,(u32)Get_Value,4); DMA_Enable(DMA1_Channel1); ADC_Config(); TIM_Config(4999,7199); while(1) {} } void TIM3_IRQHandler() //更显中断,需要把取到的ADC的值转化为电压值哦 { v0=(float)Get_Value[0]*3.3/4095; v1=(float)Get_Value[1]*3.3/4095; v2=(float)Get_Value[2]*3.3/4095; v3=(float)Get_Value[3]*3.3/4095; printf("rn%.3f %.3f %.3f %.3frn",v0,v1,v2,v3); TIM_ClearFlag(TIM3,TIM_FLAG_Update) } 运行的效果放一张图哈啊哈哈哈哈哈哈哈 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1617 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1543 浏览 1 评论
977 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
683 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1595 浏览 2 评论
1863浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
644浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
515浏览 3评论
531浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
504浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 02:42 , Processed in 0.583855 second(s), Total 47, Slave 40 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号