4771|11

420

帖子

0

TA的资源

纯净的硅(初级)

楼主
 

uart 接收发送新玩法 [复制链接]

本帖最后由 jorya_txj 于 2014-1-5 20:18 编辑

很多时候,用户发送具体消息的时候,也需要发送一个消息长度。比如在网卡中断中接收到了一包数据,发送消息给外面任务的时候,也需要告诉外面的任务消息的长度是多少。使用之前的queue模块做需要一点小技巧,但是使用queue_size模块做的话,显的很直接,直接可以发送出去。
带有消息长度的消息机制有一种很有用的用法。假设有一个串口接收中断来了,接收数据的话可以采用信号量+fifo 或者queue+块内存分配去做,但是这两种多多少少有些缺点。信号量+fifo的方式处理的话,fifo内部是关了cpu全局中断去操作的,如果数据量比较大的话,这个会严重影响实时性。queue +block内存区分配的话,如果中断接收每次来的数据都不同的话,会严重浪费内存。
有没有经济实用的不关中断,又节约内存的方式操作呢。答案是肯定的。当串口接收中断来的时候,用户需要自己维护一个简单的fifo缓冲区,但是这个缓冲区不需要关中断,写到头了重新回到头去写就好。当接收到数据填好缓冲区的时候,把缓冲区的这次数据起始地址以及数据长度通过raw_queue_size_end_post 发送出去。同时外面有一个任务调用raw_queue_size_receive接收数据。具体的示例如下:
staticRAW_U32 recv_temp_buffer[12];           (1)
staticRAW_U32  *uart_p;                       (2)
staticRAW_U32  uart_data_length               (3)
void uart_int_recevie_handle(void)
{
    RAW_U32 length_temp;
    RAW_U32 uart_recv_length;
    RAW_U8 *p_temp;
    uart_recv_length = 读串口数据的长度
    length_temp = uart_recv_length;
   
    if (raw_queue_size_full_check()) {
       /*do something thing and return*/
       return;
    }
    /*if isr receive data is faster than task data process, just ignore the data*/
    if (uart_data_length >= (12 * 4)) {
           /*do something thing and return*/
           return;
    }
    if ((uart_p + (uart_recv_length >> 2))> = (recv_temp_buffer + 12))   {
       uart_p = recv_temp_buffer;
    }
    p_temp = (RAW_U8 *)uart_p;
   while (length_temp--) {
       *p_temp++ = 串口数据;
    }
    queue_size_end_post(queue_size, uart_p, uart_recv_length);
    if(uart_recv_length & 3) {
       uart_data_length += 4u - (uart_recv_length& 3u)+ uart_recv_length;
       uart_p = uart_p + (uart_recv_length>> 2) + 1;
    }
    else {
       uart_p = uart_p + (uart_recv_length>> 2)
       uart_data_length += uart_recv_length;
    }
}
RAW_U32process_buffer[10];
void task_uart_receive()
{
    RAW_U8 receive_size;
    void * msg_ptr;
    while (1) {
        raw_queue_size_receive(&q_size,RAW_WAIT_FOREVER, &msg_ptr,
        &receive_size);
        raw_memcpy(process_buffer,msg_ptr, receive_size);
        RAW_CPU_DISABLE();
        if(receive_size & 3) {
          uart_data_length = uart_data_length - (4u- (receive_size & 3u) + receive_size);
        }
       else {
         uart_data_length -= receive_size;
       }
       RAW_CPU_ENABLE();

      /*processsreceived data, processed time must be smaller than interrupt frequecy*/
    }
}
(1)处用户自己维护了一个缓冲区,缓冲区的数据长度是48个字节。
(2)处代码的uart_p用来记录缓冲区的写位置。
(3)处代码维护一个长度,如果长度超过了缓冲区的长度就丢弃数据,返回,保证不会去覆盖缓冲区的数据。
以上的操作避免了临界区的缓冲区的操作,又节省了内存开销。而且数据执行效率上比起fifo也要高,因为少了一次copy动作。

最新回复

很受启发,结合着K60的例子和视频看了一下, if ((uart_p + (uart_recv_length >> 2))> = (recv_temp_buffer + 12))   {        uart_p = recv_temp_buffer;     } 这句代码能否解释一下,uart_p是一个指针,uart_p + uart_rec_length >> 2是? 在K60 的代码中 uart_recv_length是1,它右移了2位。。。。。不是很懂,然后让它和rece_tem_buffer+12,相比较,后者是缓冲区的尾地址吧,前者能解释下吗,这句代码的意思是,写到了尾部,那就把缓冲区地址赋给uart_p   详情 回复 发表于 2014-6-22 19:14
点赞 关注(1)

回复
举报

2

帖子

0

TA的资源

一粒金砂(初级)

沙发
 
不错,学习了
 
 

回复

147

帖子

0

TA的资源

一粒金砂(高级)

板凳
 
自己建一个FIFO,直接把串口中断的数据压入FIFO,任务中再读FIFO。FIFO满了的时候再发个信号量或者事件通知任务,比如像STM32那种,还可以利用UART的IDLE中断来通知任务该读FIFO了
 
 
 

回复

3

帖子

0

TA的资源

一粒金砂(初级)

4
 
 
 
 

回复

420

帖子

0

TA的资源

纯净的硅(初级)

5
 
本帖最后由 jorya_txj 于 2014-1-6 09:22 编辑

楼上的想法是可行的,只是自己建的fifo, 难免要关中断,数据量一大,实时性无法忍受,这个就是放弃的原因。因为中断模型不单单是uart的,其它各模块比如i2c, spi 等模块都是共通的,打造0关中断的fifo操作,是很有意义的。
 
 
 

回复

17

帖子

0

TA的资源

一粒金砂(初级)

6
 
学习了
 
 
 

回复

32

帖子

0

TA的资源

一粒金砂(中级)

7
 
不错,学习了        
 
 
 

回复

51

帖子

0

TA的资源

一粒金砂(中级)

8
 
本帖最后由 nos001 于 2014-4-28 15:12 编辑

太难懂了,要理解得把os先通读啊。
 
 
 

回复

420

帖子

0

TA的资源

纯净的硅(初级)

9
 
上面的只是一种设计思路,和os没任何关系。
 
 
 

回复

18

帖子

0

TA的资源

一粒金砂(中级)

10
 
本帖最后由 谷子木 于 2014-5-3 22:48 编辑

为什么不用 DMA 呢。。。启用DMA后,串口接收数据可以直接传送到  FIFO 里面 ,都可以不经过中断处理
 
 
 

回复

420

帖子

0

TA的资源

纯净的硅(初级)

11
 
dma 数据传到内存后,什么时候结束,还是需要中断去通知的。只是中断里面不需要去搬数据了。有一些单片机的串口是没有dma的支持的。
 
 
 

回复

65

帖子

2

TA的资源

一粒金砂(中级)

12
 
很受启发,结合着K60的例子和视频看了一下,
if ((uart_p + (uart_recv_length >> 2))> = (recv_temp_buffer + 12))   {

       uart_p = recv_temp_buffer;
    }

这句代码能否解释一下,uart_p是一个指针,uart_p + uart_rec_length >> 2是? 在K60 的代码中 uart_recv_length是1,它右移了2位。。。。。不是很懂,然后让它和rece_tem_buffer+12,相比较,后者是缓冲区的尾地址吧,前者能解释下吗,这句代码的意思是,写到了尾部,那就把缓冲区地址赋给uart_p

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表