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) 才能激活
  • 时钟配置

    • 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]
      • 总采样时间
        • Tconv = 采样时间 + 12个周期(这是固定默认的)
  • 数据保存

    • 存储
      • 规则数据保存在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.com)
 * @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 应该还要检查当前流是否可以使用的,以后补充
     */

    //通道0
    DMA_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;
    //初始化DMA
    DMA_Init(DMA2_Stream0, &DMA_InitStructure);

    //使能DMA2 Stream0
    DMA_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为第一个转换 采样周期是3
    ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_3Cycles);
    //配置通道5为第一个转换 采样周期是3
    ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_3Cycles);
    //配置通道6为第一个转换 采样周期是3
    ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 3, ADC_SampleTime_3Cycles);

    //允许DMA的请求
    ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE);
    //使能ADC DMA
    ADC_DMACmd(ADC1, ENABLE);

    //使能ADC外设
    ADC_Cmd(ADC1, ENABLE);

    //软件触发 开始转换 后面就不用触发了 因为是连续转换
    ADC_SoftwareStartConv(ADC1);
}

/**
 * @brief ADC初始化
 */
void ADC_ALLInit(void)
{
    //初始化GPIO
    ADC_GPIO_Config();
    //初始化DMA
    ADC_DMA_Config();
    //初始化ADC
    ADC_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);
		}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值