新聞中心

EEPW首頁 > 模擬技術(shù) > 牛人業(yè)話 > 單片機(jī)宏定義學(xué)習(xí)手記

單片機(jī)宏定義學(xué)習(xí)手記

作者: 時(shí)間:2016-09-26 來源:網(wǎng)絡(luò) 收藏

  (4)用我們的EMC的匯編編譯器模仿這種風(fēng)格

本文引用地址:http://m.butianyuan.cn/article/201609/310319.htm

  我們的EMC匯編編譯器同樣支持這種編譯時(shí)候的運(yùn)算,讓編譯器幫我們先處理一些基本的運(yùn)算,雖然面對(duì)C編譯器這個(gè)小功能真是見慣不怪,但是原來匯編編譯器也能,頗有點(diǎn)小

  小的有點(diǎn)意外。EMC的芯片的功能寄存器分配,真有點(diǎn)亂七八糟,唉,看著吐血,用定一種型號(hào)的IC那還好,如果用了幾種IC的話,那個(gè)叫郁悶,一個(gè)例子就是EM78P447 和

  EM78P156,本來前者是升級(jí)版,但是為啥有些控制差別會(huì)那么大呢,每次都要瘋狂的查DATASHEET,為了緩慢腦細(xì)胞的死亡速度,俺決定用宏……

  例如: 我們需要開啟EM78P260的TCCA計(jì)數(shù)器來用,初始化時(shí)候的工作,我們用帶參數(shù)的宏來實(shí)現(xiàn)。分幾步走

  1 首先定義一個(gè)宏,以后可以用這個(gè)宏來初始化了

  TCCA_SETUP MACRO TCCACNT

  clr 0x04 ; 0x04 是用來做臨時(shí)寄存器用的

  ior 0x08 ; 0x08是控制TCCA的寄存器

  and a,@0xf8 ; 屏蔽掉TCCA相關(guān)的

  mov 0x04,a

  mov a,@TCCACNT ; 讀取傳遞進(jìn)來的參數(shù)

  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

  (因?yàn)檫@個(gè)程序在初始化階段,所以改變0x04寄存器沒有所謂,不過在正常跑的時(shí)候千萬不要亂來,那個(gè)是會(huì)切換BANK的,跑飛了可不是說著玩,當(dāng)然,這里可以在RAM開辟一

  個(gè)寄存器來用,那就沒事了。喜歡的自己改)

  2 第二部就是定義一些宏的具體數(shù)值了(跟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 計(jì)數(shù)源選擇

  TCCA_EDGE_RISE / TCCA_EDGE_FALL 出發(fā)弦選擇

  ****************************************************************************/

  TCCA_SETUP TCCA_ENABLE|TCCA_SRC_INT|TCCA_EDGE_RISE

  看到了吧?

  (TCCA_DISABLE|TCCA_SRC_INT|TCCA_EDGE_RISE)一堆有意義的參數(shù),或運(yùn)算之后作為一個(gè)參數(shù)傳遞給宏 TCCA_SETUP ,修改的時(shí)候我們很簡單就能搞定,甚至絕對(duì)

  不需要查資料,例如,我們想改成外部TCCA脈沖計(jì)數(shù),只需要簡單的修改

  TCCA_SETUP TCCA_ENABLE|TCCA_SRC_EXT|TCCA_EDGE_RISE

  完工了,想禁止TCCA的話,改成 TCCA_DISABLE 就OK了,是不是很簡單?很方便? 當(dāng)然,方便的代價(jià)就是增加程序代碼,不過就多那么10來行,沒有哈大問題的,重要是不

  要過多的抹煞腦細(xì)胞~~hoho~ 可持續(xù)發(fā)展啊~~~

  (5)寄存器自動(dòng)分配

  終于到了尾聲,到了最BT的地方了,也是最有成就感的東西,怎么讓寄存器自動(dòng)分配空間,匯編跟C一個(gè)很大的區(qū)別就是,C的變量是自動(dòng)分配,看著都眼紅,那是多少好的東西

  啊,被匯編虐待了好些日子,突然發(fā)現(xiàn),原來咱們EMC的匯編編譯器也有這個(gè)功能,大喜!可能已經(jīng)有前輩懂得怎么用了,那就算在下班門弄斧好,拍拍磚~~~

  平時(shí)寫程序的習(xí)慣就是,定義一個(gè)有意義,容易記的名字去代替抽象的寄存器名,例如定義一個(gè)臨時(shí)變量用的寄存器

  TEMP EQU 0X10

  這樣,我們定義了TEMP,以后都用 TEMP 來代替 0X10 寄存器,這是最最常規(guī)的辦法。但是,問題是,我們必須每次寫程序之前都重新定義一次TEMP EQU 0X10 ,當(dāng)然,也不是說很煩,但是我們都有一些常用功能的子程序,子程序里面用到寄存器的話,也需要定義,然后做項(xiàng)目的時(shí)候,這里copy一個(gè)子程序,那里copy一個(gè)子程序,好了,一大堆沖突的寄存器定義,必須慢慢仔細(xì)的檢查,如果不走運(yùn),有兩個(gè)名字定義到同一個(gè)寄存器上面,好,慘了,很隱蔽的邏輯錯(cuò)誤就出現(xiàn)了,那是惡夢(mèng)。但是用宏可以做到自動(dòng)分配用到的是變量宏,WICE手冊(cè)里面也有說,用法是

  TEST VAR 1

  MOV A,@TEST

  TEST VAR TEST+1

  MOV A,@TEST

  對(duì)比兩次的A值,我們發(fā)現(xiàn),第一個(gè)A值為1,第二個(gè)A值為2 !!這個(gè)就是變量宏的基本原理,編譯器當(dāng)它是一個(gè)變量,可以改變的,不過這個(gè)改變,只發(fā)生在編譯的時(shí)候,生成代碼之后就沒有用的了。

  好了,下面說說我們的核心,具體怎么分配。

  首先定義個(gè)分配變量的宏,代碼如下

  ADDR_ASSIGN MACRO REGISTER

  REGISTER EQU ADDRESS

  ADDRESS VAR ADDRESS+1

  ENDM

  用了一個(gè)參數(shù),傳遞進(jìn)來的變量的名字。例如我們?cè)谥鞒绦蚶锩鎸懥?/p>

  ADDRESS VAR 0X10

  (首先定義開始分配的地址,我們是由 0X10 開始)

  ADDR_ASSIGN Temp0

  Temp0 作為參數(shù)傳遞進(jìn)來,實(shí)際上就是執(zhí)行了

  Temp EQU 0X10

  ADDRESS = ADDRESS+1 (現(xiàn)在的ADDRESS已經(jīng)是 0X11了!因?yàn)樗且粋€(gè)變量宏!)

  下次如果我們繼續(xù)定義

  ADDR_ASSIGN Temp1

  現(xiàn)在 Temp1 已經(jīng)自動(dòng)被定義為 0X11 了,然后ADDRESS滾到0X12為下個(gè)寄存器定義用。

  這樣就方便了,例如我們定義一堆寄存器

  ADDR_ASSIGN Temp0

  ADDR_ASSIGN Temp1

  ADDR_ASSIGN Temp2

  ADDR_ASSIGN Temp3

  天啊,這實(shí)在是太好用了!!!我們完全不用關(guān)心具體分配到哪個(gè)寄存器上面,反正就是分配了,反正就是可以用了,哈~~TEST一下就知道。

  牽涉的問題1

  越界問題,當(dāng)分配到 0X3F 的時(shí)候一個(gè)頁面結(jié)束了,但是ADDRESS還是繼續(xù)加上去,怕不怕?不怕,編譯器已經(jīng)報(bào)錯(cuò)了,不能編譯,這樣就不怕越界,可以放心的定義了

  牽涉的問題2

  多個(gè)bank的怎么分配?其實(shí)可以在定義宏的時(shí)候加多一個(gè)參數(shù),通過條件宏來跳轉(zhuǎn)定義就OK了,不過我怕麻煩,用了一下的辦法:

  /*---------------------------BANK 0 入口地址-------------------------------------*/

  ADDRESS VAR 0X10 ; 可分配 0x10 ~ 0x3f

  /*--------------------------- BANK 0 ----------------------------------------*/

  這里就是我們需要定義的寄存器的

  /*---------------------------BANK0 調(diào)試信息輸出----------------------------------*/

  MESSAGE "Bank0最大分配RAM:"

  ADDR_DISP ADDRESS-1

  /*-------------------------------------------------------------------------------*/

  /*---------------------------BANK 1 入口地址-------------------------------------*/

  ADDRESS VAR 0X20 ; 可分配 0x20 ~ 0x3f

  /*--------------------------- BANK 1 ----------------------------------------*/

  這里我門需要定義的bank 1 的寄存器

  /*---------------------------BANK1 調(diào)試信息輸出----------------------------------*/

  MESSAGE "Bank 1 最大分配RAM:"

  ADDR_DISP ADDRESS-1

  /*-------------------------------------------------------------------------------*/

  怎么樣?和諧了吧? 將變量嚴(yán)格分開,你需要放在 bank0 的就填到 bank0 的區(qū)域,需要分到bank1 的就填到bank1那里,因?yàn)樵赽ank1開頭,重新定義了 ADDRESS 為 0X20 ,那樣就可以繼續(xù)從 0X20開始分配,如果有多個(gè)page的,按照同樣的辦法。在每個(gè)bank結(jié)束的時(shí)候,我還放了兩個(gè)宏,他們是

  MESSAGE "Bank0最大分配RAM:"

  ADDR_DISP ADDRESS-1

  第一個(gè),簡單的顯示文字而已,第二個(gè) ADDR_DISP 是用來顯示一共最大分配到哪個(gè)寄存器,這個(gè)宏的原型是:

  ADDR_DISP macro reg

  IF reg==0x10

  MESSAGE "0x10"

  ELSEIF reg==0x11

  MESSAGE "0x11"

  ELSEIF reg==0x12

  MESSAGE "0x12"

  ELSEIF reg==0x13

  ……

  ……

  (下面的自己寫了….)

  ENDM

  很簡單,將ADDRESS最后的地址傳進(jìn)去,現(xiàn)實(shí)一下而已,因?yàn)锳DDRESS執(zhí)行多了一條自加指令的,所以我們減回,那就OK了。

  需要注意的地方,這個(gè)方法分配的全部都是全局變量,當(dāng)做小項(xiàng)目寄存器極其緊缺,需要將某個(gè)寄存器復(fù)用的時(shí)候,這辦法就見鬼了。注意一下就是了。


上一頁 1 2 下一頁

關(guān)鍵詞: 單片機(jī) 宏定義

評(píng)論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉