hufei1956的笔记 https://passport2.21ic.com/?656664 [收藏] [复制] [RSS] 既然步入了电子开发,那就坚持做吧!!!

日志

2014-06-12_Uart的环形队列的使用

热度 1已有 1741 次阅读2014-6-12 15:51 |个人分类:软件讨论|系统分类:嵌入式系统

不善于写文字的我准备记录每一个项目中遇到的一些问题,这对我来说的确是一个不小的挑战,决定自己每天拿出一个小时来记录下这些小问题。

今天准备探讨一下Uart,这个太常见了,前几天看一个文章说做完流水灯就该做有关Uart的实验了!用的多不代表高级,只能说明它简单易用易上手,但带来的问题也是显而易见了,对复杂应用常用就显得无能无力了。自己之前思考Uart时想起一个问题,网络应用有协议栈,Zigbee组网有自己的协议栈,之前自己也有看过Micro CAN Open(MCO)协议栈,为什么Uart没有自己的一个协议呢?看过STM32的固件库,对UART进行了相关的封装,在其之上能不能进行BSP的封装呢,我觉得应该是可以的!

使用Uart操作的,一般都要有其协议,简单的协议无非是:

报头 + (设备标识符)【可选】 + 数据段 + 报尾【校验】

为了使今天的问题变得简单一些,我们只考虑接收部分的封装。使用过NXP的arm7,Uart模块内部就有一个16字节的FIFO,有过方案就是隔2ms去读一次,在速率不是很高的情况下完全够用,但现在自己看来就是不够看了,完全没有考虑到数据的完整性问题;今天说的接收方案都是在开发板上目前使用的,考虑接收数据需要完整的问题。

一:二维数组的接收——这种方案来自于清华那本很有名的《数据结构》,每次中断接收到数据检查是不是报头,是的话存入第一列中,再次检查到报头,存入第二列中,列数存满回归第一列,处理部分是对每一列的数据进行处理,处理完进行下一列的处理。

接收部分的结构体:

#define     REC_QUEUE_NUM        4                                //接收队列数目

#define     REC_ELEM_LEN                300                                //接收数组长度

#define     OVER_TIMER                    200                                //超时200毫秒

typedef struct

{

        INT8U        Elem[REC_QUEUE_NUM][ REC_ELEM_LEN];        //队列元素

        INT8U        QueueFront;                //队列头

        INT8U        QueueRear;                //队列尾

        INT8U        QueueNum;                //队列数目

        INT8U        OverTime;                //超时时间

        INT8U        FindFlag;                        //找到字头

        INT8U        ElemLen;                        //正在接受队列已接收字节数目

        INT16U        Head;                        //字头

        INT16U        Tail;                                //字尾

}RecStruct;

extern RecStruct  RecType;

接受完一帧数据,然后处理一下,操作系统中处理起来很方便。


二:环形队列的接收处理——网上把这种称为Ring,本人觉得就是一个大水池子,来了放进去,用的时候取一下(频率高一点,不然池子满了就溢出了),看过老外写的关于这方面代码,感觉还是很棒的。

typedef struct

{

    __IO uint32_t rx_head;                   /*!< UART Rx ring buffer head index */

    __IO uint32_t rx_tail;                   /*!< UART Rx ring buffer tail index */

} UART_RING_BUFFER;


#define __UART1_RX_BUF_MASK        (RX_RING_BUFSIZE)

/* Check buf is empty */

#define __USART1_RX_BUF_IS_EMPTY(head,tail) ((head%__UART1_RX_BUF_MASK)==(tail%__UART1_RX_BUF_MASK))


uint32_t UsartRead(uint8_t *rxbuf, uint32_t buflen)

{

    uint8_t *data = (uint8_t *) rxbuf;

    uint32_t bytes = 0;

        /* Temporarily lock out UART receive interrupts during this read so the UART receive interrupt won't cause problems with the index values */

        USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);

/* Loop until receive buffer ring is empty or until max_bytes expires */

while ((buflen > 0) && (!(__USART1_RX_BUF_IS_EMPTY(Usart1.rx_head, Usart1.rx_tail))))

        {

                /* Read data from ring buffer into user buffer */

                *data = Usart1_rx[Usart1.rx_tail];

                data++;

        

                /* Update tail pointer */

                __USART1_RX_BUF_INCR(Usart1.rx_tail);

        

                /* Increment data count and decrement buffer size count */

                bytes++;

                if(buflen > 0)

                buflen--;

        }

}

这种方式配合DMA最好,接受中断后存入RING中,调用UsartRead函数实现读取数据,配合操作系统某个任务负责读取数据即可。

也见过国内的关于环形队列的处理,但是写起来的代码要多许多,判断条件加的比较多,没有上述代码的简洁。

    讨论一下Uart的数据接收的意义在于我们思考如何实现一个项目,针对实时需要交互的系统,环形队列应该是很好的选择了,那在其上我们是不是可以实现一个协议(姑且不成协议栈,一个协议栈要包含许多的协议),我想每家公司都会有自己的Uart通信协议标准。只是在此方面,我们还需要总结,目前的这种方式是否可以作为小范围的使用而不出现问题,还需要进一步的验证和大规模数据的验证。

下一步的计划是能够使用ETH,网络这东西一直没有时间去弄,想抽时间好好看一看,据说STM32Cube和以前用的C8051F的Config2很类似,想弄一下看看。

上次和同事聊天,他说到开发有了几年最后发现用什么单片机其实没那么重要,到了一定阶段,心中已经模糊了单片机的概念,或许这就是一种境界,就像高手不一定要有一把宝刀一样,一节树枝、一把扫帚就可以化腐朽为神奇。这也是今天想说的,很多工具的东西到了一定阶段就不需要注意的那么重要了,其实那些真正让我们关心的是算法,这些是我们需要思考的精髓。



路过

鸡蛋
1

鲜花

握手

雷人

刚表态过的朋友 (1 人)

评论 (0 个评论)