在 stm32 中 volatile unsigned signed 分别有什么作用,分别在什么场景下使用?

发布于:2025-05-22 ⋅ 阅读:(13) ⋅ 点赞:(0)

在STM32开发中,

plaintext

复制

volatile

plaintext

复制

unsigned

plaintext

复制

signed

是三个关键的关键字,它们的用途和场景如下:


1.

plaintext

复制

volatile

关键字

作用
  • 禁止编译器优化:告诉编译器该变量的值可能随时被外部因素(如硬件、中断、多线程等)改变,要求每次访问变量时都直接从内存中读取,而不是使用寄存器中的缓存值。
  • 保证内存可见性:确保变量的读写操作直接作用于内存,避免因编译器优化导致时序错误。
使用场景
  • 硬件寄存器操作
    STM32的寄存器(如

    plaintext

    复制

    GPIOx->ODR

    plaintext

    复制

    TIMx->CNT

    )必须用

    plaintext

    复制

    volatile

    修饰,因为它们的值由硬件直接修改。
     

    c

    复制

    volatile uint32_t *pReg = (volatile uint32_t*)0x40020000; // 硬件寄存器地址

  • 中断服务程序(ISR)中的共享变量
    如果变量在主循环和ISR中被共同修改,必须用

    plaintext

    复制

    volatile

    修饰,确保双方看到的变量值一致。
     

    c

    复制

    volatile uint8_t flag = 0; // 在中断中修改,在主循环中读取

  • 多线程/RTOS中的共享数据
    在实时操作系统(如FreeRTOS)中,任务间共享的变量需要

    plaintext

    复制

    volatile

    修饰(通常还需配合互斥锁)。
注意事项
  • 过度使用

    plaintext

    复制

    volatile

    可能导致性能下降(频繁内存访问)。
  • 不能替代原子操作或多线程同步机制(如互斥锁)。

2.

plaintext

复制

unsigned

plaintext

复制

signed

关键字

作用
  • 指定整型的符号性
    • plaintext

      复制

      unsigned

      :无符号整数(范围:

      plaintext

      复制

      0

      plaintext

      复制

      2^n - 1

      )。
    • plaintext

      复制

      signed

      :有符号整数(范围:

      plaintext

      复制

      -2^(n-1)

      plaintext

      复制

      2^(n-1) - 1

      )。

      plaintext

      复制

      n

      为类型位数,如

      plaintext

      复制

      uint32_t

      是32位)
使用场景
  • plaintext

    复制

    unsigned

    的典型场景
    • 硬件相关数据
      ADC采样值(如

      plaintext

      复制

      uint16_t adc_value

      )、定时器计数值(

      plaintext

      复制

      TIMx->CNT

      )等不会为负的值。
    • 位操作
      无符号数右移时高位补0,适合位掩码操作(如

      plaintext

      复制

      GPIO引脚控制

      )。
    • 避免溢出
      当数值可能超过有符号类型的正最大值时(如32位计数器的

      plaintext

      复制

      0xFFFFFFFF

      )。
  • plaintext

    复制

    signed

    的典型场景
    • 需要负值的场景
      如温度传感器读数(

      plaintext

      复制

      int16_t temperature

      )、电机速度方向(正/负表示方向)。
    • 数学运算
      涉及负数的计算(如滤波算法、PID控制)。
注意事项
  • 默认情况下,

    plaintext

    复制

    int

    plaintext

    复制

    signed

    ,但

    plaintext

    复制

    char

    的符号性取决于编译器(建议显式声明)。
  • 混合使用

    plaintext

    复制

    unsigned

    plaintext

    复制

    signed

    可能导致意外的类型提升和逻辑错误:
     

    c

    复制

    uint32_t a = 5; int32_t b = -10; if (a > b) { ... } // 这里b会被隐式转换为无符号数,导致比较结果错误!


3. 在STM32中的典型代码示例

硬件寄存器操作(必须用

plaintext

复制

volatile

):


c

复制

// 定义一个GPIO输出寄存器(volatile + unsigned) volatile uint32_t *GPIOA_ODR = (volatile uint32_t*)0x40020014; *GPIOA_ODR |= 0x00000001; // 设置PA0引脚为高电平

中断服务程序中的共享变量:

c

复制

volatile uint8_t data_ready = 0; // 主循环和UART中断共享 // 中断服务函数 void USART1_IRQHandler(void) { data_ready = 1; // 数据到达时置位标志 } // 主循环中等待标志 while (1) { if (data_ready) { process_data(); data_ready = 0; } }

使用无符号类型处理ADC数据:

c

复制

uint16_t adc_value = 0; // ADC采样值(0-4095,无符号) adc_value = HAL_ADC_GetValue(&hadc1); // 读取ADC值

使用有符号类型处理温度数据:

c

复制

int16_t temperature = -25; // 温度可能为负 if (temperature < 0) { heating_enable(); }


总结表

关键字 作用 典型场景

plaintext

复制

volatile

防止编译器优化,保证内存可见性 硬件寄存器、中断共享变量、多线程

plaintext

复制

unsigned

无符号整数(0到最大值) ADC采样、定时器计数、位操作

plaintext

复制

signed

有符号整数(含负数) 温度、速度方向、需要负值的计算

合理使用这些关键字可以避免嵌入式开发中常见的硬件操作错误、数据溢出和逻辑问题。


网站公告

今日签到

点亮在社区的每一天
去签到