最近做的專案采用的主控芯片是8位的MCU,在但是在寫下3行代碼后,就出現了無法解決的Bug,而且導師告訴我,之前去華為的那個工程師當時也遇到過這個問題,具體是怎么解決的他也不清楚,好吧,只能靠自己了,首先告訴你們,初始化配置是沒有任何問題的,但是就這3行代碼的Bug讓我找了一星期,廢話不多說,下面是代碼,
unsigned short int time_count = 0;
int main()
{
tim0_init();/* 5ms定時器初始化 */
uart1_init();/* 串口1初始化 */
printf("uart init ok!\r\n");
while(1)
{
if(time_count >= 400)
{
time_count = 0;
printf("time is end!\r\n");/* 時間到了 */
}
}
}
void tim0_isr() interrupt 1/* 5ms定時器中斷 */
{
time_count++;
}
代碼十分簡單,定義了個16位的變數,在5Ms的定時器中斷中自加,當這個變數大于等于400,即2S時,通過串口列印輸出時間到了,
但是,但是,請注意,在實際測驗時發現,偶爾,是偶爾,沒有規律,這個數到了256后就列印輸出時間到了,而且這個出現的次數是隨機的,沒有任何規律,
我瞬間懵了,這個代碼有問題?學了這么多年C喂了狗了?一剎那我都恍惚了,于是向別人請教,他人經過一番思索,折騰了一上午,最后也沒辦法解決,上網百度更是搜索不到,但是搜索到不少 “你相信玄學嗎?”,我可是一個崇尚科學的三好少年,我就不相信真的是所謂的玄學,我相信只要學的深,就能解決,
在經過不斷的思索以及上網查找資料,后來和廠家聯系,最后終于找到了問題所在,
因為使用的是8位的單片機,8位,顧名思義,一個指令周期CPU只能處理8位資料,在代碼中我定義的是16位的變數,也就是說在對這個變數進行操作時,需要兩個指令周期,但是每一個指令周期結束后,cpu都會判斷有沒有中斷產生,從而去回應中斷事件,
問題就出在這里,如果在操作這個16位變數時,恰巧有中斷產生,就可能會有問題,好,明確了問題的方向,找起來就比較簡單了,在主函式中,采用if條件判斷,判斷 count_time >= 400;一般編譯器對if條件判斷基本是采用作差的形式,即判斷 count_time - 400 是否大于0,條件為真,就成立,由于變數是16位,8位的CPU需要兩個指令周期,即兩次才能判斷出來,
第一次,用變數 count_time 的低8位 - 400的低8位,400的低8位是 (0b10010000),如果這時候剛好定時器中斷來了,那么去回應中斷事件,對 count_time這個變數自加,假如中斷來之前,count_time這個變數的值為255,即(0b11111111),那么進入中斷后,這個數就變為256,即(0b00000001 00000000),產生了高位進位,中斷處理結束后,繼續回去處理主函式,由于上一次判斷了低8位,這次判斷高8位,由于產生了進位,所以變數的高8位是1,恰巧400的高8位也是1,然后就判斷這兩個數相等,這個if條件就成立了,
這里可能有小伙伴會問,為什么要先判斷低8位呢,如果先判斷高8位,不就不會出現這個問題了嗎,這個就和編譯器有關系了,因為51單片機采用的存盤模式是大端模式,即高位資料存放在高位地址,當從這個變數的起始地址取資料時,優先取到的是低地址的資料,即變數的低位元組,因此會優先判斷低8位,
問題到此已經找到了,要解決的話就比較容易了,代碼如下:
int main()
{
unsigned short int time = 0;
tim0_init();/* 5ms定時器初始化 */
uart1_init();/* 串口1初始化 */
printf("uart init ok!\r\n");
while(1)
{
time = time_count;
if(time == time_count)
{
if(time >= 400)
{
time_count = 0;
printf("time is end!\r\n");/* 時間到了 */
}
}
}
}
這樣就可以了,先把這個值賦給一個臨時變數,然后判斷這兩個值是否相等,判斷的目的就是為了防止在賦值后出現進位的情況,如果出現了,那么這兩個數就不相等,條件不成立,等待下一次回圈到來時,就一定會相等,因為定時器中斷剛剛發生,不會立馬再進中斷,所以這樣就可以解決時間未到2s就進去的情況發生,
到此為止,問題解決,所以,還是要相信科學,我們口中所謂的玄學不過是無知罷了,哈哈,
如有錯誤之處,還請及時指正,在此謝過!
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/190742.html
標籤:其他
上一篇:MySQL的“My”
