1. 前言
本教程基于【N32WB03x SDK使用指南】的开发环境,结合官方教程开展的N32WB03xSTB开发板ADC实验,主要由读取两路ADC并打印实验和读取板载芯片温度实验两部分组成。
2. ADC 功能描述
2.1 输入通道和输入电压范围
ADC 是一种高速逐次逼近型模拟数字转换器。有多达 8 个通道,5 个外部单端,1 个差分 MIC 和 2 个内部通道。内部通道包括 VCC 检测通道和温度传感器通道。各通道的 A/D 转换可以单次、连续模式执行。配置 ADC_CTRL.ADC_CH_SEL 用于 ADC 输入通道选择。
000(默认)选择差分 MIC 通路,对应 PB11/PB13,
001~010 用于片外预分压输入,对应
PB9/PB10,无阻性负载,检测范围 0.125~0.85V,
011~101 用于直接检测,对应 PB6~PB8,输入阻抗360KΩ,检测范围 0.5~3.5V,
110 用于 VCC 检测,
111 用于片内温度传感器电压检测。
2.2 ADC 开关控制
通过设置 ADC_CTRL 寄存器的 ADC_EN 位可启动 ADC。当第一次设置 ADC_EN 位时,ADC 在开始精确转换前需要一个稳定时间 tSTAB 64 cycle。之后每个 Cycle 进行一次转换。在单次模式下,转换完成后,硬件自动关闭 ADC_EN 位。如使能中断,可产生转换结束中断。用户可以通过查询 ADC_SR 里面的 ADC_DONE_F 确认转换是否完成。在连续模式下,通过清除 ADC_EN 位可以停止转换。输入通道切换前需要先关闭 ADC_EN 位。
2.3 转换模式
2.3.1 单次转换模式
每个转换有两个阶段:采样阶段和转换阶段。
单次转换模式下,ADC 只执行一次转换。设置 ADC_CTRL.ADC_CH_SEL 选择输入通道后,可通过设置ADC_CTRL 寄存器的 ADC_EN 位启动。一旦选择通道的转换完成:
转换数据被储存在 16 位 ADC_DAT 寄存器中
ADC_DONE_F(转换结束)标志被设置
如果设置了ADC_DONE_IE,则产生中断。
转换本身很快,只需要一个 adcclk 的时钟周期。但单次模式下,ADCEN 或 ADCSEL 修改后,输入通道的切换电路需要 64 个adcclk 稳定时间。
2.3.2 连续转换模式
将 ADC_CTRL.ADC_MODE 置为“1”可以在连续模式下使用 ADC,在连续转换模式中,当前面 ADC 转
换一结束马上就启动另一次转换。设置 ADC_CTRL.ADC_CH_SEL 选择输入通道后,可通过设置ADC_CTRL 寄存器的 ADC_EN 位来触发第一次转换,但之后,将每个 adcclk 周期自动生成新的转换数据。支持过采样率设置,配置值 ADC_OVR_SAMP_CNT. OS_CNT_LD_CNT 需要>=2,OS_CNT_LD_CNT+1个数据采样一个数据。
每个转换后:
转换数据被储存在 16 位的 ADC_DAT 寄存器中
使能 DMA 模式,每次转换后会产生 DMA 请求
2.4 模拟看门狗
如果被 ADC 转换的模拟 PB10 电压低于低阈值或高于高阈值,AWDG 模拟看门狗状态位被设置。阈值位于ADC_ WDHIGH 和 ADC_WDLOW 寄存器的最低 10 个有效位中。通过设置 ADC_CTRL 寄存器的 AWD_IE位以允许产生相应中断。
3. ADC 实验
3.1 两路ADC并打印实验
项目文件地址:N32WB03x_SDK V1.2.0\N32WB03x_SDK V1.2.0\projects\n32wb03x_EVAL\peripheral\ADC\ADC_SingleRead\MDK-ARM
3.1.1 打开工程
keil5 打开后查看相关程序函数
项目简介在readme.txt
1、功能说明 此例程提供了ADC单次转换的实现。 2、使用环境 软件开发环境:KEIL MDK-ARM V5.26.2.0 硬件环境: 1、基于N32WB031_STB开发板 2、MCU:N32WB031 3、使用说明 1、系统时钟:64MHz 2、ADC通道:ADC_CTRL_CH_1(PB10)、ADC_CTRL_CH_3(PB8) 日志打印:从模式 DEMO 板 PB6(TX),波特率:115200 测试步骤与现象: a,编译下载代码复位运行 b,从串口看打印信息,验证结果两个通道ADC转换的电压 4、注意事项 开发板的J15 短接右边,J16 短接左边,选择 IO 连接到排针。
3.1.2 配置工程
主程序main.c
/***************************************************************************** * Copyright (c) 2019, Nations Technologies Inc. * * All rights reserved. * **************************************************************************** * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * * Nations' name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /** * @file main.c * @author Nations Firmware Team * @version v1.0.2 * * @copyright Copyright (c) 2019, Nations Technologies Inc. All rights reserved. */ #include "main.h" #include "log.h" void RCC_Configuration(void); void GPIO_Configuration(void); void ADC_Configuration(void); uint16_t ADCConvertedValue[2]; uint32_t voltage[2] = {0}; /** * @brief Main program */ int main(void) { log_init(); log_info("\nthis is adc single read Demo.\n"); log_info("Please make sure J15 and J16 connect the IO to pin on board!\n"); /* System Clocks Configuration */ RCC_Configuration(); /* Configure the GPIO ports */ GPIO_Configuration(); ADC_EnableBypassFilter(ADC, ENABLE); while (1) { ADC_ConfigChannel(ADC, ADC_CTRL_CH_3); ADC_Enable(ADC, ENABLE); while(ADC_GetFlagStatus(ADC,ADC_FLAG_DONE) == RESET); ADC_ClearFlag(ADC,ADC_FLAG_DONE); ADCConvertedValue[1] = ADC_GetDat(ADC); voltage[1] = ADC_ConverValueToVoltage(ADCConvertedValue[1], ADC_CTRL_CH_3); log_info("ADC CH3 value: %4d | ADC CH3 vol_mV: %4d .\r\n",ADCConvertedValue[1],voltage[1]); ADC_ConfigChannel(ADC, ADC_CTRL_CH_1); ADC_Enable(ADC, ENABLE); while(ADC_GetFlagStatus(ADC,ADC_FLAG_DONE) == RESET); ADC_ClearFlag(ADC,ADC_FLAG_DONE); ADCConvertedValue[0] = ADC_GetDat(ADC); voltage[0] = ADC_ConverValueToVoltage(ADCConvertedValue[0], ADC_CTRL_CH_1); log_info("ADC CH1 value: %4d | ADC CH1 vol_mV: %4d .\r\n\r\n",ADCConvertedValue[0],voltage[0]); Delay_ms(1000); } } /** * @brief Configures the different system clocks. */ void RCC_Configuration(void) { /* Enable peripheral clocks */ /* Enable GPIOB clocks */ RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB, ENABLE); /* Enable ADC clocks */ RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC, ENABLE); RCC_ConfigAdcClk(RCC_ADCCLK_SRC_AUDIOPLL); /* enable ADC 4M clock */ RCC_Enable_ADC_CLK_SRC_AUDIOPLL(ENABLE); } /** * @brief Configures the different GPIO ports. */ void GPIO_Configuration(void) { GPIO_InitType GPIO_InitStructure; GPIO_InitStruct(&GPIO_InitStructure); /* Configure PB.10 (ADC Channel1) PB.8 (ADC Channel3) as analog input --------*/ GPIO_InitStructure.Pin = GPIO_PIN_10|GPIO_PIN_8; GPIO_InitStructure.GPIO_Mode = GPIO_MODE_ANALOG; GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure); } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file pointer to the source file name * @param line assert_param error line source number */ void assert_failed(const uint8_t* expr, const uint8_t* file, uint32_t line) { /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ while (1) { } } #endif /** * @} */ /** * @} */ /*************** (C) COPYRIGHT Nations Technologies Inc *****END OF FILE***************/
此部分不修改
3.1.3 编译下载
N32WB03xSTB开发板自带下载器,官方已经配置好了,直接连接Type-C编译下载
3.1.4 调试验证
打开串口调试助手,修改相关配置。连接开发板,打印效果如下
此时可以用GND或者3.3V电源用杜邦线短接ADC_CTRL_CH_1(PB10)、ADC_CTRL_CH_3(PB8)
,也会有相关大小变化
[11:38:01.339]收←◆ADC CH3 value: 64 | ADC CH3 vol_mV: 77 . ADC CH1 value: 502 | ADC CH1 vol_mV: 496 . [11:38:02.373]收←◆ADC CH3 value: 65 | ADC CH3 vol_mV: 81 . ADC CH1 value: 527 | ADC CH1 vol_mV: 523 . [11:38:03.408]收←◆ADC CH3 value: 64 | ADC CH3 vol_mV: 77 . ADC CH1 value: 880 | ADC CH1 vol_mV: 908 . [11:38:04.442]收←◆ADC CH3 value: 66 | ADC CH3 vol_mV: 86 . ADC CH1 value: 159 | ADC CH1 vol_mV: 123 . [11:38:05.477]收←◆ADC CH3 value: 65 | ADC CH3 vol_mV: 81 . ADC CH1 value: 750 | ADC CH1 vol_mV: 767 . [11:38:06.511]收←◆ADC CH3 value: 59 | ADC CH3 vol_mV: 55 . ADC CH1 value: 789 | ADC CH1 vol_mV: 809 .
3.2 读取板载芯片温度实验
项目文件地址:N32WB03x_SDK V1.2.0\projects\n32wb03x_EVAL\peripheral\ADC\ADC_Temperature\MDK-ARM
3.2.1 打开工程
keil5 打开后查看相关程序函数
项目简介在readme.txt
1、功能说明 此例程提供了ADC温度传感通道转换的实现。 2、使用环境 软件开发环境:KEIL MDK-ARM V5.26.2.0 硬件环境: 1、基于N32WB031_STB开发板 2、MCU:N32WB031 3、使用说明 1、系统时钟:64MHz 2、ADC通道:ADC_CTRL_CH_7(TS) 日志打印:从模式 DEMO 板 PB6(TX),波特率:115200 测试步骤与现象: a,编译下载代码复位运行 b,从串口看打印信息,验证温度传感通道ADC转换的结果 4、注意事项 无
3.2.2 配置工程
主程序main.c
/***************************************************************************** * Copyright (c) 2019, Nations Technologies Inc. * * All rights reserved. * **************************************************************************** * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * * Nations' name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /** * @file main.c * @author Nations Firmware Team * @version v1.0.2 * * @copyright Copyright (c) 2019, Nations Technologies Inc. All rights reserved. */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "log.h" /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ #define ADC_BUF_SIZE (10) /* Private constants ---------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ uint16_t ADCConvertedBuffer[ADC_BUF_SIZE]; uint16_t ADCConvertedValue; uint32_t Voltage_mA; float Temperature; /* Private function prototypes -----------------------------------------------*/ void RCC_Configuration(void); void GPIO_Configuration(void); void ADC_Configuration(void); /* Private functions ---------------------------------------------------------*/ /** * @brief Main program */ int main(void) { DMA_InitType DMA_InitStructure; uint32_t adc_sum,i; log_init(); log_info("\nthis is adc temperature sensor read demo.\n"); /* System Clocks Configuration */ RCC_Configuration(); /* Configure the GPIO ports */ GPIO_Configuration(); /* DMA channel1 configuration ----------------------------------------------*/ DMA_DeInit(DMA_CH1); DMA_InitStructure.PeriphAddr = (uint32_t)&ADC->DAT; DMA_InitStructure.MemAddr = (uint32_t)ADCConvertedBuffer; DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC; DMA_InitStructure.BufSize = ADC_BUF_SIZE; DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE; DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_ENABLE; DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD; DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.CircularMode = DMA_MODE_CIRCULAR; DMA_InitStructure.Priority = DMA_PRIORITY_HIGH; DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE; DMA_Init(DMA_CH1, &DMA_InitStructure); DMA_RequestRemap(DMA_REMAP_ADC, DMA, DMA_CH1, ENABLE); /* Enable DMA channel 1 */ DMA_EnableChannel(DMA_CH1, ENABLE); ADC_SetOverSampleCounter(ADC,3); ADC_EnableBypassFilter(ADC, ENABLE); ADC_ConfigChannel(ADC, ADC_CTRL_CH_7); ADC_ConfigContinuousMode(ADC, ENABLE); ADC_EnableDMA(ADC, ENABLE); ADC_EnableTS(ADC, ENABLE); ADC_Enable(ADC, ENABLE); while (1) { /* Transfer complete */ while (!DMA_GetFlagStatus(DMA_FLAG_TC1, DMA)); adc_sum = 0; for(i=0;i<ADC_BUF_SIZE;i++) { adc_sum += ADCConvertedBuffer[i]; } ADCConvertedValue = adc_sum/ADC_BUF_SIZE; Temperature = ADC_ConverValueToTemperature(ADCConvertedValue); log_info("ADC temperature sensor: %.2f C\r\n",Temperature); Delay_ms(1000); } } /** * @brief Configures the different system clocks. */ void RCC_Configuration(void) { /* Enable peripheral clocks */ RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA, ENABLE); /* Enable GPIOB clocks */ RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB, ENABLE); /* Enable ADC clocks */ RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC, ENABLE); RCC_ConfigAdcClk(RCC_ADCCLK_SRC_AUDIOPLL); /* enable ADC 4M clock */ RCC_Enable_ADC_CLK_SRC_AUDIOPLL(ENABLE); } /** * @brief Configures the different GPIO ports. */ void GPIO_Configuration(void) { GPIO_InitType GPIO_InitStructure; GPIO_InitStruct(&GPIO_InitStructure); /* Configure PB.10 (ADC Channel1) PB.7 (ADC Channel4) as analog input --------*/ GPIO_InitStructure.Pin = GPIO_PIN_10|GPIO_PIN_7; GPIO_InitStructure.GPIO_Mode = GPIO_MODE_ANALOG; GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure); } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file pointer to the source file name * @param line assert_param error line source number */ void assert_failed(const uint8_t* expr, const uint8_t* file, uint32_t line) { /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ while (1) { } } #endif /** * @} */ /** * @} */ /*************** (C) COPYRIGHT Nations Technologies Inc *****END OF FILE***************/
此部分不修改
3.2.3 编译下载
N32WB03xSTB开发板自带下载器,官方已经配置好了,直接连接Type-C编译下载
3.2.4 调试验证
打开串口调试助手,修改相关配置。连接开发板,打印效果如下
此时可以用手指捂住芯片,温度会升高
,也会有相关大小变化
[11:43:40.101]收←◆ this is adc temperature sensor read demo. ADC temperature sensor: 25.00 C [11:43:41.134]收←◆ADC temperature sensor: 25.47 C [11:43:42.161]收←◆ADC temperature sensor: 24.53 C [11:43:43.189]收←◆ADC temperature sensor: 24.07 C [11:43:44.218]收←◆ADC temperature sensor: 25.47 C [11:43:45.244]收←◆ADC temperature sensor: 25.93 C [11:43:46.271]收←◆ADC temperature sensor: 26.87 C [11:43:47.299]收←◆ADC temperature sensor: 26.40 C [11:43:48.326]收←◆ADC temperature sensor: 26.40 C [11:43:49.352]收←◆ADC temperature sensor: 26.87 C
实验就结束啦!
4. 小结
🥳🥳🥳通过对这篇文章我们掌握了读取两路ADC并打印实验和读取板载芯片温度实验,接下来会有许多有趣的实验,进而丰富我们的生活。🛹🛹🛹从而实现对外部世界进行感知,充分认识这个有机与无机的环境,🥳🥳🥳科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣