关键词:ADC,RT-Thread ADC,STM32 ADC应用
说明:本笔记是记录如何开启 RT-Thread 框架的ADC功能,使用系统自带的ADC函数,并通过 STM32CubeMX 配置 STM32 ADC驱动 。
1. 打开board.h 文件,找到ADC 使用配置的流程,按流程操作。
* if you want to use adc you can use the following instructions.
* 如果您想使用adc,可以使用以下说明。
*
* STEP 1, open adc driver framework support in the RT-Thread Settings file ,
* 步骤1,在RT线程设置文件中打开adc驱动程序框架支持
*
* STEP 2, define macro related to the adc
* 第2步,定义与adc相关的宏
* such as #define BSP_USING_ADC1 例如: #define BSP_USING_ADC1
*
* STEP 3, copy your adc init function from stm32xxxx_hal_msp.c generated by stm32cubemx to the end of board.c file
* STEP 3, 将adc init函数从stm32cubemx生成的stm32xxxx_hal_msp.c复制到board.c文件的末尾
* such as void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
*
* STEP 4, modify your stm32xxxx_hal_config.h file to support adc peripherals. define macro related to the peripherals
* STEP 4,修改stm32xxxx_hal_config.h文件以支持adc外围设备。定义与外围设备相关的宏
* such as #define HAL_ADC_MODULE_ENABLED
*
*/
2.配置驱动
第1步:打开配置
* STEP 1, open adc driver framework support in the RT-Thread Settings file ,
* 步骤1,在RT线程设置文件中打开adc驱动程序框架支持
勾选如下 ADC 配置
第2步:如图打开 ADC 相关的宏,根据硬件实际使用的是 ADC1或者其他打开对应的ADC。
* STEP 2, define macro related to the adc
* 第2步,定义与adc相关的宏
* such as #define BSP_USING_ADC1 例如: #define BSP_USING_ADC1
第3步:设置ADC通道,配置ADC。(具体的生成过程参考专门的ADC驱动生成文件)
* STEP 3, copy your adc init function from stm32xxxx_hal_msp.c generated by stm32cubemx to the end of board.c file
* STEP 3, 将adc init函数从stm32cubemx生成的stm32xxxx_hal_msp.c复制到board.c文件的末尾
* such as void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
按流程配置后点击下图生成代码
找到生成的代码 adc.c
把如下代码 复制到board.c文件的末尾
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
ADC_HandleTypeDef hadc1;
/* ADC1 init function */
void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 2;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_7;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(adcHandle->Instance==ADC1)
{
/* USER CODE BEGIN ADC1_MspInit 0 */
/* USER CODE END ADC1_MspInit 0 */
/* ADC1 clock enable */
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**ADC1 GPIO Configuration
PA7 ------> ADC1_IN7
PB0 ------> ADC1_IN8
*/
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN ADC1_MspInit 1 */
/* USER CODE END ADC1_MspInit 1 */
}
}
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{
if(adcHandle->Instance==ADC1)
{
/* USER CODE BEGIN ADC1_MspDeInit 0 */
/* USER CODE END ADC1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_ADC1_CLK_DISABLE();
/**ADC1 GPIO Configuration
PA7 ------> ADC1_IN7
PB0 ------> ADC1_IN8
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_7);
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_0);
/* USER CODE BEGIN ADC1_MspDeInit 1 */
/* USER CODE END ADC1_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
第4步:打开ADC的宏
* STEP 4, modify your stm32xxxx_hal_config.h file to support adc peripherals. define macro related to the peripherals
* STEP 4,修改stm32xxxx_hal_config.h文件以支持adc外围设备。定义与外围设备相关的宏
* such as #define HAL_ADC_MODULE_ENABLED
第5步:移植ADC应用函数
官方ADC应用介绍:Docs » 设备和驱动 » ADC设备
https://www.rt-thread.org/document/site/programming-manual/device/adc/adc/
1. ADC 设备使用示例
ADC 设备的具体使用方式可以参考如下示例代码,示例代码的主要步骤如下:
1.首先根据 ADC 设备名称 “adc1” 查找设备获取设备句柄。
2.使能设备后读取 adc1 设备对应的通道 5 的采样值,然后根据分辨率为 12 位,参考电压为 3.3V 计算实际的电压值。
3.最后关闭 ADC 设备对应通道。
运行结果:打印实际读取到的转换的原始数据和经过计算后的实际电压值。
2.移植以下代码到工程里面测试
/*
* 程序清单: ADC 设备使用例程
* 例程导出了 adc_sample 命令到控制终端
* 命令调用格式:adc_sample
* 程序功能:通过 ADC 设备采样电压值并转换为数值。
* 示例代码参考电压为3.3V,转换位数为12位。
*/
#include <rtthread.h>
#include <rtdevice.h>
#define ADC_DEV_NAME "adc1" /* ADC 设备名称 */
#define ADC_DEV_CHANNEL 5 /* ADC 通道 */
#define REFER_VOLTAGE 330 /* 参考电压 3.3V,数据精度乘以100保留2位小数*/
#define CONVERT_BITS (1 << 12) /* 转换位数为12位 */
static int adc_vol_sample(int argc, char *argv[])
{
rt_adc_device_t adc_dev;
rt_uint32_t value, vol;
rt_err_t ret = RT_EOK;
/* 查找设备 */
adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);
if (adc_dev == RT_NULL)
{
rt_kprintf("adc sample run failed! can't find %s device!\n", ADC_DEV_NAME);
return RT_ERROR;
}
/* 使能设备 */
ret = rt_adc_enable(adc_dev, ADC_DEV_CHANNEL);
/* 读取采样值 */
value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
rt_kprintf("the value is :%d \n", value);
/* 转换为对应电压值 */
vol = value * REFER_VOLTAGE / CONVERT_BITS;
rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100);
/* 关闭通道 */
ret = rt_adc_disable(adc_dev, ADC_DEV_CHANNEL);
return ret;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(adc_vol_sample, adc voltage convert sample);
第6步:调试修改过的移植代码
/*
* 程序清单: ADC 设备使用例程
* 例程导出了 adc_sample 命令到控制终端
* 命令调用格式:adc_sample
* 程序功能:通过 ADC 设备采样电压值并转换为数值。
* 示例代码参考电压为3.3V,转换位数为12位。
*/
#include "user_cfg.h"
#define ADC_DEV_NAME "adc1" /* ADC 设备名称 */
#define ADC_DEV_CHANNEL 7 /* ADC 通道 */
#define REFER_VOLTAGE 330 /* 参考电压 3.3V,数据精度乘以100保留2位小数*/
#define CONVERT_BITS (1 << 12) /* 转换位数为12位 */
/* 线程 AIR_ADC_Thread 的入口函数 */
static void AIR_ADC_entry(void *param)
{
rt_adc_device_t adc_dev;
rt_uint32_t value, vol;
rt_err_t ret = RT_EOK;
while(1)
{
/* 查找设备 */
adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);
if (adc_dev == RT_NULL)
{
rt_kprintf("adc sample run failed! can't find %s device!\n", ADC_DEV_NAME);
//return RT_ERROR;
}
/* 使能设备 */
ret = rt_adc_enable(adc_dev, ADC_DEV_CHANNEL);
/* 读取采样值 */
value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
rt_kprintf("the value is :%d \n", value);
/* 转换为对应电压值 */
vol = value * REFER_VOLTAGE / CONVERT_BITS;
rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100);
/* 关闭通道 */
ret = rt_adc_disable(adc_dev, ADC_DEV_CHANNEL);
rt_thread_mdelay(1000);
rt_thread_yield();/* 放弃剩余时间片,进行一次线程切换 */
}
}
/* 线程创建 线程 函数 */
void AIR_ADC_Thread(void)
{
rt_thread_t tid1;//创建线程控制块指针来接收线程创建函数的返回值,目的是通过返回值判断线程是否创建ok
/* 创建线程 ,名称是 AIR_ZY_CON_Thread,入口是 AIR_ZY_CON_entry*/
tid1 = rt_thread_create("AIR_ADC_Thread",
AIR_ADC_entry, RT_NULL,
500,//设置内存堆栈大小
10, 50);//设置优先级,时间片参数,时间片是在有多个相同优先级线程时,这个线程每次被执行多少个时间片
/* 如果获得线程控制块,启动这个线程 */
if (tid1 != RT_NULL)
rt_thread_startup(tid1);
}
INIT_APP_EXPORT(AIR_ADC_Thread);