12 在ZStack裡實現uart資料接收功能
阿新 • • 發佈:2019-02-13
在上一篇已經實現uart資料輸出功能了,但接收資料時尚未搞好的。
在MT任務裡已實現當有uart資料需接收時,自動呼叫函式MT_UartProcessZToolData來處理資料的接收,接收資料後通過發出訊息的方法把資料傳遞到使用者任務裡去。
void MT_UartProcessZToolData ( uint8 port, uint8 event ) //
{
uint8 ch;
uint8 bytesInRxBuffer;
(void)event; // Intentionally unreferenced parameter
while (Hal_UART_RxBufLen(port)) //判斷是否已經有資料接收
{
HalUARTRead (port, &ch, 1); //接收資料
...
osal_msg_send( App_TaskID, (byte *)pMsg ); //通過給使用者任務發訊息的方式傳遞串列埠接收到的資料
}
...
}
但MT_UartProcessZToolData會對接收到資料進行加工處理的,MT層有自己的一套協議。為了省事,我們自己改造下函式好了。
typedef struct
{
osal_event_hdr_t hdr; //都是這種頭部
uint8 *msg;
} mtOSALSerialData_t; //串列埠資料訊息的型別
void MT_UartProcessZToolData ( uint8 port, uint8 event )
{
uint8 ch, *p;
uint8 len = Hal_UART_RxBufLen(port); //先獲取需要接收的資料長度
if (len <= 0) //如果沒有資料接收則直接返回
return;
pMsg = (mtOSALSerialData_t *)osal_msg_allocate(sizeof(mtOSALSerialData_t)+len+1);
//準備訊息的緩衝區,len表示串列埠資料長度, 多加的一個位元組用於存放此次接收的資料長度。
pMsg->msg = (uint8 *)(pMsg+1); //msg指向資料的開始存放位置
p = &(pMsg->msg[1]); //保留一個位元組位置用於存放接收的資料長度
len = HalUARTRead (port, p, len); //接收資料
pMsg->msg[0] = len; //記錄資料長度。 存放的格式: "訊息結構體內容" + "長度" + "接收到的資料內容"
pMsg->hdr.event = CMD_SERIAL_MSG; //設定訊息型別
osal_msg_send( App_TaskID, (byte *)pMsg ); //發出訊息
}
實現接收到串列埠資料後, 重新發回去的功能.
MyApp.c
#include "OnBoard.h"
#include "MyApp.h"
#include "hal_led.h"
#include "hal_key.h"
#include "MT_UART.h"
#include "hal_uart.h"
#include "MT.h"
#define TIME_OUT_EVENT 0x4
#define TIME_LEN 2000
uint8 mytask_id; //用於存放本身的任務號
void MyApp_Init(uint8 task_id )
{
mytask_id = task_id;
RegisterForKeys(mytask_id); //設定當前任務接收按鍵訊息
MT_UartRegisterTaskID(mytask_id);//指定當MT任務接收到串列埠資料時,傳遞到本任務來
}
uint16 MyApp_ProcessEvent(uint8 task_id, uint16 events )
{
keyChange_t *key_evt;
if ( events & SYS_EVENT_MSG ) //當有按鍵訊息時,任務的事件會是SYS_EVENT_MSG
{
key_evt = (keyChange_t *)osal_msg_receive(mytask_id);
while (key_evt)
{
if (key_evt->hdr.event == KEY_CHANGE) //按鍵事件
{
if (key_evt->keys & HAL_KEY_SW_1)
HalUARTWrite(HAL_UART_PORT_0, "btn1\n\r", 6);
if (key_evt->keys & HAL_KEY_SW_2)
HalUARTWrite(HAL_UART_PORT_0, "btn2\n\r", 6);
}
if (key_evt->hdr.event == CMD_SERIAL_MSG) //串列埠接收資料事件
{
mtOSALSerialData_t *p = (mtOSALSerialData_t *)key_evt;
HalUARTWrite(HAL_UART_PORT_0, &p->msg[1], p->msg[0]); //把接收到的資料重新發回去
}
osal_msg_deallocate( (uint8 *)key_evt ); //回收訊息的空間
key_evt = (keyChange_t *)osal_msg_receive(mytask_id); //再次接收本任務的訊息
}
}
if (events & TIME_OUT_EVENT) //定時器的事件
{
;
}
return 0;
}
注意如需實現像接收到”leds on\n”這樣的命令後操作硬體的功能,則需在串列埠接收資料事件裡先把接收到資料暫存起來,直到接收到’\r’符號(window上傳過來的是’\n’)為止.
MyApp.c
#include "OnBoard.h"
#include "MyApp.h"
#include "hal_led.h"
#include "hal_key.h"
#include "MT_UART.h"
#include "hal_uart.h"
#include "MT.h"
#include "stdio.h"
#include "string.h"
#define TIME_OUT_EVENT 0x4
#define TIME_LEN 2000
#define LEN 100
uint8 mytask_id; //用於存放本身的任務號
uint8 *line;
uint8 len_rcv;
void MyApp_Init(uint8 task_id )
{
mytask_id = task_id;
RegisterForKeys(mytask_id); //設定當前任務接收按鍵訊息
MT_UartRegisterTaskID(mytask_id);//指定當MT任務接收到串列埠資料時,傳遞到本任務來
line = osal_msg_allocate(LEN);
len_rcv = 0;
}
uint16 MyApp_ProcessEvent(uint8 task_id, uint16 events )
{
keyChange_t *key_evt;
if ( events & SYS_EVENT_MSG ) //當有按鍵訊息時,任務的事件會是SYS_EVENT_MSG
{
key_evt = (keyChange_t *)osal_msg_receive(mytask_id);
while (key_evt)
{
if (key_evt->hdr.event == KEY_CHANGE) //按鍵事件
{
if (key_evt->keys & HAL_KEY_SW_1)
HalUARTWrite(HAL_UART_PORT_0, "btn1\n\r", 6);
if (key_evt->keys & HAL_KEY_SW_2)
HalUARTWrite(HAL_UART_PORT_0, "btn2\n\r", 6);
}
if (key_evt->hdr.event == CMD_SERIAL_MSG) //串列埠接收資料事件
{
mtOSALSerialData_t *p = (mtOSALSerialData_t *)key_evt;
uint8 *d = &p->msg[1];
if (d[p->msg[0] - 1] != '\r') //接收到'\r'為止
{
memcpy(line + len_rcv, d, p->msg[0]);
len_rcv += p->msg[0];
}
else //接收到'\r'符號後輸出內容
{
HalUARTWrite(HAL_UART_PORT_0, line, len_rcv); //把接收到的資料發回去
HalUARTWrite(HAL_UART_PORT_0, "\n\r", 2);
len_rcv = 0;
}
}
osal_msg_deallocate( (uint8 *)key_evt ); //回收訊息的空間
key_evt = (keyChange_t *)osal_msg_receive(mytask_id); //再次接收本任務的訊息
}
}
if (events & TIME_OUT_EVENT) //定時器的事件
{
;
}
return 0;
} 