• 【51单片机系列】C51基础


    本文内容是关于C51语言的基础内容的,包括C51的数据类型、变量、运算符、函数以及reg52.h文件中的内容,有些与C中相同的内容没有记录在此,比如常量、某些变量、表达式、程序结构、数组等没有涉及。

    C51的数据类型

    C51的数据类型分为基本数据类型和组合数据类型。

    1. C51中的基本数据类型

    • 整型
      • 有符号
        • (signed) int、16位、-2^15 ~ 2^15-1;
        • (signed) short、16位、-2^15 ~ 2^15-1;
        • (signed) long、16位、-2^31 ~ 2^31-1;
      • 无符号
        • unsigned int、16位、0 ~ 2^16-1;
        • unsigned short int、16位、0 ~ 2^16-1;
        • unsigned long int、32位、0 ~ 2^32-1;
    • 实型
      • 有符号
        • float、32位、3.4e-38 ~ 3.4e38;
        • double、64位、1.7e-308 ~ 1.7e308;
          字符型
        • 有符号
          • char、8位、-128 ~ 127;
        • 无符号
          • unsigned char、8位、0 ~ 255;

    2. 指针类型

    指针存放的是指向另一个数据的地址,C51中指针长度一般为 1 ~ 3个字节。

    3. 特殊功能寄存器类型

    该类型是C51扩充的数据类型,用于访问51单片机中的特殊功能寄存器数据。

    分为sfrsfr16两种类型。C51中对特殊功能寄存器的访问必须先用sfr或sfr16进行声明。

    • sfr为字节型特殊功能寄存器类型,占一个字节,可以访问51内部的所有特殊功能寄存器;
    • sfr16为双字节型特殊功能寄存器,占两个字节,可以访问51内部所有两个字节的特殊功能寄存器。

    4. 位类型

    该类型也是C51扩充的数据类型,用于访问51单片机中的可寻址的位单元。

    C51支持两种位类型:bitsbit类型,在内存中都只占一个二进制位,值可以是1或0.

    • bit定义的位变量在C51编译器编译时,在不同的时候地址是可以变化的;
    • sbit定义的位变量必须与51单片机的一个可以寻址位单元或可位寻址的字节单元中的某一位联系在一起,编译时对应的位地址不可变;

    C51允许任何标准数据类型的隐式转换,优先级顺序为:
    bit → char → int → long → float → signed → unsigned

    还可以使用圆括号()进行强制转换。

    C51的变量

    C51变量定义的格式如下:

    [存储种类] 数据类型说明符 [存储器类型] 变量名1 [= 初值], 变量名2[=初值],...
    
    • 1

    1. 存储种类

    存储种类指的是变量在程序执行过程中的作用范围,C51变量的存储种类有四种,分别是自动(auto)、外部(extern)、静态(static)、寄存器(register)。

    • auto定义的变量称为自动变量,作用范围在定义它的函数体或复合语句内部,当定义它的函数体或复合语句执行时,C51才为该变量分配内存空间,结束时占用的内存空间释放。自动变量一般分配在内存的堆栈空间中。定义变量时,如果省略存储种类,该变量默认为自动变量。

    • extern定义的变量称为外部变量。在一个函数体内,要使用一个已在该函数体外或别的程序中定义过的变量时,该变量在该函数体内要用extern说明,外部变量被定义后分配固定的内存空间,在程序整个执行时间内都有效,直到程序结束释放。

    • static定义的变量称为静态变量,分为内部静态变量和外部静态变量。
      内部静态变量定义在函数体的内部,在对应的函数体内有效,一直存在,但在函数体外是不可见的,这样不仅使变量在定义它的函数体外被保护,还可以实现当离开函数时值不被改变。
      外部静态变量定义在函数外部,它在程序中一直存在,但在定义的范围之外不可见,比如在多文件或多模块处理中,外部静态变量只在本文件内部或本模块内部有效。

    • register定义的变量称为寄存器变量,它定义的变量存放在CPU内部的寄存器中,处理速度快,但数目少。C51编译器编译时能够自动识别程序中使用频率最高的变量,并自动将其作为寄存器变量,可以无需专门声明。

    没有特殊要求定义的一般是auto自动变量;
    如果每次调用函数时需要记录某个变量的值,比如记录该函数调用了多少次可以在函数体内使用static修饰位内部静态变量;
    如果在某个文件中的所有函数都需要用到某个变量,但其它文件不需要,就可以在文件中使用static修饰位外部静态变量;
    如果要在函数体内使用外部定义的变量,要用extern修饰;

    2. 存储器类型

    存储器类型用于指明变量所处的单片机的存储器区域情况。存储器类型与存储种类完全不同。
    C51编译器能够识别的存储器类型有以下几种,如果省略存储器类型,默认为存储器类型

    存储器类型描述
    data直接寻址的片内RAM低128B,访问速度快
    bdata片内RAM的可位寻址区(20H ~ 2FH),允许字节和位混合访问
    idata间接寻址访问的片内RAM,允许访问全部片内RAM
    pdata用Ri间接访问的片外RAM的低256B
    xdata用DPTR间接访问的片外RAM,允许访问全部64k片外RAM
    code程序存储器ROM 64k空间

    3. 特殊功能寄存器变量

    51系列单片机片内有许多特殊功能寄存器,通过这些特殊功能寄存器可以控制51系列单片机的定时器、计数器、串口、I/O及其它功能部件,每一个特殊功能寄存器在片内RAM中都对应一个字节单元或两个字节单元。reg52.h定义了一些常用的特殊功能寄存器变量,见本文附录。

    C51允许用户对这些特殊功能寄存器进行访问,访问时需要通过sfrsfr16类型说明符进行定义,定义时还需要指明他们所对应的片内RAM单元的地址,格式如下:

    sfr或sfr16 特殊功能寄存器名 = 地址;
    
    • 1

    特殊功能寄存器一般用大写字母表示,地址一般用直接地址形式。

    示例:

    // 特殊功能寄存器的定义
    sfr PSW = 0xd0;
    sfr SCON = 0x98;
    sfr TMOD = 0x89;
    sfr P1 = 0x90;
    sfr16 DPTR =0x82;
    sfr16 T1 = 0x8A;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4. 位变量

    C51中允许通过位类型(bit或sbit)可以定义位变量。

    • bit位类型用于定义一般的可位处理位变量,格式为:bit 位变量名;,可以加上各种修饰,但存储器类型只能是bdata、data、idata,只能是片内RAM的可位寻址区,严格说只能是bdata。
    • sbit位类型用于定义在可位寻址字节或特殊功能寄存器中的位,定义时需要指明其位地址,可以是位直接地址,也可以是可位寻址变量带位号,也可以是特殊功能寄存器名带位号。格式为sbit 位变量名 = 位地址;,如果位地址是位直接地址,取值范围为0x00 ~ 0xff;如果位地址是可位寻址变量带位号或特殊功能寄存器名带位号,则在它前面需要对可位寻址变量或特殊功能寄存器进行定义。字节地址与位号之间、特殊功能寄存器与位号之间使用^间隔。比如定义51单片机管脚,sbit LED = P1^0;表示有一个LED接到了P1的0端口。

    C51把51单片机中常用的特殊功能寄存器和特殊位进行了定义,放在reg51.hreg52.h头文件中,见本文附录,要使用时,将该头文件包含进来即可。

    C51运算符

    C51运算符同C的运算符一致,支持:

    • 赋值运算符 =
    • 算术运算符 + - * / %
    • 关系运算符 > < >= <= == !=
    • 逻辑运算符 && || !
    • 位运算符 & | ^ ~ << >>
    • 复合赋值运算符 += -= *= /= %= &= |= ^= ~= <<= >>=
    • 逗号运算符 ,
    • 条件运算符 ?:
    • 指针与地址运算符 * &

    1. 位运算符

    C51能对运算对象按位进行操作。位运算按位对变量进行运算,但不改变参与运算的变量的值。
    C51位运算符只能对整数进行操作,不能对浮点数进行操作。
    C51中的位运算符有:

    • & 按位与
    • | 按位或
    • ^ 按位异或
    • ~ 按位取反
    • << 左移
    • >> 右移

    C51中的函数

    C51函数定义的一般格式:

    函数类型 函数名(形参列表) [reentrant][interrupt m][using n]
    
    • 1

    1. reentrant修饰符

    reentrant修饰符用于把函数定义为可重入函数。可重入函数就是允许被递归调用的函数。

    函数的递归调用指当一个函数正被调用尚未返回时,又直接或间接调用函数本身,只有重入函数才允许递归调用。

    使用重入函数时需要注意:

    • reentrant修饰的重入函数被调用时,实参不允许使用bit类型的参数。函数体内也不允许任何关于位变量的操作,更不允许返回bit类型的值。
    • 编译时,系统为重入函数在内部或外部存储器中建立一个模拟堆栈区,称为重入栈。重入函数的局部变量及参数被放在重入栈中,使重入函数可以实现递归调用。
    • 在参数传递上,实际参数可以传递给间接调用的重入函数。无重入属性的间接调用函数不能包含调用参数,但是可以使用定义的全局变量进行参数传递。

    2. interrupt m修饰符

    interrupt m修饰符是C51中的一个重要修饰符,中断函数通过该修饰符进行修饰。

    当函数定义时使用了interrupt m修饰符,系统编译时把对应函数转换为中断函数,自动加上程序头段和尾段,并按51系统中断的处理方式自动把它安排在程序存储器中的相应位置。

    该修饰符中,m的取值为0 ~ 31,对应的中断情况为:

    • 0 外部中断0
    • 1 定时器/计数器T0
    • 2 外部中断1
    • 3 定时/计数器T1
    • 4 串行口中断
    • 5 定时器/计数器T2
    • 其它值预留

    附录

    reg52.h文件中定义的特殊寄存器变量及位变量如下:

    // 特殊功能寄存器
    sfr P0 = 0x80;
    sfr P1 = 0x90;
    sfr P2 = 0xA0;
    sfr P3 = 0xB0;  // 四个IO口
    sfr PSW = 0xD0;
    sfr ACC = 0xE0;
    sfr B = 0xF0;
    sfr SP = 0x81;
    sfr DPL = 0x82;
    sfr DPH = 0x83;
    sfr PCON = 0x87;
    sfr TCON = 0x88;
    sfr TMOD = 0x89;
    sfr TL0 = 0x8A;
    sfr TL1 = 0x8B;
    sfr TH0 = 0x8C;
    sfr TH1 = 0x8D;
    sfr IE = 0xA8;
    sfr IP = 0xB8;
    sfr SCON = 0x98;
    sfr SBUF = 0x99;
    
    // 8052 额外增加的寄存器变量
    sfr T2CON = 0xC8;
    sfr RCAP2L = 0xCA;
    sfr RCAP2H = 0xCB;
    sfr TL2 = 0xCC;
    sfr TH2 = 0xCD;
    
    // 位变量
    
    // PSW的位变量
    sbit CY = PSW^7;  // 即 0xD0的bit7位
    sbit AC = PSW^6;
    sbit F0 = PSW^5;
    sbit RS1 = PSW^4;
    sbit RS0 = PSW^3;
    sbit OV = PSW^2;
    sbit P = PSW^0;  // 仅8052支持
    
    // TCON寄存器的位变量
    sbit TF1 = TCON^7;
    sbit TR1 = TCON^6;
    sbit TF0 = TCON^5;
    sbit TR0 = TCON^4;
    sbit IE1 = TCON^3;
    sbit IT1 = TCON^2;
    sbit IE0 = TCON^1;
    sbit IT0 = TCON^0;
    
    // IE寄存器的位变量
    sbit EA = IE^7;
    sbit ET2 = IE^5;  // 8052 ONLY
    sbit ES = IE^4;
    sbit ET1 = IE^3;
    sbit EX1 = IE^2;
    sbit ET0 = IE^1;
    sbit EX0 = IE^0;
    
    // IP寄存器的位变量
    sbit PT2 = IP^5;
    sbit PS = IP^4;
    sbit PT1 = IP^3;
    sbit PX1 = IP^2;
    sbit PT0 = IP^1;
    sbit PX1 = IP^0;
    
    // P3口的位变量
    sbit RD = P3^7;
    sbit WR = P3^6;
    sbit T1 = P3^5;
    sbit T0 = P3^4;
    sbit INT1 = P3^3;
    sbit INT0 = P3^2;
    sbit TXD = P3^1;
    sbit RXD = P3^0;
    
    // SCON寄存器的位变量
    sbit SM0 = SCON^7;
    sbit SM1 = SCON^6;
    sbit SM2 = SCON^5;
    sbit REN = SCON^4;
    sbit TB8 = SCON^3;
    sbit RB8 = SCON^2;
    sbit TI = SCON^1;
    sbit RI = SCON^0;
    
    // P1口的位变量
    sbit T2EX = P1^1;  // 8052 ONLY
    sbit T2 = P1^1;  // 8052 ONLY
    
    // T2CON寄存器的位变量,8052 ONLY
    sbit TF2 = T2CON^7;
    sbit EXF2 = T2CON^6;
    sbit RCLK = T2CON^5;
    sbit TCLK = T2CON^4;
    sbit EXEN2 = T2CON^3;
    sbit TR2 = T2CON^2;
    sbit C_T2 = T2CON^1;
    sbit CP_RL2 = T2CON^0;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
  • 相关阅读:
    <stl系列>,vector深度剖析,掌握stl容器从这篇文章开始
    【.NET8】访问私有成员新姿势UnsafeAccessor(下)
    软件测开记录(二)
    Python模拟试卷2023(1)
    【Vue 2】Props
    有氧运动与无氧运动的区别
    【C++】一些C++11特性
    【软件】智慧树/知到网课小助手
    linux-进程(2)
    C#拾遗补阙【01】:字符串
  • 原文地址:https://blog.csdn.net/sinat_41752325/article/details/134465712