3.4
3.4.1
C語(yǔ)言對(duì)寄存器的封裝
前面的所有關(guān)于存儲(chǔ)器映射的內(nèi)容,最終都是為大家更好地理解如何用C語(yǔ)言控制讀寫(xiě)外設(shè)寄存器做準(zhǔn)備,因此此處是本章的重點(diǎn)內(nèi)容。
3.4.1.1
外設(shè)模塊基地址定義
在編程上為了方便理解和記憶,我們要把外設(shè)模塊基地址以相應(yīng)的宏定義起來(lái),外設(shè)基地址都以它們的名字作為宏名的組成部分。以下是IO端口外設(shè)基地址的宏定義。
列表1:代碼清單3?1 IOPORT外設(shè)基地址宏定義
左右滑動(dòng)查看完整內(nèi)容
/* 外設(shè)基地址 */ #defineR_PORT0_BASE 0x40080000 #defineR_PORT1_BASE 0x40080020 #defineR_PORT2_BASE 0x40080040 #defineR_PORT3_BASE 0x40080060 #defineR_PORT4_BASE 0x40080080 #defineR_PORT5_BASE 0x400800A0 #defineR_PORT6_BASE 0x400800C0 #defineR_PORT7_BASE 0x400800E0 #defineR_PORT8_BASE 0x40080100 #defineR_PORT9_BASE 0x40080120 #defineR_PORT10_BASE 0x40080140 #defineR_PORT11_BASE 0x40080160 #defineR_PFS_BASE 0x40080800 #defineR_PMISC_BASE 0x40080D00
3.4.1.2
寄存器結(jié)構(gòu)體定義
由于寄存器的數(shù)量是非常之多的,如果每個(gè)寄存器都用像*((uint32_t*)(0x40080000+0x0020*1))這樣的方式去訪(fǎng)問(wèn)的話(huà),會(huì)顯得很繁瑣、很麻煩。為了更方便地訪(fǎng)問(wèn)寄存器,我們會(huì)借助C語(yǔ)言結(jié)構(gòu)體的特性去定義寄存器和寄存器位域,這是通用的做法。
列表2:代碼清單3?2使用結(jié)構(gòu)體封裝外設(shè)寄存器
左右滑動(dòng)查看完整內(nèi)容
// 注:關(guān)于輸入輸出端口的聲明 /* C 語(yǔ)言: IO definitions (access restrictions to peripheral registers) */ //#define __I volatile const /*!< Defines 'read only'? , →permissions */ //#define __O volatile /*!< Defines 'write only'? , →permissions */ //#define __IO volatile /*!< Defines 'read / write'? , →permissions */ /* 下面的宏定義用于結(jié)構(gòu)體成員 */ /* following defines should be used for structure members */ //#define __IM volatile const /*! Defines 'read only'? , →structure member permissions */ //#define __OM volatile /*! Defines 'write only'? , →structure member permissions */ //#define __IOM volatile /*! Defines 'read / write'? , →structure member permissions */ //typedef unsigned char uint8_t; //typedef unsigned short int uint16_t; /* 無(wú)符號(hào) 16 位整型變量 */ //typedef unsigned int uint32_t; /* 無(wú)符號(hào) 32 位整型變量 */ /** * @brief I/O Ports (R_PORT0) */ typedefstruct?/*!< (@ 0x40040000) R_PORT0? , →Structure */ { union { union { __IOM?uint32_t?PCNTR1;?/*!< (@ 0x00000000) Port Control? , →Register 1 */ struct { __IOM?uint32_t?PDR :?16;?/*!< [15..0] Pmn Direction(引腳 Pmn 方向)*/ __IOM?uint32_t?PODR :?16;?/*!< [31..16] Pmn Output Data(引腳 Pmn 輸出數(shù)據(jù))*/ } PCNTR1_b; }; /* ... 代碼過(guò)長(zhǎng)省略 ... */ }; union { union { __IM?uint32_t?PCNTR2;?/*!< (@ 0x00000004) Port Control? , →Register 2 */ struct { __IM?uint32_t?PIDR :?16;?/*!< [15..0] Pmn Input Data(引腳 Pmn 輸入數(shù)據(jù))*/ __IM?uint32_t?EIDR :?16;?/*!< [31..16] Pmn Event Input Data (引腳 Pmn 事件輸入數(shù)據(jù))*/ } PCNTR2_b; }; /* ... 代碼過(guò)長(zhǎng)省略 ... */ }; union { union { __OM?uint32_t?PCNTR3;?/*!< (@ 0x00000008) Port Control? , →Register 3 */ struct { __OM?uint32_t?POSR :?16;?/*!< [15..0] Pmn Output Set(引腳 Pmn 輸出置位)*/ __OM?uint32_t?PORR :?16;?/*!< [31..16] Pmn Output Reset(引腳 Pmn 輸出復(fù)位)*/ } PCNTR3_b; }; /* ... 代碼過(guò)長(zhǎng)省略 ... */ }; union { union { __IOM?uint32_t?PCNTR4;?/*!< (@ 0x0000000C) Port Control?, →Register 4 */ struct { __IOM?uint32_t?EOSR :?16;?/*!< [15..0] Pmn Event Output Set (引腳 Pmn 事件輸出置位)*/ __IOM?uint32_t?EORR :?16;?/*!< [31..16] Pmn Event Output? →Reset(引腳 Pmn 事件輸出復(fù)位)*/ } PCNTR4_b; }; /* ... 代碼過(guò)長(zhǎng)省略 ... */ }; } R_PORT0_Type;?/*!< Size = 16 (0x10) */
3.4.1.3
外設(shè)模塊寄存器定義
我們?cè)谏弦徊揭呀?jīng)定義好了R_PORT0_Type類(lèi)型的結(jié)構(gòu)體,它包含了IOPORT的寄存器定義。接下來(lái)使用宏定義來(lái)表示結(jié)構(gòu)體指針,指針指向IOPORT外設(shè)的每個(gè)端口的寄存器首地址。
列表3:代碼清單3?3寄存器定義
#defineR_PORT0 ((R_PORT0_Type *) R_PORT0_BASE) #defineR_PORT1 ((R_PORT0_Type *) R_PORT1_BASE) #defineR_PORT2 ((R_PORT0_Type *) R_PORT2_BASE) #defineR_PORT3 ((R_PORT0_Type *) R_PORT3_BASE) #defineR_PORT4 ((R_PORT0_Type *) R_PORT4_BASE) #defineR_PORT5 ((R_PORT0_Type *) R_PORT5_BASE) #defineR_PORT6 ((R_PORT0_Type *) R_PORT6_BASE) #defineR_PORT7 ((R_PORT0_Type *) R_PORT7_BASE) #defineR_PORT8 ((R_PORT0_Type *) R_PORT8_BASE) #defineR_PORT9 ((R_PORT0_Type *) R_PORT9_BASE) #defineR_PORT10 ((R_PORT0_Type *) R_PORT10_BASE)
這樣便大功告成了,我們就可以使用這些宏來(lái)訪(fǎng)問(wèn)各個(gè)IO端口的每一個(gè)寄存器了。
3.4.2
修改寄存器操作的本質(zhì):讀-改-寫(xiě)
有了以上的對(duì)IOPORT這個(gè)外設(shè)模塊的寄存器的定義,我們便完成了“C語(yǔ)言對(duì)寄存器的封裝”這個(gè)步驟,接下來(lái)我們便可以使用C語(yǔ)言對(duì)寄存器進(jìn)行各種操作了。
對(duì)寄存器進(jìn)行操作可以是忽略寄存器原本的值,而直接覆蓋寫(xiě)入新的值;但是更為一般的操作是根據(jù)原本的寄存器值進(jìn)行修改,即:先讀出寄存器原本的值,然后修改該值,最后重新寫(xiě)入到寄存器里面,讓新的值生效。
接下來(lái)將介紹修改寄存器的幾種通用方法。
3.4.2.1
清零寄存器上的某N個(gè)位
使用C語(yǔ)言的按位與“&”運(yùn)算符可以將位進(jìn)行清零。
列表4:代碼清單3?4位清零:按位與&
//清零某個(gè)位 R_PORT0->PODR &= ~(1u<<0); //清零 PODR 寄存器的第 0?位 R_PORT0->PODR &= ~(1u<<6); //清零 PODR 寄存器的第 6?位 //清零多個(gè)位 R_PORT0->PODR &= ~(3u<<0); //清零 PODR 寄存器的第 0,1 位 R_PORT0->PODR &= ~(3u<<6); //清零 PODR 寄存器的第 6,7 位
3.4.2.2
對(duì)寄存器上的某N個(gè)位進(jìn)行置位
使用C語(yǔ)言的按位或“|”運(yùn)算符可以將位進(jìn)行置一。
列表5:代碼清單3?5位置位:按位或|
//置位某個(gè)位 R_PORT0->PODR |= 1u<<0; //PODR 寄存器的第 0?位置 1 R_PORT0->PODR |= 1u<<6; //PODR 寄存器的第 6?位置 1 //置位多個(gè)位 R_PORT0->PODR |= 3u<<0; //PODR 寄存器的第 0,1 位置 1 R_PORT0->PODR |= 3u<<6; //PODR 寄存器的第 6,7 位置 1
3.4.2.3
對(duì)寄存器上的某N個(gè)位進(jìn)行取反
使用C語(yǔ)言的按位異或“^”運(yùn)算符可以將位進(jìn)行取反。
列表6:代碼清單3?6位取反:按位異或^
//取反某個(gè)位 R_PORT0->PODR ^= 1u<<0; //取反 PODR 寄存器的第 0?位 R_PORT0->PODR ^= 1u<<6; //取反 PODR 寄存器的第 6?位 //取反多個(gè)位 R_PORT0->PODR ^= 3u<<0; //取反 PODR 寄存器的第 0,1 位 R_PORT0->PODR ^= 3u<<6; //取反 PODR 寄存器的第 6,7 位
-
mcu
+關(guān)注
關(guān)注
146文章
17834瀏覽量
360367 -
寄存器
+關(guān)注
關(guān)注
31文章
5421瀏覽量
123320 -
瑞薩
+關(guān)注
關(guān)注
36文章
22369瀏覽量
87730 -
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7630瀏覽量
140322 -
FSP
+關(guān)注
關(guān)注
0文章
41瀏覽量
7351
原文標(biāo)題:如何用C語(yǔ)言操作寄存器——瑞薩RA系列FSP庫(kù)開(kāi)發(fā)實(shí)戰(zhàn)指南(10)
文章出處:【微信號(hào):瑞薩MCU小百科,微信公眾號(hào):瑞薩MCU小百科】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
瑞薩RA系列MCU FSP庫(kù)開(kāi)發(fā)實(shí)戰(zhàn)指南(09)存儲(chǔ)器映射

評(píng)論