[問題] 8051陣列索引使用uint與uchar出現差異

看板C_and_CPP作者 (brominelove)時間7年前 (2018/08/13 19:55), 7年前編輯推噓0(0013)
留言13則, 3人參與, 7年前最新討論串1/1
開發平台(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

08/13 20:10, 7年前 , 1F
MSG_count=30 時, scanf("%s", ...); 字串結束字元放到...?!
08/13 20:10, 1F
放到MSG[MSG_count=30],請問這步有什麼可能的問題嗎? ※ 編輯: brominelove (141.113.69.183), 08/13/2018 20:23:49

08/13 21:05, 7年前 , 2F
可能會寫到外面去啊,MSG[n], n = 0~30
08/13 21:05, 2F

08/13 21:05, 7年前 , 3F
你的結束字元就被放到MSG[31]去了
08/13 21:05, 3F

08/13 21:05, 7年前 , 4F
結果就是把你的uchar弄成0了
08/13 21:05, 4F
Lipraxde:我理解你的意思了,那請問為什麼令成uint時不會有這現象呢?

08/13 21:38, 7年前 , 5F
你要的是 scanf("%s"...? scanf("%c"...? getchar()? 還是?
08/13 21:38, 5F
yvb: 我想要的是單一字符(0xXX),但我使用%c與getchar無法排除結束字元,會顯示在LCD 上,在keil上使用fflush也不成功,所以最後使用%s,請問有更好的建議嗎? ※ 編輯: brominelove (141.113.69.183), 08/13/2018 21:46:56

08/13 22:02, 7年前 , 6F
應該是中間被插了空格用來對齊,你會用debugger的話可
08/13 22:02, 6F

08/13 22:02, 7年前 , 7F
以注意看看記憶體位置
08/13 22:02, 7F

08/13 22:06, 7年前 , 8F
我建議練習一下uart中斷處理、在isr裡面手動做處理
08/13 22:06, 8F

08/13 22:19, 7年前 , 9F
用 scanf("%s"... 是讀入字串, 且用空白字元分段(略過),
08/13 22:19, 9F

08/13 22:20, 7年前 , 10F
而不是逐字讀取; 至於如何排除結束字元? 不要印它不行嗎?
08/13 22:20, 10F

08/13 22:22, 7年前 , 11F
意思就是檢查若是結束字元(其實是enter吧?) 就不加MSG_count.
08/13 22:22, 11F

08/13 22:25, 7年前 , 12F
getchar讀進來是結束字元濾掉就好了吧
08/13 22:25, 12F

08/13 22:25, 7年前 , 13F
這樣 WriteString() 就不會多印出enter符號了.
08/13 22:25, 13F
謝謝樓上幾位解說,我弄懂了也解掉bug了 :) ※ 編輯: brominelove (94.218.215.219), 08/14/2018 00:36:18
文章代碼(AID): #1RSN798j (C_and_CPP)