在上一篇已经实现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;
}
本文介绍了一种在嵌入式系统中实现串口数据接收和发送的方法。具体包括如何在MT任务中处理串口接收数据,并将这些数据传递给用户任务,以及如何将接收到的数据重新发送出去。
630





