STM32F103 利用 ADC1+DMA+TIM 实现四路模拟信号采集

STM32 ADC1+DMA+TIM 实现四路模拟信号采集

STM32 ADC

  1. 12位ADC是一种逐次逼近型模拟数字转换器。
  2. stm32f103有三个ADC,每个ADC可以测量16个外部2个内部信号源
  3. 各通道的A/D转换可以单次、连续、扫描、间断模式执行
  4. ADC的结果可以左对齐或者右对齐的方式储存在16位数据寄存器
 ~~附:刚接触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("\r\n%.3f %.3f %.3f %.3f\r\n",v0,v1,v2,v3);
  TIM_ClearFlag(TIM3,TIM_FLAG_Update)
 }

运行的效果放一张图哈啊哈哈哈哈哈哈哈
在这里插入图片描述

第一次写博文,如果有什么不对的,希望大家斧正呀;

1. 开启ADCDMA时钟 首先需要开启ADCDMA的时钟,可以通过RCC寄存器设置。 2. 配置ADC ADC需要配置以下参数: - 采样时间:每个通道的采样时间需要根据具体的输入信号进行设置。 - 触发源:可以选择软件触发或外部触发。 - 分辨率:可以选择12位或10位分辨率。 - DMA模式:需要选择DMA模式并开启DMA请求。 - 多通道:需要开启多通道模式并设置通道序列。 3. 配置DMA DMA需要配置以下参数: - 数据传输方向:可以选择从外设到内存或从内存到外设。 - 数据传输大小:根据需要设置传输数据的大小。 - 地址增量:可以选择是否自动增地址。 - 循环模式:可以选择是否循环传输数据。 4. 启动ADCDMA 最后需要启动ADCDMA进行数据采集和传输。 具体的配置代码如下: ```c // 开启ADCDMA时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // 配置ADC ADC_InitTypeDef ADC_InitStruct; ADC_InitStruct.ADC_ContinuousConvMode = DISABLE; ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; ADC_InitStruct.ADC_NbrOfChannel = 2; ADC_InitStruct.ADC_ScanConvMode = ENABLE; ADC_InitStruct.ADC_TempSensor = DISABLE; ADC_InitStruct.ADC_Vrefint = DISABLE; ADC_Init(ADC1, &ADC_InitStruct); ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5); ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); // 配置DMA DMA_InitTypeDef DMA_InitStruct; DMA_InitStruct.DMA_BufferSize = 2; DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStruct.DMA_M2M = DISABLE; DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&adc_data; 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 = (uint32_t)&ADC1->DR; DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStruct.DMA_Priority = DMA_Priority_High; DMA_Init(DMA1_Channel1, &DMA_InitStruct); DMA_Cmd(DMA1_Channel1, ENABLE); // 启动ADC采集 ADC_SoftwareStartConvCmd(ADC1, ENABLE); ```
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值