国产毛片a精品毛-国产毛片黄片-国产毛片久久国产-国产毛片久久精品-青娱乐极品在线-青娱乐精品

單片機宏定義學習手記

發布時間:2016-10-20 15:35    發布者:designapp
關鍵詞: 單片機 , 宏定義
  前言:
  這幾天在整理和生產EMC單片機程序的一些宏,發現這東西真的是好用得超乎了想象,大大的簡化了寫程序時的重復勞動。以下以 EM78P260為主,其實其他型號大通小
  異,注意修改一下寄存器就可以。
  (1)最常用的 PAGE 和 BANK
  EMC 的IC是分幾個page和幾個bank的,低端的EM78P156等只有一個bank和一個page,所以不用切換,新一點的IC基本都要切換的了,這個經常用的冬冬,做成宏就最合適,
  代碼如下:
  /*****************************************************
  * BANK SELECTION *
  *****************************************************/
  BANK macro num
  if num == 0
  bc R4,6
  bc R4,7
  elseif num == 1
  bs R4,6
  bc R4,7
  elseif num == 2
  bc R4,6
  bs R4,7
  elseif num == 3
  bs R4,6
  bs R4,7
  else
  message "warring!"
  endif
  endm
  /*****************************************************
  * PAGE SELECTION *
  *****************************************************/
  PAGE macro num
  if num == 0
  bc psw,5
  bc psw,6
  elseif num == 1
  bs psw,5
  bc psw,6
  elseif num == 2
  bc psw,5
  bs psw,6
  elseif num == 3
  bs psw,5
  bs psw,6
  else
  message "warring!"
  endif
  endm
  調用格式是
  BANK num (num是 0~3 代表4個BANK)
  PAGE num (num是 0~3 代表4個PAGE)
  這樣方便多了,而且不會出錯
  (2)帶參數的宏
  作為例子,我們假定定義一個宏“ FUNC” ,帶兩個參數,功能是單純的將傳進來的數據傳到PORT5 和 PORT6 而已,演示用法。
  首先看定義:
  FUNC MACRO ARG1,@ARG2
  MOV A,@ARG1
  MOV PORT5,A
  MOV A,ARG2
  MOV PORT6,A
  ENDM
  注意到,為什么 ARG1前面有個 @ 的符號的呢?這個代表的是宏接收的第一個參數是一個立即數,而ARG2沒有那個符號,代表宏接收的第二個參數是一個寄存器的地址。
  為了程序的統一性,做宏的時候,凡是立即數的,都加上@符號,普通寄存器變量都不加,形成統一的風格。
  好了,看在主程序怎么用:
  FUNC 0X10, @0X20
  這樣就OK了,編輯器編譯的時候,會自動進行宏替換,將0X10這個立即數作為第一個參數傳遞進去,而將0X20寄存器的內容,作為第二個參數傳遞進去,進行宏替換之后的結
  果,等效于:
  MOV A,@0x10
  MOV PORT5,A
  MOV A,0x20
  MOV PORT6,A
  基本用法就是這樣。不難,試一下就會用。
  (3)說一點C語言的一種良好風格
  C語言上面有一種比較好的編程風格,給個C51的例子:
  我們想設置TIMER0在模式1,TIMER1在模式2
  一般教程的思維和代碼就是:
  翻資料看看TMOD的位的定義,然后慢慢算,模式1和模式2該給什么值,最后寫指令:TMOD = 0x21; 完工…..
  其實我們還可以有另外一種辦法,那就是這樣寫:
  TMOD = CT0_MODE1 | CT1_MODE2 ;
  其中里面用到一些宏,具體定義是:
  #define CT0_MODE0 0x00 // Timer0/Counter0 Mode
  #define CT0_MODE1 0x01
  #define CT0_MODE2 0x02
  #define CT0_MODE3 0x03
  #define CT1_MODE0 0x00 // Timer1/Counter1 Mode
  #define CT1_MODE1 0x10
  #define CT1_MODE2 0x20
  #define CT1_MODE3 0x30
  TMOD = CT0_MODE1 | CT1_MODE2 ;
  這個應該很容易看的懂吧?中間的 “|”是或運算,這個就是編譯器在編譯的時候做的運算了,具體CT0_MODE1 代表 0X01 CT1_MODE2 代表0x20,然后“或運算”之后結果就是
  0X21 了,跟上面一樣。但是老實說,大家愿意用哪個辦法去做呢?我會毫不猶豫的選擇第二種,有意義的符號比沒有意思的數據來的好用。
                               
                                                               
                               
                  (4)用我們的EMC的匯編編譯器模仿這種風格
  我們的EMC匯編編譯器同樣支持這種編譯時候的運算,讓編譯器幫我們先處理一些基本的運算,雖然面對C編譯器這個小功能真是見慣不怪,但是原來匯編編譯器也能,頗有點小
  小的有點意外。EMC的芯片的功能寄存器分配,真有點亂七八糟,唉,看著吐血,用定一種型號的IC那還好,如果用了幾種IC的話,那個叫郁悶,一個例子就是EM78P447 和
  EM78P156,本來前者是升級版,但是為啥有些控制差別會那么大呢,每次都要瘋狂的查DATASHEET,為了緩慢腦細胞的死亡速度,俺決定用宏……
  例如: 我們需要開啟EM78P260的TCCA計數器來用,初始化時候的工作,我們用帶參數的宏來實現。分幾步走
  1 首先定義一個宏,以后可以用這個宏來初始化了
  TCCA_SETUP MACRO TCCACNT
  clr 0x04 ; 0x04 是用來做臨時寄存器用的
  ior 0x08 ; 0x08是控制TCCA的寄存器
  and a,@0xf8 ; 屏蔽掉TCCA相關的
  mov 0x04,a
  mov a,@TCCACNT ; 讀取傳遞進來的參數
  or a,0x04
  iow 0x08
  mov a,@TCCACNT ; 如果允許TCCA的話,開TCCA的中斷
  and a,@0x04 ; 否則直接跳出
  jbc 0x03,2
  jmp $+4
  ior 0x0f
  or a,@0x08
  iow 0x0f
  ENDM
  (因為這個程序在初始化階段,所以改變0x04寄存器沒有所謂,不過在正常跑的時候千萬不要亂來,那個是會切換BANK的,跑飛了可不是說著玩,當然,這里可以在RAM開辟一
  個寄存器來用,那就沒事了。喜歡的自己改)
  2 第二部就是定義一些宏的具體數值了(跟C類似)
  TCCA_ENABLE == 0X04
  TCCA_DISABLE == 0X00
  TCCA_SRC_INT == 0X00
  TCCA_SRC_EXT == 0X02
  TCCA_EDGE_RISE == 0X00
  TCCA_EDGE_FALL == 0X01
  3 第三步就是華麗的開始用了,在主程序里面,
  /*****************************************************************************
  TCCA_SETUP setup MACRO
  argument : TCCA_ENABLE / TCCA_DISABLE 是否允許
  TCCA_SRC_INT / TCCA_SRC_EXT 計數源選擇
  TCCA_EDGE_RISE / TCCA_EDGE_FALL 出發弦選擇
  ****************************************************************************/
  TCCA_SETUP TCCA_ENABLE|TCCA_SRC_INT|TCCA_EDGE_RISE
  看到了吧?
  (TCCA_DISABLE|TCCA_SRC_INT|TCCA_EDGE_RISE)一堆有意義的參數,或運算之后作為一個參數傳遞給宏 TCCA_SETUP ,修改的時候我們很簡單就能搞定,甚至絕對
  不需要查資料,例如,我們想改成外部TCCA脈沖計數,只需要簡單的修改
  TCCA_SETUP TCCA_ENABLE|TCCA_SRC_EXT|TCCA_EDGE_RISE
  完工了,想禁止TCCA的話,改成 TCCA_DISABLE 就OK了,是不是很簡單?很方便? 當然,方便的代價就是增加程序代碼,不過就多那么10來行,沒有哈大問題的,重要是不
  要過多的抹煞腦細胞~~hoho~ 可持續發展啊~~~
  (5)寄存器自動分配
  終于到了尾聲,到了最BT的地方了,也是最有成就感的東西,怎么讓寄存器自動分配空間,匯編跟C一個很大的區別就是,C的變量是自動分配,看著都眼紅,那是多少好的東西
  啊,被匯編虐待了好些日子,突然發現,原來咱們EMC的匯編編譯器也有這個功能,大喜!可能已經有前輩懂得怎么用了,那就算在下班門弄斧好,拍拍磚~~~
  平時寫程序的習慣就是,定義一個有意義,容易記的名字去代替抽象的寄存器名,例如定義一個臨時變量用的寄存器
  TEMP EQU 0X10
  這樣,我們定義了TEMP,以后都用 TEMP 來代替 0X10 寄存器,這是最最常規的辦法。但是,問題是,我們必須每次寫程序之前都重新定義一次TEMP EQU 0X10 ,當然,也不是說很煩,但是我們都有一些常用功能的子程序,子程序里面用到寄存器的話,也需要定義,然后做項目的時候,這里copy一個子程序,那里copy一個子程序,好了,一大堆沖突的寄存器定義,必須慢慢仔細的檢查,如果不走運,有兩個名字定義到同一個寄存器上面,好,慘了,很隱蔽的邏輯錯誤就出現了,那是惡夢。但是用宏可以做到自動分配用到的是變量宏,WICE手冊里面也有說,用法是
  TEST VAR 1
  MOV A,@TEST
  TEST VAR TEST+1
  MOV A,@TEST
  對比兩次的A值,我們發現,第一個A值為1,第二個A值為2 !!這個就是變量宏的基本原理,編譯器當它是一個變量,可以改變的,不過這個改變,只發生在編譯的時候,生成代碼之后就沒有用的了。
  好了,下面說說我們的核心,具體怎么分配。
  首先定義個分配變量的宏,代碼如下
  ADDR_ASSIGN MACRO REGISTER
  REGISTER EQU ADDRESS
  ADDRESS VAR ADDRESS+1
  ENDM
  用了一個參數,傳遞進來的變量的名字。例如我們在主程序里面寫了
  ADDRESS VAR 0X10
  (首先定義開始分配的地址,我們是由 0X10 開始)
  ADDR_ASSIGN Temp0
  Temp0 作為參數傳遞進來,實際上就是執行了
  Temp EQU 0X10
  ADDRESS = ADDRESS+1 (現在的ADDRESS已經是 0X11了!因為它是一個變量宏!)
  下次如果我們繼續定義
  ADDR_ASSIGN Temp1
  現在 Temp1 已經自動被定義為 0X11 了,然后ADDRESS滾到0X12為下個寄存器定義用。
  這樣就方便了,例如我們定義一堆寄存器
  ADDR_ASSIGN Temp0
  ADDR_ASSIGN Temp1
  ADDR_ASSIGN Temp2
  ADDR_ASSIGN Temp3
  天啊,這實在是太好用了!!!我們完全不用關心具體分配到哪個寄存器上面,反正就是分配了,反正就是可以用了,哈~~TEST一下就知道。
  牽涉的問題1
  越界問題,當分配到 0X3F 的時候一個頁面結束了,但是ADDRESS還是繼續加上去,怕不怕?不怕,編譯器已經報錯了,不能編譯,這樣就不怕越界,可以放心的定義了
  牽涉的問題2
  多個bank的怎么分配?其實可以在定義宏的時候加多一個參數,通過條件宏來跳轉定義就OK了,不過我怕麻煩,用了一下的辦法:
  /*---------------------------BANK 0 入口地址-------------------------------------*/
  ADDRESS VAR 0X10 ; 可分配 0x10 ~ 0x3f
  /*--------------------------- BANK 0 ----------------------------------------*/
  這里就是我們需要定義的寄存器的
  /*---------------------------BANK0 調試信息輸出----------------------------------*/
  MESSAGE "Bank0最大分配RAM:"
  ADDR_DISP ADDRESS-1
  /*-------------------------------------------------------------------------------*/
  /*---------------------------BANK 1 入口地址-------------------------------------*/
  ADDRESS VAR 0X20 ; 可分配 0x20 ~ 0x3f
  /*--------------------------- BANK 1 ----------------------------------------*/
  這里我門需要定義的bank 1 的寄存器
  /*---------------------------BANK1 調試信息輸出----------------------------------*/
  MESSAGE "Bank 1 最大分配RAM:"
  ADDR_DISP ADDRESS-1
  /*-------------------------------------------------------------------------------*/
  怎么樣?和諧了吧? 將變量嚴格分開,你需要放在 bank0 的就填到 bank0 的區域,需要分到bank1 的就填到bank1那里,因為在bank1開頭,重新定義了 ADDRESS 為 0X20 ,那樣就可以繼續從 0X20開始分配,如果有多個page的,按照同樣的辦法。在每個bank結束的時候,我還放了兩個宏,他們是
  MESSAGE "Bank0最大分配RAM:"
  ADDR_DISP ADDRESS-1
  第一個,簡單的顯示文字而已,第二個 ADDR_DISP 是用來顯示一共最大分配到哪個寄存器,這個宏的原型是:
  ADDR_DISP macro reg
  IF reg==0x10
  MESSAGE "0x10"
  ELSEIF reg==0x11
  MESSAGE "0x11"
  ELSEIF reg==0x12
  MESSAGE "0x12"
  ELSEIF reg==0x13
  ……
  ……
  (下面的自己寫了….)
  ENDM
  很簡單,將ADDRESS最后的地址傳進去,現實一下而已,因為ADDRESS執行多了一條自加指令的,所以我們減回,那就OK了。
  需要注意的地方,這個方法分配的全部都是全局變量,當做小項目寄存器極其緊缺,需要將某個寄存器復用的時候,這辦法就見鬼了。注意一下就是了。
                               
                                                               
                               
               
本文地址:http://m.qingdxww.cn/thread-176531-1-1.html     【打印本頁】

本站部分文章為轉載或網友發布,目的在于傳遞和分享信息,并不代表本網贊同其觀點和對其真實性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問題,我們將根據著作權人的要求,第一時間更正或刪除。
您需要登錄后才可以發表評論 登錄 | 立即注冊

廠商推薦

  • Microchip視頻專區
  • Chiptorials ——如何將CryptoAuthLib庫用于Microchip安全身份驗證IC
  • 無線充電基礎知識及應用培訓教程
  • Chiptorials——如何使用ATECC608 TrustFLEX實現公鑰輪換
  • Chiptorials ——使用ATECC608 TrustFLEX實現基本非對稱身份驗證
  • 貿澤電子(Mouser)專區

相關在線工具

相關視頻

關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯系我們
電子工程網 © 版權所有   京ICP備16069177號 | 京公網安備11010502021702
快速回復 返回頂部 返回列表
主站蜘蛛池模板: 国产专区在线视频 | 国产免费啪视频观看网站 | 免费国产在线观看不卡 | 久久8| 一区二区三区四区在线播放 | 免费簧片视频 | 免费视频专区一国产盗摄 | 好吊色欧美一区二区三区四区 | 2023男人天堂 | 久久久久免费观看 | 日本欧美大码a在线视频播放 | 一区卡二区卡三区卡视频 | 亚洲三级在线播放 | 四虎国产精品永久地址99 | 中文字幕av一区 | 久久大伊人 | 国产成人精品高清不卡在线 | 亚洲视频一区二区三区四区 | 天天干天天操天天摸 | 亚洲综合丁香 | 九九九精品视频 | 91好色 | 福利视频网站 | 欧美日韩国产另类在线观看 | 日韩a一级欧美一级 | 天天色天天搞 | 91精品免费看| 青青青国产免费手机视频在线观看 | 免费在线日韩 | 国产综合色香蕉精品五月婷 | 亚洲第一区精品观看 | 九九精品久久久久久噜噜 | 日韩a在线| 国产亚洲欧美在线观看的 | 国产成人综合网在线观看 | 一级女人18片毛片免费视频 | 国产精品久久久久秋霞影视 | 日本不卡二 | 亚洲精品欧洲精品 | 在线中文字幕第一页 | 四虎影视免费观看免费观看 |