ZigBee Zstack协议栈

article/2025/10/22 3:39:17

一、Zstack协议栈概述

什么是Zstack协议栈

为了使Zigbee的开发更加简单高效,TI公司推出了基于cc2530芯片的协议栈Z-STACK.协议栈的实质就是能实现各个功能的实例框架代码,我们想要实现自己的功能程序,只需要在协议栈的基础上修改或添加即可。

  • ​ Z-STACK的发展
  • ​ 由0.01版本 到 1.5.1a…
  • ​ mesh: 之前的升级版本
  • ​ HA: 家庭自动化(智能家居)
  • ​ SE: 智能能源

​ …他们的区别是应用部分不同(初学者建议用早期的版本)

二、Zstack协议栈结构

​ Z-Stack协议栈符合ZigBee协议,由物理层、MAC层、网络层和应用层组成,由于Z-Stack协议栈是一个半开源的协议栈,MAC层和网络层的部分源代码是非开源的,因此我们学习的开源部分,主要包括main函数、APP层、ZDO层、NWK层和HAL层。

1.工程目录结构

image-20210526141312372

APP: 应用层目录, 这是用户创建各种不同工程的区域, 在这个目录中包含了应用层的内容和这个项目的主要内容, 在协议栈里面一般是以操作系统的任务实现的。
HAL: 硬件层目录, 包含有与硬件相关的配置和驱动及操作函数。
MAC: MAC 层目录, 包含了 MAC 层的参数配置文件及其 MAC 的 LIB 库的函数接口文件。
MT: 监控调试层, 主要用于调试目的, 即实现通过串口调试各层, 与各层进行直接交互。
NWK: 网络层目录, 含网络层配置参数文件及网络层库的函数接口文件, APS 层库的函数接口。
OSAL: 协议栈的操作系统。
Profile: AF 层目录, 包含 AF 层处理函数文件。
Security: 安全层目录, 安全层处理函数接口文件, 比如加密函数等。
Services: 地址处理函数目录, 包括着地址模式的定义及地址处理函数。
Tools: 工程配置目录, 包括空间划分及 ZStack 相关配置信息。
ZDO: ZDO 目录。
ZMac: MAC 层目录, 包括 MAC 层参数配置及 MAC 层 LIB 库函数回调处理函数。
ZMain: 主函数目录, 包括入口函数 main( ) 及硬件配置文件。
Output: 输出文件目录, 这个 EW8051 IDE 自动生成的。

2.main函数解析

int main( void )
{/* 关闭所有中断*/osal_int_disable( INTS_ALL );/* 初始化硬件设备*/HAL_BOARD_INIT();/*电源检测*/zmain_vdd_check();/*初始化I/O*/InitBoard( OB_COLD );/*初始化硬件抽象层HAL驱动*/HalDriverInit();/*初始化NV*/osal_nv_init( NULL );/*初始化 MAC*/ZMacInit();/*确定64位IEEE地址*/zmain_ext_addr();/*初始化NV向量*/zgInit();	
	#ifndef NONWK/* AF层初始化/afInit();
#endif/*初始化任务*/osal_init_system();/*开启中断*/osal_int_enable( INTS_ALL );/*硬件I/O初始化完毕*/InitBoard( OB_READY );zmain_dev_info();/* 如果定义了LCD,初始化LCD */
#ifdef LCD_SUPPORTEDzmain_lcd_init();
#endif
#ifdef WDT_IN_PM1/* 如果定义了看门狗,看门狗使能 */WatchDogEnable( WDTIMX );
#endif/*操作系统运行*/osal_start_system();return 0;
}	

osal_int_disable()

uint8 osal_int_disable( uint8 interrupt_id )
{
/*判断ID是否为中断ID*/
if ( interrupt_id == INTS_ALL )
{
/*关掉所有中断*/
HAL_DISABLE_INTERRUPTS();
/*中断关闭成功,返回SUCCESS */
return ( SUCCESS );
}
else
{
/*如果ID与INST_ALL不同,返回
INVALID_INTERRUPT_ID*/
return ( INVALID_INTERRUPT_ID );
}
}

3.APP层解析

OSAL_SampleApp.c中包含osalInitTasks()与taskArr[]。

osalInitTasks()函数主要功能是为任务分配空间

void osalInitTasks( void )
{uint8 taskID = 0;tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));macTaskInit( taskID++ );nwk_init( taskID++ );Hal_Init( taskID++ );
#if defined( MT_TASK )MT_TaskInit( taskID++ );
#endifAPS_Init( taskID++ );
#if defined ( ZIGBEE_FRAGMENTATION )APSF_Init( taskID++ );
#endifZDApp_Init( taskID++ );
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )ZDNwkMgr_Init( taskID++ );
#endifSampleApp_Init( taskID );

image-20210526142358533

OSAL_SampleApp.c

tasksArr中存放了事件处理回调函数

const pTaskEventHandlerFn tasksArr[] = {macEventLoop,nwk_event_loop,Hal_ProcessEvent,
#if defined( MT_TASK )MT_ProcessEvent,
#endifAPS_event_loop,
#if defined ( ZIGBEE_FRAGMENTATION )APSF_ProcessEvent,
#endifZDApp_event_loop,
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )ZDNwkMgr_event_loop,
#endifSampleApp_ProcessEvent
};

image-20210526142515869

Z-Stack协议栈的APP层主要功能是实现用户定义的事件,APP层由5个文件组成

image-20210526142553502

SamplApp.c文件主要有两个功能:
(1)对应用层用户定义的任务
(2)进行初始化;调用事件处理函数。

  • 用户任务初始化函数SampleApp_Init()
  • 任务处理函数SampleApp_ProcessEvent()
  • 按键处理事件SampleApp_HandleKeys()
  • 数据发送函数SampleApp_SendFlashMessage()
  • 数据发送函数SampleApp_SendPeriodicMessage()
  • 数据接收函数SampleApp_MessageMSGCB()

SampleApp_Init()

void SampleApp_Init( uint8 task_id )
{SampleApp_TaskID = task_id;SampleApp_NwkState = DEV_INIT;SampleApp_TransID = 0;
#if defined ( BUILD_ALL_DEVICES )if ( readCoordinatorJumper() )zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;elsezgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;
#endif 
#if defined ( HOLD_AUTO_START )ZDOInitDevice(0);
#endif/*SampleApp_Periodic_DstAddr地址模式初始化为广播地址*/SampleApp_Periodic_DstAddr.addrMode =    (afAddrMode_t)AddrBroadcast;/* SampleApp_Periodic_DstAddr端点初始化*/SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF;SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup;SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP;

image-20210526143651898

SampleApp_Init()

SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_epDesc.task_id = &SampleApp_TaskID;
SampleApp_epDesc.simpleDesc= (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc;
SampleApp_epDesc.latencyReq = noLatencyReqs;afRegister( &SampleApp_epDesc );RegisterForKeys( SampleApp_TaskID );SampleApp_Group.ID = 0x0001;
osal_memcpy( SampleApp_Group.name, "Group 1", 7  );
aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );#if defined ( LCD_SUPPORTED )
HalLcdWriteString( "SampleApp", HAL_LCD_LINE_1 );
#endif
}

image-20210526143749526

SampleApp_ProcessEvent()

image-20210526143838169

SampleApp_ProcessEvent()

image-20210526143903337

SampleApp_HandleKeys()

image-20210526143922288

SampleApp_MessageMSGCB()

SampleApp_MessageMSGCB()函数主要实现数据接收功能,数据的接收通过判断簇ID来
与发送端发送的数据进行匹配。

image-20210526144842589

SampleApp_SendPeriodicMessage()

SampleApp_SendPeriodicMessage()函数主要功能是实现周期性数据的发送,通过调用
AF_DataRequest()函数进行数据的发送。

image-20210526144912513

SampleApp.h

image-20210526144937850

4.ZDO层解析

目录结构

image-20210526145815215

ZDApp_Init()函数:初始化ZDO网络设备短地址;获得64位IEEE地址信息;ZDO层初始化;网络设备启动。

5.NWK层解析

目录结构

image-20210527185136679

网络拓扑结构

/*星型网络*/
#define NWK_MODE_STAR         0
/*树型网络*/
#define NWK_MODE_TREE         1
/*网状网络*/
#define NWK_MODE_MESH         2

网络参数设置

/*协议栈模式参数*/
#define NETWORK_SPECIFIC      0
#define HOME_CONTROLS         1
#define ZIGBEEPRO_PROFILE    2
#define GENERIC_STAR          3
#define GENERIC_TREE          4
/*信道设置*/
#define MAX_CHANNELS_868MHZ     0x00000001
#define MAX_CHANNELS_915MHZ     0x000007FE
#define MAX_CHANNELS_24GHZ      0x07FFF800

6.HAL层解析

20210527184135.png

HAL目录
Common:实现了硬件初始化函数Hal_Init()、硬件抽象层驱动初始化HalDriverInit ()函数和硬件抽象层事件处理函数Hal_ProcessEvent();
Include:中主要包含了硬件资源的定义与函数声明;
Target:主要为LED等硬件资源进行配置、实现硬件资源的实现函数;

Hal_Init()函数主要为硬件抽象层注册任务ID

void Hal_Init( uint8 task_id )
{/* 注册任务 ID */Hal_TaskID = task_id;
}

HalDriverInit()函数主要实现硬件资源的初始化

void HalDriverInit (void)
{
/*定时器初始化*/
#if (defined HAL_TIMER) && (HAL_TIMER == TRUE)HalTimerInit();
#endif
/*ADC初始化*/
#if (defined HAL_ADC) && (HAL_ADC == TRUE)HalAdcInit();
#endif
/*DMA初始化*/
#if (defined HAL_DMA) && (HAL_DMA == TRUE)HalDmaInit();
#endif
/*Flash初始化*/
#if (defined HAL_FLASH) && (HAL_FLASH == TRUE)HalFlashInit();
#endif
/*AES初始化*/
#if (defined HAL_AES) && (HAL_AES == TRUE)HalAesInit();
#endif
/*LCD初始化*/
#if (defined HAL_LCD) && (HAL_LCD == TRUE)HalLcdInit();
#endif
/*LED初始化*/
#if (defined HAL_LED) && (HAL_LED == TRUE)HalLedInit();
#endif
/*UART初始化*/
#if (defined HAL_UART) && (HAL_UART == TRUE)HalUARTInit();
#endif
/*KEY按键初始化*/
#if (defined HAL_KEY) && (HAL_KEY == TRUE)HalKeyInit();
#endif
/*SPI初始化*/
#if (defined HAL_SPI) && (HAL_SPI == TRUE)HalSpiInit();
#endif
}

HHal_ProcessEvent()函数由APP层OSAL_SampleApp.c文件调用,主要实现硬件抽象层的各种事件处理,比如系统消息事件、LED闪烁事件、按键事件和睡眠模式事件。

uint16 Hal_ProcessEvent( uint8 task_id, uint16 events )
{uint8 *msgPtr;/*系统消息事件*/if ( events & SYS_EVENT_MSG ){msgPtr = osal_msg_receive(Hal_TaskID);while (msgPtr){osal_msg_deallocate( msgPtr );msgPtr = osal_msg_receive( Hal_TaskID );}return events ^ SYS_EVENT_MSG;}/*LED闪烁事件*/if ( events & HAL_LED_BLINK_EVENT ){
#if (defined (BLINK_LEDS)) && (HAL_LED == TRUE)HalLedUpdate();
#endif /* BLINK_LEDS && HAL_LED */return events ^ HAL_LED_BLINK_EVENT;}
/*按键事件*/
if (events & HAL_KEY_EVENT)
{
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
/* Check for keys */
HalKeyPoll();
if (!Hal_KeyIntEnable)
{
osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);
}
#endif
return events ^ HAL_KEY_EVENT;
}
/*睡眠模式*/
#ifdef POWER_SAVING
if ( events & HAL_SLEEP_TIMER_EVENT )
{
halRestoreSleepLevel();
return events ^ HAL_SLEEP_TIMER_EVENT;
}
#endif
return 0;
}

​ HTarget hal_board_cfg.h文件中为硬件资源LED等进行配置,在官方的协议栈中定义了3个LED,分别接CC2530的P1_0、P1_1和P1_4引脚。

/* LED1配置 */
#define LED1_BV           BV(0)
#define LED1_SBIT         P1_0
#define LED1_DDR          P1DIR
#define LED1_POLARITY     ACTIVE_HIGH#ifdef HAL_BOARD_CC2530EB_REV17/* LED2配置 */#define LED2_BV           BV(1)#define LED2_SBIT         P1_1#define LED2_DDR          P1DIR#define LED2_POLARITY     ACTIVE_HIGH/* LED3配置 */#define LED3_BV           BV(4)#define LED3_SBIT         P1_4#define LED3_DDR          P1DIR#define LED3_POLARITY     ACTIVE_HIGH
#endif

控制LED开关状态。

#if defined (HAL_BOARD_CC2530EB_REV17) && !defined (HAL_PA_LNA) && !defined (HAL_PA_LNA_CC2590)/*打开LED*/#define HAL_TURN_OFF_LED1()       st( LED1_SBIT = LED1_POLARITY (0); )#define HAL_TURN_OFF_LED2()       st( LED2_SBIT = LED2_POLARITY (0); )#define HAL_TURN_OFF_LED3()       st( LED3_SBIT = LED3_POLARITY (0); )#define HAL_TURN_OFF_LED4()       HAL_TURN_OFF_LED1()/*关闭LED*/#define HAL_TURN_ON_LED1()        st( LED1_SBIT = LED1_POLARITY (1); )#define HAL_TURN_ON_LED2()        st( LED2_SBIT = LED2_POLARITY (1); )#define HAL_TURN_ON_LED3()        st( LED3_SBIT = LED3_POLARITY (1); )#define HAL_TURN_ON_LED4()        HAL_TURN_ON_LED1()/*LED状态改变*/#define HAL_TOGGLE_LED1()         st( if (LED1_SBIT) { LED1_SBIT = 0; } else { LED1_SBIT = 1;} )#define HAL_TOGGLE_LED2()         st( if (LED2_SBIT) { LED2_SBIT = 0; } else { LED2_SBIT = 1;} )#define HAL_TOGGLE_LED3()         st( if (LED3_SBIT) { LED3_SBIT = 0; } else { LED3_SBIT = 1;} )#define HAL_TOGGLE_LED4()         HAL_TOGGLE_LED1()#define HAL_STATE_LED1()          (LED1_POLARITY (LED1_SBIT))#define HAL_STATE_LED2()          (LED2_POLARITY (LED2_SBIT))#define HAL_STATE_LED3()          (LED3_POLARITY (LED3_SBIT))#define HAL_STATE_LED4()          HAL_STATE_LED1()
#endif

​ 在Drives文件中定义了硬件资源的驱动函数文件

  • LED:在hal_led.c文件中实现,为LED提供驱动函数;
  • ADC:在hal_adc.c文件中实现,为ADC提供驱动函数;
  • KEY:在hal_key.c文件中实现,为按键提供驱动函数;
  • LCD:在hal_LCD.c文件中实现,为LCD提供驱动函数;
  • 定时器:在hal_timer.c文件中实现,为定时器提供驱动函数;
  • 串口:在hal_uart.c文件中实现,为串口提供驱动函数;
  • DMA:在hal_dma.c文件中实现,为DMA提供驱动函数;
  • flash:在hal_flash.c文件中实现,为flash提供驱动函数。

APP应用层调用LED设置函数

HalLedSet(uint8 leds,uint8 mode);
HalLedBlink(uint8 leds,uint8 numBlink,uint8 percend,uint16 period);

image-20210527185047722


http://chatgpt.dhexx.cn/article/XeAmHRd7.shtml

相关文章

快速了解ZigBee的协议栈

带大家来一起快速的看懂ZigBee的协议栈的运行流程。 1.读任何程序都需要从main函数入手,那我们先来看Zmain.c中的main函数。 问题:在main中我们会看到很多的函数,我们究竟要看哪个函数呢? 回答:这么多的函数中其实我们只需要关注…

Zigbee协议栈————广播组网

目录 1.基础概念 2.Zigbee协议栈工作流程 3。代码讲解 1.基础概念 在Zigbee网络中存在3中逻辑设备:协调器、路由器、终端。 (这个实验当中我们只用到协调器以及终端)。 协调器:协调器负责启动网络,当启动和配置好网络后,协调…

zibgee协议

1.概述 1.1解析ZigBee堆栈架构 ZigBee堆栈是在IEEE 802.15.4标准基础上建立的,定义了协议的MAC和PHY层。ZigBee设备应该包括IEEE802.15.4(该标准定义了RF射频以及与相邻设备之间的通信)的PHY和MAC层,以及ZigBee堆栈层:网络层(NWK)、应用层和安…

[ZigBee] 15、Zigbee协议栈应用(一)——Zigbee协议栈介绍及简单例子(长文,OSAL及Zigbee入门知识)...

1、Zigbee协议栈简介 协议是一系列的通信标准,通信双方需要按照这一标准进行正常的数据发射和接收。协议栈是协议的具体实现形式,通俗讲协议栈就是协议和用户之间的一个接口,开发人员通过使用协议栈来使用这个协议,进而实现无线数据收发。 如图1所示:Zigbee协议分为两部分…

ZigBee协议栈简介

文章目录 Zigbee协议栈简介如何理解Zigbee协议栈如何使用Zigbee协议栈 Zigbee协议栈简介 Zigbee协议分为2部分: IEEE 802.15.4定义了PHY(物理层)和MAC(介质访问层)技术规范。Zigbee联盟定义了NWK(网络层)、APS(应用程序支持层)、APL(应用层)技术规范。 Zigbee协议栈…

[zigbee][z-Stack]协议栈简介及工作流程

文章目录 什么是zigbee协议栈?如何使用zigbee协议栈?z-Stack工作流程 什么是zigbee协议栈? 协议栈是协议的具体实现形式,通俗点来理解就是协议栈是协议和用户之间的一个缺口,开发人员通过使用协议栈来使用这个协议的&…

相机标定和双目相机标定标定原理推导及效果展示

文章目录 前言一、相机标定1.相机的四个坐标系2.相机的畸变 二、张正友标定法1.求解内参矩阵与外参矩阵的积2.求解内参矩阵3.求解外参矩阵4.标定相机的畸变参数5.双目标定6.极线矫正(立体校正) 三、视差图与深度图 前言 参考了一些大佬的文章&#xff0c…

视觉基础之相机标定

点击上方“小白学视觉”,选择加"星标"或“置顶” 重磅干货,第一时间送达 基于视觉的图像处理,通常要在实验前进行相机的标定,以获取相应的参数。为方便查阅,遂将常用到的三种相机标定总结如下。 相机内参标定…

照相机标定

一.相机标定的原理 1.1 相机如何成像: 相机成像系统中,共包含四个坐标系:世界坐标系、相机坐标系、图像坐标系、像素坐标系。 1.1.1 世界坐标系: 世界坐标系(world coordinate),也称为测量坐…

Opencv——相机标定

相机标定的目的:获取摄像机的内参和外参矩阵(同时也会得到每一幅标定图像的选择和平移矩阵),内参和外参系数可以对之后相机拍摄的图像就进行矫正,得到畸变相对很小的图像。 相机标定的输入:标定图像上所有…

为什么需要对相机标定?

以下内容来自系统教程如何搞定单目/鱼眼/双目/阵列 相机标定? 点击领取相机标定资料和代码 为什么需要对相机标定? 我们所处的世界是三维的,而相机拍摄的照片却是二维的,丢失了其中距离/深度的信息。从数学上可以简单理解为&…

1. 相机标定原理(学习笔记)

相机标定(Camera Calibration)-学习笔记 文章目录 相机标定(Camera Calibration)-学习笔记一、简介二、原理1. 坐标系 *coordinates*2. 相机参数 *camera matrix*2.1 外参数矩阵2.2 内参数矩阵2.3 畸变矩阵2.3.1 径向畸变2.3.2 切向畸变 2.4 小结 三、相机标定方法1. 张正友相机…

相机标定目的及原理

相机标定的目的: 相机标定的目的有两个,一个就是矫正由于镜头畸变造成的图片的变形,例如,现实中的直线,拍摄成图像后会外凸或内凹,进行相机标定后可以对这种情况进行校正;另一个是根据获得得图像…

Python之OpenCV相机标定方法

本文结合OpenCV官方样例,对官方样例中的代码进行修改,使其能够正常运行,并对自己采集的数据进行实验和讲解。 一、准备 OpenCV使用棋盘格板进行标定,如下图所示。为了标定相机,我们需要输入一系列三维点和它们对应的…

相机标定,内参数与外参数

相机标定 简介 所谓的相机标定就是将外界世界的坐标信息转化为计算机(自带相机/摄像头)可以理解的“距离”,将世界坐标系转换到相机坐标系。我们可以理解为从一个坐标系转换到另一个坐标系所需要的转换关系就是相机标定。 简单滴说&#x…

相机标定——张氏标定法

目录 前言动机为什么要进行相机标定什么是张氏标定法 张氏标定法的原理透镜成像原理世界坐标系到相机坐标系的转换相机坐标系到图像坐标系的转换图像坐标系到像素坐标系单应性矩阵内参求解外参求解Matlab实操 前言 动机 前段时间在整机械臂的手眼标定,也就是标定3D…

相机标定系列(三)利用matlab进行相机标定

相机标定系列(三)利用matlab进行相机标定 文章目录 相机标定系列(三)利用matlab进行相机标定前言一、棋盘格图像的采集二、单目相机标定三、双目相机标定 前言 matlab的应用程序中含有对双目相机和单目相机的标定工具箱&#xff…

机器视觉——相机标定

1 机器视觉为什么要做相机标定 机器视觉是采用相机成像来实现对三维场景的测量、定位、重建等过程。是一个利用二维图像进行三维反推的过程,我们所处的世界是三维的,而图像或者照片是二维的,可以把相机认为是一个函数,输入量是一…

相机标定篇——相机标定

认为相机标定是三维重建的核心,研究生期间主要方向为结构光三维重建 必要的数学知识 线性方程求解 Gauss消元法;LU分解;Cholesky分解 最小二乘问题-线性方法 特征值分解;奇异值分解;超定线性方程;最小二乘…

【相机标定】相机内参

相机标定 相机在计算机视觉方面的一些应用一般需要相机标定。我们总是听到标定这个词,那么具体标定的是什么呢?相机的拍摄是一个三维到二维(透视投影)的过程,这个过程可以用数学模型去表述,标定便是计算这…