通道采样"/>
STM32F407ZGT6 ADC多通道采样
学习ADC多通道采样,参考野火的开发手册和代码
1.特点
-
精度
- 12/10/8/6
-
通道
- 16 个外部通道
- 两个内部 ADC 源
- Vbat( 在ADC1上 )
-
IO
- A/B/C/F
-
MODE
- 独立模式
- 双重模式
- 三重模式
-
转换通道
- 规则通道 16 个 (正常排队)
- 注入通道 4 个 (插队)
2. 寄存器
2.1 规则序列寄存器
- SQR3
- 一个通道占 4 个位( 最多配置6个通道 )
- 这个优先级比较高,所以是从这里开始算优先级
- 如果想配置某个通道第一次转换,那么配置那个通道到这个寄存器的[4:0]位即可
- SQR2
- SQR1
2.2 注入序列寄存器( JSQR )
只有一个JSQR,最多支持4个通道,JL[2:0]决定。
注意:如果JL<=4,则JSQR跟SQR的转换顺序不一样,刚好是相反的。如果JL==4,那么还是跟SQR一样,从最低位开始。
寄存器 | 功能 | 取值 |
---|---|---|
JSQ1[4:0] | 设置第1个转换的通道 | 通道1~4 |
JSQ2[4:0] | 设置第2个转换的通道 | 通道1~4 |
JSQ3[4:0] | 设置第3个转换的通道 | 通道1~4 |
JSQ4[4:0] | 设置第4个转换的通道 | 通道1~4 |
JL[1:0] | 需要转换多少个通道 | 1~4 |
2.3 数据寄存器
2.3.1 规则数据寄存器ADC_DR
- 只有一个
- 32位
- 低16位有效(用来存储数据)
- 对齐
- 左12位对齐
- 右12位对齐
- 由ADC_CR2 的11位ALIGN设置
- 注意
- 16 个 规则通道 公用一个 数据寄存器
- 可能数据会被覆盖
- 最好 采用 DMA 传输 或者 软件控制转换
- 仅适用于独立模式
2.3.2 通用规则数据寄存器 ADC_CDR
- 双重、三重模式下使用
- 配合 DMA 数据传输
2.3.3 注入数据寄存器ADC_JDRx
- 数据寄存器有 4 个
- 32位
- 配置跟上面同理
3. 使用
-
CR2开启
- ADON 位
- 1:启动 0:停止
- 外部触发
- 极性
- 状态
- 禁止触发检测
- 上升沿检测
- 下降沿检测
- 上升、下降都检测
- 配置
- EXTEN[1:0]
- JEXTEN[1:0]
- 状态
- EXTSEL[2:0]
- 选择触发规则通道的触发源
- 还需要配置 EXTIRIG (CR2) 才能激活
- JEXTSEL[2:0]
- 选择注入通道的触发源
- 还需要配置 JEXTTRIG (CR2) 才能激活
- 极性
- ADON 位
-
时钟配置
- ADC_CCR (PCLK2)
- 最大值为 36 Mhz
- 典型值为 30 Mhz
- 分屏系数2/4/6/8(常用的是4/6)
- 采样时间
- 最小配置采样周期是(采样时间) 3
- ADC_SMPRx
- x = 1
- 控制通道10 ~ 17
- x = 2
- 控制通道 0 ~ 9
- 通过配置 SMP[2:0]
- x = 1
- 总采样时间
- Tconv = 采样时间 + 12个周期(这是固定默认的)
- ADC_CCR (PCLK2)
-
数据保存
- 存储
- 规则数据保存在ADC_DR
- 注入数据保存在JDRx
- 无论是双重或者是三重模式都是存储到ADC_CDR
- 存储
-
中断
- 转换结束中断
- 检测标志位即可(可触发中断)
- 模拟看门狗中断
- 模拟电压低于 低阈值 或 高于高阈值时会产生中断
- 溢出中断
- 数据丢失会置位 ADC_SR的OVR位,可触发溢出中断,会在转换结束后产生中断(记得先使能中断才会响应)
- DAM 请求
- 无论是规则还是注入转换接受后,除了产生中断外,还可以产生DMA请求,把数据存储到内存中。
- 转换结束中断
4. 库函数
4.1 结构体
主要有两个结构体,一个是通用ADC结构体(模式、分屏系数、DMA/采样间隔)。另一个是配置是否连续转换、通道、外部触发、分辨率、数据对齐。
typedef struct{uint32_t ADC_Mode; // ADC模式选择uint32_t ADC_Prescaler; // ADC分频系数uint32_t ADC_DMAAccessMode; // DMA模式配置(在独立模式无效)uint32_t ADC_TwoSamplingDelay; //采样延迟(在独立模式无效)
}ADC_InitTypeDef;typedef struct{uint32_t ADC_Resolution; //ADC分辨率选择FunctionalState ADC_ScanConvMode; //ADC扫描模式(不扫描通道, 扫描通道)FunctionalState ADC_ContinuousConvMode; //ADC连续转换模式(只转换一次或者连续转换)uint32_t ADC_ExternalTrigConvEdge; //ADC外部触发极性(禁止极性、上升沿、下降、两者沿)uint32_t ADC_ExternalTrigConv; //ADC触发选择(外部触发、定时器触发、其他)uint32_t ADC_DataAlign; //输出数据对齐方式uint8_t ADC_NbrOfChannel; //转换通道数目}ADC_InitTypeDef;
4.2 函数
注意
配置ADC通道转换顺序和采样周期是通过函数配置,而不是结构体。
ADC_RegularChannelConfig(ADCx,ch,顺序(就是谁先来),采样周期)
中断
ADC_IDConfig(ADCx, 寄存器中中断位(ADC_IT_EOC), ENABLE/DISABLE);使能中断
在中断中使用 ADC_GetITStatus来检测标志位,通过ADC_ClearITPendingBit来清除中断标志位。
获取转换数据
ADC_GetConversionValue(ADCx);
这个函数可以获取到转换的数据
DMA
使能DMA请求
ADC_DMARequestAfterLastTransfercmd(ADCx,ENABLE/DISABLE);
使能ADC DMA
ADC_DMACmd(ADCx,EANBLE/DISABLE);
5. 代码实现
1. bsp_dac.h
#ifndef __BSP_ADC_H
#define __BSP_ADC_H/***************************************************************** 头文件*/
#include "stm32f4xx.h"/***************************************************************** 宏定义*/
#define CHANEEL_NUM (3)/***************************************************************** 声明变量*/extern vu16 ConvVoltage[CHANEEL_NUM]; /*!< 通道数量 >*//***************************************************************** 函数声明*/
void ADC_ALLInit(void);#endif // !__BSP_ADC_H
2.bsp_dac.c
/*** @file bsp_dac.c* @brief DAC多通道测试* @author DFY (dfy1999@foxmail)* @version 1.0* @date 2020-08-06* * @copyright Copyright (c) 2020 DFY* * @par * <table>* <tr><th>Date <th>Version <th>Author <th>Description* <tr><td>2020-08-06 <td>1.0 <td>DFY <td>创建文件* </table>*/
/***************************************************************** 头文件*/
#include "bsp_adc.h"/***************************************************************** 模块全局变量*/
/** 通道数据保存区 */
vu16 ConvVoltage[CHANEEL_NUM];/***************************************************************** 步骤* 1.配置GPIO* 1.1 引脚、模式* 2.配置DMA* 2.1 外设、内存(寄存器)、大小、方向、数量* 3.配置ADC* 3.1 模式(独立模式)分频(4分频21Mhz)* 3.2 分辨率(12)扫描模式(启动)连续转换(启动)外部触发及极性(不使用)数据对齐(右对齐)* 3.3 DMA请求使能、使能ADC DMA* 4.初始化外设***************************************************************//*** @brief 配置ADC的引脚初始化*/
static void ADC_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;/** 使能时钟 */RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);/** 配置Pin_4,5,6 */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_Init(GPIOA, &GPIO_InitStructure);
}/*** @brief 配置ADC的DMA初始化*/
static void ADC_DMA_Config(void)
{DMA_InitTypeDef DMA_InitStructure;/*** 使用DMA2、数据流0、通道0*/RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);/*** @brief 应该还要检查当前流是否可以使用的,以后补充*///通道0DMA_InitStructure.DMA_Channel = DMA_Channel_0;//外设到内存DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//数据量DMA_InitStructure.DMA_BufferSize = CHANEEL_NUM;//循环模式DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//优先级为高DMA_InitStructure.DMA_Priority = DMA_Priority_High;//外设地址DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;//指针不递增DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//数据大小为半字DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//单次突发DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//内存地址DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ConvVoltage;//指针递增DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//数据大小为半字DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//单次突发DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//禁止FIFO模式 参数可不配置DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;//由于禁止FIFO模式 参数可不配置DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;//初始化DMADMA_Init(DMA2_Stream0, &DMA_InitStructure);//使能DMA2 Stream0DMA_Cmd(DMA2_Stream0,ENABLE);
}/*** @brief ADC配置*/
static void ADC_Config(void)
{ADC_InitTypeDef ADC_InitStructure;ADC_CommonInitTypeDef ADC_CommonInitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//独立模式ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//4分频(84/4 = 21Mhz)ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;/** 下面这两个在独立模式中无效 */ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_11Cycles;ADC_CommonInit(&ADC_CommonInitStructure);ADC_StructInit(&ADC_InitStructure);//12位分辨率ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//通道扫描模式ADC_InitStructure.ADC_ScanConvMode = ENABLE;//连续转换模式ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//数据右对齐ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//通道数量ADC_InitStructure.ADC_NbrOfConversion = CHANEEL_NUM;/** 不使用外部触发,下面这两个无效 */ ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;ADC_Init(ADC1, &ADC_InitStructure);//配置通道4为第一个转换 采样周期是3ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_3Cycles);//配置通道5为第一个转换 采样周期是3ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_3Cycles);//配置通道6为第一个转换 采样周期是3ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 3, ADC_SampleTime_3Cycles);//允许DMA的请求ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE);//使能ADC DMAADC_DMACmd(ADC1, ENABLE);//使能ADC外设ADC_Cmd(ADC1, ENABLE);//软件触发 开始转换 后面就不用触发了 因为是连续转换ADC_SoftwareStartConv(ADC1);
}/*** @brief ADC初始化*/
void ADC_ALLInit(void)
{//初始化GPIOADC_GPIO_Config();//初始化DMAADC_DMA_Config();//初始化ADCADC_Config();
}
/****************************END**********************************/
3.main.c
float channel_4,channel_5,channel_6;ADC_ALLInit();while(1){channel_4 = ConvVoltage[0] * (3.3/4096);channel_5 = ConvVoltage[1] * (3.3/4096);channel_6 = ConvVoltage[2] * (3.3/4096);printf("channel_4 = %fv channel_5 = %fv channel_6 = %fv\r\n\r\n",channel_4,channel_5,channel_6);delay_ms(400);}
更多推荐
STM32F407ZGT6 ADC多通道采样
发布评论