单片机_第4章 单片机的C51语言

考试月时间,只是简单介绍了知识,一些实验和重点之后应该会标注,实验的步骤已经说明了,在本专栏的“单片机_实操过程”里面

目录

4.1 C51的程序结构

4.1.1 C51语言概述

两种51单片机编程语言:汇编语言和C51语言

创建C51程序

4.1.2 C51的程序结构

4.2 C51的数据结构

4.2.1 C51的变量(根据给出的定义说明变量的四大要素)

前言

定义一个变量的完整格式(变量具有4大要素):〔存储种类〕数据类型〔存储类型〕变量名;

4.2.2 C51的指针

4.3 C51与汇编语言的混合编程

4.4 C51仿真开发环境

4.5 C51应用编程初步

4.5.1 I/O端口的简单应用

1. 基本输入/输出单元与编程

2. LED数码管原理与编程

4.5.2 I/O端口的进阶实践

1. 数码管动态显示原理与编程

2. 行列式键盘原理与编程

本章小结


  • 4.1 C51的程序结构

    • 4.1.1 C51语言概述

      • 两种51单片机编程语言:汇编语言和C51语言

        • 汇编语言
          • 是一种面向机器的编程语言,能直接操作单片机的硬件系统,如存储器、I/O端口、定时/计数器等。
          • 优点:指令效率高、执行速度快,在实时性要求较高的场合有着不可替代的作用。
          • 缺点:汇编语言属于低级编程语言,程序可读性差,移植困难,而且编程时还必须具体组织、分配存储器资源和处理端口数据,因而编程工作量很大。
          • 51单片机操作数的简记符

        • C51语言
          • 是为51单片机设计的一种高级编程语言,属于标准C语言的一个子集。
          • 优点:具有可读性强,易于调试维护,编程工作量小的特点。由于允许直接访问物理地址,能直接对硬件进行操作,可实现汇编语言的部分功能,因而兼有高级和低级语言的特点,适用范围广。目前C51语言已成为51单片机程序开发的主流编程方法。
            • 结构化语言,代码紧凑——效率可与汇编语言媲美(但仍不如)
            • 接近真实语言,程序可读性强——易于调试、维护
            • 库函数丰富,编程工作量小——产品开发周期短
            • 机器级控制能力,功能很强——适合于嵌入式系统开发
            • 与汇编指令无关,易于掌握——在单片机基础上上手快
          • 缺点:执行效率不如汇编语言
          • C51语言所编制的源程序不能直接被计算机识别,必须转换成可执行语言(或称目标代码)后才能执行。
            • 先将高级语言源程序全部转换为目标代码,然后再执行的方式叫做编译型执行方式。
              • C51采用编译型执行方式,产生的目标代码可以脱离C51编程环境独立执行,程序执行速度快,代码效率高。
            • 将源程序边转换,边执行的方式叫做解释型执行方式。
        • C51 VS 标准C语言
          • 相同之处:语法规则、程序结构、编程方法
          • 不同之处:数据结构(第4章)、中断处理(第5章)、端口扩展(第8章)
      • 创建C51程序:

        • “新建工程文件”→“选择单片机”→“编辑源程序”→“添加源程序” →“修改工程配置”→“进行程序编译”→生成可执行文件”。
    • 4.1.2 C51的程序结构

      • C51程序的基本单位是函数,一个C51源程序至少包含一个主函数,也可以是一个主函数和若干个其他函数。
      • 主函数是程序的入口;
      • 主函数中的所有语句执行完毕,则程序结束。
      • 举例:LED闪烁控制功能

        • 程序
          • C51

          • 汇编语言

        • C51程序的基本结构

  • 4.2 C51的数据结构

    • 4.2.1 C51的变量(根据给出的定义说明变量的四大要素)

      • 前言

        • 在C语言编程中,数值可以发生改变的量称为变量。
        • 变量的基本属性是变量名和变量值
        • 在程序中定义变量,C51编译器就会给这个变量分配相应的存储单元,从而将变量名与存储单元的地址“捆绑”在一起,变量值就与存储单元的内容相对应(若存储单元中放置不同的内容,变量就会有不同的值)。
        • 使用变量的过程,就是通过变量名找到相应的内存地址,进而对该存储单元进行数据读取的操作过程。

        • 实际使用变量时要考虑的因素:
          • 如果变量要对应更大的数值就需要将多个连续地址的存储单元串联起来以便增加位数,这就涉及到变量的数据类型问题。
          • 51单片机有片内RAM和片外RAM两种数据存储器,这就涉及到变量的存储类型问题。
          • 变量与存储单元永久“绑定” 会降低存储单元的利用率,临时分配存储单元的动态方案会降低变量使用的方便性,涉及到变量的存储种类问题。
      • 定义一个变量的完整格式(变量具有4大要素):〔存储种类〕数据类型〔存储类型〕变量名;

      • 〔存储种类〕
        • 变量定义时还需考虑变量的“作用域”问题。
        • 为提高变量存储效率,比较科学的做法应该是:
          • ①对于仅有当前使用价值的变量,可以让它用完后“自动”释放占用的存储单元,以便编译器重新进行变量存储空间分配;——auto
          • ②对于具有长期使用价值的变量,可以让它处于“静态”保护下,在程序运行期间都不释放存储单元;——static
          • ③对于需要在多个程序或函数中传递数据的变量,可以让它只在一处进行定义,而在其它程序或函数中声明它的“外部”属性,从而实现该变量的数据共享;——extern
          • ④对于需要频繁改变其值的变量,可让其数值保存在CPU的“寄存器”中,避免反复访问内存,从而获得较高的执行效率。——register
        • 变量的存储类型有4种:
          • 1、自动型(auto)。
            • 具有auto属性的变量称为自动型变量。自动型变量的作用域是在定义该变量的函数体或语句组内。当函数调用结束或语句组执行完毕时,自动型变量所占用的存储单元就被释放。由于存储单元中的值是随机的,因此自动型变量在赋初值前的值也是随机的。自动型是“存储种类”的默认选项,如果变量定义时“存储种类”项省略,则变量被默认为是自动型的。
          • 2、静态型(static)。
            • 具有static属性的变量称为静态型变量。静态型变量的作用域是定义它的函数体、程序文件或语句组内。静态型变量具有变量的隐藏性、存储持久性和默认0初值3个特点。
            • 如果希望变量在离开作用域后仍能保持它已经获得的数值不丟失,或者希望变量无法被作用域外的其它同名变量所使用,或者希望变量虽经定义但缺省赋初值时能默认为0,就可在变量定义时用static进行声明。
          • 3、外部型(extern)。
            • 具有extern属性的变量称为外部型变量。如果变量的定义与使用不在同一个作用域内,则用extern声明后就能将原作用域扩展到声明所在的位置,从而将变量值带到新的作用域内。extern的这一扩展性与static的隐藏性恰好相反。变量做extern声明后可分配固定的存储单元,并在程序的整个执行期内始终有效。
          • 4、寄存器型(register)。
            • 具有register属性的变量称为寄存器型变量。如果变量在使用中需要频繁地与内存进行数据交换,可以通过register定义将变量的存储单元指定为寄存器。但是随着编译器技术不断优化,现在编译器已能将数据交换过于频繁的变量自动放入寄存器中,因而进行register声明的必要性已不大了。
        • 注意
          • auto,static和register关键词需要在变量定义的同时进行使用,不能单独使用
            • 因此下面的用法是不对的:
              • int a; (先定义整型变量a)
              • static a; (企图再对a声明为静态变量)
            • 这样做会被编译器认为是“重新定义”。正确的用法应该是:static int a;
          • 但是,extern却是可以单独进行声明的,它可对已定义过的变量进行作用域扩展,例如:
            • int b;(在另一程序文件或函数中定义了变量b)
            • extern b;(将变量b的作用域扩展至此,允许省略变量b的int类型)
          • 变量的定义和变量的声明问题
            • 实际应用中这两者常常被不加区别的随意使用,这是不严格的,因为两者间是有区别的。
            • 变量定义既涉及到变量特性的约定,也涉及到存储单元的分配问题。
            • 变量声明则是仅指出变量的特性,不涉及存储单元的分配问题。
            • 例如上面介绍过的“int a;”称为变量定义,而“extern b;”则称为变量声明。
          • 全局变量与局部变量问题
            • 根据C51规则,变量定义语句放置的位置决定了变量的作用域,其中放在程序开始处(即所有函数前面)的称为全局变量,而放在函数内部的称为局部变量。
            • 全局变量的作用域是整个源程序范围,变量值可在程序运行期间始终有效,而局部变量值仅在函数调用期间有效,调用结束后就会失效。
            • 为了合理利用存储资源,需要根据情况灵活采用全局变量或局部变量,一般情况下应尽量选用局部变量。
      • 数据类型
        • C51使用的数据类型 = 标准C语言传承的 + C51特有的
        • (一)由标准C语言传承的数据类型
          • 数据类型用于表示数据存放格式(有符号数类型可以忽略signed标识符)

          • 整型数据、字符型数据和浮点型数据
            • 1、整型变量与整型常量
            • 2、字符型变量与字符型常量
            • 3、浮点型变量与浮点型常量
        • (二)C51特有的数据类型
          • bit型、sfr型和sbit型
          • 1、bit型变量
            • 可以但不限于在位寻址区开辟内存空间,作状态变化
            • 51单片机中有许多可以按位(bit)进行读写操作的存储单元,如片内RAM中位地址为00~7FH的128个位存储单元。每个位存储单元都可存放0或1两个位型常量。与这些位存储单元相对应的变量称为位型变量或bit型变量。
            • 位型变量的一般定义形式也与整型变量基本相同,即类型说明符 变量名〔=0或1〕;例如:bit abc =1;(指定变量abc为位型变量,初值为1)
          • 2、sfr型变量
            • 80C51单片机内部有21个特殊功能寄存器(SFR),除了DPTR为16位寄存器外(在SFR中,DPTR也被分成了DPH和DPL两个8位的)(PC为16位寄存器但是不属于SFR),其余都是8位寄存器,每个SFR都有特定的字节地址,部分SFR中还有独立的位地址。
            • sfr型变量的一般定义形式为:类型说明符 变量名=8位地址常量;
              • 类型说明符:
                • 8位SFR变量的sfr,16位SFR变量的sfr16
                • 8位地址常量是指有意义的SFR字节地址
                • 例如:
                  • sfr P1 = 0x90;//指定变量P1为sfr型变量,对应地址为0x90
                  • sfr PSW = 0xd0; //指定变量PSW为sfr型变量,对应地址为0xd0
                  • sfr16 DPTR = 0x82; //指定DPTR为sfr16型变量,即DPL=0x82,DPH=0x83
          • 3、sbit型变量
            • “相对位置”是指相对于已定义过SFR名称或可位寻址字节地址的位置,其中0表示最低位,以此类推。

            • 如前所述,sbit是用于定义SFR中具有位地址变量的类型说明符,变量定义可以有以下3种不同的用法:
              • 第1种(绝对位地址):sbit 位变量名=位地址;
                • 例如, sbit CY = 0xD7;
              • 第2种(相对位地址):sbit 位变量名=可位寻址的SFR字节地址^相对位置
                • 例如,sbit CY = 0xD0^7;
              • 第3种(相对位位置):sbit 位变量名=可位寻址变量^相对位置
                • 例如,sbit CY = PSW^7;
          • 还需要注意几点:
            • ①虽然bit和sbit定义的都是位型变量,但两者还是有很大区别的:
              • bit型变量的位地址是由编译器为其随机分配的(定义时不能用户指定),位地址范围是在片内RAM的可位寻址区(bdata区)中;
              • sbit型变量的位地址则是由用户指定的,位地址范围是在可位寻址的SFR单元内(利用bdata限定变量存储类型后可将位地址范围扩大到bdata区)。
            • ②sfr型变量和sbit型变量都必须定义为全局变量,即必须在所有C51函数之前进行定义,否则就会编译出错。
            • 程序中如果使用了头文件reg51.h后,原先定义P1变量的语句(sfr P1=0x90;)便可省略。但由于头文件reg51.h中并未对P0~P3寄存器中的位单元(如P1.0)进行sbit定义,因此程序中还需重新定义如p1_0的sbit型变量。
            • bit和unsigned char这两种数据类型都可以直接支持单片机机器指令,因此代码的执行效率最高,编程时应尽量选用bit和unsigned char这两种变量。
              • signed char虽然也只占有一个字节,但CPU需要进行额外的操作来测试代码的符号位,这无疑会降低代码效率。
              • 使用浮点型变量时,编译系统将调用相应的库函数来保证运算精度,这将明显增加运算时间和程序代码长度,因此,不是十分必要时应尽量避免使用float数据类型。
          • C51常用数据类型一览表

      • 〔存储类型〕
        • 为了合理使用51单片机的存储空间,需要进一步细化存储区域的组成,为此C51将3个物理存储空间细分成6个存储类型区。

        • 片内低128B RAM空间被划分成data和bdata两个存储区,8052型单片机专有的高128B RAM被作为idata存储区,片内外统一ROM空间被作为code存储区,片外RAM空间被划分成xdata和pdata两个存储区。
        • 若省略,则默认为data区(此时位于SMALL编译模式下)

          • 实际应用中,用户对单片机存储器的需求差别很大,为此,C51编译器中设立了3种编译模式供用户选择。
            • 在SMALL编译模式下,如果变量定义语句中省略了存储类型参数,则系统会自动默认采用data存储类型。同理,COMPACT编译模式和LARGE编译模式时的默认存储类型分别是pdata和xdata。
              • 例如,在SMALL编译模式下,变量a的定义语句char a;等价于char data a;。而在LARGE编译模式下,变量a的定义语句char a;则等价于char xdata a;。
            • 编译模式可以通过µVision3工程配置窗口的“Target”页进行指定。
        • 不同存储区各有特点,适合不同类型的变量。(注意:idata区)

        • 由此可见,变量在定义时,只有将其数据类型和存储类型的信息都展现在变量定义式中才能保证编译器顺利工作。
      • 变量名
        • C51语言中规定:
          • 变量名可以由英文字母、数字和下划线3种字符组成;
          • 第1个字符必须为字母或下划线(即不能为数字);
          • 变量名长度无统一规定(视编译系统而定),一般为不超过8个字符,超过部分有可能被编译系统舍弃。
          • 例如:sum,_total,month,Student,lotus_3,BASIC,li_ling都是合法的变量名。M.D.John,¥123,3D64,a>b都是不合法的变量名。
        • 使用变量名时还应注意:
          • 1、编译系统会将大写字母和小写字母认为是两个不同的字符,即变量名是大小写敏感的,如SUM和sum,习惯上变量名用小写字母表示,常量标识符用大写字母表示。(汇编语言不敏感)
          • 2、在选择变量名时,最好做到“见名知意”,即选用有一定含意的英文单词(或其缩写)作变量名。
          • 3、编译系统规定的关键词不得作为变量名,其中包括标准C语言的32个关键字和C51语言扩展的21个新关键字。

          • 强调:头文件中定义的变量(SFR)都是大写的,若程序采取小写变量则需要重新定义。
    • 4.2.2 C51的指针

      • C语言指针的一般定义形式为:数据类型 *指针变量名 [= &被指向变量名];
        • 其中,指针变量指向一个由“数据类型”说明的变量。被指向变量和指针变量都位于C编译器默认的内存区中。
        • 举例

      • C51指针变量定义的一般形式为:数据类型〔存储类型1〕*〔存储类型2〕变量名;
        • 数据类型是被指向变量的数据类型,如char、int、long等;
        • 存储类型1是指被指向变量所在的存储类型,如data, code,xdata等,缺省时根据被指向变量的定义语句(地址赋值关系)确定;
        • 存储类型2是指针变量所在的存储类型,如data,code,xdata等缺省时根据C51 编译模式的默认值确定;
        • 指针变量名可按C51变量名的规则选取。
      • * —— 取变量内的值
      • $ —— 取地址
      • 实例
        • 图1

        • 图2

        • 图3

  • 4.3 C51与汇编语言的混合编程

  • 4.4 C51仿真开发环境

  • 4.5 C51应用编程初步

    • 4.5.1 I/O端口的简单应用

      • 1. 基本输入/输出单元与编程

        • 按键检测与控制是单片机应用系统中的基本输入/输出功能。
        • 发光二极管
          • 发光二极管作为输出状态显示设备,具有电路简单,功耗低,寿命长,响应速度快等特点。
          • 发光二极管与单片机接口可以采用低电平驱动和高电平驱动两种方式。

          • 由于低电平驱动时单片机可提供较大输出电流2.4.1 P1口 ,故低电平驱动最为常用。
          • 发光二极管限流电阻通常取值100欧姆至200欧姆。
        • 按键或开关
          • 按键或开关是最基本的输入设备,与单片机相连的简单方式是直接与I/O口线相连。

          • 当按键或开关闭合时,对应口线的电平就会发生反转,CPU通过读端口电平即可识别是哪个按键或开关闭合。(当按键未按下压时,Px.n端口为高电平;按压按键后为低电平。)
      • 2. LED数码管原理与编程

        • LED数码管具有显示亮度高,响应速度快的特点。
        • 最常用的是七段LED显示器,该显示器内部有七个条形发光二极管和一个小圆点发光二极管。

        • 这种显示器分共阴极和共阳极两种:
          • 共阳极LED显示器的发光二极管的所有阳极连接在一起,为公共端;
          • 共阴极LED显示器的发光二极管的所有阴极连接在一起,为公共端。
        • LED数码管的a~g7个发光二极管加正电压点亮,加零电压熄灭,不同亮暗的组合的组合能形成不同的字形,这种组合称为段码。

        • a~g、dp应接在单片机上,更适合共阴极
        • 动态显示时,共阴极和共阳极均不行,因为电流不够,灯不亮,应再加驱动。
    • 4.5.2 I/O端口的进阶实践

      • 1. 数码管动态显示原理与编程

        • LED数码管与单片机的接口方式有静态显示接口和动态显示接口之分。
          • 静态显示接口
            • 静态显示接口是一个并行口接一个数码管(一个数码管的引脚独立占据一根I/O口线)。
            • 优点:被显示数据只要送入并行口后就不再需要CPU干预,因而显示效果稳定。
            • 缺点:占用资源较多
          • 动态显示接口
            • 所有数码管的输入端(段码线)对应并联在一个IO口上,而每位数码管的公共端(位码线)分别由一位IO线控制;
            • 由IO口输出的显示码可被所有数码管收到,但只有满足位码线电平要求的数码管可被驱动。
            • 动态显示编程原理:
              • 快速(如10ms)切换段码值和位码值,使每一时刻只有一只数码管被驱动。利用视力暂留特性,可获得连续显示效果。
              • 优点:占用IO口资源较少(节省空间)
              • 缺点:需要CPU不断进行干预(占用机时)
      • 2. 行列式键盘原理与编程

        • 独立式键盘的电路简单,易于编程,但占用的I/O口线较多,当需要较多按键时可能产生IO口资源紧张问题。

        • 行列式键盘
          • 将I/O口分为行线和列线,按键跨接在行线和列线上,列线通过上拉电阻接正电源。
          • 行列式键盘的特点:占用I/O口线少,但软件过程复杂。
          • 行列式键盘的检测可采用软件扫描查询法进行,级根据按键压下前后,所在行线的端口电平是否发生反转,判断有无按键闭合动作。
            • 键盘列扫描(各行电平同时置1,各列电平轮流清0)
            • 按键闭合状态判断
            • 查找闭合键键号
        • 按键抖动
          • 按键抖动会造成按键状态不易确定的问题,需要采用措施消除抖动影响。
          • 单片机通常采用软件延时10ms的方法来消除抖动的影响。
          • 当检测到有键按下时,先延时10ms,然后再检测按键状态,若仍是闭合状态,则认为真正有键按下。
          • 当需要检测到按键释放时,也需做同样的处理。
  • 本章小结

    • 1. C51普通变量的一般定义形式为: (存储种类) 数据类型 (存储类型) 变量名;
      • 存储种类包括auto、 extermn、 static和register4 个说明符,缺省时为auto型。
      • 常用数据类型为char和int, C51扩充类型为bit、 sfr、 sfr16和sbit。
      • 存储类型包括data、 bdata、 idata、 pdata、 xdata和code6个具体类型,缺省类型由编译模式指定。
      • 变量名可由字母、数字和下画线3种字符组成,首字符应为字母或下画线。
    • 2. C51指针的一般定义形式为:数据类型 (存储类型1) * (存储类型2) 指针变量名;
      • 数据类型是被指向变量的数据类型。
      • 存储类型1是被指向变量的存储类型,缺省时需根据该变量的定义确定。
      • 存储类型2是指针变量的存储类型,缺省时根据C51编译模式确定。
      • 变量名可由字母、数字和下画线3种字符组成,首字符应为字母或下画线。
    • 3. 在Keil下进行C51编程的方法是:建立工程--→输入源程序--→保存为.c文件--→添加文件到工程--→检查编译参数--→编译连接--→下载调试。
    • 4.键盘分为独立式按键和行列式键盘两种基本类型,前者:每只按键独立占用1个IO口,电路简单,易于编程,但占用I/O口较多。后者:所有按键按序跨接在行线和列线上,占用较少系统资源,但编程复杂,占用机时较多。
    • 5.数码管显示分为静态显示和动态显示两种工作方式。前者:每个数码管的引脚独立占据1根1/O口线。后者:所有数码管的段码线对应并联接在1个并行口上,每只数码管的公共端分别由1位IO线控制。
    • 6.数码管分为共阴型和共阳型两种基本类型,由于段码与显示值之间没有规律可循,通常将字模存放在数组中,通过查表的方式使用。

猜你喜欢

转载自blog.csdn.net/qq_59467552/article/details/125217661