C語言操作寄存器和函數指針
typedef函數指針類型
#include <stdio.h>
//函數指針類型別名
/*
* int 函數返回值
* (int,int)函數參數,兩個參數int,int
* *PTP_TO_FUNC函數指針,指向函數的指針
*/
typedef int (*PTR_TO_FUNC)(int, int);
/*
為數組定義別名與函數指針類型別名類似
[4]數組各屬
PTR_TO_ARR指向數組的名,其數組個數與參數個數相同
在使用是當成一種類型,在為其賦值時需要重新為其添加值
*/
typedef char(*PTR_TO_ARR)[10];
//實現函數體
int max(int x, int y)
{
return x > y ? x : y;
}
int main(void)
{
//定義數組,等待指向
char str[3][10] = {
"嘿嘿",
"信息科技",
"有限公司"
};
// PTR_TO_ARR結構體指針,仍需要定義別名
PTR_TO_ARR arr = str[1];
// 指向函數
PTR_TO_FUNC func = max;
printf("max(6,3): %d\n", (*func)(6, 3));
printf("str[1]: %s\n", (*arr)); //輸出信息科技
return0;
}
寄存器
有限存貯容量的高速存貯部件 。寄存器的功能是存儲二進制代碼,它是由具有存儲功能的觸發器組合起來構成的。一個觸發器可以存儲1位二進制代碼,故存放n位二進制代碼的寄存器,需要n個觸發器來構成。
寄存器分類
基本寄存器 :只能并行送入數據,也只能并行輸出。
移位寄存器中的數據可以在移位脈沖作用下依次逐位右移或左移,數據既可以并行輸入,并行輸出,也可以串行輸入,串行輸出,還可以并行輸入,串行輸出或串行輸入,并行輸出,靈活,用途廣泛。
使用
在嵌入式編程中,常常需要對一些寄存器進行配置,有的情況下需要改變一1個字節中的某一位或者幾位,但是又不想改變其它位原有的值,就可以使用按位運算符進行操作。
假如我們只需要設置第0位bit0的值為1時, 要保持其它位 不發生變化。
TEST = 0x01
此方式如果高7位沒有使用,就不會有影響,但是如果高7位正在被使用,那么就會發生錯誤。
- 與運算 :對于二進制位操作,不管原值是0還是1,它跟0進行&與運算,得到的結果都是 0,而和1進行&運算,將保持原來的值不變
- 或運算 :不管該位原來的值是0還是1,它跟1進行 |運算,得到的結果都是1,而跟0運算,將保持原來的值不變。`
可以使用或運算:
TEST = TEST | 0x01;
// 在實際中常用
TEST |= 0x01;
給Test的低4位清 0 ,高四位保持不變:
TEST &= 0xF0; //使用十六進制
此方法在單片機中經常使用,先對需要設置的位用 &操作符進行清零操作,然后用 | 操作符設置值,改變GPIOA的狀態,先對寄存器的值進行清零操作,然后根據需要設置的值進行 | 或運算:
GPIOA->CRL &= 0XFFFFFF0F; // 將第4~7位清零
GPIOA->CRL &= 0X00000040; //設置相應的值,不改變其他位的值
移位提高可讀性
GPIOx->BSRR = (((uint32_t)0x01) << pinpox); //將0x01 左移pinpox位,
通過左移而不是直接設置一個固定的值 :為了提高代碼的可讀性,直接就知道修改了第幾位:
GPIOA->ODR |= 1<<5; //PA.5輸出高,其它位不變
設置某位為0
簡單操作:
TIMx->SR = 0xFFF7; //此方法仍然影響可讀性,
庫函數:
TIMx -> SR = (uint16_t)~TIM_FLAG;
TIM_FLAG定義
設置SR的第三位為 0 時即可設置為
TIMx->SR = (uint16_t)~TIM_FLAG_CC3;
#define TIM_FLAG_Update ((uint16_t)0x0001)
#define TIM_FLAG_CC1 ((uint16_t)0x0002)
#define TIM_FLAG_CC2 ((uint16_t)0x0004)
#define TIM_FLAG_CC3 ((uint16_t)0x0008)
#define TIM_FLAG_CC4 ((int16_t)0x0010)
#define TIM_FLAG_COM ((uint16_t)0x0020)
#define TIM_FLAG_Trigger ((uint16_t)0x0040)
#define TIM_FLAG_Break ((uint16_t)0x0080)
#define TIM_FLAG_CC1OF ((uint16_t)0x0200)
#define TIM_FLAG_CC2OF ((uint16_t)0x0400)
#define TIM_FLAG_CC3OF ((uint16_t)0x0800)
#define TIM_FLAG_CC4OF ((uint16_t)0x1000)
位域
位域:或稱之為位段,英文表達式 Bit field 是一種數據結構,可以把數據以位元的形式緊湊的存儲,并允許程序員對此結構進行位元進行操作。
優勢:
- 可以使數據單元節省存儲空間
- 位段可以很方便地訪問一個整數值的部分內容從而簡化程序源代碼。
位域可以分為兩大類,一個是結構體位域,一個是共同體位域,由于共同體和結構體兩者在定義上的形式都是相同的,從位域的定義形式上看,兩者也基本都是相同的。
struct 位域結構體
{
類型說明符 位域名 : 長度;
}結構體變量名;
// 結構體位域
struct example0
{
unsignedchar x : 3; //冒號后面的證書指定了該位段所占用的位的數目。
unsignedchar y : 2;
unsignedchar z : 1;
}ex0_t;
// 共同體位域
union example1
{
unsignedchar x : 3;
unsignedchar y : 2;
unsignedchar z : 1;
}ex1_u;
位域大小原則 :整個結構體位域的總大小為最寬基本類型成員大小的整數倍。
位域基本都使用無符號類型。
位域注意
- 結構體位域成員不能使用取址操作
- 結構體成員不能夠使用static修飾
- 結構體位域成員不能使用數組。
不同的處理器,不同的編譯器對位域的影響,位域雖然能夠以位的形式操作數據,但是也被人們告知要慎重使用,原因在于不同的處理器結構,不同的編譯器對于位域的一些特征會產生不同的結果。
處理器大端模式,小端模式的處理器也會對下面的結構體位域產生不一樣的存儲方式。
不同的編譯器,結構體位域成員不同類型,不同的編譯器對于位域會有不同的結果
當成員大小之和超過一個基本存儲空間時,不同的編譯器也會有不同的處理方式。
typedefunion
{
unsignedchar Byte;
struct
{
unsignedchar bit012 : 3;
unsignedchar bit34 : 2;
unsignedchar bit5 : 1;
unsignedchar bit6 : 1;
unsignedchar bit7 : 1;
}bits;
}registerType;
存儲0x0000 8000定義一個指針指向地址:
registerType *pReg = (register*)0x00008000;
// 使用位域寄存器進行賦值
pReg->bits.bit5 = 1;
pReg->bits.bit012 = 7;