打印

请教一下农民讲习所

[复制链接]
楼主: 一只小绵羊
手机看帖
扫描二维码
随时随地手机跟帖
21
冷漠| | 2010-1-5 09:49 | 只看该作者 回帖奖励 |倒序浏览
本帖最后由 冷漠 于 2010-1-5 10:00 编辑
......以本贴为例,如果串口一直收到数据,pIn一直增加,而主程序忙于另一件事一直没有读出数据,在接收到和缓冲区容量相同的字节后,pIn仍然等于pout,这个时候是不是可以判断缓冲区空?.......


15楼怎么没好好看我写的:“ 当 pIn 追赶上 pOut,使 pIn=pOut 时,队列满。”——是队列满,即缓冲区满,不是“缓冲区空”。缓冲区空的条件判别在主函数里:pOut=pInt。中断函数不需要判别缓冲区空,“缓冲区满了接收数据溢出丢弃,管它空不空?”同样,主函数里也不判别缓冲区满,“空了不再取,多满我也得取呀。”

缓冲区满条件TRUE之后,接收数据mData溢出丢弃。怎么可能存到缓冲区?

if  ((( pQueueBuffer->pIn ) % ILEN ) !=  pQueueBuffer->pOut )
       *( pQueueBuffer->pIn++ % ILEN ) = mData ;

当 else 的时候, 不操作 *( pQueueBuffer->pIn++ % ILEN ) = mData ;
mData 就不往队列里存了,溢出丢弃。这不是很明显吗?

使用特权

评论回复
22
desert_hawk| | 2010-1-5 10:08 | 只看该作者
你在16楼的程序,在中断调用queue_push的时候也有可能使pIn = pOut,然后中断返回后,主程序有没有可能误判断缓冲区空?

使用特权

评论回复
23
xlsbz| | 2010-1-5 10:16 | 只看该作者
楼上有几位提到互斥不互斥问题。
我想就此讲一讲。

使用特权

评论回复
24
HWM| | 2010-1-5 10:17 | 只看该作者
要判定线性环队的空与满,不仅要看头尾指针的当前状态,还要看具体是插入还是提取——即指针的下一步走向。

使用特权

评论回复
25
xlsbz| | 2010-1-5 10:17 | 只看该作者
请楼主查查以前的老帖子,提到了互斥问题。

使用特权

评论回复
26
xlsbz| | 2010-1-5 10:18 | 只看该作者
关于农民讲习所的的这种写法未必适合于楼主。

因为这种写法在我看来是乱七八糟!

这种写法估计是适合于高手!

使用特权

评论回复
27
冷漠| | 2010-1-5 10:26 | 只看该作者
20楼怎么看不懂程序?别人都看懂了。
16楼写的是中断调用函数Queue_Push( ),是pInt追赶pOut,除去初始条件,下式当然表达队列满:
if  ((( pQueueBuffer->pIn ) % ILEN ) !=  pQueueBuffer->pOut )
       *( pQueueBuffer->pIn++ % ILEN ) = mData ;

谁追赶谁,搞清楚。如果是在主函数Queue_Pop( )里,那就不是这么写了:

使用特权

评论回复
28
desert_hawk| | 2010-1-5 10:35 | 只看该作者
那你把Queue_Pop也摆出来看看啊,弄出来一半,让我们猜?

使用特权

评论回复
29
desert_hawk| | 2010-1-5 10:42 | 只看该作者
如果不引入别的标志变量,无非是这样:
if  ((( pQueueBuffer->pOut ) % ILEN ) !=  pQueueBuffer->pIn )
        mData = *( pQueueBuffer->pOut++ % ILEN ) ;
但这样就会有错误发生。

使用特权

评论回复
30
冷漠| | 2010-1-5 10:56 | 只看该作者
本帖最后由 冷漠 于 2010-1-5 11:00 编辑

char Queue_Pop( struct QueueBuffer idata *pQueueBuffer )
{   
        while( pOut!=pInt )
       return *( pQueueBuffer->pOut++ % ILEN );
}

24楼一语中的。看清谁和谁比较,pOut++ / pInt++ 指针走向,它是环形缓冲器。
if ( pOut==pInt ) 和 if ( pInt==pOut ) 不一样。

使用特权

评论回复
31
冷漠| | 2010-1-5 10:59 | 只看该作者
书上写的。我不会比书作者更高明。

使用特权

评论回复
32
desert_hawk| | 2010-1-5 11:14 | 只看该作者
按30楼的写法,可以做个假设,假设中断里调用queue_push使pIn=pOut了,即缓冲区满了,中断返回后,主程序再调用queue_pop会发生什么?
除非主程序中很频繁地调用queue_pop,使缓冲区根本就不可能满,否则就会有误判断缓冲区空的情况发生。

使用特权

评论回复
33
原野之狼| | 2010-1-5 12:20 | 只看该作者
想请教一下 冷漠:
ILEN 表示什么?

使用特权

评论回复
34
冷漠| | 2010-1-5 13:38 | 只看该作者
本帖最后由 冷漠 于 2010-1-5 14:27 编辑

回LS:  ILEN=BUFFER_MAX_SIZE   //缓冲区长度。

回32楼。建议看懂18楼 machunshui 说的是什么?别人怎么想的到?这么简单的问题都不能解决,还要去参考外国人。咱们中国人只好加一个mCount?再加上互斥机制?

把简单的事情复杂化是非常容易的事,——大多数人谁都行。但是能把复杂的事情化简,再化简,把所长的程序化简,少用一个、甚至3个成员 / 变量,那只有很少人能够做到了。

同意26楼,一个程序不是说随便想到哪就编到那。程序这里不行,我加一个mCount,加了mCount又造成了其它问题,我再利用互斥机制。互斥不行我再信号量,再不行我采用Dijkstra抽象模型,........

想起了前几天关于库函数中修改端口的帖子,所长说别人的都不行,建议采用他的方法——回调函数。1952用的是......,结果大家被误导,看来只有这2种方法了。结果一看国外教材,这类问题的解决方法早就标准化了。为什么我们总是想不到?

所长自称是“天下第一。.......”“我从不看书,照样天下第一.....”

看了书上关于环形缓冲器的操作,回过头来再看所长的程序,唉——所长能自己写出来当然比我强多了,但是要学习他怎么写恐怕就会被误导一生。
       ——还是看看书上怎么写的为好,如果谁自己觉得自己写的不错,希望能同时把书上的内容贴出来,讲解一下自己比书上改进了哪些地方。从错误中学习才是更好的学习。

使用特权

评论回复
35
desert_hawk| | 2010-1-5 16:16 | 只看该作者
楼上说的简化并没有高明到哪去。18楼说的我看到了,这种方法能用,但一个缺点是,没法简便地得到缓冲区中未读字节的数量。在一些应用中,需要经常的判断缓冲区中未读字节的数量,来判断是否收可能到了完整数据。所以这种简化有点拆东墙补西墙的意思。
另外,如果33楼不问,我还没发现,pQueueBuffer->pIn和pQueueBuffer->pOut是什么类型? 是指向字符数据的指针,在初始化的时候应该都初始化为接收缓冲区的起始地址,而不是0,所以pQueueBuffer->pIn % ILEN能起到什么效果?很让人费解。这很难想象是从书上摘抄的程序啊。

使用特权

评论回复
36
lza| | 2010-1-5 16:20 | 只看该作者
这样操作必须要关中断,14楼的对,以前自己写都是直接关,直接开,原来还有bug

使用特权

评论回复
37
desert_hawk| | 2010-1-5 16:28 | 只看该作者
据我所知在环形缓冲区中使用一个类似mCount的变量不是所长的原创。我见过两个类似的用法:一是CVAVR编译器的用户向导生成的串口代码,二是ucosii的消息队列:
typedef struct os_q {                   /* QUEUE CONTROL BLOCK                                         */
    struct os_q   *OSQPtr;              /* Link to next queue control block in list of free blocks     */
    void         **OSQStart;            /* Pointer to start of queue data                              */
    void         **OSQEnd;              /* Pointer to end   of queue data                              */
    void         **OSQIn;               /* Pointer to where next message will be inserted  in   the Q  */
    void         **OSQOut;              /* Pointer to where next message will be extracted from the Q  */
    INT16U         OSQSize;             /* Size of queue (maximum number of entries)                   */
   INT16U         OSQEntries;          /* Current number of entries in the queue                      */
} OS_Q;
别告诉我他们都是多此一举。

使用特权

评论回复
38
冷漠| | 2010-1-5 16:55 | 只看该作者
唉,别抓细节。
    pQueueBuffer->pIn % ILEN,故意这样写只是为了让您看得懂。把书抄来您不一定看得懂。请问您的接收缓冲区(队列)是不是数组类型?——可别告诉我是“队列类型”。数组类型的起始地址在哪里?指向数组的指针有没有偏移量? pIn[ILEN-1]可不可以?您的BUFFER_MAX_SIZE是不是从0开始增长的?
如果您看的懂下面:
if (p == pQueueBuffer->aBufferEnd){
        p = pQueueBuffer->aBufferStart;
    }

那么我写成 ( aBufferEnd - aBufferStart )% ILEN;    // 可不可以?结果是什么类型?
或者       ( aBufferEnd - aBufferStart )& ILEN-1   // 别说我少了个括号什么的。 结果是什么类型?

使用特权

评论回复
39
冷漠| | 2010-1-5 17:13 | 只看该作者
本帖最后由 冷漠 于 2010-1-5 17:20 编辑
18楼说的我看到了,这种方法能用,但一个缺点是,没法简便地得到缓冲区中未读字节的数量。在一些应用中,需要经常的判断缓冲区中未读字节的数量,来判断是否收可能到了完整数据。所以这种简化有点拆东墙补西墙的意思。


也不看看 machunshui 是谁。人家研究员水平想出个解决方案到您这成了缺点?!这么简单的解决方案您还没看懂?

push( )函数追赶条件:if ( ++pIn == pOut ); // 永远滞后一字节。
pop ( )函数追赶条件:  if ( pOut==pIn )  ;  //  可以相等。

缓冲区中未读字节的数量mCount = pIn - pOut ;  这个等式不否认吧。——可别说一定要我说明是绝对值,从已知条件来的。没个错。 那么mCount 是不是多余?还要互斥访问?

使用特权

评论回复
40
google的马甲| | 2010-1-5 18:40 | 只看该作者
好像是idata的,难道8位的变量也要互斥访问?迷惑中

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则