打造一个通用性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

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

ADC 介绍

12 位 ADC 是一种高速逐次逼近型模拟数字转换器。它有多个通道。各通道的 A/D 转换可以单次、连续、
扫描或间断模式执行。ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。
模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
ADC 的输入时钟不得超过 72MHz。

ADC 主要特征

 支持最多 2 个 ADC,支持单端输入和差分输入,可测量 16 个外部和 3 个内部信号源
 ADC1 支持 9 个外部通道,ADC2 支持 7 个外部通道
 支持 12 位、10 位、8 位、6 位分辨率可配置
 12bit 分辨率下最高采样速率 5.14MSPS
 10bit 分辨率下最高采样速率 6MSPS
 8bit 分辨率下最高采样速率 7.2MSPS
 6bit 分辨率下最高采样速率 9MSPS
 ADC 时钟源分为工作时钟源、采样时钟源和计时时钟源
 仅可配置 AHB_CLK 作为工作时钟源,最高可到 144MHz
 可配置 PLL 作为采样时钟源,最高可到 72MHz,支持分频 1,2,4,6,8,10,12,16,32, 64,128,256
 可配置 AHB_CLK 作为采样时钟源,最高可到 72MHz,支持分频 1,2,4,6,8,10,12,16,32
 计时时钟用于内部计时功能,频率必须配置成 1MHz
 支持定时器触发 ADC 采样
 转换结束、注入转换结束和发生模拟看门狗事件时产生中断
 单次和连续转换模式
 从通道 0 到通道 N 的自动扫描模式
 支持自校准
 带内嵌数据一致性的数据对齐
 采样间隔可以按通道分别编程
 规则转换和注入转换均有外部触发选项
 间断模式
 双重模式,ADC1 和 ADC2 组合
 ADC 供电要求:1.8V 到 3.6V
 ADC 输入范围:VREF-≤ VIN ≤ VREF+
 规则通道转换期间有 DMA 请求产生。

ADC 功能描述

下图为一个 ADC 模块的框图,表 9-1 为 ADC 引脚的说明。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ADC 开关控制

用户必须等待 PowerUp 过程完成才可以进入下一步的操作,可以通过查询 ADC_CTRL3 里面的 RDY 确认
是否上电完成。
通过设置 ADC_CTRL2 寄存器的 ON 位可给 ADC 上电。当第一次设置 ON 位时,它将 ADC 从断电状态下
唤醒。ADC 上电延迟一段时间后(tSTAB),再次设置 ON 位时开始进行转换。
通过清除 ON 位可以停止转换,并将 ADC 置于断电模式。在这个模式中,ADC 几乎不耗电(仅几个 μA)。
用户可以通过查询 ADC_CTRL3 里面的 PDRDY 确认是否下电完成。
在 ADC Disable 的时候默认都是 PowerDown 模式,这个模式下只要不断电,不需要重新校正,校正值会在ADC 自动保持。为了进一步的降低功耗 ,ADC 有设计一个深睡眠模式。会在 ADC Disable 进入深睡眠模式,ADC 内部的校正值会丢失,需要重新校正。深睡眠模式可以省大概 0.2μA 的功耗 ,注意,当在双 ADC 模式时,最好双 ADC 都选同一种睡眠模式。控制 ADC 深睡眠模式的寄存器ADC_CTRL3.DPWMOD。

内部通道

 温度传感器和通道 ADC1_IN16 相连接
 VBAT/2 和通道 ADC1_IN17 相连接
 内部参照电压 VREFINT 和 ADCx_IN18 相连接
可以按注入或规则通道对内部通道进行转换。
注意:温度传感器,VBAT/2 只能出现在主 ADC1 中。

#include "n32g4fr.h"
#include "n32g4fr_adc.h"
#include "errorno.h"
#include "bsp_adc.h"

#define ADC_REGU_CH_SEQ_LEN     1
#define ADC_WAIT_RET_TIMEOUT    1000
#define ADC_RET_INIT_VALUE      0xAB
#define ADC_VDD_POWER_MV        3299
#define ADC_DATA_MAX            4095
#define ADC_READ_INVALID_TIMES  5
/*******************************ADC1 config*****************************/
#define ADC1_MODULE              ADC1
#define ADC1_IN_PORT             GPIOA
#define ADC1_IN_PIN              (GPIO_PIN_2 | GPIO_PIN_6)
#define ADC1_IN_PORT_RCC         RCC_APB2_PERIPH_GPIOA
#define ADC1_RCC                 RCC_AHB_PERIPH_ADC1

/*******************************ADC2 config*****************************/
#define ADC2_MODULE              ADC2
#define ADC2_IN_PORT             GPIOA
#define ADC2_IN_PIN              (GPIO_PIN_2 | GPIO_PIN_4 | GPIO_PIN_7)
#define ADC2_IN_PORT_RCC         RCC_APB2_PERIPH_GPIOA
#define ADC2_RCC                 RCC_AHB_PERIPH_ADC2

typedef struct {
    ADC_Module* ADCx;
    GPIO_Module* gpio_x;
    uint16_t gpio_pin;
    uint32_t gpio_rcc;
    uint32_t adcx_rcc;
} adc_config_t;

const adc_config_t g_adc_configs[BSP_ADC_NUM] =
{
    {
        .ADCx = ADC1,
        .gpio_x = ADC1_IN_PORT,
        .gpio_rcc = ADC1_IN_PORT_RCC,
        .gpio_pin = ADC1_IN_PIN,
        .adcx_rcc = ADC1_RCC,
    },
    {
        .ADCx = ADC2,
        .gpio_x = ADC2_IN_PORT,
        .gpio_rcc = ADC2_IN_PORT_RCC,
        .gpio_pin = ADC2_IN_PIN,
        .adcx_rcc = ADC2_RCC,
    }
};

void bsp_adc_io_rcc_enable(bsp_adc_t bsp_adc)
{
    RCC_EnableAPB2PeriphClk(g_adc_configs[bsp_adc].gpio_rcc, ENABLE);
}

void bsp_adc_io_config(bsp_adc_t bsp_adc)
{
    GPIO_InitType GPIO_InitStruct;

    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.Pin = g_adc_configs[bsp_adc].gpio_pin;
    GPIO_InitPeripheral(g_adc_configs[bsp_adc].gpio_x, &GPIO_InitStruct);
}

void bsp_adc_rcc_enable(bsp_adc_t bsp_adc)
{
    RCC_EnableAHBPeriphClk(g_adc_configs[bsp_adc].adcx_rcc, ENABLE);
    RCC_ConfigHclk(RCC_SYSCLK_DIV1);
    RCC_ConfigAdcHclk(RCC_ADCHCLK_DIV32);
    RCC_ConfigAdc1mClk(RCC_ADC1MCLK_SRC_HSI, RCC_ADC1MCLK_DIV8);
}

void bsp_adc_init(bsp_adc_t bsp_adc)
{
    ADC_InitType ADC_InitType_data;
    ADC_Module* ADCx = g_adc_configs[bsp_adc].ADCx;
    int timeout = 0;

    bsp_adc_io_rcc_enable(bsp_adc);
    bsp_adc_io_config(bsp_adc);
    bsp_adc_rcc_enable(bsp_adc);

    ADC_InitType_data.WorkMode = ADC_WORKMODE_INDEPENDENT;
    ADC_InitType_data.ContinueConvEn = DISABLE;
    ADC_InitType_data.ChsNumber = ADC_REGU_CH_SEQ_LEN;
    ADC_InitType_data.DatAlign = ADC_DAT_ALIGN_R;
    ADC_InitType_data.ExtTrigSelect = ADC_EXT_TRIGCONV_NONE;
    ADC_InitType_data.MultiChEn = ENABLE;
    ADC_DeInit(ADCx);
    ADC_Init(ADCx, &ADC_InitType_data);

    ADC_Enable(ADCx, ENABLE);
    timeout = 0;
    while (RESET == ADC_GetFlagStatusNew(ADCx, ADC_FLAG_RDY))
    {
        timeout ++;
        if (timeout > ADC_WAIT_RET_TIMEOUT)
        {
            return ;
        }
    }

    ADC_StartCalibration(ADCx);
    timeout = 0;
    while (SET == ADC_GetCalibrationStatus(ADCx))
    {
        timeout ++;
        if (timeout > ADC_WAIT_RET_TIMEOUT)
        {
            return ;
        }
    }
}

uint16_t bsp_adc_get_one_data(bsp_adc_t bsp_adc, uint8_t ADC_Channel)
{
    int32_t timeout = 0;
    uint32_t adc_data = ADC_RET_INIT_VALUE;
    ADC_Module* ADCx = g_adc_configs[bsp_adc].ADCx;

    ADC_ConfigRegularChannel(ADCx, ADC_Channel, 1, ADC_SAMP_TIME_239CYCLES5);
    ADC_ClearFlag(ADCx, ADC_FLAG_ENDC);

    //ADC_Enable(ADCx,ENABLE)
    ADC_EnableSoftwareStartConv(ADCx, ENABLE);

    timeout = 0;
    while (RESET == ADC_GetFlagStatus(ADCx, ADC_FLAG_ENDC))
    {
        timeout ++;
        if (timeout > ADC_WAIT_RET_TIMEOUT)
        {
            return adc_data;
        }
    }
    adc_data = ADC_GetDat(ADCx);

    ADC_ClearFlag(ADCx, ADC_FLAG_ENDC);

    return adc_data;
}

uint16_t bsp_adc_get_data(bsp_adc_t bsp_adc, uint8_t ADC_Channel)
{
    uint32_t invalid_read_times = 0;

    for (invalid_read_times = 0;invalid_read_times < ADC_READ_INVALID_TIMES;invalid_read_times++)
    {
        bsp_adc_get_one_data(bsp_adc, ADC_Channel);
    }
    return bsp_adc_get_one_data(bsp_adc, ADC_Channel);
}

uint16_t bsp_adc_convert_to_mvoltage(bsp_adc_t bsp_adc, uint16_t adc_data)
{
    uint16_t adc_vref = bsp_adc_get_data(bsp_adc, ADC_CH_0);

    if(adc_vref != 0)
    {
        return adc_data * ADC_VDD_POWER_MV / adc_vref;
    }
    else
    {
        return adc_data * ADC_VDD_POWER_MV / ADC_DATA_MAX;
    }
}

#ifndef __BSP_ADC_H__
#define __BSP_ADC_H__

#include "typedefs.h"

typedef enum {
    BSP_ADC_1 = 0,
    BSP_ADC_2,
    BSP_ADC_NUM
} bsp_adc_t;

void bsp_adc_init(bsp_adc_t bsp_adc);
uint16_t bsp_adc_get_data(bsp_adc_t bsp_adc, uint8_t ADC_Channel);
uint16_t bsp_adc_convert_to_mvoltage(bsp_adc_t bsp_adc, uint16_t adc_data);

#endif

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