~~附:刚接触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.转换完成后返回第一步,继续转换
总结:扫描模式决定通道个数,连续模式决定检测次数
实现的功能:
通过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)
}