小熊派+E53_SF1扩展模块,如下所示:
打开board.h
文件,找到ADC的配置处,按照其提示使用:
首先,打开【RT-Thread Settings】,找到ADC设备驱动程序,将其选中,然后保存使之生效
通过查看原理图,可以知道,其连接到的引脚是ADC1的通道3,使用将board.h
的ADC1的注释打开
接下来使用CubeMx生成HAL_ADC_MspInit()函数,将ADC配置为如图所示:
将HAL_ADC_MspInit()
复制到board.c
里
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_ADC_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**ADC1 GPIO Configuration
PC2 ------> ADC1_IN3
*/
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG_ADC_CONTROL;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* USER CODE BEGIN ADC1_MspInit 1 */
/* USER CODE END ADC1_MspInit 1 */
}
}
然后打开stm32xxxx_hal_config.h
文件,将#define HAL_ADC_MODULE_ENABLED
的注释去掉:
然后要将board.c
中的SystemClock_Config()
函数也替换掉,因为要加入ADC外设的时钟初始化,
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 20;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1;
PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_HSE;
PeriphClkInit.PLLSAI1.PLLSAI1M = 1;
PeriphClkInit.PLLSAI1.PLLSAI1N = 8;
PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7;
PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2;
PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2;
PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_ADC1CLK;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
/** Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
Error_Handler();
}
}
编写main.c为如下所示:
#include
#include
#include
/* 获取LED引脚对应的编号 */
#define LED0_PIN GET_PIN(C, 13)
#define ADC_DEV_NAME "adc1" /* ADC 设备名称 */
#define ADC_DEV_CHANNEL 3 /* ADC 通道 */
#define REFER_VOLTAGE 330 /* 参考电压 3.3V,数据精度乘以100保留2位小数*/
#define CONVERT_BITS (1 << 12) /* 转换位数为12位 */
rt_adc_device_t adc_dev; /* ADC 设备句柄 */
rt_uint32_t value;
int main(void)
{
int count = 1, vol;
rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
/* 查找设备 */
adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);
/* 使能设备 */
rt_adc_enable(adc_dev, ADC_DEV_CHANNEL);
while (count++)
{
/* 读取采样值 */
value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
/* 转换为对应电压值 */
vol = value * REFER_VOLTAGE / CONVERT_BITS;
rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100);
/* set LED0 pin level to high or low */
rt_pin_write(LED0_PIN, count % 2);
rt_thread_mdelay(1000);
}
return RT_EOK;
}
编译,烧录启动,使用杜邦线将该引脚分别接到GND和3V3,可以看到,读取成功
然后我们接上E53_SF1扩展模块,同时修改主函数,将电压值转换为烟雾浓度:
/* 电压转换成烟雾浓度 */
RS = (3.3f - Vrl) / Vrl * RL;
ppm = 613.9f * pow(RS/R0, -2.074f);
sprintf(data_buf,"the voltage is :%f V, ppm is : %f \n", Vrl, ppm);
rt_kprintf(data_buf);
公式参考自https://blog.csdn.net/qq_41422043/article/details/89138213
运行结果如下
结合之前的内容:RT-Thread开发之路(4)— MQTT通信
我们将烟雾浓度数据通过邮箱发送到MQTT通信线程,然后发布主题消息到EMQ,我们先在app_mqtt.c
里定义一个邮箱结构体,
/* 定义一个烟雾浓度邮箱控制块结构体指针*/
rt_mailbox_t mq2_mailbox = RT_NULL;
然后在app_mqtt_init()创建,注意,要在创建线程之前创建邮箱
static int app_mqtt_init(void)
{
rt_err_t rt_err;
/* 使用动态创建方法创建一个邮箱 */
mq2_mailbox = rt_mb_create ("mq2 mailbox", 4, RT_IPC_FLAG_FIFO); /* 采用FIFO方式进行线程等待 */
/* 判断邮箱是否创建成功 */
if( mq2_mailbox != RT_NULL)
rt_kprintf("key mailbox create succeed. \n");
else
rt_kprintf("key mailbox create failure. \n");
/* 创建MQTT线程*/
app_mqtt_thread = rt_thread_create("app_mqtt thread",
app_mqtt_thread_entry, RT_NULL, 2048, 6, 10);
/* 如果获得线程控制块,启动这个线程 */
if (app_mqtt_thread != RT_NULL)
rt_err = rt_thread_startup(app_mqtt_thread);
else
rt_kprintf("app_mqtt_thread create failure !!! \n");
/* 判断线程是否启动成功 */
if( rt_err == RT_EOK)
rt_kprintf("app_mqtt_thread startup ok. \n");
else
rt_kprintf("app_mqtt_thread startup err. \n");
return rt_err;
}
然后获取到烟雾数据后发送到邮箱:
sprintf(msg_buf,"{\"ppm\":%.2f }", ppm);
rt_mb_send(mq2_mailbox, (rt_uint32_t)msg_buf);
在MQTT线程中将其发布到主题:
static void app_mqtt_thread_entry(void *parameter)
{
......
while(1)
{
/* 从邮箱中收取邮件 */
if (rt_mb_recv(mq2_mailbox, (rt_ubase_t *)&msg_buf, RT_WAITING_FOREVER) == RT_EOK)
{
paho_mqtt_publish(&client, QOS1, "BearPi_Pub", (char *)msg_buf);
}
rt_thread_mdelay(100);
}
}