目录
1. stdint.h
简介
stdint.h
是 C99 标准引入的一个头文件,提供了固定宽度的整数类型,提高了代码的可移植性和可读性。常见类型包括:
注意:使用前要开启C99模式哦,以keil 5为例说明 如下图:
2. 位操作
位操作是直接对二进制位进行操作的技术,在嵌入式系统中常用于寄存器操作、标志位管理、节约存储空间等。
- 基本操作:
- 与(&):将某位清0
- 或(|):将某位置1
- 异或(^):将某位取反
- 取反(~):按位取反
- 左移(<<)、右移(>>):移位操作,左移相当于乘以2,右移相当于除以2(无符号数)
以下为示例代码
GPIOA->ODR |= (1<<5); // 将GPIOA的输出数据寄存器第5位置1(假设控制LED的引脚)
GPIOA->ODR &= ~(1<<5); // 将第5位清0
GPIOA->ODR ^= (1<<5); // 将第5位翻转
实用技巧:
-
设置某一位:
x |= (1 << n);
-
清除某一位:
x &= ~(1 << n);
-
翻转某一位:
x ^= (1 << n);
3. 宏定义
宏使用 #define
定义,常用于常量定义、条件编译、简化代码等。
示例:
#define PI 3.14159
#define MAX(a, b) ((a) > (b) ? (a) : (b)) // 注意:带参数的宏,参数要用括号括起来
- 注意事项:
- 宏只是文本替换,不进行类型检查。
- 在定义函数式宏时,要注意参数可能产生的副作用(比如多次计算),以及括号的使用(避免运算符优先级问题)。
4. 条件编译
条件编译可以根据宏控制编译的内容,适用于平台区分、调试开关等。
常见指令:
#define DEBUG 1
#if DEBUG
// 调试代码
#endif
另一个常见用途:防止头文件重复包含(在每个头文件的开头和结尾):
#ifndef __MYHEADER_H__
#define __MYHEADER_H__
// 头文件内容
#endif
5. extern
声明
extern
用于声明在其他源文件中定义的变量或函数。
-
声明但不定义变量(避免重复定义):
示例:
// file1.c
int counter = 0;
// file2.c
extern int counter; // 告诉编译器:这个变量在别处定义
6. 类型别名 typedef
typedef
用于为已有类型创建新的类型名,提高可读性和移植性。
示例:
//第一种情况
typedef unsigned char uint8_t; // 定义uint8_t为无符号8位整数
//第二种情况:
typedef struct {
int x;
int y;
} Point; // 定义Point为结构体类型
- 在STM32库中大量使用
typedef
来简化结构体类型,如GPIO_TypeDef
。
7. 结构体
结构体是用户自定义的数据类型,用于组织不同类型的数据。
struct person {
char name[20];
int age;
float height;
};
struct person p1; // C语言中需要写struct关键字
// 或者使用typedef来避免写struct:
typedef struct {
char name[20];
int age;
float height;
} Person;
Person p2;
8. 指针
指针是 C 的核心特性,指向某种类型数据的内存地址。
以下是指针使用的2个最常见问题:
- 基本操作:
- 定义:
int *p;
- 取地址:
int a; p = &a;
- 解引用:
*p = 10;
(将10赋值给a)
- 定义:
- 在嵌入式开发中,指针常用于直接访问硬件地址(如寄存器映射)、传递大结构体(避免复制)等。
- 示例:通过指针访问GPIO寄存器(在STM32中,外设寄存器被映射到固定地址)
GPIO_TypeDef *pGPIOA = (GPIO_TypeDef*)0x40020000; // 假设0x40020000是GPIOA的基地址
pGPIOA->MODER = 0x55; // 通过指针设置寄存器
9. 代码规范
良好的代码规范提升可读性、可维护性、团队协作效率。
要点:
1. 命名规范:变量、函数、宏等命名要有意义。例如:变量名用下划线分隔(如button_state),宏全大写(如MAX_VALUE),函数名驼峰或下划线等。
2.缩进和空格:统一使用空格或制表符(建议空格),缩进一般为4个空格。
3.注释:对函数、复杂逻辑进行注释,但要避免过多无意义注释。
3.函数长度:尽量短小,一个函数完成一个功能。
4.减少全局变量的使用。
对于嵌入式开发,应特别注意:
1.对寄存器的操作多采用宏定义或结构体指针,使代码清晰。
2.关键操作(如中断服务函数)应加上必要的注释。
实践建议:
1.结合STM32库或示例代码,观察这些知识点的应用,如
stdint.h
的使用、位操作(寄存器配置)、结构体(外设寄存器结构)、宏定义(寄存器地址映射)等。2.尝试编写简单的STM32程序,例如通过位操作控制LED,用结构体指针访问外设寄存器。
希望这些讲解对你有帮助!如果有问题,可以针对某个点进一步探讨。