【N32L40X】学习笔记11-ADC规则通道采集+dma数据传输

ADC规则通道转换

概述

  • 支持 1 个 ADC,支持单端输入和差分输入,最多可测量 16 个外部和 3 个内部源。
  • 支持 12 位、10 位、8 位、6 位分辨率。
  • ADC 时钟源分为工作时钟源、采样时钟源和计时时钟源
    • 仅可配置 AHB_CLK 作为工作时钟源
    • 可配置 PLL 作为采样时钟源,最高可到 64MHz,支持分频 1,2,4,6,8,10,12,16,32,64,128,256。
    • 可配置 AHB_CLK 作为采样时钟源,最高可到 64MHz,支持分频 1,2,4,6,8,10,12,16,32。
    • 计时时钟用于内部计时功能,频率必须配置成 1MHz
  • 支持触发采样,包括 EXTI/TIMER。
  • 各通道的采样时间间隔可编程
  • ADC 的工作电压在 1.8V 到 3.6V 之间。
  • ADC 支持转换的电压在 VREF-和 VREF+之间。
  • 内部通道支持 TempSensor、VREFINT(内部 1.2V BG)、VREFBUFF(2.048V)
  • 支持内部参考电压(2.048V)
  • 注入通道最多4个
  • 规则通道最多16个

时钟

在这里插入图片描述

内部通道

  • 温度传感器和通道 ADC_IN17 相连接。
  • VREFINT 和通道 ADC_IN0 相连接。
  • VREFBUFF和 ADC_IN18 相连接。
  • VOP1(运放)OUT输出和通道 ADC_IN3 相连接。
  • VOP2(运放)OUT输出和通道 ADC_IN7 相连接。

单次采集就是每次采集一个通道

连续采集就是采集这个规则组或注入组

扫描模式就是一轮接着一轮的扫描,扫描模式就是讲一个规则组转换完成后,又进行下一轮转换,注入组不支持扫描模式

模拟看门狗

  • 模拟看门狗的高阈值

  • 模拟看门狗的低阈值

  • 当 ADC 转换的值高于模拟看门狗的高阈值或低于模拟看门狗的低阈值时,如果 ADC_CTRL1.AWDGIEN 已配置,则模拟看门狗标志 (ADC_STS.AWDG) 将 被 置 为 1 , 此 时 会 产 生 中 断

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ozJtAUS-1689953222576)(./picture/image-20230718190636870.png)]

间断模式

规则组:每次触发后转换 n 个通道

注入组:每次触发后转换 1个通道

实例

使用规则通道+dma数据传输+连续转换+软件触发

bsp_adc_regular.h

#ifndef _BSP_ADC_H_
#define _BSP_ADC_H_

#include <stdint.h>
#include "n32l40x.h"

typedef struct{
		GPIO_Module* gpiox;
		uint16_t pin;
		uint8_t adc_ch;
 
 }adc_ch_t;
 typedef enum 
 {
	 AIR_PRESS,//气压值
	 BATTERY,//电池电压
	 ADC_CH_NUM
 }ADC_ID;
/**
 *  adc 相关的gpio初始化
 */
void bsp_adc_init(void);
/*
	获取adc的采样值
	返回:0xff,参数错误
*/
uint16_t bsp_adc_get_value(ADC_ID id);

#endif


bsp_adc_regular.c

#include"adc/bsp_adc.h"



adc_ch_t adc_chanles[ADC_CH_NUM]= {
    {GPIOA,GPIO_PIN_3,ADC_CH_4_PA3},
    {GPIOA,GPIO_PIN_4,ADC_CH_5_PA4},
};

static uint16_t ADCConvertedValue[ADC_CH_NUM];

/*
	获取adc的采样值
	返回:0xff,参数错误
*/
uint16_t bsp_adc_get_value(ADC_ID id)
{
    if(id<ADC_CH_NUM)
    {
        return ADCConvertedValue[id];
    }
    else
    {
        return 0xffff;
    }
}

//配置dma通道
static void bsp_adc_dma_config(void)
{
    DMA_InitType DMA_InitStructure;

    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA, ENABLE);

    DMA_DeInit(DMA_CH1);
    DMA_InitStructure.PeriphAddr     = (uint32_t)&ADC->DAT;
    DMA_InitStructure.MemAddr        = (uint32_t)ADCConvertedValue;
    DMA_InitStructure.Direction      = DMA_DIR_PERIPH_SRC;
    DMA_InitStructure.BufSize        = ADC_CH_NUM;//adc传输数量
    DMA_InitStructure.PeriphInc      = DMA_PERIPH_INC_DISABLE;
    DMA_InitStructure.DMA_MemoryInc  = DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD;
    DMA_InitStructure.MemDataSize    = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.CircularMode   = DMA_MODE_CIRCULAR;
    DMA_InitStructure.Priority       = DMA_PRIORITY_HIGH;
    DMA_InitStructure.Mem2Mem        = DMA_M2M_DISABLE;
    DMA_Init(DMA_CH1, &DMA_InitStructure);
    DMA_RequestRemap(DMA_REMAP_ADC1, DMA, DMA_CH1, ENABLE);

    /* Enable DMA channel1 */
    DMA_EnableChannel(DMA_CH1, ENABLE);


    /* Enable ADC DMA */
    ADC_EnableDMA(ADC, ENABLE);
}



/**
 * @brief  adc 相关的gpio初始化
 */
static void bsp_adc_gpio_config(adc_ch_t *padc)
{
    if(padc->gpiox==GPIOA)
    {
        RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
    }
    else if(padc->gpiox==GPIOB)
    {
        RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB, ENABLE);
    }
    if(padc->gpiox==GPIOC)
    {
        RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOC, ENABLE);
    }
    if(padc->gpiox==GPIOD)
    {
        RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOD, ENABLE);
    }

    GPIO_InitType GPIO_InitStructure;

    GPIO_InitStruct(&GPIO_InitStructure);
    /* Configure PC.02 (in12)as analog input -------------------------*/
    GPIO_InitStructure.Pin       = padc->pin;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Analog;
    GPIO_InitPeripheral(padc->gpiox, &GPIO_InitStructure);
}


/**
 * @brief   adc初始化
 */
void bsp_adc_init()
{
    ADC_InitType ADC_InitStructure;


    /* adc 时钟初始化*/
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC, ENABLE);
    ADC_ConfigClk(ADC_CTRL3_CKMOD_AHB, RCC_ADCHCLK_DIV16);
    RCC_ConfigAdc1mClk(RCC_ADC1MCLK_SRC_HSE, RCC_ADC1MCLK_DIV8);  //selsect HSE as RCC ADC1M CLK Source

    /* GPIO 配置 */
    for(int i=0; i<ADC_CH_NUM; i++)
    {
        bsp_adc_gpio_config(adc_chanles+i);
    }
    ADC_DeInit(ADC);
    /* adc基本参数配置*/
    ADC_InitStructure.MultiChEn      = ENABLE;
    ADC_InitStructure.ContinueConvEn = ENABLE; //持续转换
    ADC_InitStructure.ExtTrigSelect  = ADC_EXT_TRIGCONV_NONE; //ADC触发选择
    ADC_InitStructure.DatAlign       = ADC_DAT_ALIGN_R;
    ADC_InitStructure.ChsNumber      = ADC_CH_NUM;//adc规则通道数量
    ADC_Init(ADC, &ADC_InitStructure);

    //DMA相关的配置
    bsp_adc_dma_config();

    /* ADC1 规则通道配置 */
    for(int i=0; i<ADC_CH_NUM; i++)
    {
        ADC_ConfigRegularChannel(ADC, adc_chanles[i].adc_ch, i+1, ADC_SAMP_TIME_71CYCLES5);
    }

    /* 使能 ADC */
    ADC_Enable(ADC, ENABLE);
    /* Check ADC Ready */
    while(ADC_GetFlagStatusNew(ADC,ADC_FLAG_RDY) == RESET)
        ;
    /* 开始标定ADC */
    ADC_StartCalibration(ADC);
    /* 等待ADC标定结束 */
    while (ADC_GetCalibrationStatus(ADC))
        ;

    /* 软件启动ADC转换*/
    ADC_EnableSoftwareStartConv(ADC, ENABLE);


}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>