2019年10月9日 星期三

關於 8051 C的程式碼

  1. 先列出 function calls
    1. void delay_1ms(int k): 利用空迴圈, 跑110*k次
    2. void anti_cck(): 將4顆7段顯示器 逆時針轉3圈
    3. void pili_led(): 8顆LED左右跑3次。
    4. void pulse_BZ(int count, int TH, int TL): Buzzer的震動
    5. void mode0()
    6. void main(): 主程式, press==0, press==1, press==2
      1. x==1 沒做事, 顯示00
      2. sw==0 有按下 sw按鈕, 就把x=0, TR0 TR1都打開, 會count++ & 顯示
      3. sw2==0 有按下 sw2按鈕, press_add++, 等一下, 直到sw2放開, 開, 等一下
        1. press_add==0 一開始, 沒做事
        2. press_add==1
        3. press_add==2: TR0=1要顯示bcd[1],bcd[0], TR1=0 不會count++,  
        4. press_add==3: 變回 press_add=0不做事, TR1=1要顥示 bcd[1], bcd[0]

    7. T0_int(void) interrupt 1: 5000us=5ms, 會去更新P0及P2的值, 讓 bcd[1] 及 bcd[0] 的值一直去顯示
    8. T1_int(void interrupt 3: 50000us=50ms, 會在 50ms*20=1sec去更新counter 並更新 bcd[1] bcd[0] 這兩位數, 即 00...99去(每秒)累增
  2. 開始逐行分析 (Keil C51 is based on C90)
    1. Keil C51 為 8051多了 bit, sbit, sfr, sfr16 (後3個是CPU特別register)
      1. C 語言:Keil C51 和標準 C 語言的差異

    2. AT89X52.h 
      1. atmel/at89x52.h
      2. at89s52.h
      3. at89c52.h
      4. 許多不同型號的單晶片機
    3. P1table[] 應該是 pili燈要用的順序
    4. P0table[] 是一些字, P0table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
    5. 1111 1001, 1010 0100, 1011 0000, 1001 1001, 1001 0010, 1000 0010, 1111 1000, 1000 0000, 1001 0000
    6. 合理猜測, 是7段顯示器要顯示0...9的數字
    7. 原來 0是發亮, 那了解了。
    8. 但是, pili_led()裡面, 是寫 P1=~P1table;
    9. sbit buzzer = P3^7 
    10. P0是用來決定7段顯示器, P2是用朲決定是哪一個7段顯示器
    11. P1是8顆LED, 當它是 LOW時便會發亮。所以才會 P1=~P1table[pili_ed_i], 把它正負倒過來
    12. TR0, TR1
    13. TMOD
    14. Timer工作模式0時,13位元計時/計數值最大為8192(2的13次方),因此,THx的值應為計時/計數值除以32的商,TLx的值則為計時/計數值除以32的餘數。若計時/計數值為5000時,即
    15. TL0 = # (8192-5000)×MOD×32
    16. TH0 = # (8192-5000)/32
    17. TL0 = (65536 - 9217) % 256; // 計數時間 : 9217 * 1.085us = 0.01s
    18. 比如12MHZ来说吧,机器周期是1us,就是说每1us产生一次计数,就拿50ms来说,这是你想要的计时,意思是,对机器周期进行50000计数就可以得到我想要的
    19. 50ms*20=1000ms=1sec
    20. TH0=(8192-5000)/32;
    21. 假設計時器0 每 5ms 中斷一次,因機械週期為1us  則  N=5ms/1us=5000
    22. 所以 TH0=(8192-5000)/32  ,TL0=(8192-5000%32)
  3. 接下來, 怎麼讓程式碼可以有更好的架構?
    1. 條件: 要尊重原本 8051 在程式開發的習慣, 不要做太大的修改, 以便原本熟悉的人能快速使用
    2. 8051的重點是利用 Interrupt 的方法來實作
    3. Q: delay_1ms(k) 可以等待 k ms 的作法, 是常用的習慣, 要保留
      1. 但是如果 Timer Interrupt 時, 原本 delay_1ms() 會被打斷, 則會不合理
      2. Q: 有沒有準確的 clock? (我們可以利用 Timer interrupt 來製作準確的 clock, 再提供給我們的程式使用
      3. Q: 有沒有 sleep?  A: _sleep_( ms )

    4. Q: Timer TR0 等 5000 即 5ms, Timer TR1 等 50000 即 50ms 要保留。
    5. 關鍵就是 Timer TR0,TR1 要幫忙決定要做什麼事。也成為 call back function 的基礎, 用來改變 flag, 程式碼不能太複雜。
    6. main()迴圈 就照著 flag來做事
    7. int task=1;
    8. void main(){
    9.   init_setting();
    10.   while(1){
    11.     if(task==1) task1_seg7_rotate3_cck();
    12.     else if(task==2) task2_8LED_rotate3();
    13.     else if(task==3) task3_buzzer_beep3();
    14.     else if(task==4) task4_mode0();
    15.     else if(task==5) task5_increase_counter();
    16.     else if(task==6) task6_pause();
    17.     else if(task==7) task7_reset();

    18.    // if(.... && ... ) task = ???
    19.    // else if(....&& ...
    20.   }
    21. }
  4. 接下來使用 Timer TR0, TR1 來修改 flag (含 state切換, 數值切換, 越快越好)
    1. button1, button2
      1. if(button1==0){//按下第1個按鈕, 決定上數 (or下數)
      2. if(button2==0){//按下第2個按鈕, 要判斷 2短按 1短按, 表示 Pause 還是 Resume
    2. Q: 長按按鈕 (Reset Couner), , 是 button1 還是 button2? 我先假裝是 button1, 因為 button1 就與 counter++/counter--/counter=0 有關, 容易操作
    3. Timer TR0, TR1 可以用來查 button的值, 如果是(沒有按下去變成) 按下去, 就記錄按下的時間 (Pressed)
    4. 如果是 (剛剛按下去變成) 放開, 就要記錄放開的時間 (Released)
    5. button1 都是在放開(Released)的時候, 來切換動作, 判斷是長按 or 短按

沒有留言:

張貼留言

algorithm

 #include <iostream> #include <string.h> using namespace std; int main(int argc, char** argv)  { for(int j=2;j<=100;j++)//j...