第十八节 协议栈UART实验

第十八节 协议栈UART实验


协议栈中已经用了串口的驱动,我们要做的只是对串口进行初始化,然后就可以进行串口数据的收发了。
用使用串口,第一步,需要打开使能串口功能,通过配置工程来实现,这里注意,我们现在不使用USB的CDC类来实现串口,所以HAL_UART_USB=FALSE。
HAL_UART=TRUE
HAL_UART_USB=FALSE
要使用串口必须先初始化相应的串口,那该如何初始化呢?在Hal_uart.h文件中我们可以看到如下函数。
uint8 HalUARTOpen(uint8 port, halUARTCfg_t *config);
 这个函数就是用来初始化串口的,这个函数有两个参数,第一个指定串口号,第二个是串口的配置参数。我们来看看这个结构体的定义:
typedef struct
{
  bool                configured;               // 配置与否
  uint8               baudRate;                 // 波特率
  bool                flowControl;              // 流控制
  uint16              flowControlThreshold;
  uint8               idleTimeout;              // 空闲时间
  halUARTBufControl_t rx;                       // 接收
  halUARTBufControl_t tx;                       // 发送
  bool                intEnable;                // 中断使能
  uint32              rxChRvdTime;              // 接收数据时间
  halUARTCBack_t      callBackFunc;             // 回调函数     
}halUARTCfg_t;

这个结构体成员很多,但是我们在使用串口的时候并不需要使用所有的成员。
void Serial_Init(void)
{
    halUARTCfg_t SerialCfg = {0};

    SerialCfg.baudRate = HAL_UART_BR_115200;    // 波特率
    SerialCfg.flowControl = HAL_UART_FLOW_OFF;  // 流控制

    SerialCfg.callBackFunc = SerialCb;          // 回调函数
    SerialCfg.intEnable    = TRUE;
    SerialCfg.configured   = TRUE;
    HalLcdWriteString( "Open Uart0", HAL_LCD_LINE_5 );    // 在第5行显示启动信息
    HalUARTOpen(HAL_UART_PORT_0, &SerialCfg);
    HalUARTWrite(HAL_UART_PORT_0, "Hello MT254xBoard\r\n", osal_strlen("Hello MT254xBoard\r\n"));
}

在串口回调函数中我们只做一件事,将串口接收到的数据显示到LCD中并且原样的从串口输出。回调函数的实现如下:
static void SerialCb( uint8 port, uint8 events )
{
    uint8 RxBuf[64]={0};
    if((events & HAL_UART_TX_EMPTY)||( events & HAL_UART_TX_FULL ))  // 发送区满或者空
    {
        return;
    }

    uint16 usRxBufLen = Hal_UART_RxBufLen(HAL_UART_PORT_0);  // 读取接收据量
    usRxBufLen = MIN(64,usRxBufLen);
    uint16 readLen = HalUARTRead(HAL_UART_PORT_0, RxBuf, usRxBufLen);
    HalUARTWrite(HAL_UART_PORT_0, RxBuf, usRxBufLen);
}

 实验现象,从实验现象中可以看到,一开始在串口中输出了一个标志字符串,然后我们通过串口发送了0123456789,然后数据原样的从串口输出了,这和我们预期的结果是一样的。


    但是我们发现LCD上的显示和我们预期的不一样,LCD上只显示了6789,前面的数据并没有显示,这是怎么一回事呢?进行单步调试可以发现,我们发送一次数据,回调函数被回调了两次,第一次回调只接受到了012345,第二次回调接收到了6789,而在LCD上的显示第二次覆盖了第一次的显示,所以我们会看到这种现象,解决的办法,我们需要定义一个数据帧的时间间隔,当接收数据的间隔超过了此间隔就认为接收结束。


下面我们改写接收处理,我们在接收到数据后开启定时器,定时5ms这样,当接收间隔大于5ms后,我们就可以在定时事件中处理串口接收到的数据。
static void SerialCb( uint8 port, uint8 events )
{
    if((events & HAL_UART_TX_EMPTY)||( events & HAL_UART_TX_FULL ))  // 发送区满或者空
    {
        return;
    }
    uint16 usRxBufLen = Hal_UART_RxBufLen(HAL_UART_PORT_0);  // 读取接收据量
    if(usRxBufLen)
    {
        usRxBufLen = MIN(128,usRxBufLen);
        uint16 readLen = HalUARTRead(HAL_UART_PORT_0, &SerialRxBuf[RxIndex], usRxBufLen);   // 读取数据到缓冲区
        RxIndex += readLen;
        readLen %= 128;
        osal_start_timerEx(simpleBLEPeripheral_TaskID, UART_EVENT, 5);  // 启动定时器
    }
}

事件处理代码:
if ( events & UART_EVENT )
  {
    HalLcdWriteString( (char*)SerialRxBuf, HAL_LCD_LINE_6 );    // 在第5行显示启动信息
    HalUARTWrite(HAL_UART_PORT_0, SerialRxBuf, osal_strlen(SerialRxBuf));
    osal_memset(SerialRxBuf, 0, 128);
    return (events ^ UART_EVENT);
  }

事件处理代码:经过这样的处理后,可以发现我们刚刚的问题已经解决了。



    到这里串口已经可以正常使用了,为了更加方便的使用串口,我在这里添加一个函数实现标准C中printf,这样更有利于我们输出。
int SerialPrintf(const char*fmt, ...)
{
    uint32  ulLen;
    va_list ap;

    char *pBuf = (char*)osal_mem_alloc(PRINT_BUF_LEN);  // 开辟缓冲区
    va_start(ap, fmt);
    ulLen = vsprintf(pBuf, fmt, ap);        // 用虚拟打印函数实现
    va_end(ap);

    HalUARTWrite(HAL_UART_PORT_0, (uint8*)pBuf, ulLen); // 从串口0输出
    osal_mem_free(pBuf);    // 释放内存空间
    return ulLen;
}

我们可以像使用C标准中的printf来使用这个函数,例如我们将LCD的输出全部导向串口的输出,在HalLcdWriteString的实现中添加串口输出代码,如下图:


重新编译并且烧录后可以看到LCD的输出和串口的输出是一样的了。


本文章转载自
http://www.deyisupport.com/question_answer/wireless_connectivity/bluetooth/f/103/t/69222.aspx
请勿用于商业
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值