打印

请教一下农民讲习所

[复制链接]
17163|100
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一只小绵羊|  楼主 | 2010-1-4 15:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
这是农民讲习所的大作,有点疑问,比如串口中在接受中断中调用Queue_Push在主函数中调用Queue_Pop

//------------------------------------------------------------
//将数据压入队列
//------------------------------------------------------------
void Queue_Push( struct QueueBuffer idata * pQueueBuffer, unsigned char mData )
{
    unsigned char idata *p;
    p = pQueueBuffer->pIn;

    *p++ = mData;
    if (p == pQueueBuffer->aBufferEnd){
        p = pQueueBuffer->aBufferStart;
    }
    pQueueBuffer->pIn = p;

    pQueueBuffer->mCount ++;
}

//------------------------------------------------------------
//将数据弹出队列
//------------------------------------------------------------
unsigned char Queue_Pop( struct QueueBuffer idata *pQueueBuffer )
{
    unsigned char mData;
    unsigned char idata *p;
    p = pQueueBuffer->pOut;

    mData = *p;
    if( ++p == pQueueBuffer->aBufferEnd ){
        p = pQueueBuffer->aBufferStart;
    }
    pQueueBuffer->pOut = p;

    pQueueBuffer->mCount --;

    return mData;
}

相关帖子

沙发
一只小绵羊|  楼主 | 2010-1-4 15:11 | 只看该作者
但是看keil编译出来的文件,一个变量的--操作对应的操作为
;;;220                    flagCAN1RecData--;
0002aa  4860              LDR      r0,|L1.1068|
0002ac  7800              LDRB     r0,[r0,#0]  ; flagCAN1RecData
0002ae  1e40              SUBS     r0,r0,#1
0002b0  495e              LDR      r1,|L1.1068|
0002b2  7008              STRB     r0,[r1,#0]

使用特权

评论回复
板凳
一只小绵羊|  楼主 | 2010-1-4 15:14 | 只看该作者
那么是否存在一个问题,比如现在mCount 的值是10,马上执行pQueueBuffer->mCount --但是执行到中间的时候比如变量已经载入了寄存器,这时中断来了,在中断中执行pQueueBuffer->mCount ++,中断执行完了mCount 的值就是11了,接着执行主函数中的--操作,结果mCount 的值就是9了,这就出错了吧

使用特权

评论回复
地板
原野之狼| | 2010-1-4 15:18 | 只看该作者
农民叔叔已经很久没有来了
另外
农叔的代码里没有标记缓冲满这个错误

2楼汇编文件有什么不对么?

使用特权

评论回复
5
一只小绵羊|  楼主 | 2010-1-4 15:20 | 只看该作者
:)你看看3楼的,有啥不清楚,咱再聊聊,就是有点想不通。。

使用特权

评论回复
6
desert_hawk| | 2010-1-4 16:13 | 只看该作者
变量的互斥访问,确实应该关中断。

使用特权

评论回复
7
原野之狼| | 2010-1-4 16:38 | 只看该作者
这个互斥问题 是在调用 push 和 pop 函数的时候考虑
我想农民伯伯是这么认为的
当然在 push 和 pop 中考虑互斥也行

使用特权

评论回复
8
一只小绵羊|  楼主 | 2010-1-4 16:52 | 只看该作者
除了关中断,还有什么方法互斥,再定义一个变量?

使用特权

评论回复
9
红金龙吸味| | 2010-1-4 17:29 | 只看该作者
农民叔叔已经成为一个传说了.......

使用特权

评论回复
10
冷漠| | 2010-1-4 20:12 | 只看该作者
本帖最后由 冷漠 于 2010-1-4 20:15 编辑

所长自己还没整明白呢。

环形缓冲器中(数组表示)的数据队列具有2个指针,一个指向队列头,也即:pQueueBuffer->pIn;另一个指向队列尾,也即 pQueueBuffer->pOut 。
      接收中断中接收到一字符,将其加入到队列头,pIn 指针+1;主函数从队列尾 取一字符,pOut 指针也+1。当pOut 追赶上 pIn,使pOut=pIn 时,队列空;  当 pIn 追赶上 pOut,使 pIn=pOut 时,队列满。
     pIn / pOut 是互不搭界的2个指针,根本不需要互斥访问。

如果使用pQueueBuffer->mCount=0;来达到判别队列空/满,还要互斥访问,是不是有点多此一举?把简单的事情复杂化了。

使用特权

评论回复
11
desert_hawk| | 2010-1-4 20:43 | 只看该作者
楼上大概没明白楼主说的意思。中断中调用queue_push, 主程序调用queue_pop,两个函数一个对pQueueBuffer->mCount 进行增操作,另一个对pQueueBuffer->mCount 进行减操作,会不需要互斥?

使用特权

评论回复
12
desert_hawk| | 2010-1-4 20:51 | 只看该作者
7楼所说的意思大概是调用queue之前关中断,调用完了再开中断,这样也能互斥。但这样增加了关中断时间,也就增加了中断延迟,个人觉得在编程时应该尽量减小关中断的时间。
to 8楼:你说的“再定义一个变量”,应该指的是“测试并置位”的方法,不过“测试并置位”这个操作本身一般也需要关中断,所以像这个帖子的例子,互斥的最简便有效地办法就是直接关中断然后开中断。

使用特权

评论回复
13
冷漠| | 2010-1-4 21:12 | 只看该作者
楼上的大概还没明白我的意思,环形缓冲器不需要pQueueBuffer->mCount这么个成员。这是所长自创的,你要用这么个没用的东西,还要采用互斥技术。岂不是多做之过?

利用pIN /pOut 足够了。所长反而没用到。看懂这一句:

当pOut 追赶上 pIn,使pOut=pIn 时,队列空;  当 pIn 追赶上 pOut,使 pIn=pOut 时,队列满。

这就是所谓“ pQueueBuffer->mCount 进行增操作,另一个对pQueueBuffer->mCount 进行减操作,”的作用。所长使用pQueueBuffer->mCount ,也没体现出如何判别缓冲器空/满结果的作用。

使用特权

评论回复
14
jerkoh| | 2010-1-4 21:21 | 只看该作者
void Queue_Push(struct QueueBuffer  *pQueueBuffer,unsigned char mData)
{
   
    bit fEaReg;                                       
        /*注意:如果是重入函数内部不能使用Bool变量*/
        /*重入函数 KEIL默认 将所有变量定位到外部RAM的最高处,而外部RAM不可以位寻址*/       
        *pQueueBuffer->pIn++ = mData;
        if(pQueueBuffer->pIn==pQueueBuffer->aBufferEnd)
        {
           pQueueBuffer->pIn=pQueueBuffer->aBufferStart;
        }
        fEaReg=EA;
        EA=0;
        pQueueBuffer->mCount++;
        EA=fEaReg;

}

/*********************************************************************************
**函数:unsigned char Queue_Pop(struct QueueBuffer  *pQueueBuffer)
**入参:QueueBuffer *pQueueBuffer
**返回:mData
**功能: 将数据弹出队列
**时间:12/19/09
**说明:null
*********************************************************************************/
unsigned char Queue_Pop(struct QueueBuffer  *pQueueBuffer)
{
        unsigned char mData;
    bit fEaReg;                                       

        mData=*pQueueBuffer->pOut ;
        if(++pQueueBuffer->pOut==pQueueBuffer->aBufferEnd)
        {
           pQueueBuffer->pOut=pQueueBuffer->aBufferStart;
        }
        fEaReg=EA;
        EA=0;
        pQueueBuffer->mCount--;
        EA=fEaReg;
        return mData;
}


EA 都关了

使用特权

评论回复
15
desert_hawk| | 2010-1-4 21:27 | 只看该作者
“环形缓冲器不需要pQueueBuffer->mCount这么个成员”,个人不太同意这个观点。
以本贴为例,如果串口一直收到数据,pIn一直增加,而主程序忙于另一件事一直没有读出数据,在接收到和缓冲区容量相同的字节后,pIn仍然等于pout,这个时候是不是可以判断缓冲区空?如果此时串口又收到一个字节,是不是可以认为缓冲区内有一个数据? 而有了pQueueBuffer->mCount,可以判断缓冲区内的数据是否有被覆盖的情况,如果被覆盖了,可以根据需要进行一些相应的出错处理。
ucosii的消息队列是标准的环形缓冲区吧,它的控制块也有一个pq->OSQEntries成员,来表示消息队列中当前的消息数量。

使用特权

评论回复
16
冷漠| | 2010-1-4 21:41 | 只看该作者
本帖最后由 冷漠 于 2010-1-4 21:42 编辑

看老外写的:

void Queue_Push ( struct QueueBuffer idata * pQueueBuffer, unsigned char mData )
{

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

使用特权

评论回复
17
红金龙吸味| | 2010-1-4 22:14 | 只看该作者
冷漠和desert_hawk 说的都有道理。
当pIn 赶上pOut 时候一定是pIN 丢了pOut一整圈,这个时候缓冲区是满的。(需要满足mCount == BUFFER_MAX_SIZE)
当pOut追赶上pIn时候,队列是空的。(需要满足mCount == 0)

if((pIn == pOut) && (mCount == BUFFER_MAX_SIZE))//缓冲区满
if((pIn == pOut) && (mCount == 0))//缓冲区空

使用特权

评论回复
18
machunshui| | 2010-1-5 00:11 | 只看该作者
另一种方法是空一个字节永远不用,
使pOut永远落后pIn一位.

使用特权

评论回复
19
呆板书生| | 2010-1-5 06:14 | 只看该作者
同意冷漠的说法

使用特权

评论回复
20
desert_hawk| | 2010-1-5 09:19 | 只看该作者
不知道16楼的办法在pIn等于POut时,如何判断缓冲区是空还是满?

使用特权

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

本版积分规则

个人签名:她说,你的睫毛看起来那么温顺,就像一只小绵羊。

15

主题

207

帖子

1

粉丝