官术网_书友最值得收藏!

  • ARM接口編程
  • 唐振明主編
  • 1395字
  • 2018-12-29 04:01:43

1.4 嵌入式C語言

1.4.1 寄存器定義解釋

在具體講解寄存器的定義及使用方式之前,首先看一個例子。

          #ifdef __BIG_ENDIAN
          #define rBCDSEC    (*(volatile unsigned char*)0x57000070)
          #else

根據上述定義,思考如下問題:

? 為何要分字節序符定義?

? volatile表示什么含義?

? 為何要用無符號的數字?

? 宏定義最前面的*表示什么含義?

1.為何要分字節序符定義

寄存器的地址位于一個線性空間上,但是不同字節序下,同一寄存器的地址會發生變化。這可參見CPU的手冊,為了隱藏這個細節,所以定義兩套。

另外,已經知道32位寄存器的各個位是固定的,不同的CPU字節序有不同的結果,這樣進行對位操作時,同一個寄存值在不同字節序下,會產生不同的位排列。因此為防止字節序對寄存器進行干擾,后面的ADS的C代碼一般會直接采用大端字節序,在Linux下很多時候會采用移位來排除字節序的干擾。

2.volatile表示的含義

volatile關鍵字是一種類型修飾符,用它聲明的類型變量表示可以被某些編譯器未知的因素更改,如操作系統、硬件或者其他線程等。遇到這個關鍵字聲明的變量,編譯器對訪問該變量的代碼就不再進行優化,從而可以提供對特殊地址的穩定訪問。

volatile能區分C程序員和嵌入式系統程序員最基本的問題。嵌入式程序員經常同硬件、中斷、RTOS等打交道,所有這些都要用到volatile變量,因此必須熟悉volatile的相關知識。

當要求使用volatile聲明的變量值時,系統總是重新從它所在的內存讀取數據,即使它前面的指令剛剛從該處讀取過數據,并且讀取的數據立刻被保存。

如一個變量沒有volatile,則編譯器會自動進行優化,如自動清零。如果這個整數是一個多線程,或硬件地址,那么可能會帶來意想不到的結果。

volatile的應用場合:

? 存儲器映射的硬件寄存器通常也要加volatile說明,因為每次對它的讀寫都可能有不同的意義,如并行設備的硬件寄存器(如狀態寄存器)。

? 中斷服務程序中修改的供其他程序檢測的全局變量需要加volatile,如一個中斷服務子程序中會訪問到的非自動變量(Non-automatic variables)。

? 多任務環境下各任務間共享的數據,如多線程應用中被幾個任務共享的變量。

3.為何要用無符號的數字

數字有兩種移位:一種是算術移位,一種是邏輯移位。前者在有符號位的情況下,會對符號位做特殊處理。而且寄存器對應的就是原始位,最高位也有特定的含義。這種情況下,指定為無符號位數是為了防止編譯器對最高位采用特殊算術移位,從而違反設計者的本意。

4.宏定義最前面的*表示的含義

表示取指針的內容,類似于char *p=&a; *p='A'但這里不是一個變量,而是一個常量地址。但效果是一樣的,相當于取對應地址的內容,或者對這個地址賦值。

1.4.2 寄存器操作

因為每個寄存器都為32位寬,因此在程序中可將寄存器的值看成一個無符號整數,對寄存器的取值看成是取一個整數值,而對寄存器設置看成是對一個整數變量賦值。

在很多情況下,人們需要取寄存器某一位或某幾位的值。這時需要用到兩個固定的位操作,即置位操作和取位操作。通常的操作方法為:置1位操作采用 |=,置0位操作采用 &=~。

1.置某一位為0

? 置第一位為0。

          //1取反,表示0x11111110 ,與上rRTCCON表示將最低0位置0,其余位不變
              rRTCCON&=~1;    //RTC read and write disable

? 置第三位為0。

          //0x0100 取反。再與上相應的寄存器地址
            rRTCCON &= ~0x4;

? 假設置12~13 bit為0,則二進制展開為11000000000000,換算為0x3000。

            rADCDAT0 &=~0x3000;

? 置采用左移或右移來置位,以置14bit為0為例。

            rADCDAT0 &=~(0x1<<14);

2.置某一位為1

? 置第一位為1。

          //1取反,表示0x00000001 ,或上rRTCCON表示將最低0位置1,其余位不變
              rRTCCON|=1;      //RTC read and write disable

? 置第三位為1。

          //0x0100,再或上相應的寄存器地址
            rRTCCON |= 0x4;

? 假設置12~13bit為1,則二進制展開為11000000000000。

            rADCDAT0 |=0x3000;

? 置采用左移,或右移來置位,以置14bit為例。

            rADCDAT0 |=(0x1<<14);

3.取位操作

? 假設是否判斷rADCDAT0的第14位的值。

            If(rADCDAT0&(0x01<<14))  //值為1的操作
              else   //值為0的操作,假設取rADCDAT0的12~13bit的值
             (rADCDAT0 & 0x3000)>>12;

現在來看一個例子:

          rGPBCON&=~0x3;         //set GPB0 as tout0,pwm output
          rGPBCON|=0x2;           //

在上面的程序中,0x3的二進制表示為00000011,取反就是11111100。與上(&)它,表示將低1、低2位置0,現在看一下GPBCON的DataSheet,GPB端口描述如表1.2所示。

表1.2 GPB端口描述

rGPBCON &=~3表示將GPB0端口設為00,即設為input端口。

再次執行rGPBCON |=2即將GPB0設為0x2=00000010,即TOUT0的端口。

主站蜘蛛池模板: 贺兰县| 潍坊市| 洛宁县| 丰顺县| 班玛县| 安庆市| 雷波县| 石景山区| 新巴尔虎右旗| 青龙| 浏阳市| 浪卡子县| 乌鲁木齐县| 灵石县| 洞头县| 抚州市| 金华市| 清水河县| 安远县| 乌拉特前旗| 克东县| 焉耆| 江阴市| 馆陶县| 甘泉县| 剑阁县| 当涂县| 峨边| 临沭县| 肥乡县| 星子县| 秦皇岛市| 老河口市| 策勒县| 萍乡市| 丰镇市| 神农架林区| 托里县| 渝中区| 沈阳市| 会昌县|