STM32 中C 预处理指令:
#define
-
#define BOOTLOADER_ADDRESS 0x08000000
- 定义常量
- 例如:#define BOOTLOADER_ADDRESS 0x08000000,在程序中使用BOOTLOADER_ADDRESS就相当于使用0x08000000。用于数学计算或者配置参数中,比如设置定时器的分频系数等。
#define TIM_PRESCALER_VALUE 7199
预处理指令定义了定时器的分频系数为7199
- 例如:#define BOOTLOADER_ADDRESS 0x08000000,在程序中使用BOOTLOADER_ADDRESS就相当于使用0x08000000。用于数学计算或者配置参数中,比如设置定时器的分频系数等。
- 定义宏
- 可以定义带参数的宏来实现简单的函数功能。例如:
#define getFlashUint8Value(address) (*((unsigned char *)(address)))
,getFlashUint8Value(0x08007000)
就会被替换为(*((unsigned char *)(0x08007000)))
。在 STM32 编程中,可能用于对寄存器操作进行简单的封装,比如#define LED1_1 GPIOA->BSRR = GPIO_Pin_8
,用于设置某个寄存器的指定位。
- 可以定义带参数的宏来实现简单的函数功能。例如:
#include
- 包含头文件
- 例如:
#include "stm32f10x.h"
,这是 STM32 编程中常见的,用于包含特定芯片型号的标准外设库头文件,其中定义了芯片的寄存器映射、外设结构体等。 - 也可以使用
<>
包含标准库头文件,如#include <stdio.h>
用于在程序中使用标准输入输出函数。
- 例如:
#if、#ifdef、#ifndef、#else、#endif
- 条件编译
#if
用于根据条件判断是否编译某段代码。例如:#if defined(STM32F103) &&!defined(DEBUG)
,只有当定义了STM32F103
且没有定义DEBUG
时,才会编译后续的代码块。#ifdef
和#ifndef
分别用于判断某个标识符是否已经定义。例如,在不同的开发阶段可能需要不同的配置,#ifdef DEBUG
可以用来在调试阶段执行一些额外的调试输出代码,而在正式发布版本中不编译这些代码。
#pragma
在 STM32 编程中,#pragma
指令有以下一些常见的用法:
1. 控制结构体的字节对齐方式
- 作用
- 在与硬件寄存器交互或者进行数据序列化时,需要精确控制结构体的内存布局,确保数据在内存中的存储方式与硬件的预期相符。
- 示例代码
// 设置结构体成员按 1 字节对齐
#pragma pack(1)
typedef struct {
uint8_t field1;
uint16_t field2;
uint32_t field3;
} MyStruct;
// 恢复默认对齐方式
#pragma pack()
在上述代码中,#pragma pack(1)
强制结构体 MyStruct
的成员按 1 字节对齐。这样,field1
、field2
和 field3
在内存中是连续存储的,没有额外的填充字节。#pragma pack()
用于恢复编译器默认的字节对齐方式。
2. 控制代码的优化选项
- 作用
- 可以根据程序的具体需求,通过
#pragma
指令来调整编译器的优化级别,以平衡代码的执行效率和可调试性。
- 可以根据程序的具体需求,通过
- 示例代码
// 禁用当前函数的优化
#pragma GCC optimize ("O0")
void myFunction() {
// 函数体
}
// 恢复默认优化级别
#pragma GCC optimize ("O2")
在这个例子中,#pragma GCC optimize ("O0")
禁用了对 myFunction
函数的优化,这在调试时可能很有用,因为优化后的代码可能会导致调试信息不准确。#pragma GCC optimize ("O2")
恢复了编译器的默认优化级别(假设默认是 - O2)。
3. 控制中断函数的编译
- 作用
- 在 STM32 中,中断服务函数需要特殊的编译处理,以确保它们能够正确响应中断并遵循特定的编程模型。
- 示例代码
// 指定函数为中断服务函数
#pragma vector = TIM2_IRQn
__interrupt void TIM2_IRQHandler(void) {
// 中断处理代码
}
这里,#pragma vector = TIM2_IRQn
告诉编译器该函数是定时器 2 中断(TIM2_IRQn)的服务函数。__interrupt
是特定编译器用于标识中断函数的关键字。不同的编译器可能有不同的方式来实现这一点。