使用单播模式:终端(按键每按一次发送字符串)—>协调器(通过串口打印接收到的数据)
- 单播:在zigbee网络里,模块之间要进行通信,发射模块非常明确知道接收模块网络地址,以这个地址发送数据接收模块。
- ZigBee模块的地址特点:模块在入网的时候,父节点随机分配网络地址给子节点。但是协调器模块在网络里面的网络地址永远是0x0000。(终端—>协调器)
- 本次只要使用两个文件代码+两块开发板(分别下载发送 、接收函数)
注:
a.在下载程序的时候需要选择不同的模式下载。
b.发送模块代码是选择 终端 修改。
c.接收模块代码是选择 协调器 修改。
发送模块:
S5按下一次,向0x0000发送"Hello World\n"
#define LEDApp_MY_EVT 0x0004
if ( events & LEDApp_MY_EVT )
{
if(P0_4 == 0)//S5
{
char theMessageData[] = "Hello World\n";
LED02 =~LED02;
LEDApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
LEDApp_DstAddr.addr.shortAddr = 0x0000;
// Take the first endpoint, Can be changed to search through endpoints
LEDApp_DstAddr.endPoint = LEDApp_ENDPOINT;
//发送 (byte)osal_strlen( theMessageData ) + 1表示发送的字节
AF_DataRequest( &LEDApp_DstAddr, &LEDApp_epDesc,
LEDApp_CLUSTERID,
(byte)osal_strlen( theMessageData ) + 1,
(byte *)&theMessageData,
&LEDApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
}
if(P0_5 == 0)//S5
{
LED02 =~LED02;
}
接收模块:
通过串口打印接收的信息
static void LEDApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
switch ( pkt->clusterId )
{
case LEDApp_CLUSTERID:
// "the" message
#if defined( LCD_SUPPORTED )
HalLcdWriteScreen( (char*)pkt->cmd.Data, "rcvd" );
#elif defined( WIN32 )
WPRINTSTR( pkt->cmd.Data );
#endif
// pkt->cmd.DataLength;//得到接收数据的长度
// pkt->cmd.Data[0];//首地址
UartTX_Send_String( pkt->cmd.Data,pkt->cmd.DataLength);//串口打印
break;
}
}
我们可以知道LEDApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
是在《LEDApp.c 》->uint16 LEDApp_ProcessEvent( uint8 task_id, uint16 events )
,里面调用的;也就是说当接收到消息后,就将进入LEDApp_MessageMSGCB( MSGpkt );
处理。
效果:
附:
- 按键 key.c key.h S5–>P04 S7–>P05
key.c
#include <iocc2530.h>
#include "key.h"
#include "LEDApp.h"
#include "OSAL_Timers.h"
extern byte LEDApp_TaskID;
//p0.5 下降沿 0 0 1 0 0000
//p0.4 下降沿 0 0 0 1 0000
void keyio_init(void)
{
P0SEL &=~0x30;//通用
P0DIR &=~0x30;//输入
P0INP |= 0x30; //上拉
P0IEN |= 0x30; //P01设置为中断方式
PICTL |= 0X01; //下降沿触发
IEN1 |= 0X20; // P0设置为中断方式;
P0IFG = 0x00; //初始化中断标志位
}
#pragma vector = P0INT_VECTOR
__interrupt void P0_ISR(void)
{
if(P0IFG > 0X00)//按键中断
{
osal_start_timerEx(LEDApp_TaskID,LEDApp_MY_EVT,25);
}
P0IFG = 0;
P0IF = 0; //清中断标志
}
key.h
#ifndef KEY_H
#define KEY_H
void keyio_init(void);
#endif /* KEY_H */
注意:如果自己使用的引脚和官方指定的引脚不同时。
a. 使用自己写的代码添加自己初始化函数尽量在osal_start_system();
之前,官方自带是函数后。
b.可以修改ZMain.cHalDriverInit();
–>对应的条件;
我这里是屏蔽了官方key初始化,或者使能#if (defined HAL_KEY) && (HAL_KEY == TRUE)
条件不成立,也就是说把《hal_board_cfg.h 448行》#define HAL_KEY TRUE
改为#define HAL_KEY FALSE
c.最好必须屏蔽官方库的按键中断函数,在《hal_key.c 470行-最后》HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR );HAL_ISR_FUNCTION( halKeyPort2Isr, P2INT_VECTOR )
d.当然可以去修改官方定义的引脚,。。。。。《hal_key.c 开头处》
2. 串口 myuart.c myuart.h
myuart.c
#include <iocc2530.h>
#include "myuart.h"
char Txdata[25]="HELLO! zigbee!\n";
void Delay_us(unsigned char time)
{
while(time--)
{
asm("nop");
asm("nop");
asm("nop");
}
}
void UartTX_Send_String(char *Data,int len)
{
int j;
for(j=0;j<len;j++)
{
U0DBUF = *Data++;
while(UTX0IF == 0);
UTX0IF = 0;
}
}
void myuart_init()
{
PERCFG &=~0x01;//外部设备控制
P0SEL |= 0X0C;//通用I/O口
P2DIR &= ~0XC0;//P0优先作为UART0
U0CSR |= 0x80;//UART方式
U0GCR |= 11;
U0BAUD |= 216; //波特率设为115200
UTX0IF = 0; //UART0 TX中断标志初始置位0
}
myuart.h
#ifndef MYUART_H
#define MYUART_H
void Delay_us(unsigned char time);
void UartTX_Send_String(char *Data,int len);
void myuart_init();
#endif /* MYUART_H */
注意:我这只是修改了HAL_UART的宏定义
端点:
- 它是一个字节编号(0-255)的,数据接收和发送的基本单元,在模块通信的时候,发送模块必须指定收发双方模块的网络地址和端点。
- 端点要使用必须要和模块里的某个任务挂钩定义。
首先每一个端点可以看成是一个1个字节数字编号的开有一扇门的房间,数据最终的目标是进入到无线数据包指定任务的目标房间,而取无线数据这个相关的任务代码在任务处理事件函数里,TI协议栈有那么多的任务事件处理函数,所以必须指定在哪个任务事件处理函数,来取这个无线数据包里面的有用数据。 - 一个端点只能挂钩在一个任务上,而一个任务可以挂钩多个端点,且端点对所有的任务是公用的,定义一个就少一个。
注:一个端点加入可以挂钩在多个任务上,那么接收模块接到无线数据时候,这个时候一个端点有多个任务事件处理函数去处理(不合理);一个任务上挂多个端点,发送给协调器模块的多端点的数据都会进入到应用层任务事件处理函数里,仅仅做个判断到底是在哪个应用层就OK。 - 接收模块 定义端点和任务挂钩的基础实验代码
在《LEDApp.c 188行void LEDApp_Init( uint8 task_id )
里》
// Fill out the endpoint description.
LEDApp_epDesc.endPoint = LEDApp_ENDPOINT;//LEDApp_ENDPOINT=10的 端点编号为10
LEDApp_epDesc.task_id = &LEDApp_TaskID;//和应用层挂钩 10号端点
LEDApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t *)&LEDApp_SimpleDesc;//更加详细描述端点情况。
LEDApp_epDesc.latencyReq = noLatencyReqs;//必须调用才能完成整个挂钩操作
// Register the endpoint description with the AF
afRegister( &LEDApp_epDesc );
注:此次实验主要 0xa406 10号 0x0000 10号无线数据包发出以后,首先目标协调器模块的网络地址0x0000就对上,协调器在底层可以拿到这个无线数据包任务,判断10号端点房间已经定义且和我们应用层任务caseAF_INCOMING_MSG_CMD:LEDApp_MessageMSGCB( MSGpkt ); break;
在这个消息UartTX_Send_String( pkt->cmd.Data,pkt->cmd.DataLength);
通过串口把接收到书记打印。
5. 簇(CLUSTERID)接收端的最终目标者,2字节,在射频发送的时候,必须设定指定的接收目标;
注:定义多个端点,多个目标应该写为
6. 接收模块 定义端点和任务挂钩的基础实验代码
在发送模块代码里,我们用的数据发送源端点也是10,所以我们定义这个10号端点也挂钩应用层任务,原则上,外部给我们终端模块10号端点,来数据,也会进入终端应用层任务事件处理函数里。而我们这个端点仅仅作为发送模块,但是我们也要使用10端点,必须要挂钩定义。
char theMessageData[] = "Hello World\n";
LED02 =~LED02;
LEDApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
LEDApp_DstAddr.addr.shortAddr = 0x0000;//接收模块的网络地址
// Take the first endpoint, Can be changed to search through endpoints
LEDApp_DstAddr.endPoint = LEDApp_ENDPOINT;//接收模块的端点号
//LEDApp_epDesc结构体 端点描述符有源端点的信息,延时10
//发送 (byte)osal_strlen( theMessageData ) + 1表示发送的字节
AF_DataRequest( &LEDApp_DstAddr, &LEDApp_epDesc,
LEDApp_CLUSTERID,//目标端点簇,房间的连接端点数据宏是1,2个字节,所以在射频是0x0001
(byte)osal_strlen( theMessageData ) + 1,//发送字符串的长度
(byte *)&theMessageData,//字符串内容数组的首地址
&LEDApp_TransID,//记录我们应用层任务发送的数据包个数
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
**属性:**在应用层有用的数据载荷,做专门规定最小单元。