ZIGBEE通讯-10.ZigBee协议栈的无线点灯
在ZIGBEE协议栈中已经自带了按键与LED的驱动与使用函数,所以只需要将按键与LED修改为使用的开发板所连接IO就可以使用了。接下来将主要分析在协议栈中按键的初始化、按键的检测以及按键事件的传递与处理。按键流程分析过后,着手于无线数据传输,而协议栈已经写好了无线广播,只需要直接调用就可以使用了。
1、修改LED灯IO
由于协议栈中按键与LED所配置IO口与使用的开发板不同,所以需要对按键LED的IO口进行修改。
在协议栈ZMain.c文件中的main函数中找到函数HAL_BOARD_INIT(),右键go to进入该函数,可以看到关于LED的配置,由于本实验使用的开发板只有两个LED,所以我们只需要修改LED1、LED2的IO口就可以了。同样的,利用右键找到LED底层定义的地方(文件)hal_board_cfg.h中,将其修改如下:
/* 1 - Green */
#define LED1_BV BV(3) // BV(0)改为BV(3)
#define LED1_SBIT P1_3 // P1_0改为P1_3
#define LED1_DDR P1DIR
#define LED1_POLARITY ACTIVE_HIGH/* 2 - Red */
#define LED2_BV BV(2) // BV(1)改为BV(2)
#define LED2_SBIT P1_2 // P1_1改为P1_2
#define LED2_DDR P1DIR
#define LED2_POLARITY ACTIVE_HIGH
LED的开与关也需要进行修改,原理同不带协议栈的无线点灯实验。在函数HAL_BOARD_INIT()中,右键进入HAL_TURN_OFF_LED1()中,可以找到两个LED的开关定义,修改如下:
#define HAL_TURN_OFF_LED1() st( LED1_SBIT = LED1_POLARITY (1); ) // 括号中0改为1
#define HAL_TURN_OFF_LED2() st( LED2_SBIT = LED2_POLARITY (1); ) // 括号中0改为1
#define HAL_TURN_OFF_LED3() st( LED3_SBIT = LED3_POLARITY (0); )
#define HAL_TURN_OFF_LED4() HAL_TURN_OFF_LED1()#define HAL_TURN_ON_LED1() st( LED1_SBIT = LED1_POLARITY (0); ) // 括号中1改为0
#define HAL_TURN_ON_LED2() st( LED2_SBIT = LED2_POLARITY (0); ) // 括号中1改为0
#define HAL_TURN_ON_LED3() st( LED3_SBIT = LED3_POLARITY (1); )
#define HAL_TURN_ON_LED4() HAL_TURN_ON_LED1()
2、按键IO修改与流程分析
在main函数中找到函数HalDriverInit(),右键进入其中,可以看到有很多外设的初始化,其他的在这里我们都不关心,我们只关注按键KEY,找到KEY的初始化函数右键进入其中,KEY_SW_6即为接下来我们要用的按键 ,JOY为摇杆按键,我们用不到,不用关心或者注释掉。右键进入到HAL_KEY_SW_6_SEL定义的地方,进行如下修改:
/* SW_6 is at P1.1 */
#define HAL_KEY_SW_6_PORT P1 // P0改为P1
#define HAL_KEY_SW_6_BIT BV(1)
#define HAL_KEY_SW_6_SEL P1SEL // P0SEL改为P1SEL
#define HAL_KEY_SW_6_DIR P1DIR // P0DIR改为P1DIR
/* SW_6 interrupts */
#define HAL_KEY_SW_6_IEN IEN2 // IEN1改为IEN2
#define HAL_KEY_SW_6_IENBIT BV(5) // 5改为4 IEN2第4位P1中断
#define HAL_KEY_SW_6_ICTL P1IEN // P0IEN改为P1IEN
#define HAL_KEY_SW_6_ICTLBIT BV(1) /* P1EN – P1.1 enable/disable bit */
#define HAL_KEY_SW_6_PXIFG P1IFG /* Interrupt flag at source */
按键初始化后, InitBoard( OB_READY )用来配置按键触发方式以及按键的回调函数,如下:
/********************************************************************** @fn InitBoard()* @brief Initialize the CC2420DB Board Peripherals* @param level: COLD,WARM,READY* @return None*/
void InitBoard( uint8 level )
{if ( level == OB_COLD ){// IAR does not zero-out this byte below the XSTACK.*(uint8 *)0x0 = 0;// Interrupts offosal_int_disable( INTS_ALL );// Check for Brown-Out resetChkReset();}else // !OB_COLD{/* Initialize Key stuff */// 配置为按键中断不使能,扫描触发 回调函数HalKeyConfig(HAL_KEY_INTERRUPT_DISABLE, OnBoard_KeyCallback);}
}
进入HalKeyConfig函数中,根据所传参数HAL_KEY_INTERRUPT_DISABLE,中断不使能的话,就会配置为定时检测,这个时候会触发HAL_KEY_EVENT事件:
else /* Interrupts NOT enabled */{HAL_KEY_SW_6_ICTL &= ~(HAL_KEY_SW_6_ICTLBIT); /* don't generate interrupt */HAL_KEY_SW_6_IEN &= ~(HAL_KEY_SW_6_IENBIT); /* Clear interrupt enable bit */osal_set_event(Hal_TaskID, HAL_KEY_EVENT); // 触发HAL_KEY_EVENT事件}
这个事件将会在HAL层事件处理函数中被处理,在OSAL_SampleApp.c文件中找到HAL层事件处理函数Hal_ProcessEvent,进入其中,可以看到这样一个判断:
if (events & HAL_KEY_EVENT) // HAL_KEY_EVENT事件{#if (defined HAL_KEY) && (HAL_KEY == TRUE)/* Check for keys */HalKeyPoll(); // 检测按键/* if interrupt disabled, do next polling */if (!Hal_KeyIntEnable){osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);}
#endif // HAL_KEYreturn events ^ HAL_KEY_EVENT;}
如果判断成功,就会调用HalKeyPoll()对按键进行扫描,进入这个扫描函数,函数前一部分都是跟摇杆按键有关的,可以直接删除或者注释,或者将下部分对KEY_SW_6按键的判断放在前面,不然会影响按键的检测,如下:
/*************************************************************************************************** @fn HalKeyPoll** @brief Called by hal_driver to poll the keys** @param None** @return None**************************************************************************************************/
void HalKeyPoll (void)
{uint8 keys = 0;if (HAL_PUSH_BUTTON1()) // 按键检测判断{keys |= HAL_KEY_SW_6;}/* Invoke Callback if new keys were depressed */if (keys && (pHalKeyProcessFunction)){(pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL); // 调用回调函数}
}
由于官方板按键按下去是高电平,所以检测if判断里读取按键状态的函数需要进行修改,右键goto之后,将PUSH1_POLARITY的定义以及PUSH1_SBIT的定义进行修改,如下:
/* S1 */
#define PUSH1_BV BV(1)
#define PUSH1_SBIT P1_1 // P0_1 改为 P1_1
#define PUSH1_POLARITY ACTIVE_LOW // ACTIVE_HIGH改为ACTIVE_LOW
最后函数调用按键回调函数将按键检测值传进去,又回到了一开始初始化时配置的回调函数。在回调函数OnBoard_KeyCallback()中,我们并不会在这里对按键事件进行处理,而是通过函数OnBoard_SendKeys( keys, shift )将检测值又传递到了其他地方,如下:
/********************************************************************** @fn OnBoard_SendKeys** @brief Send "Key Pressed" message to application.** @param keys - keys that were pressed* state - shifted** @return status*********************************************************************/
uint8 OnBoard_SendKeys( uint8 keys, uint8 state )
{keyChange_t *msgPtr;if ( registeredKeysTaskID != NO_TASK_ID ){// Send the address to the taskmsgPtr = (keyChange_t *)osal_msg_allocate( sizeof(keyChange_t) );if ( msgPtr ){msgPtr->hdr.event = KEY_CHANGE; // 按键事件msgPtr->state = state;msgPtr->keys = keys;osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr ); // 把事件发往绑定的任务}return ( ZSuccess );}elsereturn ( ZFailure );
}
在这个函数里,又将按键检测值标记为KEY_CHANGE事件,通过osal_msg_send()函数将事件打包发给了registeredKeysTaskID任务,registeredKeysTaskID为任务号,通过RegisterForKeys()进行注册,注册在APP层里面,现在我们去APP层的初始化任务中查找一下,可以通过osal_init_system()函数找到osalInitTasks()函数,在任务初始化函数中调用了APP层的初始化函数,在SampleApp_Init()中调用了RegisterForKeys(),把按键事件绑定在了APP层,如下:
// Register for all key events - This app will handle all key eventsRegisterForKeys( SampleApp_TaskID ); // 这句代码在SampleApp_Init()中
所以按键事件最后会到达APP层,被APP层事件处理函数处理,如下图:
最后如果事件判断成功,就会调用SampleApp_HandleKeys()函数,在这个函数中,我们就可以对按键事件作出相应,比如接下来我们要做的,通过调用无线发送函数,发送一个数据,如下:
void SampleApp_HandleKeys( uint8 shift, uint8 keys )
{(void)shift; // Intentionally unreferenced parameterif(keys & HAL_KEY_SW_6){SampleApp_SendPeriodicMessage(); // 广播发送一个数据}
}
在广播发送函数中,将会发送出去一个0,如下:
void SampleApp_SendPeriodicMessage( void )
{if ( AF_DataRequest( &SampleApp_Periodic_DstAddr, &SampleApp_epDesc,SAMPLEAPP_PERIODIC_CLUSTERID, // 数据类型ID 现在为表示广播1, // 发送数据长度(uint8*)&SampleAppPeriodicCounter, // 发送数据的地址 变量值为0&SampleApp_TransID,AF_DISCV_ROUTE,AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ){}else{// Error occurred in request to send.}
}
3、LED灯响应
发送部分完成之后,再来看接收部分。小灯响应部分比较简单,首先需要关注数据的来源,来源就是无线广播接收,这个事件的处理也在APP层事件处理函数中,如图:
在事件处理函数中,会调用SampleApp_MessageMSGCB( MSGpkt )函数对接到的数据包进行处理,判断如果接到的数据为0,即为接收正确,就可以让小灯响应了,如下:
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{uint16 flashTime;switch ( pkt->clusterId ){case SAMPLEAPP_PERIODIC_CLUSTERID: // 判断为广播数据if( *pkt->cmd.Data == 0) // 从数据包中找到用户数据{HalLedSet(1,HAL_LED_MODE_TOGGLE); // 切换LED的状态}break;case SAMPLEAPP_FLASH_CLUSTERID:flashTime = BUILD_UINT16(pkt->cmd.Data[1], pkt->cmd.Data[2] );HalLedBlink( HAL_LED_4, 4, 50, (flashTime / 4) );break;}
}
从数据包中找到用户数据有必要说明一下,首先函数传进来的参数类型为afIncomingMSGPacket_t,这个结构体内存放了所有的数据,如下:
typedef struct
{osal_event_hdr_t hdr; /* OSAL Message header */uint16 groupId; /* Message's group ID - 0 if not set */uint16 clusterId; /* Message's cluster ID */afAddrType_t srcAddr; /* Source Address, if endpoint is STUBAPS_INTER_PAN_EP,it's an InterPAN message */uint16 macDestAddr; /* MAC header destination short address */uint8 endPoint; /* destination endpoint */uint8 wasBroadcast; /* TRUE if network destination was a broadcast address */uint8 LinkQuality; /* The link quality of the received data frame */uint8 correlation; /* The raw correlation value of the received data frame */int8 rssi; /* The received RF power in units dBm */uint8 SecurityUse; /* deprecated */uint32 timestamp; /* receipt timestamp from MAC */uint8 nwkSeqNum; /* network header frame sequence number */afMSGCommandFormat_t cmd; /* Application Data 用户数据*/
} afIncomingMSGPacket_t;
这个结构体里面又包含了一个结构体afMSGCommandFormat_t,这个结构体用于存放用户数据,如下:
typedef struct
{uint8 TransSeqNumber;uint16 DataLength; // Number of bytes in TransDatauint8 *Data; // 数据
} afMSGCommandFormat_t;
而我们通过无线发送的数据就在以Data为首地址的内存中。
实验完成,将程序分别下载到协调器和终端节点。点击协调器的按键,终端节点的LED状态会随之切换。
ZIGBEE通讯-10.ZigBee协议栈的无线点灯相关推荐
- ZIGBEE通讯-7.ZigBee协议栈简介
想要学习协议栈,必须先知道协议是什么.协议定义的是一系列的通信标准,通信双方需要共同按照这一标准进行正常的数据收发,而协议栈是协议的具体实现形式,通俗的理解为用代码实现的函数库,以便于开发人员调用. ...
- Zigbee 学习计划——第4天——基于CC2530 Basic RF的无线点灯
就像Hellow world一样,无线点灯也是Zigbee的经典例子.根据<网蜂实战演练>中介绍,虽然还没有用到协议栈,但它体现出来的数据发送.接收和用协议栈是差不多的,而且TI公司的Ba ...
- zigbee无线传感网技术与应用开发v2.0_物联网通讯协议——Zigbee
一.什么是Zigbee ZigBee是一种新兴的短距离.低速率无线网络技术.具有成本低.体积小.能量消耗小和传输速率低等优势. ZigBee是介于无线标识技术和蓝牙之间的一种技术,主要用于近距离无线连 ...
- ZigBee远程无线点灯
ZigBee远程无线点灯 一.任务要求: 二.任务逻辑分析: 三.逻辑代码实现: 四.开发中注意的事项: 一.任务要求: 大棚种植区改造过程中提出新的需求,要求部分设备需要支持短距离无线 通讯控制风扇 ...
- Zigbee通讯之开发篇(基于TI 的Z-Stack)
1.Zigbee协议和Z-Stack Zigbee协议和Z-Stack是什么关系?这可能是初学Zigbee同学想知道的问题.给大家举个例子吧,我们生活中使用的插排是要符合一定的标准的,现在国家标准 ...
- Zigbee通讯漫谈(初次见面)
郑重声明:以下文章内容适合初学Zigbee的童鞋们,大神请略过-- 1 缘由: 工作中听说过Zigbee技术,只是知道是一种无线通讯技术,具体技术细节及使用都不是很清楚.不料,一个项目中需要使用Z ...
- zigbee通讯技术复习笔记
这门课对于我一个学嵌入式的来说,还是比较重要的,所以我还是以老师给出的大纲为主体,好好复习一下! 题型:选择题24x1.5 判断10x1 填空15x1 简答4x5 程序1x5 另外一个设计题1x14 ...
- 【ember zigbee】序章:协议栈相关文档学习笔记
原文地址:https://blog.csdn.net/tainjau/article/details/90648114 文章目录 写在前面 一.材料出处 二.文档解析 2.1.EZSP Protoco ...
- zigbee zcl规范及其协议栈实现3 读取服务器端属性值
zigbee zcl规范及其协议栈实现2 中有介绍 对通用命令的处理,按照那个思路和信息流程添加读取服务器端属性值的功能 客户端samplesw想要知道与自己的12号端点SAMPLESW_ENDP ...
最新文章
- 脑细胞膜等效神经网路
- JMeter入门,测试计划编写(http请求)
- [C++11]自动类型推导auto
- 每卖出一部新款iPhone SE,苹果就要赚1500元?
- 常用的关系型数据库的优劣与选择
- 当开源奔向物流,阿里云 PolarDB-X 数据库与韵达携手的背后
- 批处理查找html,批处理(bat)实现全盘搜索指定文件获取其完整路径方法大全,bat大全分享...
- React路由配置:React Router
- spring boot2整合dubbox全注解
- 阿里云 centos 7.6 安装和启动redis 6
- 工作中windows客户端常见问题
- idea 字体颜色设置 + 背景图片
- 中国国际电子商务中心与易观分析联合发布:2021年4季度全国网络零售发展指数同比增长0.6%
- vbs教程《弹出窗口》
- 你拍一我拍一上学得学计算机,儿歌你拍一我拍一
- 轻松编写您自己的拖拉机算法,进行算法大战
- 结构化数据 VS 半结构化数据 VS 非结构化数据
- 计算机主硬盘,电脑是固态和机械双盘系统在固态为什么显示主硬盘是机械盘
- 去除重复字母Python解法
- 论文超详细精读|五千字:STGR