打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

LiSun

打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

12.1 ADC介绍

12 位 ADC 是一种逐次逼近型模拟数字转换器。它有多达 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行。ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。
模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
ADC 的输入时钟不得超过 28 MHz,它是由 PCLK2 经分频产生,参见图 3-2。

12.2 ADC主要特征

  • 12位分辨率
  • 转换结束、注入转换结束和发生模拟看门狗事件时产生中断
  • 单次和连续转换模式
  • 从通道0到通道n的自动扫描模式
  • 自校準時間: 156個ADC時鐘週期
  • 带内嵌数据一致性的数据对齐
  • 采样间隔可以按通道分别编程
  • 规则转换和注入转换均有外部触发选项
  • 间断模式
  • ADC转换时间 – 时钟为28MHz时为0.5 μs
  • ADC供电要求:2.6V到3.6V
  • ADC输入范围:VSSA ≤ VIN ≤ VDDA
  • 规则通道转换期间有DMA请求产生

在这里插入图片描述

名称信号类型注解
VDDA输入,模拟电源等效于 VDD的模拟电源且:2.6V ≤ VDDA ≤ VDD(3.6V)
VSSA输入,模拟电源地等效于 VSS的模拟电源地
ADCx_IN[9:0]模拟输入信号18 个模拟输入通道

注意: 温度传感器和 VREFINT 只能出现在主 ADC1 中。

温度传感器和通道 ADC1_IN16 相连接, 内部参照电压 VREFINT和 ADC1_IN17 相连接。 可以按注入或规则通道对这两个内部通道进行转换。

/********************************************************************************
* @file    bsp_adc.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2022-02-10
* @brief   NULL
********************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

#include "RTE_Components.h"
#include CMSIS_device_header
#include "at32f4xx.h"
#include "at32f4xx_adc.h"

#include "bsp_gpio.h"
#include "bsp_exti.h"
#include "bsp_adc.h"

/* Private Includes ----------------------------------------------------------*/
#include "business_gpio.h"
#include "business_function.h"

/* Private Define ------------------------------------------------------------*/
#define ADC0_CH_NUM                   18

#define ADC0_CH0                      0
#define ADC0_CH1                      1
#define ADC0_CH2                      2
#define ADC0_CH3                      3
#define ADC0_CH4                      4
#define ADC0_CH5                      5
#define ADC0_CH6                      6
#define ADC0_CH7                      7
#define ADC0_CH8                      8
#define ADC0_CH9                      9
#define ADC0_CH10                     10
#define ADC0_CH11                     11
#define ADC0_CH12                     12
#define ADC0_CH13                     13
#define ADC0_CH14                     14
#define ADC0_CH15                     15
#define ADC0_CH16                     16
#define ADC0_CH17                     17

#define CH_NUM  (BS_ADC0_CH0 + BS_ADC0_CH1 + BS_ADC0_CH2 + BS_ADC0_CH3 + BS_ADC0_CH4 + BS_ADC0_CH5 + BS_ADC0_CH6 + BS_ADC0_CH7 + BS_ADC0_CH8 + BS_ADC0_CH9 + BS_ADC0_CH10 + BS_ADC0_CH11 + BS_ADC0_CH12 + BS_ADC0_CH13 + BS_ADC0_CH14 + BS_ADC0_CH15 + BS_ADC0_CH16 + BS_ADC0_CH17)
/* Private Variables ---------------------------------------------------------*/
// ADC初始化状态(0--deinit 1--init)
static bool g_adc_init = false;
// ADC采集数据存储buff
uint16_t bsp_adc0_val[ADC0_CH_NUM] = {0};
uint16_t bsp_adc0_temp_val[CH_NUM] = {0};

// 定义ADC采集完毕回调函数
typedef void(*bsp_adc0_callback)(void);
static bsp_adc0_callback irq_callback;
static uint8_t adc0_sample_tick = 0;
/****************结构体定义****************/
#if BS_ADC0_EN
ADC_InitType adc0_handle_t =
{
    .ADC_Mode              = ADC_Mode_Independent,
    .ADC_ScanMode          = ENABLE,                        // DISABLE 单通道  ENABLE 双通道
    .ADC_ContinuousMode    = DISABLE,                       // DISABLE 单次    ENABLE 连续
    .ADC_ExternalTrig      = ADC_ExternalTrig_None,
    .ADC_DataAlign         = ADC_DataAlign_Right,
    .ADC_NumOfChannel      = CH_NUM
};
#endif
/* External Variables --------------------------------------------------------*/
/* Public Function Prototypes ------------------------------------------------*/
#if BS_ADC0_EN
/**
 * @brief  将ADC采集的值重新排序到另一个数组
 */
static void bsp_adc0_val_copy(void)
{
    uint8_t num = 0;
    bool flag = false;

    for (uint8_t i = 0; i < ADC0_CH_NUM; i++)
    {
        if (i == ADC0_CH0 && BS_ADC0_CH0)
        {
            flag = true;
        }
        else if(i == ADC0_CH1 && BS_ADC0_CH1)
        {
            flag = true;
        }
        else if(i == ADC0_CH2 && BS_ADC0_CH2)
        {
            flag = true;
        }
        else if(i == ADC0_CH3 && BS_ADC0_CH3)
        {
            flag = true;
        }
        else if(i == ADC0_CH4 && BS_ADC0_CH4)
        {
            flag = true;
        }
        else if(i == ADC0_CH5 && BS_ADC0_CH5)
        {
            flag = true;
        }
        else if(i == ADC0_CH6 && BS_ADC0_CH6)
        {
            flag = true;
        }
        else if(i == ADC0_CH7 && BS_ADC0_CH7)
        {
            flag = true;
        }
        else if(i == ADC0_CH8 && BS_ADC0_CH8)
        {
            flag = true;
        }
        else if(i == ADC0_CH9 && BS_ADC0_CH9)
        {
            flag = true;
        }
        else if(i == ADC0_CH10 && BS_ADC0_CH10)
        {
            flag = true;
        }
        else if(i == ADC0_CH11 && BS_ADC0_CH11)
        {
            flag = true;
        }
        else if(i == ADC0_CH12 && BS_ADC0_CH12)
        {
            flag = true;
        }
        else if(i == ADC0_CH13 && BS_ADC0_CH13)
        {
            flag = true;
        }
        else if(i == ADC0_CH14 && BS_ADC0_CH14)
        {
            flag = true;
        }
        else if(i == ADC0_CH15 && BS_ADC0_CH15)
        {
            flag = true;
        }
        else if(i == ADC0_CH16 && BS_ADC0_CH16)
        {
            flag = true;
        }
        else if(i == ADC0_CH17 && BS_ADC0_CH17)
        {
            flag = true;
        }
        if (flag)
        {
            flag = false;
            bsp_adc0_val[i] = bsp_adc0_temp_val[num];
            num++;
            if (num == CH_NUM)
            {
                break;
            }
        }
    }
}


/**
 * @brief  ADC0初始化,并使能通道
 */
void bsp_adc0_init(void)
{
    uint8_t ch = 0;
#if CH_NUM
    if (g_adc_init)
    {
        return;
    }
    /* ADCCLK = PCLK2/4 */
    RCC_ADCCLKConfig(RCC_APB2CLK_Div4);
    /* Enable ADC1 clocks */
    RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_ADC1, ENABLE);
    /* ADC1 configuration */
    ADC_Init(ADC1, &adc0_handle_t);
    // 使能通道
#if BS_ADC0_CH0
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH1
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH2
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_2, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH3
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_3, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH4
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_4, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH5
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_5, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH6
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_6, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH7
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_7, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH8
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_8, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH9
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_9, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH10
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_10, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH11
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_11, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH12
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_12, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH13
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_13, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH14
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_14, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH15
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_15, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH16
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_16, ch, ADC_SampleTime_28_5);
#endif
#if BS_ADC0_CH17
    ch++;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_17, ch, ADC_SampleTime_28_5);
#endif
    /* Regular discontinuous mode channel number configuration */
    ADC_DiscModeChannelCountConfig(ADC1, 1);
    /* Enable regular discontinuous mode */
    ADC_DiscModeCtrl(ADC1, ENABLE);

    /* Enables Temperature Sensor and Vrefint Channel */
    ADC_TempSensorVrefintCtrl(ENABLE);
    ADC_INTConfig(ADC1, ADC_INT_EC, ENABLE);

    /* Enable ADC1 */
    ADC_Ctrl(ADC1, ENABLE);

    /* Enable ADC1 reset calibration register */   
    ADC_RstCalibration(ADC1);
    /* Check the end of ADC1 reset calibration register */
    while(ADC_GetResetCalibrationStatus(ADC1));

    /* Start ADC1 calibration */
    ADC_StartCalibration(ADC1);
    /* Check the end of ADC1 calibration */
    while(ADC_GetCalibrationStatus(ADC1));

    NVIC_InitType NVIC_InitStructure;
    /* Configure and enable ADC interrupt */
    NVIC_InitStructure.NVIC_IRQChannel                      = ADC1_2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority    = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority           = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                   = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    g_adc_init = true;
#endif
}

/**
 * @brief  ADC0功能关闭,并移除
 */
void bsp_adc0_deinit(void)
{
#if CH_NUM
    if (!g_adc_init)
    {
        return;
    }
    ADC_Reset(ADC1);
    g_adc_init = false;
#endif
}

/**
 * @brief  ADC0 启动采样功能
 */
void bsp_adc0_start(void)
{
#if CH_NUM
    if (!g_adc_init)
    {
        return;
    }
    /* Enable ADC1 */
    ADC_Ctrl(ADC1, ENABLE);
    /* Start ADC1 Software Conversion */ 
    ADC_SoftwareStartConvCtrl(ADC1, ENABLE); // 启动ADC中断转换
    adc0_sample_tick = 0;
#endif
}

/**
 * @brief  ADC0 停止采样功能
 */
void bsp_adc0_stop(void)
{
#if CH_NUM
    if (!g_adc_init)
    {
        return;
    }
    /* Stop ADC1 Software Conversion */ 
    ADC_SoftwareStartConvCtrl(ADC1, DISABLE); // 停止ADC中断转换
    /* Stop ADC1 */
    ADC_Ctrl(ADC1, DISABLE);
#endif
}

#else
void bsp_adc0_init(void)
{
}

void bsp_adc0_deinit(void)
{
}

void bsp_adc0_start(void)
{
}
void bsp_adc0_stop(void)
{
}
#endif

/**
  * @brief  This function handles ADC1 and ADC2 global interrupts requests.
  */
#define CTRL2_EXTTRIG_SWSTR_Set     ((uint32_t)0x00500000)
void ADC1_2_IRQHandler(void)
{
#if BS_ADC0_EN
    if (ADC_GetINTStatus(ADC1, ADC_INT_EC))
    {
        bsp_adc0_temp_val[adc0_sample_tick] = (uint16_t) ADC1->RDOR;
        adc0_sample_tick ++;
        if (adc0_sample_tick > CH_NUM - 1)
        {
            adc0_sample_tick = 0;
            bsp_adc0_stop();
            bsp_adc0_val_copy();
            if (irq_callback)
            {
                irq_callback();
            }
        }
        else
        {
            ADC1->CTRL2 |= CTRL2_EXTTRIG_SWSTR_Set;
        }
        /* Clear ADC1 EC pending interrupt bit */
        ADC_ClearINTPendingBit(ADC1, ADC_INT_EC);
    }
#endif
}

/**
 * @brief  得到ADC0采样值
 * @param  ch_num: 通道值
 * @retval 通道对应的ADC值
 */
uint16_t bsp_adc0_get_ch_val(uint8_t ch_num)
{
    if (ch_num >= ADC0_CH_NUM)
    {
        return 0xFFFF;
    }
    return bsp_adc0_val[ch_num];
}

/**
 * @brief  注册ADC0采样完毕回调函数
 * @param  *event: 绑定回调事件
 * @retval 0--失败 1--成功
 */
bool bsp_adc0_irq_callback(void *event)
{
    if (irq_callback != NULL)
    {
        return false;
    }
    else
    {
        irq_callback = (bsp_adc0_callback)event;
    }
    return true;
}

/********************************************************************************
* @file    bsp_adc.h
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-04-10
* @brief   ADC操作
********************************************************************************/

#ifndef __BSP_ADC_H
#define __BSP_ADC_H

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>

/* Public Function Prototypes -----------------------------------------------*/

void bsp_adc0_init(void);
void bsp_adc0_deinit(void);

void bsp_adc0_start(void);
void bsp_adc0_stop(void);

uint16_t bsp_adc0_get_ch_val(uint8_t ch_num);

bool bsp_adc0_irq_callback(void *event);

#endif

posted on 2022-08-13 11:00  xuejianqiang  阅读(82)  评论(0编辑  收藏  举报
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033