打印

请教 PICC 疑惑(有進展,玩PICC的都來說說你們遇到過么)

[复制链接]
4334|23
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Light_David|  楼主 | 2011-10-5 22:34 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Light_David 于 2011-10-18 20:50 编辑

搞了一个AD累加64次然后求平均的简单滤波器。
读AD结果先赋到临时变量(int型),再加总就是对的,
而改成最下面那句就不能得到正确结果.
请教一下这是为什么?
用PICC9.60+MPLAB8.33;
结构体里面的AD_RESULT[0]也是int型,不能解释为类型升级失败吧?

for(k=0;k<64;k++)
{
ADGO=1;
while(ADGO);
m = (256*ADRESH+ADRESL);
AD.AD_RESULT[0] += m;            //正确
//AD.AD_RESULT[0] += (256*ADRESH+ADRESL);//错误
delay_ms(5);
}

另外发现MPLAB SIM有一个不知道算不算bug的bug;
16F系列(新的4位数字编号的增强型除外)
T2输入分频结构描述到:
T2CON最低两位
00=1:1
01=4:1
1X=16:1
可是如果写入的是11的话,SIM中用跑秒看,是当作64:1的!!!
(新的4位数字编号的增强型才有64:1)
就这样被俺认为神器一样的跑秒功能给无情的忽悠了。
看起来以后对Datasheet中描述的X都要认为只能写0了....
沙发
Light_David|  楼主 | 2011-10-9 11:43 | 只看该作者
这么些天过去了,没人回复:(

使用特权

评论回复
板凳
virtualtryon| | 2011-10-9 12:02 | 只看该作者
LZ把编译以后的汇编代码发上来看一下,有可能是强制类型转换出问题了.

使用特权

评论回复
地板
yewuyi| | 2011-10-9 12:29 | 只看该作者
1、m = (256*ADRESH+ADRESL);
AD.AD_RESULT[0] += m;            //正确
//AD.AD_RESULT[0] += (256*ADRESH+ADRESL);//错误
delay_ms(5);
A1:在我见到的所有的PICC16版本中,写成AD.AD_RESULT[0] += (256*ADRESH+ADRESL);编译的结果几乎都与设想的不对,这主要是256*ADRESH造成的,你可以在这个前面加unsigned int强制转换一下看看,这个涉及到局部变量的处理问题,而且在我用其它编译器测试的结果来看,基本也都是和PICC16一样的,那很显然了,就是需要强制类型转换了。
2、T2CON
A2:这个问题没有注意过,不过,俺也不用IDE的那个跑表功能,跑表一般没什么太大用途,你把它当成神器,估计和你代码中的那些delay_ms(5);有关吧?!!!

使用特权

评论回复
5
XIEYUANBIN| | 2011-10-9 15:55 | 只看该作者
PICC,对于过于复杂的语句编译出错几率太大,最好不用。
近期由于新品太多,PICC升级BUG增多,硬件也有很多小问题出现,也是很头疼的问题。

使用特权

评论回复
6
Light_David|  楼主 | 2011-10-10 18:45 | 只看该作者
5# XIEYUANBIN
:L 由汇编一路走来就怕代码長(是一行一指令)经常些寫类似下面这样的代码:
(沒人像我这样吧,呵呵;各位可能会以为下面是乱码嗎? 哦,不对,只是烂碼而已)
若PICC真是这样,还真有些怕怕..:Q

void Draw_word2(char d_where,char page,char width,const char *p,char n,char x)
{char k,j;
if((d_where>23)||(page>3))return;
d_where=d_where*5;
page|=0xb8;
p+=n*(width*1);
p-=0x20*5;
for(k=0;k<(width*1);k++)
  {
        lcd_cmd(((d_where+(k%width))>60)?2:1,(d_where+(k%width))%61);
        lcd_cmd(((d_where+(k%width))>60)?2:1,page+((k<width)?0:1));
        lcd_dat(((d_where+(k%width))>60)?2:1,x?(*(p+k))+0x80:*(p+k));
  }
}

if(FL_B.ALL)
{NG=1;send_lcd(0XC0,CLS);
//send_lcd(0XC0,"SH:");for(k=0;k<5;k++){if(fail_buff[THN-1][0][k]){lcd_DAT(k+0x41);lcd_DAT('-');for(j=0;j<4;j++)if(fail_buff[THN-1][0][k]&(1<<j))lcd_DAT(j+0x31);lcd_DAT(',');}}
  send_lcd(0XC0,FL_B.onebit.SH?"SH:":FL_B.onebit.VF_H?"VH:":CLS);if(FL_B.onebit.SH||FL_B.onebit.VF_H){for(k=0;k<5;k++){if(fail_buff[THN-1][FL_B.onebit.SH?0:3][k]){lcd_DAT(k+0x41);lcd_DAT('-');for(j=0;j<4;j++)if(fail_buff[THN-1][FL_B.onebit.SH?0:3][k]&(1<<j))lcd_DAT(j+0x31);lcd_DAT(',');}}}
  send_lcd(0X94,FL_B.onebit.OP?"OP:":FL_B.onebit.VF_L?"VL:":CLS);if(FL_B.onebit.OP||FL_B.onebit.VF_L){for(k=0;k<5;k++){if(fail_buff[THN-1][FL_B.onebit.OP?1:4][k]){lcd_DAT(k+0x41);lcd_DAT('-');for(j=0;j<4;j++)if(fail_buff[THN-1][FL_B.onebit.OP?1:4][k]&(1<<j))lcd_DAT(j+0x31);lcd_DAT(',');}}}
  send_lcd(0XD4,FL_B.onebit.TU?"TU:":FL_B.onebit.CH?  "CH:":CLS);if(FL_B.onebit.TU||FL_B.onebit.CH  ){for(k=0;k<5;k++){if(fail_buff[THN-1][FL_B.onebit.TU?2:5][k]){lcd_DAT(k+0x41);if(FL_B.onebit.TU){lcd_DAT('-');for(j=0;j<4;j++)if(fail_buff[THN-1][2][k]&(1<<j))lcd_DAT(j+0x31);}lcd_DAT(',');}}}
}

使用特权

评论回复
7
Light_David|  楼主 | 2011-10-10 18:50 | 只看该作者
4# yewuyi
谢谢叶斑,等改天有时间再看看反汇编代码,看看到底编译成神马了.

使用特权

评论回复
8
谈的元| | 2011-10-10 19:21 | 只看该作者
“256*ADRESH造成的,你可以在这个前面加unsigned int强制转换”

我以前也经常遇到这个问题,就是没加强制转换的问题

使用特权

评论回复
9
l4157| | 2011-10-10 23:17 | 只看该作者
应该用unsigned int,int 是有符号整数...

使用特权

评论回复
10
Light_David|  楼主 | 2011-10-18 16:10 | 只看该作者
:$ 感謝LS兩位提醒,這是PICC的BUG(至少是9.6的,其他版本不知),跟加不加unsigned int沒有關係。

已經跟蹤到ASM代碼 是最終做結果的低位相加運算時取錯了地址造成的。

使用特权

评论回复
11
Light_David|  楼主 | 2011-10-18 16:43 | 只看该作者
本帖最后由 Light_David 于 2011-10-18 16:44 编辑
1、m += (256*ADRESH+ADRESL);...
在我见到的所有的PICC16版本中,写成AD.AD_RESULT[0] += (256*ADRESH+ADRESL);编译的结果几乎都与设想的不对, ...
yewuyi 发表于 2011-10-9 12:29


不應該最新的版本還會這樣吧?還以為只是在9.6版本中有問題...

這個BUG侷限在:
m += 256*ADRESH+ADRESL; //這樣語句中
m= 256*ADRESH+ADRESL;  //并沒有問題
m += 256*a+b;                     //也是沒有問題的。a,b同樣char型,

同樣,實驗過:
先   
a=ADRESH;b=ADRESL;
然後
m += 256*a+b;
這樣也沒有問題,(說明和AD模塊沒有關係)。
不知道這錯誤代碼是怎麽生出來的,怕怕

使用特权

评论回复
12
yewuyi| | 2011-10-18 16:50 | 只看该作者
如果你加了恰当的强制转换代码,则是可以通过的。

另外,如果你写成:AdVal+=(ADRESH<<8)+ADRESL;

你可以试试看结果如何!!!

使用特权

评论回复
13
Light_David|  楼主 | 2011-10-18 18:41 | 只看该作者
本帖最后由 Light_David 于 2011-10-18 18:43 编辑

12# yewuyi
葉斑竹有確實試過嗎?
還正中是你的籤名的那句話?

1.我將改成這樣都沒辦法獲取到正確的結果:

AdVal +=(unsigned int)((unsigned int)((unsigned int)ADRESH<<8)+(unsigned int)ADRESL);

2.AdVal+=(ADRESH<<8)+ADRESL;一樣不行.

使用特权

评论回复
14
Light_David|  楼主 | 2011-10-18 20:05 | 只看该作者
有使用如下的簡單測試代碼驗證這個問題:
(有耐心的請看完,一定有所收穫)
測試代碼:
#include<htc.h>
__CONFIG(0X1FF2);
unsigned char a,b;
unsigned int c;
main()
{
c=a*256+b;
while(1);
}

截取關鍵ASM Code:

8:                 c = a*256+b;
   
   7FA    1283     BCF 0x3, 0x5
   7FB    0820     MOVF 0x20, W
   7FC    00A3     MOVWF 0x23
   7FD    0821     MOVF 0x21, W
   7FE    00A2     MOVWF 0x22
9:                  
                   while(1);
   7FF    2FFF     GOTO 0x7ff

說明一下:
  地址位置:  變量
   0X20      a
     0X21      b
     0X22      c低8位
   0X23      c高8位

c=a*256+b;
可以看到這段代碼非常簡單,優化的也很好;就兩步
1.直接將a的內容放到c的高8位(等於*256)
2.將b的內容放到c的低8位。
即完成了整個運算。


再看
c += a*256+b;

8:                 c +=a*256+b;

   7EB    1283     BCF 0x3, 0x5
   7EC    0820     MOVF 0x20, W
   7ED    1283     BCF 0x3, 0x5
   7EE    00A5     MOVWF 0x25
   7EF    01A4     CLRF 0x24
   7F0    0821     MOVF 0x21, W
   7F1    00A6     MOVWF 0x26
   7F2    01A7     CLRF 0x27
   7F3    0824     MOVF 0x24, W
   7F4    07A6     ADDWF 0x26, F
   7F5    1803     BTFSC 0x3,0
   7F6    0AA7     INCF 0x27, F
   7F7    0825     MOVF 0x25, W
   7F8    07A7     ADDWF 0x27, F
   7F9    0826     MOVF 0x26, W
   7FA    07A2     ADDWF 0x22, F
   7FB    1803     BTFSC 0x3, 0
   7FC    0AA3     INCF 0x23, F
   7FD    0827     MOVF 0x27, W
   7FE    07A3     ADDWF 0x23, F

9:
                   while(1);
   7FF    2FFF     GOTO 0x7ff

初看這個反彙編有些暈是嗎,不怕
其實很簡單0X24~0X27是兩個int型臨時變量,暫且命名為temp1L,temp1H,temp2L,temp2H。
這下就方便看了.
   7EC    0820     MOVF a, W
   7EE    00A5     MOVWF temp1H
   7EF    01A4     CLRF temp1L          //a放到臨時變量1高位(*256嘛),清臨時變量低位,作用:完成a*256 并將結果放到int型臨時變量temp1中
  7F0    0821     MOVF b, W
   7F1    00A6     MOVWF tempL
   7F2    01A7     CLRF tempH     //b放到臨時變量2低位,清臨時變量2高位,作用:完成 b複制到臨時變量temp2中
   7F3    0824     MOVF temp1L, W
    7F4    07A6     ADDWF temp2L, F //兩個臨時變量低位相加
   7F5    1803     skpnc
    7F6    0AA7     INCF temp2H, F  //確認進位
   7F7    0825     MOVF temp1H, W  
    7F8    07A7     ADDWF temp2H, F //高位相加       
                                  //典型的int型數據加法運算,結果放到temp2中


   7F9    0826     MOVF temp2L, W
     7FA    07A2     ADDWF c, F
     7FB    1803     skpnc
     7FC    0AA3     INCF (high)c, F
     7FD    0827     MOVF temp2H, W
     7FE    07A3     ADDWF (high)c, F
//不需要羅嗦了,temp2和c相加并將結果放到c,即告完成

這就完成了c +=a*256+b;
步驟是這樣的:
1.先計算a*256 并放到臨時變量,然後計算b(b就是一個複制過程)
2.用a*256的臨時結果与b相加
3.再用上一步的計算結果和c相加.

看到這裏,可見一切是多麽的正常;

   好吧,那請再往下看::P

使用特权

评论回复
15
Light_David|  楼主 | 2011-10-18 20:37 | 只看该作者
再看有問題的代碼;
    c +=(256*ADRESH)+ADRESL;
這裏先說明下ADRESH/L等特殊寄存器在PICC的頭文件中被定義為static volatile unsigned char ,
上面驗證c +=a*256+b時,我已經將a,b聲明成static volatile unsigned char,但是并沒有像這樣出錯,好吧,只能再看反彙編了...

c +=(256*ADRESH)+ADRESL;
關鍵ASM代碼
   7EB    081E     MOVF 0x1e, W
    7EC    00A3     MOVWF 0x23
    7ED    01A2     CLRF 0x22
    7EE    1683     BSF 0x3, 0x5
    7EF    081E     MOVF 0x1e, W
    7F0    1283     BCF 0x3, 0x5
    7F1    00A4     MOVWF 0x24
    7F2    01A5     CLRF 0x25
    7F3    0822     MOVF 0x22, W
    7F4    07A4     ADDWF 0x24, F
    7F5    1803     BTFSC 0x3, 0
    7F6    0AA5     INCF 0x25, F
    7F7    0823     MOVF 0x23, W
    7F8    07A5     ADDWF 0x25, F
    7F9    0822     MOVF 0x22, W
    7FA    07A0     ADDWF 0x20, F
    7FB    1803     BTFSC 0x3, 0
    7FC    0AA1     INCF 0x21, F
    7FD    0823     MOVF 0x23, W
    7FE    07A1     ADDWF 0x21, F

還是先人工修飾一下容易看些

1. ADRESH和ADRESL地址都為0X1E(所在bunk不同)
2. c變量地址為0X20(LSb),0X21(Msb)
3. 0x22~0x25為兩個int 臨時變量,
   還取名temp1L,temp1H,temp2L,temp2H,

   7EB    081E     MOVF ADRESH, W
   7EC    00A3     MOVWF temp1H
   7ED    01A2     CLRF temp1L                //完成ADRESH*256 并將結果放到temp1中
  7EE    1683     BSF 0x3, 0x5
                                               //轉bank1
   7EF    081E     MOVF ADRESL, W
   7F0    1283     BCF 0x3, 0x5
   7F1    00A4     MOVWF temp2L
   7F2    01A5     CLRF temp2H                //完成ADRESL取值 并將結果放到temp2中
  7F3    0822     MOVF temp1L, W
   7F4    07A4     ADDWF temp2L, F     
   7F5    1803     BTFSC 0x3, 0
   7F6    0AA5     INCF temp2H, F
   7F7    0823     MOVF temp1H, W
   7F8    07A5     ADDWF temp2H, F
                                              //又是典型的兩個int數據相加,--兩個臨時變量相加,並將結果放到temp2中,注意是temp2

   7F9    0822     MOVF temp1L, W
   7FA    07A0     ADDWF c, F
   7FB    1803     BTFSC 0x3, 0
   7FC    0AA1     INCF (high)c, F     //哈哈,問題出現了,將上面的臨時結果再次和c相加時,取的時temp1,!!而不是temp2..

   7FD    0823     MOVF temp1H, W
   7FE    07A1     ADDWF (high)c, F    //這結果若是對了,那就奇怪了。:L

使用特权

评论回复
16
Light_David|  楼主 | 2011-10-18 20:45 | 只看该作者
這個看似小問題隱藏的其實很深。
使用PIC的AD時我們經常要連續採集多次AD取平均
可能會使用下面這樣的代碼:
  c +=(256*ADRESH)+ADRESL;
可是這樣的代碼在PICC裏面并不能得到想像中結果,

隨後大家可能馬上想到是不是數據類型提升規則的問題猛加強制類型轉換或者違背自己的想法猛加()優先機製,
可這樣做仍不能得到正確結果,讓人很懊惱、

本想進一步瞭解此問題的原因,
使用下的這樣的代碼來模擬算算看
  c +=(256*a)+b;
新鮮的事發生了,這樣的計算确是可以得到正確的結果了。
讓人感覺非常奇怪,甚至詭異.

由上面的反彙編看來這應該是PICC的一個BUG.
隨後又有做測試驗證,
c +=(256*a)+b;

只要將a和b其中之一或者一起放到非bank0中即會出現這樣的錯誤!!!




使用特权

评论回复
17
yewuyi| | 2011-10-19 08:24 | 只看该作者
12# yewuyi
葉斑竹有確實試過嗎?
還正中是你的籤名的那句話?

1.我將改成這樣都沒辦法獲取到正確的結果:

AdVal +=(unsigned int)((unsigned int)((unsigned int)ADRESH ...
Light_David 发表于 2011-10-18 18:41


有测试,我自己一直都是AdVal+=(ADRESH<<8)+ADRESL;
如上可以正常编译通过。

使用特权

评论回复
18
lanyong| | 2011-10-19 08:24 | 只看该作者
好长时间没有这样的好贴了。

兄弟,台湾工程师?

还没细看,兄弟精神可嘉,加油。

使用特权

评论回复
19
lanyong| | 2011-10-19 08:27 | 只看该作者
我的建议是,尽量使用简单的语句。多写几行。

使用特权

评论回复
20
yewuyi| | 2011-10-19 08:30 | 只看该作者
1、bank的问题没有测试过,不清楚。
2、不是猛加强制转换就一定可以通过的。
3、在“AdVal+=(ADRESH<<8)+ADRESL;”中的“(ADRESH<<8)”应当会被编译器进行位数扩展,扩展之后就成了16位字长,然后形成一个整型数据和字节型ADRESL相加求和。

使用特权

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

本版积分规则

个人签名:二姨提醒你:此人回答问题基本都是扯D.

15

主题

273

帖子

2

粉丝