SOGO論壇
  登入   註冊   找回密碼
查看: 1638|回覆: 6
列印 上一主題 下一主題

[問題求助] 這個程式有些地方需要解惑 [複製連結]

Rank: 2

狀態︰ 離線
跳轉到指定樓層
1
發表於 2016-4-9 21:33:36 |只看該作者 |倒序瀏覽
關於以下程式我想了解的是計時中斷副程式的TH0=(65536-1000)/256;
                                                         TL0=(65536-1000)%256;

以及主程式的                    IE=0x8A;                                 
                                     TMOD=0x11;

                                    if (sw1==0){
                                    while(sw1!=0);
                                     cnt=(cnt+1)%2;
是什麼意思呢  ?
中斷副程式的-1000 據我所知為我所使用的震盪器是12MHz 所以掃描的速度為1u*1000 所以是1mS
但是不了解他的原理
而主程式的IE.TMOD則是完全沒有概念
在SW1的部分  我的開關是使用紅外線功能為 當感測到第一次 會開始計時 感測到第二次則會停止
但是不了為何程式的部分要這樣寫希望能解答
另外我的CNT=狀態 如高態低態這樣的想法是正確的嗎
以上希望能求解
# include<reg51.h>
sbit sw1=P1^7;
unsigned char seg[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x27,0x7f,0x67};  //0~9的字型碼
unsigned char com[]={0x10,0x20,0x40,0x80,0x01,0x02,0x04,0x08};  
unsigned char cnt=0,hour,min,sec,ms,index,disp[8];
/*  顯示副程式   */
void display(void)                      
  { disp[0]=seg[hour/10];  // 放小時的拾位數
    disp[1]=seg[hour%10];  // 放小時的個位數
    disp[2]=seg[min/10];   
    disp[3]=seg[min%10];  
    disp[4]=seg[sec/10];
    disp[5]=seg[sec%10];
    disp[6]=seg[ms/10];
    disp[7]=seg[ms%10];  
}
/******  T0 計時中斷的副程式 ******/
void timer0 (void) interrupt 1  
  { TH0=(65536-1000)/256; // TH0存放商數
    TL0=(65536-1000)%256; // TL0存放餘數
    P2=0xff;                // 顯示器不亮
    P0=~disp[index];        // 顯示的字型碼由P1輸出
    P2=~com[index];        //顯示器的掃描碼由P0輸出
    index++;if(index>=8) index=0; //輪流掃描顯示器
  }
/*****  T1 計時中斷的副程式 *****/
void timer1 (void) interrupt 3
  { TH1=(65536-10000)/256;          // TH1存放商數
    TL1=(65536-10000)%256;          // TL1存放餘數
    if(cnt==1){
                ms++;}
        if(ms > 99){
                ms=0;
                sec++;}
        if(sec > 59){
                sec=0;
                min++;}
        if(min > 59){
                min=0;
                hour++;}
        if((hour==23)&&(min==59)&&(sec==59)&&(ms==99)){
                TR1=0;}                                   
        display();                                //呼叫顯示副程式
}


/*****   主程式   *****/
void main( ){         
        IE=0x8A;                                 
    TMOD=0x11;                                
        TR0=TR1=1;                                //啟動Timer 0 ,Timer 1
        while(1){
        if (sw1==0){
                while(sw1!=0);
                cnt=(cnt+1)%2;
        }}}
喜歡嗎?分享這篇文章給親朋好友︰
               感謝作者     

Rank: 5Rank: 5

數位軟體勳章

狀態︰ 離線
2
發表於 2016-4-10 16:02:49 |只看該作者
本帖最後由 alphi 於 2016-4-10 16:03 編輯

1. 標準8051 的Timer Clock是Fosc/12 (也就是當外面石英震盪器為12MHz, 內部Timer為12MHz/12=1MHz 處理速度)
  1.     TH0=(65536-1000)/256;
  2.     TL0=(65536-1000)%256;
  3.    
複製代碼
由於8051是Up-Counter , 也就是當計數值達到65536 才會發OVF中斷, 那要如何得到1ms ,已經知道8051 是要65536才會發生中斷,也就是設定
  1.     TIMER_COUNT = 65536-1000 = 64536
  2.    
複製代碼
但由於8051 的TIMER 設定值只有TH0,TL0兩個8位元,而很明顯64536 超過8位元的長度,所以要分成兩個放在,所以TIMER設定就會像你提到的設定一樣
  1.     TH0=(65536-1000)/256;
  2.     TL0=(65536-1000)%256;
  3.    
複製代碼
2.主程式中
  1.   void main( ){         
  2.         IE=0x8A;                                 
  3.     TMOD=0x11;                                 
  4.         TR0=TR1=1;                                //啟動Timer 0 ,Timer 1
  5.         while(1){
  6.         if (sw1==0){
  7.                 while(sw1!=0);
  8.                 cnt=(cnt+1)%2;
  9.         }}}
複製代碼
IE = 0x8A 是設定中斷控制器開啟全域中斷(EA=1),TIMER1中斷(ET1=1),TIMER0中斷(ET0=1)
TMOD = 0x11 是設定TIMER模式為two-8bit, 這個跟你上面的TH0,THL1設定會衝突(8bit 計數值最高為255, 而你要設定到64336) 這在時間上會出問題,你應該設定為TMOD=0x01 (16bit 模式)
  1. while(1){
  2.         if (sw1==0){
  3.                 while(sw1!=0);
  4.                 cnt=(cnt+1)%2;
  5.         }}
複製代碼
在嵌入式設計中使用% 取於數是很沒效率法.
  1. cnt = (cnt +1) %2;
複製代碼
結果只會cnt = 0,cnt=1,cnt= 0 , cnt= 1,...
你可以改成
  1. cnt ^=1 //(cnt 做xor) cnt =0, cnt =1, cnt =2
複製代碼
或者
  1. cnt = (cnt +1) & 1 (對最後一個bit 做AND)
複製代碼
都比cnt = (cnt +1) % 2 有效率多
已有 1 人評分威望 收起 理由
紅塵孤鳥 + 2 感謝您熱心幫助會員解決問題,論壇需要您的.

總評分: 威望 + 2   查看全部評分

失敗只有一種:那就是半途而廢

Rank: 2

狀態︰ 離線
3
發表於 2016-4-10 23:40:03 |只看該作者
好的  謝謝解答
1.那麼如果有人問到 CNT是什麼該如何解釋呢?
2.為何0x01 會等於16位元可以請教計算方式嗎?
3如果未來此作品要延伸 是否可以朝向一次計時多個事件的方向呢?
如:常用的秒錶有記錄功能那樣子的
目前作品的元件只有簡單的七段顯示器及一個紅外線感測器  
4.如果可以我應該加入什麼元件 ﹐程式該修改什麼呢?

Rank: 5Rank: 5

數位軟體勳章

狀態︰ 離線
4
發表於 2016-4-11 12:37:58 |只看該作者
1. CNT 看程式碼應該是當你壓下按鈕送0,在壓一次送1, 一直循環(也就是當壓下開關就是啟動一次)
2. TMOD=0x01, 請參考8051 設計資源.網路上有許多老師授課資料
3. 這是可以甚至你可以使用到SoftTimer 技巧,用一個Timer 實現多個Timer 計時值
4. 網路上資源很多,看你的應用有電像是賽跑透過紅外線感測器紀錄多個跑者時間, 這個應該不適很難做
已有 1 人評分SOGO幣 收起 理由
紅塵孤鳥 + 5 感謝您熱心幫助會員解決問題,論壇需要您的.

總評分: SOGO幣 + 5   查看全部評分

失敗只有一種:那就是半途而廢

Rank: 2

狀態︰ 離線
5
發表於 2016-4-11 23:18:47 |只看該作者
不好意思 想請教一下您所說的
3.使用SoftTimer 技巧,用一個Timer 實現多個Timer 計時值
是指一次能夠計時多個不同數值
還是......?

Rank: 4

狀態︰ 離線
6
發表於 2016-4-13 01:40:27 |只看該作者
記數的timer要看您使用的MCU有幾個可以用,如果只是要記數,那就在程式的中斷裡,多設幾個變數,不斷的++就好了,應該是這樣吧??

Rank: 5Rank: 5

數位軟體勳章

狀態︰ 離線
7
發表於 2016-4-20 14:58:12 |只看該作者
本帖最後由 alphi 於 2016-4-20 15:03 編輯
K.Justin 發表於 2016-4-13 01:40  
記數的timer要看您使用的MCU有幾個可以用,如果只是要記數,那就在程式的中斷裡,多設幾個變數,不斷的++就 ...


類似 不過可以改成更有可讀性的寫法
定義
  1. #define MAX_SOFT_TIMER 4

  2. struct soft_timer_t
  3. {
  4.     int period;
  5.     int count;
  6.     bool flag;
  7. }softtimer[MAX_SOFT_TIMER];
複製代碼
初始值
  1. softtimer[0].period = 1000;
  2. softtimer[0].count  = 1000;
  3. softrimer[0].flag = 0;

  4. softtimer[1].period = 2000;
  5. softtimer[1].count = 2000;
  6. softrimer[1].flag = 0;

  7. ...
複製代碼
3.中斷處里
  1. void TIMER_Handler(void)
  2. {
  3.    if(--softtimer[count].count == 0) //當數到0
  4.    {
  5.            softtimer[count].flag = 1;
  6.            softtimer[count].count = softtimer[count].period; //重新給定值
  7.    }
  8.    count = (count < MAX_SOFTTIMER) ?  (count +1) : 0;
  9. }
複製代碼
可以根據需求去設定真實Timer 的interval (例如1ms,100us ,....) 等以此為Base

當Timer 不夠多,且解析度不用太高如100ns,1us 這種 , 可以考慮此方法(也可以長時間計數)



已有 1 人評分威望 收起 理由
紅塵孤鳥 + 2 感謝您熱心幫助會員解決問題,論壇需要您的.

總評分: 威望 + 2   查看全部評分

失敗只有一種:那就是半途而廢
請注意︰利用多帳號發表自問自答的業配文置入性行銷廣告者,將直接禁訪或刪除帳號及全部文章!
您需要登錄後才可以回覆 登入 | 註冊


本論壇為非營利自由討論平台,所有個人言論不代表本站立場。文章內容如有涉及侵權,請通知管理人員,將立即刪除相關文章資料。侵權申訴或移除要求:abuse@oursogo.com

GMT+8, 2024-4-24 17:08

© 2004-2024 SOGO論壇 OURSOGO.COM
回頂部