【转】如何建立cc2430串口与上位机通信的任务
2010-10-25 21:44
671 查看
作者:吴家华
引文地址:http://nireus.uueasy.com/read-htm-tid-12.html
在一些工业测控领域会用到串口与上位机进行通信,以获取实时的数据和控制信息。那么上位机和串口是如何进行通信的呢?本文是基于z-stack-1.4.3-1.2.1的Utilities/SerialApp的例子。
OSAL_SerialApp.c是应用于操作系统的接口,先不用看,首先看应用程序SerialApp.c里的外部函数:extern
void SerialApp_Init( byte task_id
);
extern UINT16
SerialApp_ProcessEvent( byte task_id, UINT16 events
);系统主函数就是调用这两个函数来实现串口功能的。按照TI的编程风格,后面带init(initial)的一定是初始化函数,完成应用的一些变量的初始化和一些功能的配置。后面带ProcessEvent则是进程的扫描函数。
串口应用执行的流程:串口接收到数据包或者其他应用程序有串口发送请求 对串口的task对应的event置位->
SerialApp_ProcessEvent( uint8 task_id, UINT16 events )轮训事件
->SerialApp_ProcessMSGCmd,SerialApp_ProcessZDOMsgs,SerialApp_HandleKey,
这三个函数完成相应函数功能具体调用。
void SerialApp_Init( uint8 task_id
)
{
halUARTCfg_t uartConfig;
SerialApp_MsgID =
0x00;
SerialApp_SeqRx = 0xC3;
SerialApp_TaskID =
task_id;
SerialApp_DstAddr.endPoint =
0;//
SerialApp_DstAddr.addr.shortAddr = 0;//
SerialApp_DstAddr.addrMode =
(afAddrMode_t)AddrNotPresent;//
SerialApp_RspDstAddr.endPoint =
0;//
SerialApp_RspDstAddr.addr.shortAddr =
0;//
SerialApp_RspDstAddr.addrMode =
(afAddrMode_t)AddrNotPresent;//
afRegister( (endPointDesc_t
*)&SerialApp_epDesc );//端口初始化,注册端口
RegisterForKeys( task_id
);//注册按键时间
uartConfig.configured = TRUE; // 2430 don't
care.
uartConfig.baudRate =
SERIAL_APP_BAUD;//设置串口通信的波特率
uartConfig.flowControl =
TRUE;
uartConfig.flowControlThreshold =
SERIAL_APP_THRESH;
uartConfig.rx.maxBufSize =
SERIAL_APP_RX_MAX;//最大接收字节
uartConfig.tx.maxBufSize =
SERIAL_APP_TX_MAX;//最大发送字节
uartConfig.idleTimeout =
SERIAL_APP_IDLE; // 2430 don't care.
uartConfig.intEnable =
TRUE; // 2430 don't care.
#if
SERIAL_APP_LOOPBACK
uartConfig.callBackFunc =
rxCB_Loopback;
#else
uartConfig.callBackFunc =
rxCB;
#endif
HalUARTOpen (SERIAL_APP_PORT, &uartConfig);//打开串口
#if
defined ( LCD_SUPPORTED )
HalLcdWriteString( "SerialApp2", HAL_LCD_LINE_2
);
#endif
ZDO_RegisterForZDOMsg( SerialApp_TaskID, End_Device_Bind_rsp
);
ZDO_RegisterForZDOMsg( SerialApp_TaskID, Match_Desc_rsp
);
}
串口任务的初始化函数,完成功能:初始化TaskID,注册endpoint,对串口进行设置,打开串口。注册设备对象消息。
在来看看UINT16
SerialApp_ProcessEvent( uint8 task_id, UINT16 events
)串口进程轮询函数。
{
if ( events
& SYS_EVENT_MSG )
{
afIncomingMSGPacket_t *MSGpkt;
while ( (MSGpkt = (afIncomingMSGPacket_t
*)osal_msg_receive(
SerialApp_TaskID )) )
{
switch (
MSGpkt->hdr.event )
{
case
ZDO_CB_MSG://zdo层接收到消息
SerialApp_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt
);
break;
case KEY_CHANGE:
SerialApp_HandleKeys( ((keyChange_t
*)MSGpkt)->state,
((keyChange_t *)MSGpkt)->keys
);
break;
case
AF_INCOMING_MSG_CMD//接收到命令,然后执行 这里就要说说了,zigbee协议信息的传递有两种方式:消息和命令,消息长度不限,命令的大小则严格规定
SerialApp_ProcessMSGCmd( MSGpkt
);://执行进来消息命令的回调函数
break;
default:
break;
}
osal_msg_deallocate( (uint8 *)MSGpkt ); //
Release the memory.
}
//
Return unprocessed events
return ( events ^ SYS_EVENT_MSG
);
}//系统消息事件
if ( events & SERIALAPP_MSG_SEND_EVT
)
{
SerialApp_SendData( otaBuf, otaLen );
return ( events ^ SERIALAPP_MSG_SEND_EVT
);
}//串口发送请求,这里是指串口通过CC2430发送到灵位一个无线设备
if ( events &
SERIALAPP_MSG_RTRY_EVT )
{
if ( --rtryCnt )
{
AF_DataRequest(
&SerialApp_DstAddr,
(endPointDesc_t
*)&SerialApp_epDesc,
SERIALAPP_CLUSTERID1, otaLen,
otaBuf,
&SerialApp_MsgID, 0, AF_DEFAULT_RADIUS );
osal_start_timerEx(
SerialApp_TaskID, SERIALAPP_MSG_RTRY_EVT,
SERIALAPP_MSG_RTRY_TIMEOUT
);
}
else
{
FREE_OTABUF();
}
return ( events ^
SERIALAPP_MSG_RTRY_EVT
);
}//重发事件,这里搞了很长时间才搞明白是什么意思,如果callback返回没有发送成功的话,cc2430就会重发信息,rtryCnt是重发的次数。
if ( events & SERIALAPP_RSP_RTRY_EVT
)
{
afStatus_t stat = AF_DataRequest(
&SerialApp_RspDstAddr,
(endPointDesc_t
*)&SerialApp_epDesc,
SERIALAPP_CLUSTERID2,
SERIAL_APP_RSP_CNT,
rspBuf,
&SerialApp_MsgID, 0, AF_DEFAULT_RADIUS );
if ( stat != afStatus_SUCCESS
)
{
osal_start_timerEx( SerialApp_TaskID,
SERIALAPP_RSP_RTRY_EVT,
SERIALAPP_RSP_RTRY_TIMEOUT );
}
return ( events ^ SERIALAPP_RSP_RTRY_EVT
);
}//回应重发事件,说实在的这个协议栈搞这么多冬冬挺烦人的,这也是为了防止阻塞丢包嘛!~
#if
SERIAL_APP_LOOPBACK
if ( events & SERIALAPP_TX_RTRY_EVT )
{
if (
rxLen )
{
if ( !HalUARTWrite( SERIAL_APP_PORT, rxBuf, rxLen )
)
{
osal_start_timerEx( SerialApp_TaskID,
SERIALAPP_TX_RTRY_EVT,
SERIALAPP_TX_RTRY_TIMEOUT
);
}
else
{
rxLen = 0;
}
}
return ( events ^
SERIALAPP_TX_RTRY_EVT );
}
#endif
return ( 0 ); // Discard unknown
events.
}
由上面的程序可以看出,在串口Task中定义了五个事件:SYS_EVENT_MSG,SERIALAPP_MSG_SEND_EVT,SERIALAPP_MSG_RTRY_EVT,SERIALAPP_RSP_RTRY_EVT,SERIALAPP_TX_RTRY_EVT,其中,SYS_EVENT_MSG是系统时间,每个任务中都有,它是完成系统任务之间信息的交换。
SERIALAPP_MSG_SEND_EVT
//数据发送
SERIALAPP_MSG_RTRY_EVT
//数据重发
SERIALAPP_RSP_RTRY_EVT
//回应重发
框架程序读懂了,接下来就是实现我的串口功能了。我要实现的串口功能很简单,协调器,也就是采集器采集到的数据通过串口传给上位机,上位机的指令通过串口传给采集器,然后采集器再发给目标终端。
现在要把串口任务加到我们的工程里面去了。
怎么加进去呢?首先,把SerialApp。c和SerialApp。h加到工程的souce文件夹里面,然后
分三步:第一,把初始化函数SerialApp_Init(),加入到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++
);
#endif
APS_Init( taskID++ );
ZDApp_Init( taskID++ );
SAPI_Init(
taskID++);
SerialApp_Init(taskID);
}在这里操作系统会分配任务ID
第二步,把串口轮询函数SerialApp_ProcessEvent()的函数名,加入任务数组
const
pTaskEventHandlerFn tasksArr[] =
{
macEventLoop,
nwk_event_loop,
Hal_ProcessEvent,
#if defined(
MT_TASK
)
MT_ProcessEvent,
#endif
APS_event_loop,
ZDApp_event_loop,
SAPI_ProcessEvent,
SerialApp_ProcessEvent
};
第三步:修改执行程序
在修改执行程序时,首先我们要定义好自己的事件,和相应数据、命令、数据结构。再定义相应的功能实现函数。
先定义事件1.、coordinater接收到传感器数据事件,要上传给上位机
事件二2、coordinator接收到上位机发送来的命令,
引文地址:http://nireus.uueasy.com/read-htm-tid-12.html
在一些工业测控领域会用到串口与上位机进行通信,以获取实时的数据和控制信息。那么上位机和串口是如何进行通信的呢?本文是基于z-stack-1.4.3-1.2.1的Utilities/SerialApp的例子。
OSAL_SerialApp.c是应用于操作系统的接口,先不用看,首先看应用程序SerialApp.c里的外部函数:extern
void SerialApp_Init( byte task_id
);
extern UINT16
SerialApp_ProcessEvent( byte task_id, UINT16 events
);系统主函数就是调用这两个函数来实现串口功能的。按照TI的编程风格,后面带init(initial)的一定是初始化函数,完成应用的一些变量的初始化和一些功能的配置。后面带ProcessEvent则是进程的扫描函数。
串口应用执行的流程:串口接收到数据包或者其他应用程序有串口发送请求 对串口的task对应的event置位->
SerialApp_ProcessEvent( uint8 task_id, UINT16 events )轮训事件
->SerialApp_ProcessMSGCmd,SerialApp_ProcessZDOMsgs,SerialApp_HandleKey,
这三个函数完成相应函数功能具体调用。
void SerialApp_Init( uint8 task_id
)
{
halUARTCfg_t uartConfig;
SerialApp_MsgID =
0x00;
SerialApp_SeqRx = 0xC3;
SerialApp_TaskID =
task_id;
SerialApp_DstAddr.endPoint =
0;//
SerialApp_DstAddr.addr.shortAddr = 0;//
SerialApp_DstAddr.addrMode =
(afAddrMode_t)AddrNotPresent;//
SerialApp_RspDstAddr.endPoint =
0;//
SerialApp_RspDstAddr.addr.shortAddr =
0;//
SerialApp_RspDstAddr.addrMode =
(afAddrMode_t)AddrNotPresent;//
afRegister( (endPointDesc_t
*)&SerialApp_epDesc );//端口初始化,注册端口
RegisterForKeys( task_id
);//注册按键时间
uartConfig.configured = TRUE; // 2430 don't
care.
uartConfig.baudRate =
SERIAL_APP_BAUD;//设置串口通信的波特率
uartConfig.flowControl =
TRUE;
uartConfig.flowControlThreshold =
SERIAL_APP_THRESH;
uartConfig.rx.maxBufSize =
SERIAL_APP_RX_MAX;//最大接收字节
uartConfig.tx.maxBufSize =
SERIAL_APP_TX_MAX;//最大发送字节
uartConfig.idleTimeout =
SERIAL_APP_IDLE; // 2430 don't care.
uartConfig.intEnable =
TRUE; // 2430 don't care.
#if
SERIAL_APP_LOOPBACK
uartConfig.callBackFunc =
rxCB_Loopback;
#else
uartConfig.callBackFunc =
rxCB;
#endif
HalUARTOpen (SERIAL_APP_PORT, &uartConfig);//打开串口
#if
defined ( LCD_SUPPORTED )
HalLcdWriteString( "SerialApp2", HAL_LCD_LINE_2
);
#endif
ZDO_RegisterForZDOMsg( SerialApp_TaskID, End_Device_Bind_rsp
);
ZDO_RegisterForZDOMsg( SerialApp_TaskID, Match_Desc_rsp
);
}
串口任务的初始化函数,完成功能:初始化TaskID,注册endpoint,对串口进行设置,打开串口。注册设备对象消息。
在来看看UINT16
SerialApp_ProcessEvent( uint8 task_id, UINT16 events
)串口进程轮询函数。
{
if ( events
& SYS_EVENT_MSG )
{
afIncomingMSGPacket_t *MSGpkt;
while ( (MSGpkt = (afIncomingMSGPacket_t
*)osal_msg_receive(
SerialApp_TaskID )) )
{
switch (
MSGpkt->hdr.event )
{
case
ZDO_CB_MSG://zdo层接收到消息
SerialApp_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt
);
break;
case KEY_CHANGE:
SerialApp_HandleKeys( ((keyChange_t
*)MSGpkt)->state,
((keyChange_t *)MSGpkt)->keys
);
break;
case
AF_INCOMING_MSG_CMD//接收到命令,然后执行 这里就要说说了,zigbee协议信息的传递有两种方式:消息和命令,消息长度不限,命令的大小则严格规定
SerialApp_ProcessMSGCmd( MSGpkt
);://执行进来消息命令的回调函数
break;
default:
break;
}
osal_msg_deallocate( (uint8 *)MSGpkt ); //
Release the memory.
}
//
Return unprocessed events
return ( events ^ SYS_EVENT_MSG
);
}//系统消息事件
if ( events & SERIALAPP_MSG_SEND_EVT
)
{
SerialApp_SendData( otaBuf, otaLen );
return ( events ^ SERIALAPP_MSG_SEND_EVT
);
}//串口发送请求,这里是指串口通过CC2430发送到灵位一个无线设备
if ( events &
SERIALAPP_MSG_RTRY_EVT )
{
if ( --rtryCnt )
{
AF_DataRequest(
&SerialApp_DstAddr,
(endPointDesc_t
*)&SerialApp_epDesc,
SERIALAPP_CLUSTERID1, otaLen,
otaBuf,
&SerialApp_MsgID, 0, AF_DEFAULT_RADIUS );
osal_start_timerEx(
SerialApp_TaskID, SERIALAPP_MSG_RTRY_EVT,
SERIALAPP_MSG_RTRY_TIMEOUT
);
}
else
{
FREE_OTABUF();
}
return ( events ^
SERIALAPP_MSG_RTRY_EVT
);
}//重发事件,这里搞了很长时间才搞明白是什么意思,如果callback返回没有发送成功的话,cc2430就会重发信息,rtryCnt是重发的次数。
if ( events & SERIALAPP_RSP_RTRY_EVT
)
{
afStatus_t stat = AF_DataRequest(
&SerialApp_RspDstAddr,
(endPointDesc_t
*)&SerialApp_epDesc,
SERIALAPP_CLUSTERID2,
SERIAL_APP_RSP_CNT,
rspBuf,
&SerialApp_MsgID, 0, AF_DEFAULT_RADIUS );
if ( stat != afStatus_SUCCESS
)
{
osal_start_timerEx( SerialApp_TaskID,
SERIALAPP_RSP_RTRY_EVT,
SERIALAPP_RSP_RTRY_TIMEOUT );
}
return ( events ^ SERIALAPP_RSP_RTRY_EVT
);
}//回应重发事件,说实在的这个协议栈搞这么多冬冬挺烦人的,这也是为了防止阻塞丢包嘛!~
#if
SERIAL_APP_LOOPBACK
if ( events & SERIALAPP_TX_RTRY_EVT )
{
if (
rxLen )
{
if ( !HalUARTWrite( SERIAL_APP_PORT, rxBuf, rxLen )
)
{
osal_start_timerEx( SerialApp_TaskID,
SERIALAPP_TX_RTRY_EVT,
SERIALAPP_TX_RTRY_TIMEOUT
);
}
else
{
rxLen = 0;
}
}
return ( events ^
SERIALAPP_TX_RTRY_EVT );
}
#endif
return ( 0 ); // Discard unknown
events.
}
由上面的程序可以看出,在串口Task中定义了五个事件:SYS_EVENT_MSG,SERIALAPP_MSG_SEND_EVT,SERIALAPP_MSG_RTRY_EVT,SERIALAPP_RSP_RTRY_EVT,SERIALAPP_TX_RTRY_EVT,其中,SYS_EVENT_MSG是系统时间,每个任务中都有,它是完成系统任务之间信息的交换。
SERIALAPP_MSG_SEND_EVT
//数据发送
SERIALAPP_MSG_RTRY_EVT
//数据重发
SERIALAPP_RSP_RTRY_EVT
//回应重发
框架程序读懂了,接下来就是实现我的串口功能了。我要实现的串口功能很简单,协调器,也就是采集器采集到的数据通过串口传给上位机,上位机的指令通过串口传给采集器,然后采集器再发给目标终端。
现在要把串口任务加到我们的工程里面去了。
怎么加进去呢?首先,把SerialApp。c和SerialApp。h加到工程的souce文件夹里面,然后
分三步:第一,把初始化函数SerialApp_Init(),加入到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++
);
#endif
APS_Init( taskID++ );
ZDApp_Init( taskID++ );
SAPI_Init(
taskID++);
SerialApp_Init(taskID);
}在这里操作系统会分配任务ID
第二步,把串口轮询函数SerialApp_ProcessEvent()的函数名,加入任务数组
const
pTaskEventHandlerFn tasksArr[] =
{
macEventLoop,
nwk_event_loop,
Hal_ProcessEvent,
#if defined(
MT_TASK
)
MT_ProcessEvent,
#endif
APS_event_loop,
ZDApp_event_loop,
SAPI_ProcessEvent,
SerialApp_ProcessEvent
};
第三步:修改执行程序
在修改执行程序时,首先我们要定义好自己的事件,和相应数据、命令、数据结构。再定义相应的功能实现函数。
先定义事件1.、coordinater接收到传感器数据事件,要上传给上位机
事件二2、coordinator接收到上位机发送来的命令,
相关文章推荐
- 如何建立cc2430串口与上位机通信的任务
- [置顶] stm32+ucosII建立串口通信等多任务的实现
- CC2530串口通信中如何接收上位机的一串字符串
- CC2530串口通信中如何接收上位机的一串字符串
- 如何建立多线程之间的消息通信
- LabVIEW上位机与串口通信
- 如何在windows系统下用串口通信完爆raspberry pi(树莓派)
- 如何实现虚拟机与宿主机之间的串口通信
- Windows Mobile中如何建立GPRS连接以便Socket能正常通信
- 如何使用CnComm开发串口通信程序
- Windows Mobile中如何建立GPRS连接以便Socket能正常通信
- 如何建立一个小型的局域网,来实现电脑与电脑之间的通信
- qt实现串口,UDP,TCP与嵌入式通信上位机软件
- 如何用Delphi开发串口通信程序
- 在Linux中如何使用命令进行RS-232串口通信和数据包解析
- 该如何处理,启动任务计划的时候有“任务计划程序服务不可用。任务计划程序将尝试重新与其建立连接。”
- Windows Mobile中如何建立GPRS连接以便Socket能正常通信
- 做机械臂导航时遇到的问题5:如何使用ROS内嵌serial功能包实现串口通信
- C#学习与上位机开发之串口通信模块介绍
- 如何使用CnComm开发串口通信程序