【Linux 物联网网关主控系统-感知层部分(三)】

Linux 物联网网关主控系统-感知层部分(三)

一、核心设备程序(3 类)

1. 协调器程序:coordinator.c

核心作用:ZigBee 网络的创建者、数据汇聚中心、控制指令下发端,是整个网络的核心节点。

建网:初始化网络并分配唯一 PAN ID,开放入网权限,允许路由器 / 终端加入;

数据接收:接收终端节点上传的温湿度、光照、气体、人体红外等环境数据,通过串口输出(上位机可读取);

指令下发:通过串口接收外部控制指令,解析后无线下发给指定终端节点,控制继电器、蜂鸣器、LED;

基础初始化:完成 UART、LCD、ZigBee 端点注册、OSAL 任务初始化,注册按键、网络状态等事件回调。

coordinator.c新增代码

新增 串口初始化,绑定接收回调函数 rxCB

新增 LCD 初始化与清屏函数

改写 rxCB():发送(电脑 → 协调器 → 终端)

改写 GenericApp_MessageMSGCB(): 接收(终端 → 协调器 → 电脑)

1.rxCB()

电脑发指令 → 协调器收到 → 转发给 ZigBee 终端

c 复制代码
// 串口接收回调函数:电脑发指令 → 协调器转发给终端节点
static void rxCB(uint8 port,uint8 event)
{
	uint8 uartbuf[4] = {0};  // LCD显示缓存
	uint8 cmd;               // 串口接收的指令
	
	HalUARTRead(0,&cmd,1);   // 从串口读取1字节指令
        
    // 判断是否为合法节点号(0~3号节点)
    if((cmd & STO_MASK) == (0 << 6)
	   ||(cmd & STO_MASK) == (1 << 6)
       ||(cmd & STO_MASK) == (2 << 6)
       ||(cmd & STO_MASK) == (3 << 6)
       ) 
    {
		sprintf(uartbuf,"cmd:%x",cmd);    // 格式化指令
		HalLcdWriteString(uartbuf,HAL_LCD_LINE_4);  // LCD第四行显示

		// ZigBee无线发送指令到终端设备
		if(AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
		               GENERICAPP_CLUSTERID,
		               1,
		               &cmd,
		               &GenericApp_TransID,
		               AF_DISCV_ROUTE, AF_DEFAULT_RADIUS )==afStatus_SUCCESS)
		{
		}
    }
}

2.clear_lcd()

LCD 清屏

c 复制代码
// LCD清屏函数
void clear_lcd(void)
{
	BACK_COLOR=MAGENTA;        // 背景色
	POINT_COLOR=YELLOW;        // 字体色
	LCD_Clear(BACK_COLOR);     // 清屏
	return;
}

LCD

c 复制代码
HalLcdInit();//LCD初始化
clear_lcd();//清屏

3.GenericApp_Init初始化部分也新增

主要是串口初始化

c 复制代码
halUARTCfg_t uartConfig; 
  uartConfig.configured = TRUE; 
  uartConfig.baudRate = HAL_UART_BR_115200; 
  uartConfig.flowControl = FALSE; 
  uartConfig.flowControlThreshold = 1; 
  uartConfig.rx.maxBufSize = 255; 
  uartConfig.tx.maxBufSize = 255; 
  uartConfig.idleTimeout = 1; 
  uartConfig.intEnable = TRUE; 
  uartConfig.callBackFunc = rxCB; 
  HalUARTOpen (HAL_UART_PORT_0, &uartConfig);

4.GenericApp_MessageMSGCB

协调器收到终端发来的传感器数据 → 直接通过串口上传给电脑显示

c 复制代码
// 接收ZigBee终端发来的数据的回调函数
static void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
	// 判断收到的是哪个簇ID(对应不同终端/传感器)
	switch ( pkt->clusterId )
	{
	 	case GENERICAPP_CLUSTERID1:   // 终端1数据
	 	case GENERICAPP_CLUSTERID2:   // 终端2数据
	 	case GENERICAPP_CLUSTERID3:   // 终端3数据
	 	case GENERICAPP_CLUSTERID4:   // 终端4数据			
			HalUARTWrite(0, pkt->cmd.Data,24);	// 把数据通过串口发给电脑
			break;
	}
}

2. 路由器程序:router.c

核心作用:ZigBee 网络的信号中继器、数据转发端,扩展网络覆盖范围,无独立业务逻辑。

入网:自动搜索并加入协调器创建的网络,作为 FFD 全功能设备运行;

转发:透明转发协调器与终端之间的所有数据 / 指令(无需解析),解决终端与协调器距离过远的通信问题;

基础适配:与协调器共用核心协议栈逻辑,仅简化了硬件初始化(无 LCD、串口指令解析),仅保留 ZigBee 通信能力。

3. 终端节点程序:enddevice.c

核心作用:ZigBee 网络的数据采集端、外设执行端,是感知层核心,负责物理世界的信息采集和设备控制。

入网:自动搜索并加入协调器 / 路由器的网络,作为 RFD 精简功能设备运行,功耗更低;

数据采集:定时采集温湿度(DHT11)、光照、气体浓度、人体红外等环境数据,封装为统一的_EnvMsg数据结构;

定时上报:基于 OSAL 定时器实现周期性数据上报(默认 1 秒),通过 ZigBee 无线发送给协调器;

外设控制:接收协调器下发的控制指令,解析后驱动继电器、蜂鸣器、LED 执行对应动作;

硬件初始化:完成所有传感器、外设的底层初始化,以及 ZigBee 端点、OSAL 任务注册。

enddevice.c新增代码

引入传感器 / 外设驱动头文件,支持硬件扩展

新增 LCD 功能:清屏函数 + 中文标题显示

初始化新增:外设、传感器、LCD 初始化

新增 SyncData ():采集所有传感器数据并显示

新增定时上报:定时器事件 → 采集数据 → 无线发给协调器

新增外设控制函数:蜂鸣器、LED 开关控制

新增指令解析:接收协调器指令 → 控制外设

最核心

1.发送:定时采集传感器数据 → 无线发给协调器

实现:SyncData() + 定时器事件 + AF_DataRequest()

2.接收:接收协调器控制指令 → 控制外设

实现:GenericApp_MessageMSGCB() + XXXCtrl()

1.传感器等头文件

c 复制代码
#include"dht11.h"
#include"beep.h"
#include "led.h"
#include"relay.h"
#include"Gas_head.h"
#include"Infrare_head.h"
#include"light.h"
#include"Temperature_head.h"
#include"stdio.h"
#include"string.h"
#include"relay.h"
#include "chinese.h"

2.屏幕相关

c 复制代码
void clear_lcd(void);
void clear_lcd(void)
{
	

	BACK_COLOR=MAGENTA;
	POINT_COLOR=YELLOW;
	LCD_Clear(BACK_COLOR); 


	return;
}
void show_title(void);

void show_title(void)
{
	char offset = 20;
	showhanzi16x16(0 + offset,30,0,wu,YELLOW,BACK_COLOR);
	showhanzi16x16(17+ offset,30,0,xian,YELLOW,BACK_COLOR);
	showhanzi16x16(34+ offset,30,0,chuan,YELLOW,BACK_COLOR);
   
    showhanzi16x16(51+ offset,30,0,gan,YELLOW,BACK_COLOR);
    showhanzi16x16(68+ offset,30,0,wang,YELLOW,BACK_COLOR);
	return;
}

3.GenericApp_Init

其中在调用初始化

c 复制代码
	InitBeep();
	InitLed();
	InitRelay();
    	    
	Init_infrare();
	HalLcdInit();
	clear_lcd();

4.同步数据并显示

终端节点采集所有传感器数据 → 统一存入结构体 EnvMsg → 同时显示在 LCD 上

c 复制代码
#define HONGWAI P0_5 

struct _EnvMsg EnvMsg;
void SyncData(unsigned char  sto_no)  //把所有采集的数据同步到ç>>"æž„ä½"EnvMsg中
{
	char buf[10]={0};

	memset(&EnvMsg,0,sizeof(EnvMsg));
	
	EnvMsg.head[0] = 's';
	EnvMsg.head[1] = 't';
	EnvMsg.head[2] = ':';
	EnvMsg.type = 'e'; 
	EnvMsg.ep_no = sto_no;
	
	readDHT11();

	EnvMsg.temp[0] = (unsigned char)ucharT_data_L;
	EnvMsg.temp[1] = (unsigned char)ucharT_data_H;

	EnvMsg.hum[0] = (unsigned char)ucharRH_data_L;  
	EnvMsg.hum[1] = (unsigned char)ucharRH_data_H;

	sprintf(buf,"temp:%d",EnvMsg.temp[1]);
	HalLcdWriteString(buf,HAL_LCD_LINE_5);	

	sprintf(buf,"hum:%d",EnvMsg.hum[1]);
	HalLcdWriteString(buf,HAL_LCD_LINE_6);	

	EnvMsg.lux =  (unsigned int)myApp_ReadLightLevel();

	sprintf(buf,"li:%d",EnvMsg.lux);

	HalLcdWriteString(buf,HAL_LCD_LINE_7);
	
	EnvMsg.hongwai = HONGWAI; 

	EnvMsg.gas =  (unsigned int)myApp_ReadGasLevel(); 
	sprintf(buf,"gas:%d",EnvMsg.gas);

	HalLcdWriteString(buf,HAL_LCD_LINE_8);
}

5.定时器定时上报传感器数据

c 复制代码
// 定时器事件:每隔一段时间发送一次传感器数据
if ( events & GENERICAPP_SEND_MSG_EVT )
{
	// 1. 采集所有传感器数据(温湿度、光照、气体、红外)
	SyncData(ENDDEVICE_ID);
	
	// 2. 把结构体数据拷贝到发送缓冲区
	memcpy(sendbuf, &EnvMsg, 24);	
	
	// 3. 通过 ZigBee 无线把 24 字节数据发给协调器
	AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
	           GENERICAPP_CLUSTERID1,
	           24, 
	           (uchar *)&EnvMsg,
	           &GenericApp_TransID, 
	           AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );

	// 4. 重新启动定时器,循环上报
	osal_start_timerEx( GenericApp_TaskID,
	            GENERICAPP_SEND_MSG_EVT,
	            ENDDEVICE_SEND_MSG_TIMEOUT );

	// 清除事件标志
	return (events ^ GENERICAPP_SEND_MSG_EVT);
}

6.相关Ctrl

c 复制代码
uint8_t DeviceStatus;

void BeepCtrl(uint8_t cmd)
{

	switch(cmd)
	{
		case BEEP_OFF:
			DeviceStatus &= ~0x02;
			BeepOff();
			//HalLcdWriteString("beep on",HAL_LCD_LINE_5);
			break;
		case BEEP_ON:
			DeviceStatus |= 0x02;
			BeepOn();
			//HalLcdWriteString("beep off",HAL_LCD_LINE_5);
			break;
		default:
			break;
	}
}
void LedCtrl(uint8_t cmd)
{
	switch(cmd)
	{
		case LED_OFF:
			DeviceStatus &= ~0x04;
			//HalLcdWriteString("led off",HAL_LCD_LINE_5);
			LedOff();
			break;
		case LED_ON:
			DeviceStatus |= 0x04;
			//HalLcdWriteString("led on",HAL_LCD_LINE_5);
			LedOn();  
			break;
		default:
			break;
	}
}
int cmdcount = 0;

七、GenericApp_MessageMSGCB

c 复制代码
// 终端接收协调器无线指令的回调函数
static void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
	uint8_t cmd = 0;
	char buf[10];

	// 判断是不是控制指令
	switch ( pkt->clusterId )
	{
		// 收到协调器发来的控制指令
		case GENERICAPP_CLUSTERID:
        
            // 取出1字节指令
            cmd = *(pkt->cmd.Data);
		
			// 判断:这个指令是不是发给【本终端】的
			if((cmd & STO_MASK) == (ENDDEVICE_ID << 6))
			{
				// 把指令显示在LCD + 串口
				sprintf(buf,"cmd:%x",cmd);
				HalUARTWrite(0, buf,strlen(buf));	
				HalLcdWriteString(buf,HAL_LCD_LINE_4);	
                
                // 判断:控制哪个设备(继电器/蜂鸣器/LED)
				switch(cmd & DEV_MASK)
				{
					case RELY:        // 控制继电器
						RelyCtrl(cmd & CMD_MASK);
						break;
					case BEEP:        // 控制蜂鸣器
						BeepCtrl(cmd & CMD_MASK);
						break;
					case LED:         // 控制LED灯
						LedCtrl(cmd & CMD_MASK);
						break;
					default :
						break;
				}
			}
			break;
	}
}

二、传感器驱动模块(6 类)

传感器驱动模块说明

模块文件 对应传感器 核心作用
dht11.c/dht11.h DHT11 温湿度传感器 初始化 IO 口,实现温湿度数据的读取、校验,提供 readDHT11() 核心接口
Human_Body_infrared.c/Infrare_head.h 人体红外传感器 初始化 P0.5 口,检测人体存在状态,返回格式化的状态字符串(KaTeX parse error: Expected 'EOF', got '#' at position 4: yes#̲/no#)
Gas.c/Gas_head.h 气体传感器 初始化 ADC 采集通道,读取气体浓度模拟值,完成 AD 转换并格式化输出
light.c/light.h 光照传感器 初始化 ADC 采集通道,读取光照强度模拟值,完成 AD 转换并格式化输出
Temperature_head.h 18B20 温度传感器 预留 18B20 驱动接口(未实现完整代码),兼容数字温度传感器采集

三、外设驱动模块(4 类)

外设驱动模块说明

模块文件 对应外设 核心作用
beep.c/beep.h 蜂鸣器 初始化 P0.0 口,提供 BeepOn()/BeepOff() 蜂鸣器开关接口
led.c/led.h LED 灯 初始化 P1.0/P1.1/P1.4 口,提供 LedOn()/LedOff() LED 组控接口,支持状态上报
relay.c/relay.h 继电器 初始化 P1.3 口,提供 RelayOn()/RelayOff() 继电器开关接口,封装 RelyCtrl() 指令控制接口
head.h 公共类型定义 定义通用数据类型(uchar/uint)、宏常量(SIZE),作为所有驱动的基础头文件

四、协议栈 / 应用层公共模块(3 类)

  1. GenericApp.h
    应用层公共头文件,是整套系统的业务约定核心,所有设备程序、驱动模块均依赖此文件,定义了:

ZigBee 通信参数:端点号、配置文件 ID、簇 ID(区分不同节点 / 数据类型);

数据结构:_EnvMsg统一环境数据结构(温湿度、光照、气体、红外等),规范终端与协调器的数据交互格式;

控制指令掩码:节点号掩码(STO_MASK)、设备号掩码(DEV_MASK)、命令字掩码(CMD_MASK),规范控制指令的解析规则;

宏常量:外设控制命令(如 BEEP_ON/LED_OFF)、定时器超时时间、OSAL 事件定义;

公共函数声明:外设控制、数据同步等跨模块函数。

  1. OSAL_GenericApp.c
    Z-Stack OSAL 任务调度配置,是协议栈的任务入口,定义了:

任务数组tasksArr[]:按优先级排列所有协议栈任务(MAC、NWK、HAL、APS 等)和应用层任务(GenericApp),应用层任务优先级最低;

任务初始化osalInitTasks():依次初始化所有协议栈任务和应用层GenericApp_Init(),为应用层分配 Task ID;

核心作用:实现 OSAL 操作系统的任务调度,让应用层基于事件驱动运行(如定时器事件、数据接收事件、网络状态事件)。

  1. 协议栈底层依赖(无独立文件,集成在 Z-Stack 中)

包含 MAC 层、NWK 层、APS 层、ZDO 层等,封装了 ZigBee 无线通信的底层细节,向上提供统一的 API(如AF_DataRequest()数据发送、osal_start_timerEx()定时器、ZDO_STATE_CHANGE网络状态事件),让开发者无需关注底层通信,仅需开发应用层业务。

五、各模块之间的核心关联关系

Z-Stack协议栈(MAC/NWK/APS/OSAL)

↓ 提供通信/调度API

核心设备程序(coordinator/enddevice/router)

↓ 调用驱动接口采集/控制

传感器驱动/外设驱动模块

↓ 操作硬件寄存器

物理硬件(传感器/外设/无线射频)

PS:关于Zigbee部分

GenericApp.h

OSAL_GenericApp.c

Z-Stack 协议栈底层文件(所有底层)

它们是 TI 官方给的框架,只使用,不修改。

对于本项目,只写在这两个文件里:

coordinator.c ------ 协调器(收数据、发指令)

enddevice.c ------ 终端节点(采传感器、控制外设)

ZigBee 协调器与终端节点数据交互流程

  1. 上位机通过串口发送数据给协调器;
  2. 触发协调器串口回调函数 rxCB() ,通过 HalUARTRead() 从串口提取出数据;
  3. 协调器通过 AF_DataRequest() 将数据发送给网络中其他设备,通过 id: GENERICAPP_CLUSTERID,表明该数据是协调器发送;
  4. 触发终端节点回调函数 GenericApp_MessageMSGCB() ,协调器 id 存放在 pkt->clusterId 中,发送的数据存放在 pkt->cmd.data 中;
  5. 终端节点可以采集传感器数据,发送数据在缓冲区 data 中,然后通过函数 AF_DataRequest() 发送数据,填充 id: GENERICAPP_CLUSTERID2,表示数据是节点 2 发送;
  6. 触发协调器的回调函数 GenericApp_MessageMSGCB()
  7. 协调器提取出终端节点发送的数据 pkt->cmd.data,通过 HalUARTWrite() 发送给上位机。
相关推荐
newsxun2 小时前
与IOT组队,同态加密技术重塑电力项目数据管理模式
物联网·区块链·同态加密
云道轩2 小时前
在rocky linux 9.x上安装 Chrome
linux
小疙瘩2 小时前
VirtualBox 下 CentOS-10 下 Docker 安装 Mysql57 (包括 使用 Docker Compose 部署)
linux·docker·centos
郝学胜-神的一滴2 小时前
Linux高性能网络编程基石:epoll核心与文件描述符限制全解
linux·服务器·网络·c++·后端
cnnews2 小时前
Termux中安装python包
android·linux·开发语言·python·安卓·termux
淼淼爱喝水3 小时前
openEuler 下 Ansible 模块缺失 / 损坏后重装完整教程
linux·openeuler·技术实操
山城码农笑松哥3 小时前
Rocky Linux Centos 9.6 完全离线安装rabbitmq4.2
linux·rabbitmq
江畔何人初8 小时前
iptables 和 IPVS 代理模式 Service 的区别
linux·运维·服务器·网络·云原生·kubernetes·代理模式
123过去11 小时前
nfc-list使用教程
linux·网络·测试工具·安全