概述
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
最后
以上就是动听糖豆为你收集整理的[单片机框架][bsp层][N32G4FR][bsp_adc] ADC配置和使用的全部内容,希望文章能够帮你解决[单片机框架][bsp层][N32G4FR][bsp_adc] ADC配置和使用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复