|
發布時間: 2021-12-4 20:59
正文摘要:用定時器實現準確的延時,準確地控制對應的燈閃爍的時間間 隔,并通過按鍵改變時間間隔。比如:開始時,第一個燈閃爍,時間 間隔為1s。當按下按鍵后,前兩個燈閃爍,時間間隔為2s,如此循環, 若在時間間隔為8s時 ... |
datouyuan 發表于 2021-12-13 10:21 學到了很多,謝謝大佬 |
莉雅絲 發表于 2021-12-10 17:11 串口輸出字符串用sprintf函數最省事 sprintf可以自動輸出負號和小數點,也可以不輸出小數點,對于數據處理最省事,至少占用內存什么的,那是單片機累,我不累就行 char k[10]; //這里不能加code限定符,否則計算不正確,數組長度隨意,不出錯就可以 char a; sprintf(k,"%.1f",Data_Send); //把浮點數據分割成字符串,并存放在k數組中,"%.1f"的2f表示小數點后再顯示1位數,不顯示小數就是0f for(a=0;(k[a]!='\0');a++) { Send_Out_COM(k[a]); //發送(串口發送函數),發送的是ASCII碼,避免出現0x00數據 } void Send_Out_COM(unsigned char COM) //發送一個字節數據(串口發送函數) { while(Busy); //等待上次發送完成,Busy在串口2完成發送后清除 Busy=1; S2BUF=COM; } |
莉雅絲 發表于 2021-12-10 17:11 stdio.h解決不了問題,要重定向putch才可以。 |
本帖最后由 datouyuan 于 2021-12-13 10:57 編輯 莉雅絲 發表于 2021-12-10 17:11 printf("已點亮%bd個燈\n",x);//x為8bit數 用stdio.h的printf函數是最容易做的方法。你只要完成char putchar (char c) 這個函數就行。 void send(char* c);//串口發送字符 void sends(char* str,unsigned char len);//串口發送字符串 假如不用stdio.h,你需要完成上面2個函數。 sends("已點亮",6); send(x/10+'0');send(x%10+'0');//x范圍00~99 sends("個燈\n",5);//一個中文字符算2個字節,ascii算1個字節,所以長度為5 |
xianfajushi 發表于 2021-12-6 09:25 我好像找到解決方案了,好像包括一個stdio.h庫文件就能用里面的函數輸出字符串了,不知道有沒有其他方法 |
|
|
| 定時器假如1MS? 那么是不是可以在定時中斷函數里面給個標志位?比如F_1MS=1? WHILE(1){}里面我們把所有的程序都放在這個if(F_1MS){}里面可以不? 這就是前后臺程序架構。 對付8位單片機足矣。 |
莉雅絲 發表于 2021-12-5 16:31 真想學很好,會有人幫助的,我也不是專門說你,只是一時感慨而已,論壇上真想學的人和只想復制粘貼的人都遇到過,前天就有人向我索要圖片中的代碼,我問老婆她都不同意直接給代碼,不想學的人連圖片拿去識別都不做, 我有代碼,但回復大部分只給代碼圖片,為的就是不給直接復制了事,真想學的人要么就參考我的思路寫法,要么就自己照著動手打代碼,要么就去識別圖片,不管別人如何看待我用代碼圖片回復,只做認為該做的,當然不包括我博客發布的代碼可以復制,我學習時基本就是看別人的思路與寫法,不需要復制粘貼. |
天ノ憶 發表于 2021-12-5 17:28 謝謝指導,幫助很多,剛初學沒有注意這個排版,辛苦了,買的板子還沒到,用仿真做的,就沒寫消抖了,以后一定注意排版π_π。 |
本帖最后由 188610329 于 2021-12-6 02:02 編輯 莉雅絲 發表于 2021-12-5 16:27 自己改 Mainforse 值為,你的晶振頻率 #include <STC89C5xRC.H> typedef unsigned char u8; #define Mainforse 24000000L #define Timer_Base (65536 - (Mainforse / 12 / 256)) u8 T0_Count,Sec_Count,Mode,Old_Mode,New_Mode; sbit Key = P3^2; void main() { TMOD = 0x01; TL0 = Timer_Base % 256; TH0 = Timer_Base / 256; TCON = 0x11; //INT0 下降沿中斷 IE = 0x83; while(1) { New_Mode = Mode; if(New_Mode != Old_Mode) { Old_Mode = New_Mode; P1 = 0xff; } if(Sec_Count > Old_Mode) { Sec_Count = Sec_Count - Old_Mode - 1; switch(Old_Mode) { case 0: P1 ^= 0x01; break; case 1: P1 ^= 0x03; break; case 2: P1 ^= 0x07; break; case 3: P1 ^= 0x0F; break; case 4: P1 ^= 0x1F; break; case 5: P1 ^= 0x3F; break; case 6: P1 ^= 0x7F; break; case 7: P1 ^= 0xFF; break; default: break; } } } } void ET0_INT(void) interrupt 0 { while(!Key); //等待按鍵抬起, 可以不需要 Mode++; Mode &= 0x07; // Mode 0~7 } void T0_INT(void) interrupt 1 { TL0 = Timer_Base % 256; TH0 = Timer_Base / 256; T0_Count++; if(T0_Count == 0) Sec_Count++; } |
188610329 發表于 2021-12-5 16:35 不太懂中斷這一塊,我能用定時器0寫一個延時函數,然后在case里調用嗎 |
|
你這程序按鍵那個地方就不對,你隨便找本書,關于按鍵地方肯定會寫消抖,你這程序里并沒有消抖,這會導致數據出錯,當然也不是一定會出錯,只是出錯的幾率大大增加。 定時器設置直接抄書就可以,但是最好是自己理解清楚。 延時函數可以去燒錄那個軟件生成一個。 switch()里面為什么要這么寫,先說P1 = 0xFE;之后緊跟一句P1 = 0XFF;你這個寫法意思是人眼視覺停留時間比單片機運行一條指令的時間還短嗎,你中間不加個延時怎么用眼睛看到IO口變化, 其次,你這for循環也起不到改變間隔的作用,因為你if成立之后程序還要跑完剩下的for,加起來間隔是一樣的, 如果按你這個想法倒不如這樣寫
好像這樣不知不覺就寫完了,最后,最重要的一點就是,你代碼的排版簡直爛透了,不要為了圖省事就隨便寫,代碼排版好看點對人對己都有好處 |
本帖最后由 188610329 于 2021-12-5 20:30 編輯 莉雅絲 發表于 2021-12-5 16:27 代碼如下,你要覺得能用就用,不能用就算了。 #include <STC89C5xRC.H> typedef unsigned char u8; #define Mainforse 24000000L #define Timer_Base (65536 - (Mainforse / 12 / 256)) u8 T0_Count,Sec_Count,Mode,Old_Mode,New_Mode; sbit Key = P3^2; void main() { TMOD = 0x01; TL0 = Timer_Base % 256; TH0 = Timer_Base / 256; TCON = 0x11; //啟動TR0, INT0 下降沿中斷 IE = 0x83; //EA = 1, EX0 =1 , ET0 = 1 while(1) { New_Mode = Mode; if(New_Mode != Old_Mode) { Old_Mode = New_Mode; P1 = 0xff; } if(Sec_Count > Old_Mode) { Sec_Count = Sec_Count - Old_Mode - 1; switch(Old_Mode) { case 0: P1 ^= 0x01; break; case 1: P1 ^= 0x03; break; case 2: P1 ^= 0x07; break; case 3: P1 ^= 0x0F; break; case 4: P1 ^= 0x1F; break; case 5: P1 ^= 0x3F; break; case 6: P1 ^= 0x7F; break; case 7: P1 ^= 0xFF; break; default: break; } } } } void INT0(void) interrupt 0 { while(!Key); //等待按鍵抬起, 如IT0 = 1, 可以不需要 Mode++; Mode &= 0x07; // Mode 0~7 } void T0_INT(void) interrupt 1 { TL0 = Timer_Base % 256; TH0 = Timer_Base / 256; T0_Count++; if(T0_Count == 0) Sec_Count++; } |
莉雅絲 發表于 2021-12-5 16:18 如果,你用delay 延時來讓燈閃爍,你的按鍵,就必須用 中斷來檢測, 如果按鍵不想用 中斷,那么閃爍就必須用 定時器中斷來控時,總之, 要達到你的最終目的, 必須要有 1個以上的中斷。 |
xianfajushi 發表于 2021-12-5 08:09 我其實沒有想復制粘貼,交這個作業還要講解思路,而且我也是真心想學單片機 |
liuzx66 發表于 2021-12-5 13:15 這跟我思路不一樣,我試試,感謝思路 |
188610329 發表于 2021-12-4 22:09 第一次提問,沒想到這個問題 |
|
1、定時器定時1ms中斷,中斷程序里面用一個變量來記錄中斷次數。變量類型要能存儲足夠大的數據,能夠滿足你的要求。 2、主程序判斷這個變量,到1S(1000ms)做什么,到2S做什么......以此類推。 3、到最后把變量清零,重新開始。如果不清零變量就要特殊處理一下也可以。 |
| 首先你需要知道什么功能要放在while循環中讓他不斷重復,很明顯你這個按鍵檢測是必需的,燈的閃爍是根據按鍵的值被選擇的,至于定時器只起到了一個調整間隔的作用,你可以先寫按鍵檢測,在這個基礎上加入燈,每個模式封裝成一個函數,按鍵掃描的值存到一個變量中,根據這個變量來調用不同的模式,在不同模式下調整計時器 |
本帖最后由 xianfajushi 于 2021-12-5 11:08 編輯
|
| 現在網絡提供的代碼較多了,可能是為了防止新生不學無術,題目都稍有改動新生就不能即刻復制粘貼了事,老師也是被逼無奈,為了新生的苦心!所以我現在看到稍有不同的題目直接不去回復,新生應該通過理解稍加修改即可。本題隨意設定定時器時間都只是基本的數學計算問題。比如定時50毫秒乘10就是半秒閃爍就是一秒,之后10乘以2就是2秒閃爍,如此類推,按鍵也是很簡單的控制一個量值即可實現循環控制。 |
|
你多多少少寫點出來,那么人家根據你的代碼,評估一下你的水平,適當的幫你改一改,也不是不可能。 你現在是出題? 然后,人家答題? 人家隨便扔個代碼上來,你確定你就能用了么?確定能看懂么? |