看板 C_and_CPP 關於我們 聯絡資訊
開發平台(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