- 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的端口。
- 筆記本電腦使用、維護與故障排除實戰
- 基于ARM的嵌入式系統和物聯網開發
- Spring Cloud微服務架構實戰
- Building 3D Models with modo 701
- 面向對象分析與設計(第3版)(修訂版)
- 深入理解序列化與反序列化
- LPC1100系列處理器原理及應用
- Python Machine Learning Blueprints
- FreeSWITCH Cookbook
- 嵌入式系統設計大學教程(第2版)
- 基于S5PV210處理器的嵌入式開發完全攻略
- Arduino案例實戰(卷Ⅳ)
- 快·易·通:2天學會電腦組裝·系統安裝·日常維護與故障排除
- The Deep Learning Workshop
- 微型計算機原理及應用教程(第2版)