新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > C51編程中的自定義“位”及其保存方案

        C51編程中的自定義“位”及其保存方案

        作者: 時間:2013-02-17 來源:網絡 收藏

          引言

          在現有的教課書及相關文章中,都難得提到在單片機C語言編程中對于“位”的狀態進行保存的理念。

          當單片機C語言編程中提及“位”的概念時,人們自然會想到狀態字PSW中PSW.5的F0與PSW.1的F1兩個用戶通用。這兩個均可參與布爾運算、“位”控操作,也可隨狀態字PSW一起保存。但是,往往會忽視這一點:在一些特定的情況下,如在C語言編程的中斷服務程序中,對狀態字PSW中PSW.5的F0與PSW.1的F1這兩個用戶的操作可能是無效的。如:

          void EX1_ISR() interrupt 2 {//外部中斷1

          static unsigned int tempaddr;//定義接收地址緩存

          static unsigned int tempkey;//定義接收數據緩存

          unsigned int timecnt;

          timecnt=TH1*256+TL1;

          TH1=0;

          TL1=0;

          TR1=1;//定時器1啟動

          F0=~F0;//取反F0

          if(F0) {

          tempaddr=tempaddr1;

          }

          else {

          tempkey=tempkey1;

          }

          }

          以上是一段單片機外部中斷1的中斷服務程序,乍看似乎沒什么問題,仿真調試時也能通過“編輯”。但實際上這是一段錯誤的程序——其中對“F0”用戶標志位的“取反”操作是達不到其預期效果的。因為對“F0”用戶標志位的“取反”操作是在中斷服務程序中進行的。在進入中斷時,C語言自動會保護“中斷現場”——將程序指針PC、累加器ACC、狀態字PSW等壓入堆棧保護起來……直到中斷返回時彈出堆棧并覆蓋了中斷服務時的變值,恢復到壓入堆棧之前的原樣。因此,狀態字PSW中的F0也不例外,如果壓入堆棧之前F0是處于邏輯“0”狀態,中斷返回后還是復原成邏輯“0”狀態——不管中斷服務程序中怎么取反改變——也就是說,在中斷服務程序中試圖改變F0之值的操作是有失偏頗的。對于上文例舉的那段中斷服務程序來說,若F0的初始狀態為邏輯“0”,即進入中斷服務之前和中斷返回之后總是邏輯“0”,那么進入執行“F0=~F0”指令后F0總是邏輯“1”,因而接下運行的是“if(F0)”下花括號中“tempaddr=tempaddr1;”指令,而“else”下花括號中“tempkey=tempkey1”指令永遠也運行不到。所以,若要中斷服務程序達到預期的效果——“if(F0)”下花括號中的指令與“else”下花括號中的指令輪番運行,必須設立一個不受中斷現場保護等影響的標志位。

          1標志“位”的保存

          在C語言編程中,自定義標志位的運用概率很大,有的一個程序中就會有好多的自定義標志位,且其中幾個可能是必須要保存的。譬如有些控制器件中對一些控制狀態進行保持,即使是停電之后再來電了這種控制狀態依然能保持不變——這就牽涉到保存問題。

          例舉2:我們曾搞過一個鐳射投影屏幕升降的無線遙控裝置。這個以單片機為核心的控制裝置與屏幕升降的卷動電機等都安裝固定在一個直徑不足50 mm的狹長鐵桶里面,因此裝入或拆卸都非常麻煩。為了一次性成功——避免再次拆卸裝入的麻煩,在用C語言編程時我特意多用了一個自定義的標志位——翻轉標志位“switch_sign”。因為無線遙控手柄上的向上“▲”、暫?!啊觥薄⑾蛳隆皑嫛钡逆I標志都已是做定的,因此,如果由于接線等失誤導致按向下“▼”鍵時投影屏幕向上卷、按向上“▲”鍵時投影屏幕卻向下伸……有了“switch_sign”自定義的標志位就不用怕這些了。相關的C語言程序段如下:

          #defineuint unsigned int

          #defineuchar unsigned char

          uint Decode_addr,Decode_key,addr;

          sbit JD1_out=P0^4;//定義繼電器1控制輸出端

          sbit JD2_out=P0^5;//定義繼電器2控制輸出端

          sbit BEEP=P0^3;//定義蜂鳴聲響輸出

          bit bdata switch_sign;//自定義的翻轉標志位(應作全局變量定義)

          voidTelecontrol_Data() {

          ……

          if(Decode_addr==0x5535) {//地址碼核對

          if(Decode_key==0x00C0) {//“▲”鍵碼核對

          BEEP=1;//蜂鳴聲響輸出

          if(switch_sign) {//翻轉標志位

          JD1_out=0;//繼電器1控制輸出端

          JD2_out=1; //繼電器2控制輸出端

          }

          else {

          JD1_out=1;//繼電器1控制輸出端

          JD2_out=0;//繼電器2控制輸出端

          }

          }

          if(Decode_key==0x0030) {//“■”鍵碼核對

          BEEP=1;//蜂鳴聲響輸出

          JD1_out=0;//繼電器1控制輸出端

          JD2_out=0;//繼電器2控制輸出端

          }


        上一頁 1 2 3 下一頁

        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 大庆市| 泾阳县| 怀柔区| 博乐市| 胶南市| 苍梧县| 巴林右旗| 永宁县| 靖宇县| 襄城县| 磐石市| 余江县| 阜阳市| 谷城县| 华阴市| 崇州市| 兴义市| 峨眉山市| 瑞安市| 昌邑市| 临猗县| 迁西县| 喜德县| 长武县| 顺昌县| 门源| 南部县| 阿拉善盟| 苏尼特右旗| 玉林市| 清苑县| 西林县| 拜泉县| 百色市| 盐山县| 祁门县| 茌平县| 泸西县| 礼泉县| 保定市| 长春市|