打印

请教一下农民讲习所

[复制链接]
楼主: 一只小绵羊
手机看帖
扫描二维码
随时随地手机跟帖
81
本帖最后由 xlsbz 于 2010-1-7 17:05 编辑
73楼的这个我记得“救火车”曾经有个51上的例子,就是因为一个16bit的变量,当从0x00ff加1的时候,中间被打断,造成在主函数中读到的数据为0x1ff, 这种情况就会出错了,虽然它在调用的函数中是只读的。
就像在主函数 ...
一只小绵羊 发表于 2010-1-7 15:38


帖子的地址我都贴出来了 ,你难道没有看见么?

在前面某楼,自己找找!!

给你找到了,在54楼!!!

使用特权

评论回复
82
xlsbz| | 2010-1-7 17:07 | 只看该作者
76# 一只小绵羊

看看54楼!

你这只小绵羊,.........

使用特权

评论回复
83
冷漠| | 2010-1-7 20:48 | 只看该作者
讨论问题最好用实际代码说话。没实验过,凭空只是想象。

使用特权

评论回复
84
冷漠| | 2010-1-7 20:49 | 只看该作者

这里有意设 pIn ,pOut 为uint类型。

本帖最后由 冷漠 于 2010-1-13 14:07 编辑

看汇编结果。

    12: char _PopRing (void)  {
    13:  
    14:  unsigned char  mCount;
    15:  
    16:   while  (pIn != pOut)  {   
    17:  
C:0x0000    E50B     MOV      A,0x0B
C:0x0002    6509     XRL      A,0x09
C:0x0004    7004     JNZ      C:000A
C:0x0006    E50A     MOV      A,pIn(0x0A)
C:0x0008    6508     XRL      A,pOut(0x08)
C:0x000A    6017     JZ       C:0023
    18:     mCount=pIn - pOut;
    19:  
C:0x000C    C3       CLR      C
C:0x000D    E50B     MOV      A,0x0B
C:0x000F    9509     SUBB     A,0x09
C:0x0011    F50C     MOV      0x0C,A
    20:   return (inbuf[pOut++ & (ILEN-1)]);
    21:   
C:0x0013    0509     INC      0x09
C:0x0015    E509     MOV      A,0x09
C:0x0017    7002     JNZ      C:001B
C:0x0019    0508     INC      pOut(0x08)
C:0x001B    14       DEC      A
C:0x001C    5407     ANL      A,#0x07
C:0x001E    240D     ADD      A,#inbuf(0x0D)
C:0x0020    F8       MOV      R0,A
C:0x0021    E6       MOV      A,@R0
C:0x0022    FF       MOV      R7,A
    22: }
C:0x0023    22       RET      
C:0x0024    00       NOP      
C:0x0025    00       NOP

使用特权

评论回复
85
冷漠| | 2010-1-7 21:34 | 只看该作者
本帖最后由 冷漠 于 2010-1-13 14:09 编辑

好像0002处会因为中断改变pIn 结果,破坏 (pIn != pOut) 计算结果;
好像0011处会因为中断改变pOut 结果,破坏 mCount=pIn-pOut 计算结果;

是吗?程序设计者不是没想到:就算修改了也没什么呀?改变就改变吧,pIn 总是超前的,pOut滞后一位或几位提前判断“缓冲器空”又怎么了?再怎么样pOut也不会因差额而越过 pIn 吧?就因为这一点就大叫要加互斥?就否定 lxyppc ?!就把操作系统搬出来?

你们谁的方法都没"我"好,machunshui   ”这种方法可以用,不过有一个缺点.....”   lxyppc?“ 不是也要加互斥吗?....如果pIn 是指针你就玩不转了吧....”(意思也是有缺陷)哈哈,就自己的完美?

84楼的代码有缺陷吗?“滞后一个字节就是不行,就应该加互斥。....”

纯粹的卖弄,别人都看不到这一点?都是菜鸟,就他慧眼先发现了?“这里会因为中断造成错误..."

我不过是说话直接罢了,我周围这种人多的是,他们不是靠自己的智慧去创新,对别人首先想到的精彩横竖看不顺眼。横加指责,“不行不行,这缺点那不足,...你创新课题写论文,把我往哪放?...."

有能力自己做个漂亮的,再不济把你慧眼发现的谁都没看出来的缺陷想个绝美的办法帮别人修改一下,别老盯着别人只动嘴,装师傅行不行?

    12: char _PopRing (void)  {
    13:  
    14:  unsigned char  mCount;
    15:  
    16:   while  (pIn != pOut)  {   
    17:  
C:0x0000    E50B     MOV      A,0x0B
C:0x0002    6509     XRL      A,0x09
C:0x0004    7004     JNZ      C:000A
C:0x0006    E50A     MOV      A,pIn(0x0A)
C:0x0008    6508     XRL      A,pOut(0x08)
C:0x000A    6017     JZ       C:0023
    18:     mCount=pIn-pOut;
    19:  
C:0x000C    C3       CLR      C
C:0x000D    E50B     MOV      A,0x0B
C:0x000F    9509     SUBB     A,0x09
C:0x0011    F50C     MOV      0x0C,A
    20:   return (inbuf[pOut++ & (ILEN-1)]);
    21:   
C:0x0013    0509     INC      0x09
C:0x0015    E509     MOV      A,0x09
C:0x0017    7002     JNZ      C:001B
C:0x0019    0508     INC      pOut(0x08)
C:0x001B    14       DEC      A
C:0x001C    5407     ANL      A,#0x07
C:0x001E    240D     ADD      A,#inbuf(0x0D)
C:0x0020    F8       MOV      R0,A
C:0x0021    E6       MOV      A,@R0
C:0x0022    FF       MOV      R7,A
    22: }
C:0x0023    22       RET      
C:0x0024    00       NOP      
C:0x0025    00       NOP

使用特权

评论回复
86
一只小绵羊|  楼主 | 2010-1-7 22:04 | 只看该作者
假如mCount是unsigned short类型呢?
     9: char _popRing(void)
    10: {
    11:         unsigned short mCount;
    12:         while(pIn!=pOut)
C:0x008F    E509     MOV      A,0x09
C:0x0091    650B     XRL      A,0x0B
C:0x0093    7004     JNZ      C:0099
C:0x0095    E508     MOV      A,pIn(0x08)
C:0x0097    650A     XRL      A,pOut(0x0A)
C:0x0099    601D     JZ       C:00B8
    13:         {
    14:                 mCount = pIn-pOut;
C:0x009B    C3       CLR      C
C:0x009C    E509     MOV      A,0x09
C:0x009E    950B     SUBB     A,0x0B
C:0x00A0    F516     MOV      0x16,A
C:0x00A2    E508     MOV      A,pIn(0x08)
C:0x00A4    950A     SUBB     A,pOut(0x0A)
C:0x00A6    F515     MOV      0x15,A
    15:                 return(buf[pOut++ & (LEN-1)]);
C:0x00A8    050B     INC      0x0B
C:0x00AA    E50B     MOV      A,0x0B
C:0x00AC    7002     JNZ      C:00B0
C:0x00AE    050A     INC      pOut(0x0A)
C:0x00B0    14       DEC      A
C:0x00B1    5407     ANL      A,#0x07
C:0x00B3    240C     ADD      A,#buf(0x0C)
C:0x00B5    F8       MOV      R0,A
C:0x00B6    E6       MOV      A,@R0
C:0x00B7    FF       MOV      R7,A
    16:         }
    17: }

代码如上所示,在计算减法的时候是先计算的LSB的字节(大端格式)pIn现在是0x00ff, 执行到0x00A2 的中断到了加1,pIn变成了0x100,再回来计算结果算出来的结果是pIn==0x1ff-pOut。

使用特权

评论回复
87
原野之狼| | 2010-1-7 22:12 | 只看该作者
这个帖子很火

使用特权

评论回复
88
一只小绵羊|  楼主 | 2010-1-7 22:14 | 只看该作者
:o结贴了还能回复

使用特权

评论回复
89
冷漠| | 2010-1-8 10:14 | 只看该作者
本帖最后由 冷漠 于 2010-1-13 14:25 编辑

不做不知道。原来LZ的问题解决方法如此简单。从下式看,mCount 有意设的 uchar类型,pIn/pOut 是uint类型,结果编译器优化只运算pIn/pOut低字节。

   18:     mCount=pIn-pOut;
    19:  
C:0x000C    C3       CLR      C
C:0x000D    E50B     MOV      A,0x0B
C:0x000F    9509     SUBB     A,0x09
C:0x0011    F50C     MOV      0x0C,A

那么LZ的问题解决方法只要简单地把 mCount 的类型改为 uchar 单字节类型就行了。这大概无论在8位、16位机器上,mCount++/mCount-- 都是单条语句指令。

这样修改的条件肯定满足的,依据:
1、你的缓冲区长度不会达到0xFF,所以mCount 类型uchar没问题。
2、pIn/pOut指针高位一定在同一段内!
   证明:连接定位器肯定不会把队列(数组)定位在超过段边界(一页)的2个不同段,即使你的队列长到不合理,也可以通过连接器参数定位在也页边界。(INPAGE),所以指向队列头尾的指针pIn/pOut 高位也肯定相同。
   51单片机的DATA 指针仅仅一个字节而已,高位为00.  LZ的pIn / pOut 也可设置为指向DATA空间的单字节指针?

   所以,LZ的所长程序可用。但要做相应修改。既然LZ是8位机器,那么根本不存在 mCount需要互斥这类问题。

    86楼已经想到了?你的问题只是设想吧。编译器优化早就解决了。你设想的情况是不合理的异常,以上几个问题可能发生吗?pIn , pOut  2个指针分别指向了不同的内存页?缓冲区长度设置到了大于0xff  ? 编译器优化能通过么。编译器有很多规则,不会让你那么干。

     结果,即使pIn/pOut 是指针类型,mCount = pIn - pOut; 也是对的。(无需互斥)

接着可以证明inbuffer[pIn(指针类型)% ILIN ]也是对的,——编译器默认指针类型= int 类型。这一点可以在自己的编译器上试试,也可以查查《C语言大全》关于类型转换。

(“pIn/pOut 如果是指针,你就玩不转了吧...." )说这话的人不好下台了。尴尬。

使用特权

评论回复
90
一只小绵羊|  楼主 | 2010-1-14 16:58 | 只看该作者
发个周立功的代码
unsigned char CAN_ucReadPacketBuffer (void  *pBuf, void  *pRead)
{
    tCANPacketBuff *pRecBuf;
        tCANPacket *pReadBuf;

        pRecBuf  = (tCANPacketBuff *)pBuf;
        pReadBuf = (tCANPacket *)pRead;

        if (pRecBuf->ucSize == 0 )
        {
            pRecBuf->ucBufEmpty = EMPTY;
            pRecBuf->ucBufFull  = NOT_FULL;

            return EMPTY;
        }

        pRecBuf->ucSize --;
        *pReadBuf = pRecBuf->Buffer[pRecBuf->ucRead];
        pRecBuf->ucRead = (pRecBuf->ucRead + 1) % PACKET_MAX_BUF;
  
        return NOT_EMPTY;
}

使用特权

评论回复
91
一只小绵羊|  楼主 | 2010-1-14 16:59 | 只看该作者

;;;206            pRecBuf->ucSize --;
;;;207            *pReadBuf = pRecBuf->Buffer[pRecBuf->ucRead];
;;;208            pRecBuf->ucRead = (pRecBuf->ucRead + 1) % CAN_MAX_Buffer;
;;;209      
;;;210            return NOT_EMPTY;
;;;211    }
000092  e8bd81f0          POP      {r4-r8,pc}
                  |L1.150|
000096  78a8              LDRB     r0,[r5,#2]            ;206
000098  1e40              SUBS     r0,r0,#1              ;206
00009a  70a8              STRB     r0,[r5,#2]            ;206
00009c  7928              LDRB     r0,[r5,#4]            ;207
00009e  eb000280          ADD      r2,r0,r0,LSL #2       ;207
0000a2  f1050008          ADD      r0,r5,#8              ;207
0000a6  eb000182          ADD      r1,r0,r2,LSL #2       ;207
0000aa  2214              MOVS     r2,#0x14              ;207
0000ac  4638              MOV      r0,r7                 ;207
0000ae  f7fffffe          BL       __aeabi_memcpy4
0000b2  7928              LDRB     r0,[r5,#4]            ;208
0000b4  1c40              ADDS     r0,r0,#1              ;208
0000b6  2114              MOVS     r1,#0x14              ;208
0000b8  fb90f2f1          SDIV     r2,r0,r1              ;208
0000bc  fb010012          MLS      r0,r1,r2,r0           ;208
0000c0  7128              STRB     r0,[r5,#4]            ;208
0000c2  2005              MOVS     r0,#5                 ;210
0000c4  e7e5              B        |L1.146|

使用特权

评论回复
92
一只小绵羊|  楼主 | 2010-1-14 16:59 | 只看该作者
;;;206            pRecBuf->ucSize --;
;;;207            *pReadBuf = pRecBuf->Buffer[pRecBuf->ucRead];
;;;208            pRecBuf->ucRead = (pRecBuf->ucRead + 1) % CAN_MAX_Buffer;
;;;209      
;;;210            return NOT_EMPTY;
;;;211    }
000092  e8bd81f0          POP      {r4-r8,pc}
                  |L1.150|
000096  78a8              LDRB     r0,[r5,#2]            ;206
000098  1e40              SUBS     r0,r0,#1              ;206
00009a  70a8              STRB     r0,[r5,#2]            ;206

00009c  7928              LDRB     r0,[r5,#4]            ;207
00009e  eb000280          ADD      r2,r0,r0,LSL #2       ;207
0000a2  f1050008          ADD      r0,r5,#8              ;207
0000a6  eb000182          ADD      r1,r0,r2,LSL #2       ;207
0000aa  2214              MOVS     r2,#0x14              ;207
0000ac  4638              MOV      r0,r7                 ;207
0000ae  f7fffffe          BL       __aeabi_memcpy4
0000b2  7928              LDRB     r0,[r5,#4]            ;208
0000b4  1c40              ADDS     r0,r0,#1              ;208
0000b6  2114              MOVS     r1,#0x14              ;208
0000b8  fb90f2f1          SDIV     r2,r0,r1              ;208
0000bc  fb010012          MLS      r0,r1,r2,r0           ;208
0000c0  7128              STRB     r0,[r5,#4]            ;208
0000c2  2005              MOVS     r0,#5                 ;210
0000c4  e7e5              B        |L1.146|

使用特权

评论回复
93
一只小绵羊|  楼主 | 2010-1-14 16:59 | 只看该作者
也有这种问题

使用特权

评论回复
94
一只小绵羊|  楼主 | 2010-1-14 17:00 | 只看该作者
小概率

使用特权

评论回复
95
wangwo| | 2010-1-14 18:20 | 只看该作者
以前还撞上过:)

使用特权

评论回复
96
冷漠| | 2010-1-14 20:02 | 只看该作者

keil 的用法。没有用到mCount这个变量。空/满照样判别。

本帖最后由 冷漠 于 2010-1-15 10:18 编辑

****************************************************************************/
/*                                                                          */
/*       SERIAL.C:  Interrupt Controlled Serial Interface                   */
/*                                                                          */
/****************************************************************************/
#pragma CODE DEBUG OBJECTEXTEND
#include <reg52.h>                    /* special function register 8052     */

#define  ILEN  8                      /* size of serial receiving buffer    */
unsigned char  istart;                /* receiving buffer start index       */
unsigned char  iend;                  /* receiving buffer end index         */
idata    char  inbuf[ILEN];           /* storage for receiving buffer       */


/****************************************************************************/
/*       _getkey:  interrupt controlled _getkey                             */
/****************************************************************************/
char _getkey (void)  {
  return (inbuf[istart++ & (ILEN-1)]);
}

/****************************************************************************/
/*       serial:  serial receiver / transmitter interrupt                   */
/****************************************************************************/
serial () interrupt 4 using 1  {     /* use registerbank 1 for interrupt    */
  unsigned char c;
  bit   start_trans = 0;
  if (RI)  {                         /* if receiver interrupt               */
    c = SBUF;                        /* read character                      */
    RI = 0;                          /* clear interrupt request flag        */
   
        if (istart + ILEN != iend)  {
          inbuf[iend++ & (ILEN-1)] = c;
        }
    }

}

使用特权

评论回复
97
冷漠| | 2010-1-15 10:33 | 只看该作者

以前的思维太局限了。

本帖最后由 冷漠 于 2010-1-15 10:44 编辑

突然看出 Keik 关键精彩的地方,让我们无谓地争论了半天。
          mCount=pIn-pOut;
上式2个变量pIn / pOut 位置放错了! 应该是:
         mCount= ILEN - (pIn-pOut)  = ILEN+pOut-pIn ;
或者就是: mCount=pOut-pIn;        //pIn 是由其他函数改变的量,应放在后面。
不放心就: mCount=abs( pOut-pIn );





看懂了别人写的精彩之处才知道自己几斤几两。

使用特权

评论回复
98
itelectron| | 2010-1-23 19:23 | 只看该作者
MARK 逆时针

使用特权

评论回复
99
lczsx2000| | 2012-1-27 13:16 | 只看该作者
顶上来,看我以前08年回复一个网友的帖子
https://bbs.21ic.com/icview-33190-1-1.html
21ic保留不完整,我做的关键的两段优化过程也不见了。
对于kfifo的51上修订版本gfifo,在单核51上,在单写单读的fifo应用中,不需要互斥保护,而且代码质量比本帖子网友提到的任何一个代码解决方案都要好(从时间、空间、代码可读性和通用性都要好)。

使用特权

评论回复
100
刘前辈| | 2012-1-27 20:10 | 只看该作者
64楼冷漠

     那么“变量的赋值和引用越近越好,变量的跨度和生存时间越小越好。”这是使用变量的基本规则吧?

    我能够在本函数内部利用已知条件求得局部变量 mCount,我为什么要把自己的“攻击窗口”扩大到另一个函数?!
    只有在迫不得已的情况下才不得不存在攻击窗口。41楼认为无法利用已知条件求得mCount ,所以不得不设立了大跨度、长存活时间的攻击窗口。那么 lxyppc 怎么就能利用函数内部已知条件求得 mCount ?特别是Keil 也是这么做的。——能够缩小变量作用域,取决于程序员的“智力上的可管理性。”(而不是“方便性”)


冷漠兄说的都是书上看来的内容,反对者都是自己的“创新想象”。

能有创新想象的人应该去写书。和书上教授辩论能说明自己更高明?听说冷漠写的书快出版了,我想他不会再来这里和谁辩论了。最好自己也写一本比冷漠还高明的书才体现个人的尊严。



、、

使用特权

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

本版积分规则