核心内容摘要
linux基本命令 -7 Shell alias,history命令
define关键字
定义常量示例硬件寄存器地址// 定义GPIO端口基地址define GPIOA_BASE_ADDRESS 0x40020000Udefine GPIOB_BASE_ADDRESS 0x40020400U// 定义寄存器偏移量define GPIO_MODER_OFFSET 0x00Udefine GPIO_OTYPER_OFFSET 0x04U// 使用示例uint32_t gpioa_moder (uint32_t )(GPIOA_BASE_ADDRESS GPIO_MODER_OFFSET);解释在嵌入式系统中处理器外设的寄存器有固定的内存映射地址。
使用define定义这些地址
提高代码可读性 - GPIOA_BASE_ADDRESS比 0x40020000U更有意义
方便维护 - 如果地址改变只需修改一处
STM32等MCU的寄存器地址都是固定的这种定义方式非常常见
定义配置参数示例系统配置// 时钟配置define SYSTEM_CLOCK_FREQ 16000000UL // 16MHzdefine AHB_PRESCALER 1Udefine APB1_PRESCALER 2U// 通信参数define UART_BAUD_RATE 115200Udefine SPI_CLOCK_DIV 16U// 超时设置define WATCHDOG_TIMEOUT_MS 1000Udefine I2C_TIMEOUT_TICKS 10000U解释嵌入式系统需要各种配置参数
时钟频率配置 - 确定系统运行速度
通信参数 - 确保设备间正常通信
超时设置 - 防止系统死锁
使用UL后缀确保无符号长整型避免溢出
定义位掩码和位操作示例寄存器位操作// 状态寄存器位定义define STATUS_REG_ERROR_BIT (1U
define STATUS_REG_BUSY_BIT (1U
define STATUS_REG_DATA_READY (1U
// GPIO引脚位掩码define PIN_0_MASK 0x0001Udefine PIN_5_MASK 0x0020Udefine ALL_PINS_MASK 0xFFFFU// 使用示例uint16_t status_reg read_status_register();if (status_reg STATUS_REG_DATA_READY) {// 数据就绪进行处理}解释嵌入式编程中经常需要位操作
位掩码用于选择/操作特定位
(1U n) 创建第n位为1的掩码
提高代码可读性和可维护性
避免魔法数字magic numbers
带参数的宏函数式宏示例硬件操作封装// 读取寄存器位define READ_BIT(REG, BIT) ((REG) (BIT))// 设置寄存器位define SET_BIT(REG, BIT) ((REG) | (BIT))// 清除寄存器位define CLEAR_BIT(REG, BIT) ((REG) ~(BIT))// 切换寄存器位define TOGGLE_BIT(REG, BIT) ((REG) ^ (BIT))// 使用示例volatile uint32_t gpioa_odr (uint32_t )0x40020014U;SET_BIT(gpioa_odr, PIN_5_MASK); // 设置GPIOA第5引脚为高电平解释
函数式宏比函数调用更高效无函数调用开销
常用于频繁调用的简单操作
注意参数必须用括号括起避免运算符优先级问题
适用于对性能要求高的嵌入式场景详细解析每个宏1#define READ_BIT(REG, BIT) ((REG) (BIT))原理分析是按位与操作符REG BIT的结果如果BIT位为1返回非零值具体值取决于REG对应位的值如果BIT位为0返回0示例READ_BIT(0b10101100, 0b
0b000001002SET_BIT(REG, BIT)- 设置位为1#define SET_BIT(REG, BIT) ((REG) | (BIT))原理分析|是按位或赋值操作符REG REG | BIT将BIT指定的位设为1其他位不变示例0b10101100 | 0b000001000b101011003CLEAR_BIT(REG, BIT)- 清除位为0#define CLEAR_BIT(REG, BIT) ((REG) ~(BIT))原理分析~是按位取反操作符是按位与赋值操作符~BIT将BIT位变为0其他位变为1REG ~BIT将BIT位清零其他位不变示例0b10101100 ~0b000001000b101010004TOGGLE_BIT(REG, BIT)- 切换位状态#define TOGGLE_BIT(REG, BIT) ((REG) ^ (BIT))原理分析^是按位异或赋值操作符异或特性相同为0不同为1BIT位为1的位会被反转BIT位为0的位保持不变示例0b10101100 ^ 0b000001000b
条件编译示例多平台支持// 目标平台选择define TARGET_STM32F1// define TARGET_STM32F4// define TARGET_AVR// 调试模式控制define DEBUG_MODE 1define RELEASE_MODE 0define CURRENT_MODE DEBUG_MODE// 条件编译ifdef TARGET_STM32F1define SYSTEM_CORE_CLOCK 72000000ULinclude stm32f1xx.helif defined(TARGET_STM32F
define SYSTEM_CORE_CLOCK 168000000ULinclude stm32f4xx.hendifif CURRENT_MODE DEBUG_MODEdefine DEBUG_PRINT(msg) uart_send_string(msg)elsedefine DEBUG_PRINT(msg) // 空宏发布版本不包含调试代码endif解释
支持不同硬件平台
调试/发布版本控制
功能模块选择
减小最终代码大小未选中的代码不编译
字符串化操作符示例调试信息define DEBUG_ASSERT(condition, message) \do { \if (!(condition)) { \debug_log(Assertion failed: condition , message); \while(
; / 停机 / \} \} while(
// 版本信息define FIRMWARE_VERSION
1.
3define LOG_VERSION() debug_log(Firmware: FIRMWARE_VERSION)// 使用示例DEBUG_ASSERT(buffer ! NULL, Buffer pointer is NULL);解释
操作符将宏参数转换为字符串
用于创建有意义的调试信息
可以结合条件编译控制调试输出
便于追踪错误来源
连接操作符示例寄存器访问宏// 寄存器名称生成define REGISTER(port, reg) port_reg// GPIO寄存器定义define GPIOA_MODER REGISTER(GPIOA, MODER)define GPIOA_OTYPER REGISTER(GPIOA, OTYPER)// 外设基地址映射define PERIPH_BASE 0x40000000Udefine APB1PERIPH_BASE (PERIPH_BASE 0x00000000U)define APB2PERIPH_BASE (PERIPH_BASE 0x00010000U)define GPIOA_BASE (APB2PERIPH_BASE 0x0800U)// 使用示例uint32_t moder_value GPIOA_MODER; // 展开为访问GPIOA_MODER寄存器解释
操作符连接两个标记为一个新标记
用于生成一致的命名模式
减少重复代码
在寄存器映射和外设驱动中特别有用
多行宏定义示例复杂操作封装// 初始化GPIO引脚define GPIO_INIT(port, pin, mode, speed) \do { \/ 使能时钟 / \RCC-AHB1ENR | RCC_AHB1ENR_portEN; \/ 配置模式 / \port-MODER ~(0x3U (2 (pin))); \port-MODER | ((mode) (2 (pin))); \/ 配置速度 / \port-OSPEEDR ~(0x3U (2 (pin))); \port-OSPEEDR | ((speed) (2 (pin))); \/ 上拉/下拉 / \port-PUPDR ~(0x3U (2 (pin))); \} while(
// 使用示例GPIO_INIT(GPIOA, 5, GPIO_MODE_OUTPUT_PP, GPIO_SPEED_FREQ_HIGH);解释
do { ... } while(
创建复合语句块
确保宏像单个语句一样工作
可以包含多条语句和局部变量
分号使用更自然
类型定义和大小定义示例可移植类型定义// 固定宽度整数类型define UINT8 unsigned chardefine INT8 signed chardefine UINT16 unsigned shortdefine INT16 signed shortdefine UINT32 unsigned longdefine INT32 signed long// 缓冲区大小定义define TX_BUFFER_SIZE 256define RX_BUFFER_SIZE 256define MAX_PACKET_SIZE 1024// 内存区域定义define FLASH_START 0x08000000Udefine FLASH_SIZE (128 1024U) // 128KBdefine SRAM_START 0x20000000Udefine SRAM_SIZE (20 1024U) // 20KB解释
提高代码可移植性
明确数据大小避免平台差异
便于内存管理和优化
配合硬件规格定义
错误代码定义示例统一错误处理// 错误代码定义define ERROR_NONE 0define ERROR_TIMEOUT 1define ERROR_INVALID_PARAM 2define ERROR_HARDWARE_FAULT 3define ERROR_BUFFER_FULL 4define ERROR_BUFFER_EMPTY 5// 模块特定错误define UART_ERROR_OVERRUN 0x10define UART_ERROR_FRAMING 0x11define SPI_ERROR_MODF 0x20define I2C_ERROR_BERR 0x30// 错误处理宏define CHECK_ERROR(code) \if ((code) ! ERROR_NONE) { \error_handler(code, __FILE__, __LINE__); \}// 使用示例int result spi_transmit(data, length);CHECK_ERROR(result);解释
统一错误代码管理
模块化错误定义
__FILE__ 和 __LINE__ 是预定义宏提供调试信息
便于错误追踪和处理最佳实践和
注意事项
括号使用// 错误示例define SQUARE(x) x x// 如果使用 SQUARE(a
展开为 a1a1// 正确示例define SQUARE(x) ((x) (x))
避免副作用// 危险示例define MAX(a, b) ((a) (b) ? (a) : (b))// MAX(i, j) 会导致i或j被多次递增// 解决方案使用内联函数static inline int max_int(int a, int b) {return (a b) ? a : b;}
命名约定define CONSTANT_VALUE // 全大写下划线分隔define function_like_macro() // 小写类似函数define _INTERNAL_MACRO // 下划线开头表示内部使用
嵌入式特殊考虑// volatile使用define REG_READ(addr) ((volatile uint32_t )(addr))define REG_WRITE(addr, val) ((volatile uint32_t )(addr) (val))// 内存屏障防止编译器重排define MEMORY_BARRIER() __asm__ volatile( ::: memory)// 内联汇编define NOP() __asm__ volatile(nop)define WFI() __asm__ volatile(wfi)
总结在嵌入式系统中define的使用非常广泛且重要。
合理使用宏可以