關於嵌入式學習隨筆->3《C語言基礎》
1、位操作
位操作主要用於在進行寄存器操作的時候,為了使實現某一功能而又不改變原來的功能所需要用到的一種按位運算的方法。比如我們要改變GPIOA->ODR的狀態,一般來說需要兩步,第一步,將原來位置的數據清除,第二步在將要存入的數據寫入。
運算符 | 含義 | 運算符 | 含義 |
& | 按位與 | ~ | 取反 |
| | 安慰或 | << | 左移 |
^ | 按位異或 | >> | 右移 |
操作及其示例代碼:
1)對某位進行操作
GPIOA->ODR &=0XFF0F;//將第4-7位清0。
GPIOA->ODR |=0X0040;//設置相應位的值,不改變其他位的值。
2)位移操作提高代碼的可讀性
GPIOA->ODR |= 1<<5;//將ODR寄存器第五位設置位1,其他位置不變。
GPIOA->ODR = 0X0020;//這樣也是第五位置1,但是其他位會強制清0,改變了原來的配置。
3)取反操作
GPIOA->ODR &= 0XFFF7;//可讀性不高,其實就是第3位清0,其他位置不變。
-》按位移來操作:
GPIOA->ODR |= ~(1<<3);//將第3位清0
如果有幾位同時需要置1,可以取成8421碼格式,來按整體位移。
註意:C語言中沒有同或運算符。
2、define宏定義關鍵詞
define 時C語言中的預處理命令,它用於宏定義,可以提高源代碼的可讀性,為編程提供方便。
一般使用方法為:
#define 標識符 字符串(可以是常數、表達式、格式串等)
1 #define Author Yimiu 2 #define number 123
在聲明之後就可以用標識符來代替原來的字符串或數字。
3.條件編譯
一般#ifdef語句要與#else、#end連用:即定義了情況一就編譯程序段1,否則編譯程序段2。
1 #ifndef condition1 2 //程序段1 3 #else 4 //程序段2 5 #endif
#ifndef、#define、#endif往往在頭文件中使用,防止重復定義。
1 #ifndef __DELAY_H 2 #define __DELAY_H 3//頭文件及其函數聲明 4 #endif
另外還有#if、#endif語句:滿足condition1則編譯程序段1,滿足condition2則編譯程序段2否則編譯程序段3
1 #if condition1 2 //程序段1 3 #elseif condition2 4 //程序段2 5 #else 6 //程序段3 7 #endif
4、extern變量聲明
在C語言中extern可以放在函數聲明或是變量聲明之前,它的作用是提示編譯器在遇到此變量和函數時在其他文件或是模塊中尋找其定義,需要註意的是,對於變量或是函數的extern聲明可以有很多次,但是變量或是函數的定義只能有一次。
1 extern void function(void); 2 extern u8 Author;
5、typedef類型別名
除了可以直接使用C提供的標準類型名(如int、char、float、double和long等)和程序員自己聲明的機構提、共用體、美劇類型外,還可以用typedef制定新的類型名來代替已有的類型名。有以下兩種情況:
1)簡單的用一個新的類型名代替原有的類型名
1 typedef int integer;//指定用integer來做類型名,作用於int相同 2 typedef float Real;//指定用Real來做類型名,作用於float相同 3 integer a;//實際上就是int a
2)命名一個簡單的類型名代替復雜的表示方法
--》1>命名一個新的類型名代表結構體類型
1 typedef struct 2 { 3 int month; 4 int day; 5 int year; 6 }Data; 7 //聲明了一個新的類型名Date,來代表上邊的結構體類型 8 Date birthday;//定義結構體類型變量birthday 9 Date *p; //定義結構體指針變量p,指向此結構體類型數據
--》2>命名一個新的類型名代表數組類型
1 typedef int Num[100];//聲明Num為整型數組類型名 2 Num a; //定義a為整型數組名,它有一百個元素
--》3>命名一個新的類型名代表指針類型
1 typedef char *string; //聲明string為字符指針類型 2 string p,s[10]; //聲明p字符指針變量,s為字符指針數組
--》4>命名一個行的類型名代表指向函數的指針
1 typedef int (*pointer)(); //聲明pointer為指向函數的指針類型,該函數返回整型值 2 pointer p1,p2; //p1、p2為pointer類型指針變量
簡單的說,就是按定義變量的方式,把變量名換上新類型名,並且在最前面加上“typedef”,就聲明了新類型名代表原來的類型。
6、結構體
結構體聲明:
1 struct struct_name 2 { 3 //成員列表 4 }; 5 stuct Student 6 { int number; 7 char name; 8 char sex; 9 int age; 10 float score; 11 };//註意分號 12 Student Yimiu;//定義了一個Yimiu結構體變量 13 //可以通過“.”來呼出變量成員 14 Yimiu.number = 092414216 15 Yimiu.name = yimi 16 //這樣就為名為Yimiu的結構體變量成員賦值了
7、static關鍵字
除了從變量的作用域(也就是空間上)來說的角度觀察,分為全局變量和局部變量外,還可以從兩外一個角度,即變量存在時間的長短(即生存期)角度來觀察。有的變量在程序運行過程中都是存在的,而又的變量在則是在調用其所在函數時才會零時分配存儲單元,當執行完畢後就會被釋放,變量就不存在了。也就是說變量存儲兩種方式:靜態存儲方式和動態存儲方式。靜態存儲方式是指在程序運行期間由系統分配固定的存儲空間,而動態存儲方式則是在程序運行期間根據需要進行動態的分配存儲空間的方式。
static關鍵字為靜態局部變量聲明,用此關鍵字聲明的變量在函數調用後不會消失而繼續保留原值,也就是其占用的存儲空間沒有被釋放,下一次調用該函數時,該變量已經有值(上一次運行結果)。
1 int func(int a) 2 { 3 suto int b=0; 4 static c=3; 5 b=b+1; 6 c=c+1; 7 return(a+b+c); 8 } 9 int main() 10 { 11 int a=2,i; 12 for(i=0;i<3;i++) 13 { 14 printf("%d\n\r",func(a)); 15 } 16 }//註意在STM32系列中主函數雖然為int型,但是不用返回函數值
運行的結果為7、8、9可以自行分析。
8、__weak弱函數
__weak關鍵字用來聲明的函數叫做弱函數,我們可以這樣理解,當應用層沒有定義此函數時,那麽系統默認編譯此弱函數中的內容(系統必須要調用此函數),若我們在其他地方定義了沒有用弱函數聲明的函數時,此時就會編譯我們自己定義的函數。其實當程序運行到某一函數時,系統先找其定義,若果沒有再找其弱定義,最後都沒有時會報錯。
1 __weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 2 { 3 /* Prevent unused argument(s) compilation warning */ 4 UNUSED(huart); 5 6 /* NOTE : This function should not be modified, when the callback is needed, 7 the HAL_UART_RxCpltCallback can be implemented in the user file 8 */ 9 } 10 ********************************************************************************* 11 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 12 { 13 #if EN_USART1_RX 14 if(huart->Instance==USART1)//如果是串口1 15 { 16 if((USART_RX_STA&0x8000)==0)//接收未完成 17 { 18 if(USART_RX_STA&0x4000)//接收到了0x0d 19 { 20 if(aRxBuffer[0]!=0x0a)USART_RX_STA=0;//接收錯誤,重新開始 21 else USART_RX_STA|=0x8000; //接收完成了 22 } 23 else //還沒收到0X0D 24 { 25 if(aRxBuffer[0]==0x0d)USART_RX_STA|=0x4000; 26 else 27 { 28 USART_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ; 29 USART_RX_STA++; 30 if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收數據錯誤,重新開始接收 31 } 32 } 33 } 34 35 }
當我們不使用UART回調功能時,那麽我們就不用寫此函數,系統就會執行相應的弱定義函數,在整個工程當中,往往會有大量的弱函數被定義。
關於嵌入式學習隨筆->3《C語言基礎》