目录

一、前言

环境监测传感器是工业与民用场景中常用的传感器类型,本次基于 STM32F030 开发板设计环境监测传感器程序,核心实现两类功能:一是 DO 外设(蜂鸣器、LED)的远程控制,二是 AI 外设(光敏电阻、可调电阻)的 ADC 电压采集。程序沿用 PC→STM32H5→STM32F030 的通信架构,通过 Modbus 协议与 PC 端 Modbus Poll 软件交互,完成环境光强、电阻电压的采集及声光外设的精准控制。

二、硬件引脚与 CubeMX 配置

1. 硬件引脚映射

环境监测模块的外设功能、引脚、工作逻辑及寄存器类别对应如下,需根据该表在 CubeMX 中完成基础 GPIO/ADC 配置:

模块 功能 引脚 工作逻辑 寄存器类别
环境监测模块 BEEP1 PB15 高电平触发响铃 DO
BEEP2 PB14 高电平触发响铃 DO
LED1 PB11 低电平点亮 DO
LED2 PB12 低电平点亮 DO
LED3 PB13 低电平点亮 DO
OPTO_ADC PA1 电压值与光强成反比 AI
RES_ADC PA2 电压值与可调电阻成反比 AI

2. CubeMX 配置注意事项

除基础的 GPIO(DO 外设设为输出)、ADC(AI 外设设为模拟输入)配置外,需重点注意:配置 ADC 时必须启用Discontinuous Conversion Mode(离散转换模式),保障多通道 ADC 采集的稳定性。

三、点表设计:通信规则标准化

为明确 PC 与 F030 环境监测传感器的通信规则,设计如下点表,清晰定义设备地址、寄存器地址、类别及功能:

设备地址 寄存器地址 寄存器类别 用途 描述
02H 0000H DO 控制蜂鸣器 1 1 - 响
02H 0001H DO 控制蜂鸣器 2 1 - 响
02H 0002H DO 控制 LED1 1 - 亮
02H 0003H DO 控制 LED2 1 - 亮
02H 0004H DO 控制 LED3 1 - 亮
02H 0000H AI 读取光敏电阻电压 0xfff 对应 3.3V(12 位精度)
02H 0001H AI 读取可调电阻电压 0xfff 对应 3.3V(12 位精度)

补充:AI 寄存器为 12 位 ADC 采集值,最大值 0xfff 对应 3.3V 参考电压,可通过电压值换算光敏电阻的光强、可调电阻的阻值。

四、F030 程序实现:ADC 校准 + 寄存器联动

环境监测传感器使用 ADC 采集模拟电压,需先完成 ADC 校准保障采集精度;程序通过宏定义区分传感器类型,实现 DO 外设控制与 AI 电压采集的核心逻辑,代码及关键注释如下(未修改原有代码逻辑):

// 启用环境监测传感器功能(宏定义便于切换不同传感器逻辑)
#define USE_ENV_MONITOR_SENSOR 1

#ifdef USE_ENV_MONITOR_SENSOR
// 声明ADC句柄(由CubeMX自动生成)
extern ADC_HandleTypeDef hadc;

// 从机地址(对应点表中的02H)
#define SLAVE_ADDR 2
// DO寄存器(线圈状态)数量:5个(2个蜂鸣器+3个LED)
#define NB_BITS             5
// DI寄存器(离散输入状态)数量:0(本传感器未使用)
#define NB_INPUT_BITS       0 
// 保持寄存器数量:0(本传感器未使用)
#define NB_REGISTERS        0
// AI寄存器(输入寄存器)数量:2个(光敏电阻+可调电阻)
#define NB_INPUT_REGISTERS  2  

#endif

void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
    // 存储GPIO读取状态(本传感器未使用,保留兼容)
    GPIO_PinState val;
	// Modbus请求报文缓冲区
	uint8_t *query;
	// Modbus RTU上下文
	modbus_t *ctx;
	// 函数返回值,判断操作是否成功
	int rc;
	// Modbus寄存器映射结构体
	modbus_mapping_t *mb_mapping;

#ifdef USE_ENV_MONITOR_SENSOR
    // ADC校准:保障12位电压采集精度(环境监测传感器核心步骤)
    HAL_ADCEx_Calibration_Start(&hadc);
#endif

	// 创建串口1的Modbus RTU上下文:波特率115200、无校验、8数据位、1停止位
	ctx = modbus_new_st_rtu("uart1", 115200, 'N', 8, 1);
	// 设置从机地址(匹配点表中的02H)
	modbus_set_slave(ctx, SLAVE_ADDR);
	// 分配请求报文缓冲区(FreeRTOS内存接口)
	query = pvPortMalloc(MODBUS_RTU_MAX_ADU_LENGTH);

	// 初始化寄存器映射:基于宏定义的寄存器数量配置
	mb_mapping = modbus_mapping_new_start_address(0,
												  NB_BITS,        // DO寄存器数量
												  0,
												  NB_INPUT_BITS,  // DI寄存器数量
												  0,
												  NB_REGISTERS,   // 保持寄存器数量
												  0,
												  NB_INPUT_REGISTERS); // AI寄存器数量
	
	// 建立Modbus RTU连接
	rc = modbus_connect(ctx);
	if (rc == -1) {
		//fprintf(stderr, "Unable to connect %s\n", modbus_strerror(errno));
		modbus_free(ctx);
		vTaskDelete(NULL);; // 连接失败则删除任务
	}

	// 无限循环接收并响应PC端Modbus请求
	for (;;) {
		do {
			// 接收PC端请求报文,过滤无效请求(返回0的查询)
			rc = modbus_receive(ctx, query);
			/* Filtered queries return 0 */
		} while (rc == 0);
 
		/* The connection is not closed on errors which require on reply such as
		   bad CRC in RTU. */
		// 非CRC错误则继续循环,不退出
		if (rc == -1 && errno != EMBBADCRC) {
			/* Quit */
			continue;
		}

        /* update values of registers
         * a. read gpio
         * b. update reg
         */
// 开关量传感器逻辑(保留兼容,本传感器未启用)
#ifdef USE_SWITCH_SENSOR
        /* key1 */
        val = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3);
        if (val == GPIO_PIN_RESET)
        {
            mb_mapping->tab_input_bits[0] = 1;
        }
        else
        {
            mb_mapping->tab_input_bits[0] = 0;
        }

        /* key2 */
        val = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4);
        if (val == GPIO_PIN_RESET)
        {
            mb_mapping->tab_input_bits[1] = 1;
        }
        else
        {
            mb_mapping->tab_input_bits[1] = 0;
        }

        /* key3 */
        val = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5);
        if (val == GPIO_PIN_RESET)
        {
            mb_mapping->tab_input_bits[2] = 1;
        }
        else
        {
            mb_mapping->tab_input_bits[2] = 0;
        }

#endif

// 环境监测传感器:读取ADC值更新AI寄存器
#ifdef USE_ENV_MONITOR_SENSOR
        /* READ ADC to update tab_input_registers */
        // 循环采集2路ADC(光敏电阻、可调电阻),更新AI寄存器
        for (int i = 0; i < 2; i++)
        {
            // 启动ADC采集
            HAL_ADC_Start(&hadc);
            // 等待采集完成(超时100ms)
             if (HAL_OK == HAL_ADC_PollForConversion(&hadc, 100))
             {
                // 将ADC采集值写入AI寄存器
                mb_mapping->tab_input_registers[i] = HAL_ADC_GetValue(&hadc);
             }
        }
#endif

		// 解析请求并回复PC端(包含更新后的AI寄存器数据)
		rc = modbus_reply(ctx, query, rc, mb_mapping);
		if (rc == -1) {
			//break;
		}

// 开关量传感器DO控制逻辑(保留兼容,本传感器未启用)
#ifdef USE_SWITCH_SENSOR
        /* switch1 */
		if (mb_mapping->tab_bits[0])
            HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET); //switch1
		else
			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET); //switch1

        /* switch2 */
		if (mb_mapping->tab_bits[1])
            HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET); //switch2
		else
			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET); //switch2

		if (mb_mapping->tab_bits[2])
            HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET); //LED1
		else
			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET); //LED1

		if (mb_mapping->tab_bits[3])
            HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); //LED2
		else
			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); //LED2

		if (mb_mapping->tab_bits[4])
            HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET); //LED3
		else
			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET); //LED3
#endif

// 环境监测传感器:根据DO寄存器值控制外设
#ifdef USE_ENV_MONITOR_SENSOR
            /* beep1 */
            // DO寄存器0号控制蜂鸣器1(PB15):1-响(高电平)、0-停(低电平)
            if (mb_mapping->tab_bits[0])
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_SET); //beep1
            else
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_RESET); //beep1
    
            /* beep2 */
            // DO寄存器1号控制蜂鸣器2(PB14):1-响(高电平)、0-停(低电平)
            if (mb_mapping->tab_bits[1])
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_SET); //beep2
            else
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_RESET); //beep2
    
            // DO寄存器2号控制LED1(PB11):1-亮(低电平)、0-灭(高电平)
            if (mb_mapping->tab_bits[2])
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET); //LED1
            else
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET); //LED1
    
            // DO寄存器3号控制LED2(PB12):1-亮(低电平)、0-灭(高电平)
            if (mb_mapping->tab_bits[3])
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); //LED2
            else
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); //LED2
    
            // DO寄存器4号控制LED3(PB13):1-亮(低电平)、0-灭(高电平)
            if (mb_mapping->tab_bits[4])
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET); //LED3
            else
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET); //LED3
#endif

	}

	// 释放资源(实际循环不会执行到此处)
	modbus_mapping_free(mb_mapping);
	vPortFree(query);
	modbus_close(ctx);
	modbus_free(ctx);

	vTaskDelete(NULL);
    
  /* USER CODE END StartDefaultTask */
}

五、功能验证:Modbus Poll 测试

将编译后的程序烧录至 STM32F030 开发板,保持 STM32H5 转接板的 RS485-USB 透传功能开启,通过 PC 端 Modbus Poll 软件按照点表规则测试:

1. DO 寄存器控制硬件

改写 DO 寄存器值可精准控制蜂鸣器、LED 的启停 / 亮灭,例如向寄存器地址 3 发送 On 指令,LED2 成功点亮,测试效果如下:

请添加图片描述

2. AI 寄存器采集电压

读取 AI 寄存器可获取光敏电阻、可调电阻的 ADC 电压值,下图显示的采集结果表明此时环境光强较弱:

请添加图片描述

六、总结

  1. 环境监测传感器需配置 ADC 离散转换模式,并在程序中完成 ADC 校准,保障 12 位电压采集精度;
  2. 程序通过宏定义区分传感器类型,兼顾兼容性的同时实现 DO 外设控制与 AI 电压采集;
  3. 点表明确了设备地址、寄存器映射规则,是 PC 与传感器稳定通信的核心依据。

七、结尾

本次完成了 STM32F030 环境监测传感器的全流程程序设计,实现了模拟量(ADC 电压)采集与数字量(DO 外设)控制的 Modbus 通信闭环,这套设计思路可直接适配各类包含模拟采集、数字控制的工业传感器开发。掌握环境监测传感器的开发逻辑,是进阶实现温湿度、气体浓度等复杂环境传感器的关键基础。感谢各位的阅读,持续关注本系列笔记,一起探索更多工业级 Modbus 传感器的开发与优化技巧!加粗样式

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐