RT-Thread开发之路(5)— 通过ADC采集MQ2烟雾传感器数据

通过ADC采集MQ2烟雾传感器数据

一、硬件准备

小熊派+E53_SF1扩展模块,如下所示:
在这里插入图片描述

二、开启ADC

打开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();
  }
}

三、读取ADC的值

编写main.c为如下所示:

#include <rtthread.h>
#include <board.h>
#include <rtdevice.h>

/* 获取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);
    }
}

运行后,在EMQ上订阅主题,可以接收到:
在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值