One Shot Mode - Polling Mode
该示例通过使用 ADC 单次采样模式进行电压检测。
该示例通过轮询 ADC_INT_ONE_SHOT_DONE
中断的方式进行 ADC 采样。当检测到采样完成时,读取 ADC FIFO 内的采样数据 raw data 并进行电压转换计算。
该示例中可通过配置宏 ADC_MODE_DIVIDE_OR_BYPASS
选择 ADC 的电压采样范围。
环境需求
该示例支持以下开发套件:
Hardware Platforms |
Board Name |
---|---|
RTL8752H HDK |
RTL8752H EVB |
更多信息请参考 快速入门。
硬件连线
连接 P2_7 至外部电压输入。
配置选项
该示例可配置的宏如下:
ADC_MODE_DIVIDE_OR_BYPASS
:配置该宏可选择 ADC 的电压采样范围,可选择的值如下。ADC_DIVIDE_MODE
:在 Divide Mode 下,ADC 的采样电压值范围为 0~3.3V。ADC_BYPASS_MODE
:在 Bypass Mode 下,ADC 的采样电压值范围为 0~0.9V。
编译和下载
该示例的工程路径如下:
Project file: board\evb\io_sample\ADC\OneShotMode_Polling\mdk
Project file: board\evb\io_sample\ADC\OneShotMode_Polling\gcc
请按照以下步骤操作构建并运行该示例:
打开工程文件。
按照 快速入门 中 编译 APP Image 给出的步骤构建目标文件。
编译成功后,在路径
mdk\bin
或gcc\bin
下会生成 app binapp_MP_xxx.bin
文件。按下 reset 按键,开始运行。
测试验证
ADC 初始化配置:
若配置为
ADC_DIVIDE_MODE
,则会打印如下 log。[ADC] ADC sample mode is divide mode !
若配置为
ADC_BYPASS_MODE
,则会打印如下 log。[ADC] ADC sample mode is bypass mode !
ADC 采样结束后,会在 Debug Analyzer 工具内打印采集得到的 raw data 和转换后的电压值。
[io_adc] io_adc_voltage_calculate: ADC one shot mode sample data_0 = xxx, voltage_0 = xxxmV [io_adc] io_adc_voltage_calculate: ADC one shot mode sample data_1 = xxx, voltage_1 = xxxmV ...
代码介绍
该章节分为以下几个部分:
源码路径
工程路径:
sdk\board\evb\io_sample\ADC\OneShotMode_Polling
源码路径:
sdk\src\sample\io_sample\ADC\OneShotMode_Polling
该工程的工程文件代码结构如下:
└── Project: adc_oneshot_polling
└── secure_only_app
└── include
├── app_define.h
└── rom_uuid.h
├── cmsis includes CMSIS header files and startup files
├── overlay_mgr.c
├── system_rtl876x.c
└── startup_rtl876x.s
├── lib includes all binary symbol files that user application is built on
├── rtl8752h_sdk.lib
├── gap_utils.lib
├── ROM.lib
└── adc.lib
├── peripheral includes all peripheral drivers and module code used by the application
├── rtl876x_rcc.c
├── rtl876x_pinmux.c
├── rtl876x_nvic.c
└── rtl876x_adc.c
├── profile
└── app includes the ble_peripheral user application implementation
└── main.c
初始化
当 EVB 复位启动时,执行 main
函数,执行以下流程:
int main(void)
{
extern uint32_t random_seed_value;
srand(random_seed_value);
adc_demo();
while (1)
{
DBG_DIRECT("[ADC]Polling reads adc sample data !");
adc_sample_demo();
for (uint32_t i = 500000; i > 0; i--);
ADC_Cmd(ADC, ADC_ONE_SHOT_MODE, ENABLE);
}
}
在 adc_demo
中,包含了 ADC 校准、PAD/PINMUX 设置,ADC 外设的初始化等流程。
void adc_demo(void)
{
/* Initialize adc k value! */
bool adc_k_status;
adc_k_status = ADC_CalibrationInit();
if (false == adc_k_status)
{
APP_PRINT_ERROR0("[ADC]ADC_CalibrationInit fail!");
}
/* Configure pad and pinmux firstly! */
board_adc_init();
/* Initialize adc peripheral */
driver_adc_init();
/* Enable adc */
ADC_Cmd(ADC, ADC_ONE_SHOT_MODE, ENABLE);
}
board_adc_init
为 PAD/PINMUX 设置,包含如下流程:
配置 PAD:设置引脚、SW 模式、PowerOn、无内部上拉、输出失能。
driver_adc_init
为 ADC 外设的初始化,包含如下流程:
使能 RCC 时钟。
配置 ADC 的采样通道,配置所有通道为 P2_7 单端模式,设置 Bitmap 为 0xFFFF。
若开启 Bypass Mode,执行函数
ADC_BypassCmd()
开启对应引脚的 Bypass 模式。配置 ADC
ADC_INT_ONE_SHOT_DONE
中断。
void driver_adc_init(void)
{
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE);
ADC_InitTypeDef ADC_InitStruct;
ADC_StructInit(&ADC_InitStruct);
ADC_InitStruct.ADC_SampleTime = 255;
for (uint8_t i = 0; i < 16; i++)
{
#ifdef INTERNAL_VBAT_TEST
ADC_InitStruct.ADC_SchIndex[i] = INTERNAL_VBAT_MODE;
#else
ADC_InitStruct.ADC_SchIndex[i] = EXT_SINGLE_ENDED(ADC_SAMPLE_CHANNEL_7);
#endif
}
ADC_InitStruct.ADC_Bitmap = 0xFFFF;
ADC_InitStruct.ADC_PowerAlwaysOnEn = ADC_POWER_ALWAYS_ON_ENABLE;
ADC_Init(ADC, &ADC_InitStruct);
#if (ADC_MODE_DIVIDE_OR_BYPASS == ADC_BYPASS_MODE)
/* High bypass resistance mode config, please notice that the input voltage of
adc channel using high bypass mode should not be over 0.9V */
ADC_BypassCmd(ADC_SAMPLE_CHANNEL_6, ENABLE);
DBG_DIRECT("[ADC]ADC sample mode is bypass mode !");
#else
DBG_DIRECT("[ADC]ADC sample mode is divide mode !");
#endif
ADC_INTConfig(ADC, ADC_INT_ONE_SHOT_DONE, ENABLE);
}
功能实现
执行
ADC_Cmd()
,开启 ADC 采样。在主函数中,循环执行adc_sample_demo
,对 ADC 采样数据进行处理。在
adc_sample_demo
中,循环判断 ADC 单次转换完成中断状态。ADC 单次转换完成后,清除中断标志位。执行
ADC_ReadRawData()
,读取 ADC 采样数据。执行
ADC_GetVoltage()
,将采样数据转换为电压值。void adc_sample_demo(void) { uint16_t sample_data[16] = {0}; float sample_voltage[16] = {0}; ADC_ErrorStatus error_status = NO_ERROR; while (ADC_GetINTStatus(ADC, ADC_INT_ONE_SHOT_DONE) == RESET); ADC_ClearINTPendingBit(ADC, ADC_INT_ONE_SHOT_DONE); for (uint8_t i = 0; i < 16; i++) { sample_data[i] = ADC_ReadRawData(ADC, ADC_Schedule_Index_0 + i); } for (uint8_t i = 0; i < 16; i++) { #if (ADC_MODE_DIVIDE_OR_BYPASS == ADC_BYPASS_MODE) sample_voltage[i] = ADC_GetVoltage(BYPASS_SINGLE_MODE, (int32_t)sample_data[i], &error_status); #else sample_voltage[i] = ADC_GetVoltage(DIVIDE_SINGLE_MODE, (int32_t)sample_data[i], &error_status); #endif if (error_status < 0) { DBG_DIRECT("[ADC]adc_sample_demo: ADC parameter or efuse data error! i = %d, error_status = %d", i, error_status); } else { DBG_DIRECT("[ADC] adc_sample_demo: ADC one shot mode sample data_%d = %d, voltage_%d = %dmV ", i, sample_data[i], i, (uint32_t)sample_voltage[i]); } } }
常见问题
若拿到的 IC 未经过 FT 校验,ADC 则无法转换为正确的电压值。在 log 工具内会打印如下信息。
[ADC]ADC_CalibrationInit fail!
若 ADC 采样值不正确,则会打印错误状态信息。
ADC parameter or efuse data error! i = xxx, error_status = xxx