作者brominelove (brominelove)
看板C_and_CPP
標題[問題] 8051陣列索引使用uint與uchar出現差異
時間Mon Aug 13 19:55:49 2018
開發平台(Platform): (Ex: Win10, Linux, ...)
Windows 7
編譯器(Ex: GCC, clang, VC++...)+目標環境(跟開發平台不同的話需列出)
Keil C51
額外使用到的函數庫(Library Used): (Ex: OpenGL, ...)
reg51.h, stdio.h
問題(Question):
在一個把終端機藉由UART送一個一個字元給8051、再讓8051與LCD溝通使LCD顯示終端機送
的字元的練習中,發現陣列索引使用uchar和uint宣告,得到的結果不同(索引最大到31)。
LCD是16*2顯示,我構想的是在終端機上一個字輸入完後按enter再輸入下一個字,排列滿
LCD第一列16字時就寫到第二列,最高塞滿31字,當輸入超過第31個字時,所有的字往前擠
一位,第一位被捨棄,而第31位放最新輸入的字,以此類推。
餵入的資料(Input):
例:
1234567890abcdef
ghijklmnopqrstu_ (_是游標) -->再輸入v(enter) w(enter) x(enter)三個字元
預期的正確結果(Expected Output):
4567890abcdefghi
jklmnopqrstuvwx_
錯誤結果(Wrong Output):
vwx_567890abcdef
ghijklmnopqrstu
程式碼(Code):(請善用置底文網頁, 記得排版,禁止使用圖檔)
#include <reg51.h>
#include <stdio.h>
(省略LCD1602介面函數)
void init_uart(void)
{
SCON = 0x50;
TMOD = 0x20;
TCON = 0x40;
TH1 = 253;
TI = 1;
PCON |=0x80;
}
void main()
{
unsigned char k;
unsigned char MSG[31];
unsigned int MSG_count = 0;
init_uart();
initial();
while(1)
{
if (MSG_count <=30)
{
scanf("%s", &MSG[MSG_count]);
MSG_count++;
}
else
{
for (k=0; k<30; k++)
MSG[k] = MSG[k+1];
scanf("%s", &MSG[30]);
}
WriteString(MSG_count, MSG);
}
}
補充說明(Supplement):
預期結果的部分是由上述程式碼正確得出的,但在debug前我是將標黃色的那欄宣告成
uchar形態,發現送的字超過第31個時會跑到第一位去;debug模式下觀察發現MSG_count會
從30(0x1E)直接跳回1(0x01),進不去else的迴圈,而造成LCD顯示成上述的錯誤結果;然
而改成uint後MSG_count會一直卡在31,符合我的期望。
想不透為什麼,照理來說uchar範圍是0-255,不應該在這出現溢位跑回0而進不了else迴圈
才對?能否有人告知我哪裡有錯誤?感謝。
因為在debug模式中觀察到的行為與LCD顯示相同,故推測中間跟LCD1602的溝通介面應該與
上述錯誤無關,為了方便閱讀,將其省略,若有人懷疑問題源於介面,我會再po上來。
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 141.113.69.183
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1534161353.A.22D.html
→ yvb: MSG_count=30 時, scanf("%s", ...); 字串結束字元放到...?! 08/13 20:10
放到MSG[MSG_count=30],請問這步有什麼可能的問題嗎?
※ 編輯: brominelove (141.113.69.183), 08/13/2018 20:23:49
→ Lipraxde: 可能會寫到外面去啊,MSG[n], n = 0~30 08/13 21:05
→ Lipraxde: 你的結束字元就被放到MSG[31]去了 08/13 21:05
→ Lipraxde: 結果就是把你的uchar弄成0了 08/13 21:05
Lipraxde:我理解你的意思了,那請問為什麼令成uint時不會有這現象呢?
→ yvb: 你要的是 scanf("%s"...? scanf("%c"...? getchar()? 還是? 08/13 21:38
yvb: 我想要的是單一字符(0xXX),但我使用%c與getchar無法排除結束字元,會顯示在LCD
上,在keil上使用fflush也不成功,所以最後使用%s,請問有更好的建議嗎?
※ 編輯: brominelove (141.113.69.183), 08/13/2018 21:46:56
→ Lipraxde: 應該是中間被插了空格用來對齊,你會用debugger的話可 08/13 22:02
→ Lipraxde: 以注意看看記憶體位置 08/13 22:02
→ Lipraxde: 我建議練習一下uart中斷處理、在isr裡面手動做處理 08/13 22:06
→ yvb: 用 scanf("%s"... 是讀入字串, 且用空白字元分段(略過), 08/13 22:19
→ yvb: 而不是逐字讀取; 至於如何排除結束字元? 不要印它不行嗎? 08/13 22:20
→ yvb: 意思就是檢查若是結束字元(其實是enter吧?) 就不加MSG_count. 08/13 22:22
→ sarafciel: getchar讀進來是結束字元濾掉就好了吧 08/13 22:25
→ yvb: 這樣 WriteString() 就不會多印出enter符號了. 08/13 22:25
謝謝樓上幾位解說,我弄懂了也解掉bug了 :)
※ 編輯: brominelove (94.218.215.219), 08/14/2018 00:36:18