1、stdint.h簡介
stdint.h 是從 C99 中引進的一個標準 C 庫的文件
路徑:D:\MDK5.34\ARM\ARMCC\include
大家都統一使用一樣的標準,這樣方便移植
配置MDK支持C99
位操作
如何給寄存器某個值賦值
舉個例子:uint32_t temp = 0;
宏定義
帶參數的宏定義
https://blog.csdn.net/xiaoyilong2007101095/article/details/77067686
去看一下宏定義
#define LED1(x) do{ x ? \HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_SET) : \HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_RESET); \}while(0)
建議大家使用 do{ ... }while(0)
來 構造宏定義,這樣不會受到大括號、分號、運算符優先級等的影響,總是會按你期望的方式調用運行!
假設LED1(1)
參數為真 ,那么就執行第一句,如果是LED1(0)
,那么就執行第二句
條件編譯
讓編譯器只對滿足條件的代碼進行編譯,不滿足條件的不參與編譯!
extern聲明
類型別名(typedef)
為現有數據類型創建一個新的名字,或稱為類型別名,用來簡化變量的定義
/*typedef 現有類型 新名字*/
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
類型別名應用
下面是結構體應用typedef
struct GPIO_TypeDef
{__IO uint32_t CRL;__IO uint32_t CRH;//…
};
struct GPIO_TypeDef gpiox; //聲明typedef struct
{__IO uint32_t CRL;__IO uint32_t CRH;//…
} GPIO_TypeDef;
GPIO_TypeDef gpiox; //聲明
在C中定義一個結構體類型要用typedef:
typedef struct Student
{int a;
}Stu;
于是在聲明變量的時候就可:Stu stu1;
如果沒有typedef
就必須用struct Student stu1;
來聲明
這里的Stu
實際上就是struct Student
的別名。
另外這里也可以不寫Student
(于是也不能struct Student stu1;
了)
typedef struct
{int a;
}Stu;
但在c++里很簡單,直接
struct Student
{int a;
};
于是就定義了結構體類型Student
,聲明變量時直接Student stu2;
2其次:
在c++中如果用typedef的話,又會造成區別:
struct Student
{int a;
}stu1;//stu1是一個變量
typedef struct Student2
{int a;
}stu2;//stu2是一個結構體類型
使用時可以直接訪問stu1.a
但是stu2則必須先 stu2 s2;
然后 s2.a=10;
3 掌握上面兩條就可以了,不過最后我們探討個沒多大關系的問題
如果在c程序中我們寫:
typedef struct
{int num;int age;
}aaa,bbb,ccc;
結構體
由若干基本數據類型集合組成的一種自定義數據類型,也叫聚合類型
struct 結構體名
{成員列表;
} 變量名列表(可選);
struct student
{char *name; /* 姓名 */int num; /* 學號 */int age; /* 年齡 */char group; /* 所在學習小組 */float score; /* 成績 */
}stu1, stu2;
應用舉例(定義&使用)
struct student
{char *name; /* 姓名 */int num; /* 學號 */int age; /* 年齡 */char group; /* 所在學習小組 */float score; /* 成績 */
};struct student stu3,stu4;
stu3.name = "張三";
stu3.num = 1;
stu3.age = 18;
stu3.group = 'A';
stu3.score = 80.9;
用上typedef
typedef struct
{char *name; /* 姓名 */int num; /* 學號 */int age; /* 年齡 */char group; /* 所在學習小組 */float score; /* 成績 */
}student;student stu3,stu4;
stu3.name = "張三";
stu3.num = 1;
stu3.age = 18;
stu3.group = 'A';
stu3.score = 80.9;
應用舉例(ST源碼,使用類型別名)
typedef struct
{uint32_t Pin ; /* 引腳號 */uint32_t Mode ; /* 工作模式 */uint32_t Pull ; /* 上下拉 */uint32_t Speed ; /* IO速度 */
} GPIO_InitTypeDef;
指針
指針就是內存的地址
指針變量是保存了指針的變量
類型名 * 指針變量名
char * p_str = “This is a test!”;
//*p_str:*是間接尋址運算符,取p_str變量的值,p_str是指針,*p_str就是取指針p_str指向的地址的值,實際就是'T'
//p_str是地址,p_str[0] 和 *p_str 一樣都是 'T'
//&p_str:取p_str變量的地址,取指針的地址
舉例
uint8_t buf[5] = {1, 3, 5, 7, 9};
uint8_t * p_buf = buf;
*p_buf = ?
p_buf[0] = ?
p_buf[1] = ?
p_buf++;
*p_buf = ?
p_buf[0] = ?
uint8_t buf[5] = {1, 3, 5, 7, 9}; //假設此時buf的首地址為0x0002
uint8_t * p_buf = buf; //此時指針指向地址0x0002
//下面就是答案
*p_buf = 1 //此時 p_buf和buf一樣指向地址為0x0002的空間
p_buf[0] = 1
p_buf[1] = 3
p_buf++; //此時指針指向地址0x0003
*p_buf = 3 //此時指針指向地址0x0003
p_buf[0] = 3 //此時指針指向地址0x0003
指針使用的2大最常見問題
1,未分配(申請)內存就用
2,越界使用
//錯誤用法(未分配內存)
char * p_buf;
p_buf[0] = 100;
p_buf[1] = 120;
p_buf[2] = 150;
//錯誤用法(越界使用)
uint8_t buf[5] = {1, 3, 5, 7, 9};
uint8_t * p_buf = buf;
p_buf[5] = 200;
p_buf[6] = 250;
嵌入式單片機 C代碼規范與風格
規范的關鍵點:
- 所有函數/變量名字非特殊情況,一般使用小寫字母;
- 注釋風格使用 doxgen 風格,除屏蔽外,一律使用 /* */ 方式進行注釋;
- TAB 鍵統一使用 4 個空格對齊,不使用默認的方式進行對齊;
- 每兩個函數之間,一般有且只有一個空行;
- 相對獨立的程序塊之間,使用一個空行隔開;
- 全局變量命名一般用 g_開頭,全局指針命名一般用 p_開頭;
- if、 for、 while、 do、 case、 switch、 default 等語句單獨占一行,
一般無論有多少行執行語句,都要用加括號: {}。