1 平台条件
1.软件: gecko_sdk_3.2.3
2:硬件:EFR32BG22C224F512GM32
3.IDE工具:SimpliStudio 5
4.官方提供的例程链接 访问链接
2 代码的添加
官方有自己的库,以及应用历程,可以添加以及计算
需要包含的.h文件
#include “em_device.h”
#include “em_cmu.h”
2.1 ADC的初始化
// Set CLK_ADC to 10kHz (this corresponds to a sample rate of 1ksps)
#define CLK_SRC_ADC_FREQ 5000000 // CLK_SRC_ADC; largest division is by 4
#define CLK_ADC_FREQ 10000 // CLK_ADC; IADC_SCHEDx PRESCALE has 10 valid bits
// When changing GPIO port/pins above, make sure to change xBUSALLOC macro's
// accordingly.
#define IADC_INPUT_BUS CDBUSALLOC
#define IADC_INPUT_BUSALLOC GPIO_CDBUSALLOC_CDEVEN0_ADC0
// Stores latest ADC sample and converts to volts
static volatile IADC_Result_t sample;
static volatile double singleResult;
static uint16_t batt_valu =0;
uint8_t batt_level =100;
void read_adc(void);
/**************************************************************************//**
* @brief IADC Initializer
*****************************************************************************/
void initIADC (void)
{
// Declare init structs
IADC_Init_t init = IADC_INIT_DEFAULT;
IADC_AllConfigs_t initAllConfigs = IADC_ALLCONFIGS_DEFAULT;
IADC_InitSingle_t initSingle = IADC_INITSINGLE_DEFAULT;
IADC_SingleInput_t initSingleInput = IADC_SINGLEINPUT_DEFAULT;
// Enable IADC clock
CMU_ClockEnable(cmuClock_IADC0, true);
// Reset IADC to reset configuration in case it has been modified
IADC_reset(IADC0);
// Configure IADC clock source for use while in EM2
// CMU_ClockSelectSet(cmuClock_IADCCLK, cmuSelect_FSRCO);//2022-3-3
// Modify init structs and initialize
init.warmup = _IADC_CTRL_WARMUPMODE_KEEPINSTANDBY;
// Set the HFSCLK prescale value here
init.srcClkPrescale = IADC_calcSrcClkPrescale(IADC0, CLK_SRC_ADC_FREQ, 0);
// Configuration 0 is used by both scan and single conversions by default
// Use unbuffered AVDD as reference
initAllConfigs.configs[0].reference = iadcCfgReferenceInt1V2 ;
initAllConfigs.configs[0].vRef =1210;
// Divides CLK_SRC_ADC to set the CLK_ADC frequency for desired sample rate
initAllConfigs.configs[0].adcClkPrescale = IADC_calcAdcClkPrescale(IADC0,
CLK_ADC_FREQ,
0,
iadcCfgModeNormal,
init.srcClkPrescale);
// Single initialization
initSingle.dataValidLevel = _IADC_SINGLEFIFOCFG_DVL_VALID1;
// Set conversions to run continuously
initSingle.triggerAction = _IADC_TRIGGER_SCANTRIGACTION_ONCE;
// Set alignment to right justified with 12 bits for data field
initSingle.alignment = iadcAlignRight12;
// Configure Input sources for single ended conversioniadcPosInputDvdd;选择读取源//
initSingleInput.posInput = iadcPosInputAvdd;
initSingleInput.negInput = iadcNegInputGnd;
// Initialize IADC
IADC_init(IADC0, &init, &initAllConfigs);
// Initialize Scan
IADC_initSingle(IADC0, &initSingle, &initSingleInput);
// Allocate the analog bus for ADC0 inputs
GPIO->IADC_INPUT_BUS |= IADC_INPUT_BUSALLOC;
// Enable interrupts on data valid level
IADC_enableInt(IADC0,IADC_IEN_SINGLEFIFODVL );//
// Enable ADC interrupts
NVIC_ClearPendingIRQ(IADC_IRQn);
NVIC_EnableIRQ(IADC_IRQn);
}
2.2 ADC的disable
/****************************************************************
*iadc_uinit
*/
void iadc_uinit(void)
{
// Reset IADC to reset configuration in case it has been modified
IADC_reset(IADC0);
IADC_disableInt(IADC0,IADC_IEN_SINGLEFIFODVL);
// Enable IADC clock
CMU_ClockEnable(cmuClock_IADC0, false);
NVIC_DisableIRQ(IADC_IRQn);
}
2.3 ADC读取函数
void read_adc(void)
{
initIADC();
// Start single
IADC_command(IADC0, iadcCmdStartSingle);
}
2.4 ADC执行读取函数后,进行中断数据的处理
/**************************************************************************//**
* @brief ADC Handler
*****************************************************************************/
void IADC_IRQHandler(void)
{
float temp_batt=0.0;
// Read data from the FIFO, 12-bit result
sample = IADC_pullSingleFifoResult(IADC0);
// For single-ended the result range is 0 to +Vref, i.e., 16 bits for the
// conversion value.
singleResult = (sample.data*1.21)/0x0FFF;
uint16_t temp =singleResult*1000;
batt_valu=temp*4;
BLE_RTT("singleResult===%d.....valu=%d\r\n",sample.data,batt_valu);
IADC_clearInt(IADC0, IADC_IF_SINGLEFIFODVL);
iadc_uinit();
}
2.5 注意点
系列0和系列1的一些Silincon Labs的蓝牙、MCU芯片采取的是把内部LDO的参考源电压x2来提升测量范围,才能测量VDD,系列2的EFR32BG22系列蓝牙SOC简化了这个过程。EFR32BG22如果不采用外部的参考源,测量VDD时,会采用内部的1.21V作为参考源,VDD作为输入信号源。那么问题来了: VREF=1.21V,而VDD一般会大于1.22V,介于1.8V到3V之间,超过了量程,是否根本无法测量?
连接来源:访问地址
但是EFR32BG22有一个特点,当VDD作为ADC的输入源时,实际上有进行1/4分压,如下:
所以当输入源=VDD/4时,1.21V的VREF量程是足够的。
实现过程:
开始GPIO和IADC时钟
// Enable GPIO clock branch
CMU_ClockEnable(cmuClock_GPIO, true);
// Enable IADC clock
CMU_ClockEnable(cmuClock_IADC0, true);
参考源选择内部1.21V
initAllConfigs.configs[0].reference = iadcCfgReferenceInt1V2;
参考源选择,直接选择VDD,例如:这里VDD为电池供电3V,那么实际内部输入电压只有0.75V,小于参考源电压,可以测量出来VDD的电压:
initSingleInput.posInput = iadcPosInputDvdd;
initSingleInput.negInput = iadcNegInputGnd;
4. VDD电压计算
采集到的IDAC数据:sample = IADC_pullSingleFifoResult(IADC0).data;
计算输入电压:singleResult = (sample * 1.21) / 0xFFFF;
还原VDD实际电压:VDD = singleResult *4;