zigbee笔记:十、ZStack(2.3.0-1.4.0)的OSAL使用分析

server/2024/9/20 4:01:40/ 标签: zigbee工程, OSAL

        zigbee笔记:九中,我们已经学会了利用模板,定制自己的个性开发工程,本文为协议栈(ZStack-CC2530-2.3.0-1.4.0)代码使用分析笔记,来进一步掌握协议栈的使用。

一、协议栈使用知识点

        1、协调器、路由器、终端代码下载

        通过选项卡选择不同的节点类型工程(分别是协调器、路由节点和终端节点工程),就会导致参与编译的配置文件不同,配置不同就会导致部分宏定义不同,宏定义不同就会导致工程里某些宏的值不同。这些宏值的不同会影响程序执行的流程,就会导致出现不同的功能,如下图所示。

        在选项卡里每一种版本模块都貌似有2个分为不带Pro和带Pro。zigbee协议在发展过程中经历了3个版本,其中zigbee在7出的是最新的规范这个规范有2个版本 zigbee2007和 zigbeePro他们之间的区别是,功能基本相同,Pro版本功能稍微强大咱们一般都选 Pro 。

        2、信道选择与网络PANID设置

        在工程配置文件f8wConfig.cfg中, 参数-DDEFAULT_CHANLIST和-DZDAPP_CONFIG_PAN_ID。

        (1)-DDEFAULT_CHANLIST 参数

        信道编码采用64位独热码,当需要多信道通信时,可以采用或运算,如编码为0x00001800表示采用11和12信道,把结果作为 DEFAULT CHANLIST值。

        路由器和终端:可以在参与或操作的这些信道上选择一个相对于我来说最佳的网络,加入进去。

        协调器: 可以在参与或操作的这些信道上选择一个最佳的信道并在这个信道上创建自己的Zigbee网络()。

        (2)-DZDAPP_CONFIG_PAN_ID 参数

 -DZDAPP_CONFIG_PAN_ID值非0xFFFF时:

         路由器和终端:必须要加入到PANID为参数值这样一个Zigbee无线局域网。

        协调器:我要创建一个网络,并且把这个参数值作为这个网络的PANID。

-DZDAPP_CONFIG_PAN_ID值为0xFFFF时:

        路由器和终端:在加入网络的时候没有PANID的限制。

        协调器:可以随机生成一个值,把这个随机值作为这个网络的PANID。

(3)补充:

        问1:   当2个模块下载相同的协调器代码,并且指走的PANID参数值为非0xFFFF,后果会怎样?

       答: 先上电的模块可以创建0xFFFB这样-个zigbee网络,后上电的模块创建一个在DXFFF8基础上加1的网络。

        问2:网络创建成功后,协调器的网络短地址固定为0x0000

        3、引脚初始化准备

        启动osal之前main函数中还初始化调用了TI的一些硬件实验,其中很多引脚的功能已经被初始化为片上外设了,所以我们使用时要自己修改,不能漏步骤。如果添加自己的一些外设初始化要放在osal_start_system函数前面,WatchDogEnable之后,如初始化LED,如果缺少配置为普通IO模式这一步骤,可能会导致LED无法使用。

        4、OSAL操作系统

        OSAL(Operating System Abstraction Layer),能够实现任务调度的微操作系统,在OSAL操作系统中非常重要的两个概念是任务和事件,还有消息也比较重要

(1)OSAL的启动流程

        如下图所示,系统启动后,先完成一系列的初始化,然后进入如无轮询主循环。

        在zstack协议栈工程目录ZMAIN下的ZMain.c包含了主程序的入口地址

        (2) 两个重要的函数

        main函数中完成了一系列的初始,其中对开发者比较重要有两个函数

        1)OSAL初始化函数 osal_init_system()

       函数osal_init_system() 其中包含的任务初始化函数osalInitTasks(),完成系统任务和用户自定义任务

         函数osalInitTasks()包含的任务初始化函数完成系统任务和用户自定义任务

        2)系统启动函数 osal_start_system(),其功能是不断查询任务事件数组,如果有事件产生,则根据事件在taskArr数组中查询任务事件处理函数进行处理。从tasksEvents数组中tasksEvent[0](0号任务事件变量)去读一直读到tasksEvent[8],如果发现哪一个任务事件变量值为非0,就会跳出循环,此时的idx值就是它的任务ID。跳出上面的循环后,此时就会将idx中存的任务ID和event中存的任务事件变量值,通过函数指针的方法调用相应的任务事件处理函数。

        (3) OSAL(操作系统抽象层)原理

        1)应用层是一个任务,它有一个系统分配给它的数值唯一的编号叫做任务ID。

        2)任务可以处理事件,处理事件的这些代码都在一个函数里,这个函数叫做应用层任务事件处理函数。应用层任务还有一个2个字节的变量,这个变量叫做任务事件变量,如果事件变量和某个事件的宏值&操作为1,那么表示应用层任务将要处理这个事件。

        3)系统在运行的时候,会不断地读取应用层任务事件变量,如果应用层任务事件变量为非0,就会认为应用层任务有事件需要处理,此时就会调用应用层任务事件处理函数StarryApp_ProcessEvent,并将任务事件变量的值传给events,在处理函数中会将events分别与应用层定义的所有任务事件宏值进行与操作,如果值为1,就会去执行这个事件处理的相应代码;当发现任务事件变量为0的时候,就会认为应用层任务没有事件需要处理。

       4) 函数 uint8 osal_set_event( uint8 task_id, uint16 event_flag ) 为事件产生函数,调用执行某个任务中的某个事件, para1是任务ID,para2是任务中的某个事件宏。

        本质是,把taskID(应用层任务)的任务事件变量中对应于宏event_flag值为1的那个位变为1,这样的话首先这个任务事件变量就变成了非0,系统在检测到任务事件变量为非0,就会去调用任务事件处理函数***App_ProcessEvent。在这个函数里,任务事件变量肯定和任务宏的值与操作为1,所以必定会执行这个事件相关的代码。

        5)在ZStack里按照代码功能来划分,分成不同的层,比如,硬件操作相关硬件层,网络相关的代码叫网络层,自己写应用程序部分叫应用层。几乎每一个层都是一个任务,系统为每一个任务分配一个字节的唯一数值编号, 我们把这个数值编号叫做任务ID(task_id)。每一个任务都能处理一些他们能够处理的事物,叫做事件(event_flag)。TI在设计的时候把任务事件处理函数和任务事件变量都封装成了数组:

        函数数组={任务事件处理函数A,任务事件处理函数B,任务事件处理函数C...}

        变量数组={任务事件变量A,任务事件变量B,任务事件变量C...}

        6)任务ID,系统不是随便分配的,我们可以通过这个值立即找到这个任务自己的任务事件处理函数和任务事件变量。任务ID就是数组的下标,通过下标就可以找到相应的任务事件处理函数和任务事件变量。由函数osalInitTasks()包含的任务初始化函数完成系统任务和用户自定义任务,详见 4(2)。

        7)事件是系统需要处理的事情,必须有对应的任务进行处理,事件采用16位独热码,即每种任务可以有16种事件(event_flag)。例如,在应用层,系统事件已被定义,占用编码为0x8000,还有15种用户可定义的事件。

        8)所有Zstack协议栈在稳定工作时,它的行为是在for(;;){}死循环里不断去读所有任务的任务事件变量。如果发现所有任务的任务事件变量都为0,没问题,说明所有任务都没有事件将要去处理;不断重复这个过程,直到发现,某个任务事件变量不为0,就会通过不为0的这个任务ID找到这个任务事件处理函数,去处理相应的事件。

        9) 当事件数量较多,编码无法表示时,可采用消息,系统事件就是采用消息进行事件传递的。 OSAL任务与事件的关系 ,如下图所示。

        10) 消息*******************************************

        4、事件处理函数的编写

        以应用层任务的事件为例, 事件处理函数要在xxApp.c里的xx应用事件处理函数中编写(xxApp_ProcessEvent),如下图所示。

        5、函数总结:

        (1)uint8 osal_set_event( uint8 task_id, uint16 event_flag );

        事件产生函数,调用执行某个任务中的某个事件, para1是任务ID,para2是任务中的事件

        (2)uint8 osal_start_timerEx( uint8 task_id, uint16 event_flag,unit16 timeout_value );

        事件定时器触发函数,等待一定时间执行某个任务中的某个事件,para1是任务编号,para2是参数是要处理的事务,para3是是时间(毫秒)。

        (3)uint8 osal_msg_send( uint8 destination_taskID, uint8 *msg_ptr );

发送消息的函数,para1是要接收此Message的目标任务ID,para2是所要发送的消息Message指针。

        (4)MSGpkt =(afIncomingMSGPacket t *)osal_msg_receive( SampleApp TasklD );

        接收消息的函数,para1是任务ID的参数,用于指定从哪个任务的消息队列中接收消息。osal_msg_receive函数从任务的消息队列中取出一个消息,该消息是一个指向afIncomingMSGPacket_t 类型的指针,然后将其强制类型转换为 afIncomingMSGPacket_t 类型(osal_msg_receive()函数返回的是一个指向 void 类型的指针),最后将其赋值给 MSGpkt 变量,这个操作通常在一个任务中用于接收其他任务发送的消息,以便进行进一步的处理。

    

二、常见注意和错误解决

        1、编译时Error[Pa045]: **** has no prototype ,prototypes取消勾选

        在协议栈中添加使用自己写程序的时候,编译时要把设置中的prototypes取消勾选。

        2、编译基于协议栈代码生成hex文件

        (1)首先设置选项,如下图所示

        (2)取消f8w2530.xcl文件内的部分代码,如下图所示

        3、 Warning[w2]: Symbol ?PBANK is redefined in command-line

        (1) IAR  编译zigbee工程时 报的警告如下:

         (2)可以在配置文件中修改,Tools文件夹下的f8w2530.xcl中屏蔽掉-D?PBANK=93这一行。

        (3)重新全部编译

        4、Warning[Pe223]: function **** declared implicitly 

        这个告警是提示我,我调用的这个 **** 函数没有进行函数声明,一般出现这种情况就是没有调用该函数声明的头文件,或者是没有对其进行外部声明。 解决办法

        1、将使用的函数的头文件包含进去。

        2、对其使用关键字"extern"声明

extern void ****(void);

        3、还有一种就是如果只在一个文件中调用函数,就将这个函数定义移到最前面也可以解决。

        5、取消TI协议栈默认功能配置

         在使用协议栈模版时,会有一些默认的功能配置,会与自行配置能有冲突。例如,协议栈模版会有对串口和按键做一些默认配置,我在自行开发时需要使用串口和按键时,尽量先把串口和按键的默认配置取消,不进行模版的默认初始化配置。

        (1)模版的默认初始化配置函数在ZMain目录下的ZMain.c文件中的main函数中,如下图。

        定位到它的定义处

        (2)以取消串口的默认初始化(就是不进行协议栈默认的串口初始化)为例。

        PS: 不能直接删除对应的初始化函数来取消默认初始化。就通过将宏定义值改为FALSE即可。

         6、注释TI协议栈默认编写的中断函数

        (1)使用某些中断时,我们会自己编写中断函数,但是TI中有些中断函数已经被默认编写,造成重复编写,会发生冲突,需要注释TI协议栈中默认编写的中断函数。以外部中断为例,我需要开发按键触发外部中断,会在自己的C文件中编写一个外部中断函数,如下图

        (2)然而,TI协议栈中对外部中断会有默认的使用,已经在其他文件中对外部中断函数有编写,我们需要将其注释,如下图

参考链接

(1)lesson7上协议栈的使用_1_哔哩哔哩_bilibili

(2)ZigBee协议栈 -- Zstack协议栈(Zstack2.5.1a)-CSDN博客

(3)zigbee之Zstack协议栈使用_z-stack协议栈-CSDN博客

(4)lesson7-3 OSAL操作系统抽象层原理_osal运行机制-CSDN博客

(5)lesson7-2 Zigbee协议栈的使用_zigbee协议栈如何创建一个新任务-CSDN博客


http://www.ppmy.cn/server/102062.html

相关文章

fetch跨域请求数据的前端设置和后端php的header设置

跨源请求,也称为CORS(Cross-Origin Resource Sharing)请求,是Web开发中常见的一种需求,允许一个网页的JavaScript代码向与该网页不同源的服务器发出HTTP请求。以下是使用JavaScript中的fetch函数进行跨源请求的一个基本…

【51单片机】让AI识别电路图,帮你进行编码(以51单片机为例)

让AI识别电路图,帮你进行编码(以51单片机为例) ​ 这里使用的AI大模型使用的是 Copilot。(两个前提:1. 科学上网、2. 有微软账号) 今天测试了一下Copilot识别图片的能力,能力还是可圈可点的。 首先准备一…

C语言日常练习 Day17

目录 一、找出一个二维数组的鞍点 二、有一篇文章,共有3行文字,每行有80个字符。要求分别统计出其中的英文大写字母、小写字母、数字、空格以及其他字符的个数 三、有一行电文,已按下面规律编译成密码:A->Z,a->z,B->Y,…

wordpress视频模板

视频背景wordpress官网主题 红色风格的wordpress主题,首页视频背景,鼠标滚动翻转展示内容,适合公司官网使用。 https://www.jianzhanpress.com/?p7288 MCN传媒wordpress主题 红色风格wordpress大视频背景主题,适合做直播业务的…

【Harmony OS 4.0】水果排行榜案例

ets/example2/Models export class FruitsData {id: stringname: stringvote: stringconstructor(id: string, name: string, vote: string) {this.id idthis.name namethis.vote vote} }ets/example2/TitleComponent // app标题子组件 import APPContext from ohos.app.a…

【ARM 芯片 安全与攻击 5.4 -- Meltdown 攻击与防御介绍】

文章目录 什么是 Meltdown 攻击?Meltdown 攻击的基本原理Meltdown 攻击代码示例Meltdown 攻击在芯片中的应用应用场景Meltdown 攻击与瞬态攻击、测信道攻击的关系针对 Meltdown 攻击的防御硬件级防御Summary什么是 Meltdown 攻击? Meltdown 攻击是一种利用处理器乱序执行(o…

【网络编程】组播的实现(C语言,linux,Ubuntu)

组播 1> 组播也是实现一对多的通信方式,对于广播而言,网络需要对每个消息进行复制转发,会占用大量的带宽,导致网络拥塞 2> 组播可以实现小范围的数据传播:将需要接收数据的接收端加入多播组,发送端…

Linux---05---用户组权限

课程回顾 vim编辑器 本章重点 文件权限 用户管理 用户组管理 一、文件权限 由于Linux是一个多人多任务的系统,因此经常会出现同一台机器同时有多个人进行操作,为了考虑每个人的隐私权以及每个人喜好的工作环境,所以文件的权限归属就至关…

50Kg大载重六旋翼无人机技术详解

50Kg大载重六旋翼无人机的机体结构设计是确保其高承载能力和飞行稳定性的基础。该机体通常采用轻质高强度的材料如碳纤维、铝合金或复合材料构建,以在保证结构强度的同时减轻整机重量。设计过程中,需考虑空气动力学原理,优化机臂布局、机身形…

Leetcode面试经典150题-189.轮转数组

解法都在代码里,不懂就留言或者私信 class Solution {public void rotate(int[] nums, int k) {/**向右轮转 1 步: [7,1,2,3,4,5,6]向右轮转 2 步: [6,7,1,2,3,4,5]向右轮转 3 步: [5,6,7,1,2,3,4]....向右轮转 7 步: [1,2,3,4,5,6,7] *//**既然反转数组的倍数是不需…

oracle使用sql生成表结构文档

oracle使用sql生成表结构文档 背景 客户要求数据资产盘点,需要提供相关表字段的说明文档,指定具体格式。手动是不可能手动的, 使用SQL实现。 要求 实现 生成脚本sql 查询所有非临时表 SELECT table_name FROM all_tables WHERE temporary N;--默认…

sp-eric靶机

端口扫描 靶机ip地址为192.168.7.46 目录扫描 访问80端口 拼接访问 /admin.php 发现登录框 测试sql注入,弱口令等,无结果 扫描目录发现了.git文件,存在源码泄漏 将其下载到kali上读取 python2 GitHack.py -u http://192.168.7.180/.git/…

深入探索CANoe的CAPL语言

概述 在汽车电子和嵌入式系统开发领域,仿真和测试是确保功能正确性和性能标准的关键步骤。Vector公司的CANoe软件是这一领域的佼佼者,它提供了一个强大的平台,用于模拟、测试和分析汽车网络,特别是CAN网络。今天,我们…

无人机电池详解!!!

娱乐型和玩具型无人机 这类无人机的电池容量通常较小,以满足短时间娱乐飞行的需求。电池容量范围一般在500mAh至3000mAh之间,轻便、易携带,适合初学者和休闲玩家。 航拍无人机 普通航拍无人机追求高续航能力,电池容量一般在500…

玩转单例模式

目录 1. 饿汉式 2. 懒汉式 3. volatile解决指令重排序 4. 反射破坏单例模式 5. 枚举创建单例模式 所谓单例模式,就是是某个类的实例对象只能被创建一次,单例模式两种实现:饿汉式和懒汉式。 1. 饿汉式 所谓饿汉式,顾名思义…

Lambda表达式与流式编程

一、Lambda表达式 1.1 什么是lambda表达式 Lambda表达式是 jdk1.8 引入的一个新特性,它是函数式编程在Java中的一种体现。也是1.8最值得学习的新特性。 1. Lambda表达式实际上就是匿名内部类的简化版本。 2. Lambda表达式是jdk1.8引入的一个最重要的新特性&…

VUE(一)——nextTick

DOM更新循环结束后执行延迟回调,在数据修改以后立即使用该方法可获取更新后的DOM。 (*问题1)DOM更新循环? VUE中使用异步执行DOM更新,在修改数据之后视图不会立即更新,而是等同一事件循环中的所有数据变化…

Java后端面试题(mq相关)(day9)

目录 为什么用MQ? 异步 、削峰、解耦1. 异步处理2. 解耦3. 削峰填谷 Exchange类型什么是死信队列?如何保证消息的可靠性?RabbitMQ中如何解决消息堆积问题?RabbitMQ中如何保证消息有序性?如何防止消息重复消费?(如何保证消息幂等…

ARM——体系结构

计算机体系结构:冯诺伊曼 哈佛 冯诺依曼结构 冯诺依曼结构,也称冯诺依曼模型或普林斯顿结构,是根据冯诺依曼提出的存储程序概念设计的计算机体系结构。其主要特点包括: 存储程序:指令与数据都…

嵌入式 | 嵌入式 Linux 系统使用摄像头

点击上方"蓝字"关注我们 01、引言 >>> 在嵌入式 Linux 系统使用摄像头 俗话说“眼见为实”,这或许是为什么近年来摄像头在嵌入式系统上快速增长的原因。它们被用于不同的场景,如: 远程监控:典型的例子是闭路电视,监控人员在监视环境(或许你所在的大楼…