volatile关键字

在单片机开发中,volatile是一个关键字,用于告诉编译器该变量的值可能在程序的执行过程中被意外地改变,因此编译器不应进行优化操作,以确保程序的正确性。

当一个变量被声明为volatile时,编译器会在每次使用该变量时都重新读取它的值,而不是使用之前缓存的值。这是因为该变量的值可能会由于硬件中断、外部设备或其他并行代码的操作而发生变化,而这些变化编译器无法预测到。

查看STC8H.H文件,可以看到一个典型的寄存器宏定义如下:

  1. #define P2IM0 (*(unsigned char volatile xdata *)0xfd22)

这里就用到了volatile关键字。

volatile关键字的作用主要有两个方面:

  1. 防止编译器优化:编译器在进行优化时,可能会假设一个变量的值在其它代码段没有被修改的情况下保持不变。然而,在并行操作、中断处理等情况下,这种假设是不正确的。通过使用volatile关键字,可以告诉编译器不要进行这种优化,确保每次使用变量时都从内存中读取最新的值。
  2. 与外部设备的交互:在单片机开发中,我们经常需要与外部设备进行交互,例如使用寄存器与外设进行通信。由于外设的状态可能会在任何时候发生变化,我们需要使用volatile关键字来声明与外设交互的寄存器,以确保读取和写入操作的正确性。

下面是一个示例,展示了如何在C语言中使用volatile关键字:

  1. volatile int flag = 0; // 声明一个volatile变量
  2. int main() {
  3. while (1) {
  4. if (flag == 1) { // 检查变量值
  5. // 执行相应操作
  6. flag = 0; // 重置变量值
  7. }
  8. // 其他代码
  9. }
  10. }

在上面的示例中,变量flag被声明为volatile int,因此在每次使用它时,编译器将重新读取其值,而不是使用之前的缓存值。这确保了在其他代码或中断中修改flag的值后,主循环能够及时检测到变化并执行相应操作。

sfrsbit关键字

在单片机开发中,sfrsbit和是特定于某些编译器或单片机体系结构的关键字,用于定义和访问特殊功能寄存器(Special Function Registers,SFR)、位(Bit),它们作用如下:

  1. sfr(Special Function Register):sfr用于定义和访问特殊功能寄存器。特殊功能寄存器是单片机中的一些特殊寄存器,用于控制和配置硬件功能,如控制器、定时器、串口等。sfr关键字允许程序员为这些特殊功能寄存器分配易于使用的名称,并提供对这些寄存器的访问和操作。

以下是一个使用sfr定义和访问特殊功能寄存器的示例(基于Keil C51编译器):

  1. sfr P1 = 0x90; // 定义一个特殊功能寄存器 P1
  2. sfr TCON = 0x88; // 定义一个特殊功能寄存器 TCON
  3. void main() {
  4. P1 = 0xFF; // 对 P1 进行写操作
  5. if (TCON & 0x01) {
  6. // 如果 TCON 的最低位为 1,则执行某些操作
  7. }
  8. }


在上面的示例中,通过使用sfr关键字,我们为特殊功能寄存器P1和TCON分配了易于理解的名称,并能够对它们进行读写操作。

  1. sbit(Special Bit):sbit用于定义和访问特殊功能寄存器中的位(bit)。单片机中的特殊功能寄存器通常包含多个位,每个位都用于控制或表示特定的功能或状态。sbit关键字允许程序员为这些位分配易于使用的名称,并提供对它们的访问和操作。

以下是一个使用sbit定义和访问特殊功能寄存器位的示例:

  1. sfr P1 = 0x90; // 定义一个特殊功能寄存器 P1
  2. sbit LED = P1^0; // 定义一个位 LED,位于 P1 的第 0 位
  3. void main() {
  4. LED = 1; // 对 LED 进行写操作,置为高电平
  5. if (LED == 0) {
  6. // 如果 LED 为低电平,则执行某些操作
  7. }
  8. }


在上面的示例中,我们使用sbit关键字将P1寄存器中的第0位定义为LED,并可以对LED进行读写操作。

xdata, idata, code等存储类型

51单片机采用哈佛微控制器架构,keil的C51中定义了xdata、idata、xdata、code几种域修饰符。内存空间编址有重叠。这些修饰符决定了变量访问方式。使用这些关键字可以帮助程序员更好地管理内存空间,从而提高程序的效率。举个例子,假设我们正在编写一个实时控制系统,在这个系统中需要频繁读写一些变量,如传感器数据、控制指令等。我们可以使用xdata或code来存储这些变量,以便快速读写和响应。

STC8H8K64U的存储器分配图
STC8H 系列单片机内部的数据存储器在物理和逻辑上都分为两个地址空间

  • 内部 RAM(256 字节)
  • 内部扩展 RAM

其中内部 RAM 的高 128 字节的数据存储器与特殊功能寄存器(SFRs)地址重叠,实际使用时通过不同的寻址方式加以区分。

内部 RAM (256 字节)

内部 RAM 共 256 字节,可分为 2 个部分:低 128 字节 RAM 和高 128 字节 RAM。

  • 低 128 字节 RAM(data)的数据存储器与传统 8051 兼容,既可直接寻址也可间接寻址。
  • 高 128 字节 RAM(idata)在 8052 中扩展了高 128 字节 RAM

    特殊功能寄存器区SFRs

    idata与特殊功能寄存器区SFRs共用相同的逻辑地址,都使用 80H~FFH,但在物理上是分别独立的,使用时通过不同的寻址方式加以区分。高 128 字节 RAM 只可间接寻址,特殊功能寄存器区只可直接寻址。

    内部扩展 RAM (8K)

    在 C 语言中,可使用 xdata 声明存储类型为内部扩展RAM。例如:unsigned char xdata i;
    pdata 即为 xdata 的低 256 字节。

    外部扩展RAM (64K)

    STC8H 系列封装管脚数为 40 及其以上的单片机具有扩展 64KB 外部数据存储器的能力。

以下是这几种存储类型的总结表格:

存储类型 存储内容 存储位置 读写速度 存储空间
data 固定指前面0x00-0x7F的128个RAM(默认) 内部RAM 快速 较小
idata 固定指前面0x00-0xFF的256个RAM
其中前128和data的128完全相同
内部RAM 快速 较小
bdata 位数据(只有0和1的数据)
访问位寻址的片内存储器
内部RAM
16字节0x20~0x2f
快速 较小
xdata 频繁读写的变量或数据8K+64K 内部&外部扩展RAM 快速 较大
pdata 指针数据 扩展RAM的低256个字节 快速 较小
code 程序代码,只读64K 内部ROM 较慢 较大

需要注意的是,具体的存储位置、读写速度和存储空间可能因不同的芯片型号、厂商和配置而有所不同。

数学公式神器

手绘数学公式:http://webdemo.myscript.com/views/math/index.html#
识别公式截图:https://mathpix.com/