寄存器,是集成電路中非常重要的一種存儲單元,通常由觸發器組成。在集成電路設計中,寄存器可分為電路內部使用的寄存器和充當內外部接口的寄存器這兩類。內部寄存器不能被外部電路或軟件訪問,只是為內部電路的實現存儲功能或滿足電路的時序要求。而接口寄存器可以同時被內部電路和外部電路或軟件訪問,CPU中的寄存器就是其中一種,作為軟硬件的接口,為廣泛的通用編程用戶所熟知。本文主要詳解寄存器操作方法以及對寄存器操作的通用方法總結,具體的跟隨小編來了解一下。
一、寄存器操作
1、#define方法
1)寄存器地址的定義:
#define UART_BASE_ADRS (0x10000000) /* 串口的基地址 */
#define UART_RHR *(volatile unsigned char *)(UART_BASE_ADRS + 0) /* 數據接受寄存器 */
#define UART_THR *(volatile unsigned char *)(UART_BASE_ADRS + 0) /* 數據發送寄存器 */
2)寄存器讀寫操作:
UART_THR = ch; /* 發送數據 */
ch = UART_RHR; /* 接收數據 */
也可采用定義帶參數宏實現
#define WRITE_REG(addr, ch) *(volatile unsigned char *)(addr) = ch
#define READ_REG(addr, ch) ch = *(volatile unsigned char *)(addr)
3)對寄存器相應位的操作方法:
定義寄存器
#define UART_LCR *(volatile unsigned char *)(UART_BASE_ADRS + 3) /* 線控制寄存器 */
定義寄存器相應位的值
#define CHAR_LEN_5 0x00
#define CHAR_LEN_6 0x01
#define CHAR_LEN_7 0x02
#define CHAR_LEN_8 0x03 /* 8 data bit */
#define LCR_STB 0x04 /* Stop bit control */
#define ONE_STOP 0x00 /* One stop bit! */
#define LCR_PEN 0x08 /* Parity Enable */
#define PARITY_NONE 0x00
#define LCR_EPS 0x10 /* Even Parity Select */
#define LCR_SP 0x20 /* Force Parity */
#define LCR_SBRK 0x40 /* Start Break */
#define LCR_DLAB 0x80 /* Divisor Latch Access Bit */
定義寄存器相應位的值另一種方法
#define CHAR_LEN_5 0〈〈0
#define CHAR_LEN_6 1〈〈0
#define CHAR_LEN_7 1〈〈1
#define CHAR_LEN_8 (1〈〈0)|(1〈〈1) /* 8 data bit */
#define LCR_STB 1〈〈2 /* Stop bit control */
#define ONE_STOP 0〈〈2 /* One stop bit! */
#define LCR_PEN 1〈〈3 /* Parity Enable */
#define PARITY_NONE 0〈〈3
#define LCR_EPS 1〈〈4 /* Even Parity Select */
#define LCR_SP 1〈〈5 /* Force Parity */
#define LCR_SBRK 1〈〈6 /* Start Break */
#define LCR_DLAB 1〈〈7 /* Divisor Latch Access Bit */
對寄存器操作只需對相應位或賦值
UART_LCR = CHAR_LEN_8 | ONE_STOP | PARITY_NONE; /* 設置 8位數據位,1位停止位,無校驗位 */
4)對寄存器某一位置位與清零
對某一寄存器第7位置位
XX_CRTL |= 1〈〈7;
XX_CRTL &= ~(1〈〈7);
UART_LCR |= LCR_DLAB; /* 時鐘分頻器鎖存使能 */
UART_LCR &= ~(LCR_DLAB); /* 禁止時鐘分頻器鎖存 */
5 判斷寄存器某一位是否置位或為0的方法
#define UART_LSR *(volatile unsigned char *)(UART_BASE_ADRS + 5) /* 線狀態寄存器 */
#define LSR_DR 1〈〈0 /* Data Ready */
當UART_LSR的第0位為1時結束循環
while (!(UART_LSR & LSR_DR)) /* 等待數據接收完 */
2、共用體結構體位域的應用實例
【例】設count 是一個16 位的無符號整型計數器,最大計數為十六進制0xffff,要求將這個計數值以十六進制半字節的形式分解出來。
對于上述實例通常采用移位的方法求解,而采用共用體結構體位域的方法不需要通過移位運算。以下,對CCS 在頭文件中大量使用的共用體結構體位域進行注解。
先定義一個共用體結構體位域:
…
Uint16 cont,g,s,b,q; //16 位無符號整型變量定義
cont=0xfedc; //對cont 賦值
…
union //共用體類型定義
{ Uint16 i; //定義i 為16 位無符號整型變量
struct //結構體類型定義
{
Uint16 low:4; //最低4 位在前。從最低4 位開始,取每4 位構成半字節
Uint16 mid0:4;
Uint16 mid1:4;
Uint16 high:4; //最高4 位在后
}HalfByte; //HalfByte 為具有所定義的結構體類型的變量
}Count; //Count為具有所定義的共用體類型的變量
union 定義一個共用體類型,它包含兩個成員:一個是16 位無符號整型變量i,另一個是包含4 個半字節變量(low,mid0,mid1,high)的結構體類型。它們占用同一個內存單元,通過對i(Count.i)進行賦值,可以完成對結構體4 個變量的賦值。
上面的程序,在定義共用體類型和結構體類型的同時,直接完成了這兩個類型變量的定義,而未定義共用體和結構體類型名。即HalfByte 是一個具有所定義的結構體類型的變量,Count 是一個具有所定義的共用體類型的變量。理解了共用體與結構體之間的關系,下面的賦值指令就清楚了。
Count.i = cont; //對共用體類型成員i 進行賦值
g = Count.HalfByte.low; //將cont 的0~3 位賦值給g,g=0x000c
s = Count.HalfByte.mid0; //將cont 的4~7 位賦值給s,s=0x000d
b = Count.HalfByte.mid1; //將cont 的8~11 位賦值給b,b=0x000e
q = Count.HalfByte.high; //將cont 的12~15 位賦值給q,q=0x000f
通過共用體結構體定義,當對共用體類型成員i 進行賦值時,由于結構體類型變量HalfByte 與i 占用同一個內存單元,因此,也就完成了對HalfByte 的各成員的賦值。
C 語言的共用體結構體位域定義,可以完成對寄存器位域的訪問。至于被訪問的位域在內存中的具體位置則由編譯器安排,編程者可以不必關注。
下面是一個訪問寄存器位域的例子,供讀者參考。
先建立一個共用體結構體位域定義,將某個寄存器的16 位,從最低位到最高位分別
定義為Bit1,Bit2,…,Bit16。
union //共用體類型定義
{ Uint16 all; //定義all 為16 位無符號整型變量
struct //結構體類型定義
{
Uint16 Bit1:1; //0 位Bit1 取寄存器最低位0 位,以下順序取1 位直到最高位
Uint16 Bit2:1; //1
Uint16 Bit3:1; //2
Uint16 Bit4:1; //3
Uint16 Bit5:1; //4
Uint16 Bit6:1; //5
Uint16 Bit7:1; //6
Uint16 Bit8:1; //7
Uint16 Bit9:1; //8
Uint16 Bit10:1; //9
Uint16 Bit11:1; //10
Uint16 Bit12:1; //11
Uint16 Bit13:1; //12
Uint16 Bit14:1; //13
Uint16 Bit15:1; //14
Uint16 Bit16:1; //15
}bit; //bit為具有所定義的結構體類型的變量
}CtrlBit; //CtrlBit 為具有所定義的共用體類型的變量
有了上面的定義之后,要訪問某一個位或某些位就很容易了。比如要置Bit4,Bit8,Bit12 及Bit16 為1,可用兩種方法進行:
方法一:
CtrlBit.bit.Bit4 = 1;
CtrlBit.bit.Bit8 = 1;
CtrlBit.bit.Bit12 = 1;
CtrlBit.bit.Bit16 = 1;
二、對寄存器操作的通用方法總結
對寄存器的操作有時候要考慮對其不同的位進行先后順序不同的設置,但是對寄存器操作的方法是固定的。
首先要明白邏輯運算符(!,&&,||)和位運算符(〈〈,〉〉,~,|,^,&)的區別:
對寄存器的操作使用的是位運算符,
邏輯運算符一般用于在程序中判斷邏輯中使用。
例如 定義一個8位的寄存器(0xf0是寄存器的地址): #define REG 0xF0
1)對單個的位進行賦值
(1)將寄存器REG的第5位置“1”: REG |= (1 〈〈 5);
(2)將寄存器REG的第5位清“0”: REG &= ~(1 〈〈 5);
(3)將寄存器REG的第3和第5位置“1”:REG |= (1 〈〈 5) | (1 〈〈 3);
(4)將寄存器REG的第3和第5位清“0”:REG &= ~( (1 〈〈 5) | (1 〈〈 3) );
該段總結如下:
將某位置1,移位后使用位運算“|” ;
將某位清0,移位取反后,使用位運算“&”
2)直接賦值
(1)將寄存器REG的1、2、3、5、7位置“1”
REG = 0x5E; (即給寄存器REG1賦值為1010 1110,這種方法多在初始化中使用)
(2)分別將寄存器REG的1、3、5、7位置“1”;0、2位清“0”
u8 temp;
temp = REG;
temp |= (1 〈〈 1); //將第1位置“1”
temp |= (1 〈〈 3);
temp |= (1 〈〈 5);
temp |= (1 〈〈 7);
temp &= ~(1 〈〈 0) ; //將第0位清“0”,等價于temp &= ~0x01
temp &= ~(1 〈〈 2); //將第2位清“0”
REG = temp;
-
寄存器
+關注
關注
31文章
5363瀏覽量
121155
發布評論請先 登錄
相關推薦
評論