单片机原理及应用-第3章80C51单片机C语言程序设计_第1页
单片机原理及应用-第3章80C51单片机C语言程序设计_第2页
单片机原理及应用-第3章80C51单片机C语言程序设计_第3页
单片机原理及应用-第3章80C51单片机C语言程序设计_第4页
单片机原理及应用-第3章80C51单片机C语言程序设计_第5页
已阅读5页,还剩60页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

2023/10/131第3章80C51单片机C语言程序设计C51对标准C的扩展3.1C51的指针3.2C51的函数3.3C51与汇编程序的接口3.42023/10/1323.1C51对标准C的扩展3.1.1C51的数据类型数据是计算机操作的对象,包含常量和变量。C51扩展了ANSIC,以适应单片机的结构和特点。

数据类型就是数据的格式,它决定数据的值域范围、占用存储单元的个数及能参与哪种运算。

编写C51程序,先要确定数据类型、储存分区应尽可能采用无符号格式(unsigned)

C51中,多字节数据采用“大端对齐”格式数据起始字节置于高地址端2023/10/133数据类型长度(位)取值范围字符型signedchar8-128~127unsignedchar80~255整型signedint16-32768~32767unsignedint160~65535长整型signedlong32-21474883648~21474883647unsignedlong320~4294967295浮点型float32±1.75494E-38~±3.402823E+38位型bit10,1sbit10,1访问SFRsfr80~255sfr16160~65535C51数据类型表2023/10/134bit定义位变量名字,编译器在位寻址区自动分配该位变量;Sbit声明位变量的名字和地址,地址是确定的(SFR区确定位、位寻址区变量的某确定位)。几点说明:unsigned

charbdata

ibase;sbit

mybitf=ibase^0;sbitCY=0xD7;bitflag1=0;含义:赋值含义:声明2023/10/1353.1.2C51数据的存储分区存储器类型对应单片机存储器bdata片内RAM位寻址区,共128位。(亦能字节访问)data直接寻址,共128字节。idata间接寻址,共256字节。pdata片外

RAM分页间址,共256字节。(MOVX@Ri)xdata间接寻址,共64k字节。(MOVX@DPTR)codeROM间接寻址,共64k字节。(MOVCA,@A+DPTR)经常使用的变量应该置于片内RAM中,要用bdata、data、idata来定义不常使用的变量或规模较大的变量应该置于片外RAM中,要用pdata、xdata来定义bitbdataflags;

//位变量flags定位在片内位寻址区chardatavar;

//字符变量var定位在片内RAM区floatidata

x,y;

//实型变量x,y定位在片内间址RAM区unsignedcharpdataz;

//无符号字符变量z定位在片外分页间址RAM区2023/10/137编译模式默认存储分区特点SMALLdata小模式。变量默认在片内RAM。空间小,速度块。COMPACTpdata紧凑模式。变量默认在片外RAM的页(256字节,页号由P2口决定)。LARGExdata大模式。变量默认在片外RAM的64KB范围。空间大,速度慢。编译模式默认的变量存储分区3.1.3C51的编译模式未对变量存储分区定义时,C51编译器采用默认存储分区。例如:charvar;

//SMALL模式时,var定位于data存储区

//COMPACT模式时,var定位于pdata存储区

//LARGE模式时,var定位于xdata存储区2023/10/1393.1.4用_at_定义变量绝对地址用关键字“_at_”定义变量存放的首地址

idata

inty_at_0x30;//idata区域整型变量y的首地址为0x30例如:又如:xdatacharstring[20]_at_0x3000;//xdata中字符型数组string的首地址为0x3000

注意,C51编程时不要轻易使用绝对地址定位变量。

2023/10/13103.2

C51的指针对于一个变量a,利用&a表示变量a的地址。则语句

p=&a;表明把a的地址赋给了指针变量p,则“p指向了变量a”。

可以用*P表示变量a指针变量的定义

char*p;//定义指针变量P

p=30H;//指针变量赋值,30H为片内RAM地址x=*p;//30H单元的内容送给变量x*P指针变量数据变量3.2.1已定义数据存储分区的指针定义时就指定了所指向数据的存储分区。

该指针占1个字节(idata*,data*,pdata*)或2个字节(code*,xdata*)

示例:char

data*str;

//指针str指向的char型数据存于data空间int

xdata*num;

//指针num指向的int型数据存于xdata

空间

基于存储器的指针长度比通用指针短,可以节省存储器空间,运行速度快,但它所指对象具有确定的存储器空间,兼容性不好。数据数据分区2023/10/1312定义时未指定所指向的数据的存储分区。也称通用指针。3.2.2未定义数据存储分区的指针---通用指针通用指针占3个字节第一字节存放该指针的默认存储器类型编码(见表)第二字节存放该指针的高位地址偏移量第三字节存放该指针的低位地址偏移量

存储器类型编码存储器类型bdata/data/idataxdatapdatacode编码0x000x010xfe0xff2023/10/1313通用指针定义示例:char*xdata

strptr;

//指针本身存于xdata

空间,它指向char型数据int*datanumber;

//指针本身存于data空间,它指向int型数据由于指向对象的存储空间在编译时无法确定(运行时确定),因此必须生成通用代码以保证对任意空间的对象进行存取。所以通用指针生成的代码速度较慢。指针char型数据指针分区2023/10/13143.2.3利用指针进行绝对地址访问unsignedchardata*p;p=0x40;*p=0x55;

//数据0x55送入内部RAM的0x40单元

例如:

C51编译器提供了一组宏定义实现对80C51绝对地址的访问。这组宏定义原型放在absacc.h文件中,形如:

#defineDBYTE((unsignedcharvolatiledata*)0)从而使DBYTE用于以字节形式对data区访问,可以写成:*(DBYTE)=0x55H;或

DBYTE[0]=0x55H;

与此类似:CBYTE用于以字节形式对code区进行访问;PBYTE用于以字节形式对pdata区进行访问;XBYTE用于以字节形式对xdata区进行访问。CWORD、DWORD、PWORD和XWORD用于以字形式对code区、data区、pdata区和xdata区进行访问。

3.2.4C51程序编写示例【例3-1】将30H至3FH共16个RAM单元初始化为“55H”。#include<reg52.h>#include<absacc.h>voidmain(void){ unsignedchari; for(i=0;i<=15;i++) { DBYTE[0x30+i]=0x55; } while(1);}编译系统自动连接了startup.a51生成代码一是将内部RAM的00H~7FH清0;二是设置堆栈指针SP。

有全局变量赋值时编译系统会自动连接init.a51生成代码C:0x0000020011LJMPC:0011C:0x0003E4CLRAC:0x0004FFMOVR7,AC:0x00057430MOVA,#0x30C:0x00072FADDA,R7C:0x0008F8MOVR0,AC:0x00097655MOV@R0,#0x55C:0x000B0FINCR7C:0x000CBF10F6CJNER7,#0x10,C:0005C:0x000F80FESJMPC:000FC:0x0011787FMOVR0,#0x7FC:0x0013E4CLRAC:0x0014F6MOV@R0,AC:0x0015D8FDDJNZR0,C:0014C:0x0017758107MOVSP,#0x07C:0x001A020003LJMPC:0003反汇编如下:编译系统自动连接了startup.a51生成代码一是将内部RAM的00H~7FH清0;二是设置堆栈指针SP。

另:全局变量赋值时编译系统会自动连接init.a51生成代码2023/10/13193.3

C51的函数3.3.1C51函数的定义一般形式:返回值类型函数名(形式参数列表)[编译模式][reentrant][interrupt

n][usingn]{

函数体}编译模式为SMALL、COPACT或LARGEreentrant用于定义可重入函数interruptn用于定义中断函数,n为中断号,可以为0~31usingn确定工作寄存器组,取值为0~3

【例3-2】延时nMs函数示例(晶振11.0592MHz)。voidDelayMs(unsignedintn)//延时函数{ unsignedcharj; while(n--) { for(j=0;j<113;j++); }}调试:Registers窗口中的sec值。

3.3.2C51函数定义的选项编译模式

SMALL模式:变量默认在片内RAM;COMPACT模式:变量默认在片外RAM的页内;LARGE模式:变量默认在片外RAM的64KB范围。reentrant定义为重入函数

ANSIC中,函数默认都是可重入的

C51函数默认是不可重入的,使用可重入函数会消耗较多的存储器资源,应该尽量少用。interruptn定义中断函数常用的中断源对应的中断号usingn确定中断服务函数所使用的工作寄存器组中断源外中断0定时器0外中断1定时器1串行口定时器2中断号012345【例3-3】中断函数定义示例#include<reg51.h>sbitP10=P1^0;voidIntSrv(void)interrupt0

{ if(INT0==0) //测开关状态

{ P10=!P10; while(INT0==0); }}3.3.3C51的库函数常用的C51库函数参见附录B.2

【例3-4】C51库函数调用示例。#include“intrins.h”//在intrins.h中有对函数_nop_()的定义voidDelay(void){

inti=5000;

while(i--)_nop_();}【例3-5】C51标准输入输出函数调用示例。#include<reg51.h>#include<stdio.h>voidInitSPort(void){SCON=0x50;//串口方式1,允许接收TMOD=0x20;//T1方式2(自动重装)TH1=0xFD;//波特率9600 TR1=1;//启动T1TI=1;//发送中断置1}voidmain(void){

InitSPort();

printf("HelloWorld\n");while(1);}标准I/O的重定向!

在调试状态:ViewSerialWindowsUART#13.4

C51与汇编程序的接口3.4.1在C51程序中嵌入汇编指令【例3-6】利用预编译指令。#include"reg51.h"voidInit(void);voidmain(){while(1){Init();}}voidInit(void){

#pragma

asm MOVR7,#16 MOVR1,#20H MOVA,#55HLP:MOV@R1,A INCR1 DJNZR7,LP

#pragma

endasm return;}要进行以下设置:2023/10/1327将嵌有汇编语句的源文件加入工程文件,将鼠标指向该文件,选择右键菜单“optionfor‘insertasm.c’”。将属性properties书签下的“GenerateAssemblerSRCFile”与“AssembleSRCFile”选项置成“√”。再加入库文件(如C51S.LIB),然后编译。

3.4.2在C51程序中调用汇编子程序【例3-7】不含参数传递的子程序调用。先构造汇编语言源文件:d1ms:MOVR6,#249;DL:NOP ;1µsNOP ;1µsDJNZR6,DL;2µs,循环内约1msRET

END

?PR?d1ms?EP4_7BSEGMENTCODE

PUBLICd1ms RSEG?PR?d1ms?EP4_7B注:d1ms对应C51的d1ms()EP4_7B对应ep4_7b.asm编写C51语言程序如下,完成汇编子程序调用:#include<reg51.h>sbitP2_0=P2^0;externvoidd1ms(void);voidmain(){ for(;;) { P2_0=0;

d1ms();/*调用汇编子程序*/ P2_0=1;

d1ms();/*调用汇编子程序*/ }}主调函数要向被调函数传递所需的参数传递给被调函数的数据称为实参实参向形参的传递是单向的参数传递可以采用寄存器、固定存储器位置方式

参数传递寄存器参数传递传递的参数char、1字节指针int、2字节指针long、float通用指针参数1R7R6、R7R4~R7R1、R2、R3参数2R5R4、R5R4~R7R1、R2、R3参数3R3R2、R3R1、R2、R3SMALL模式下,在内部RAM中完成COMPACT模式下,在外部RAM中完成LARGER模式下,在外部RAM中完成固定存储器位置参数传递80C51单片机不采用堆栈传递参数。但C51提供一种模拟堆栈,从而支持可重入函数的递归调用。

函数返回值使用的寄存器返回数据的类型寄存器说

明bitC进位标志位char、unsignedchar、1字节指针R7int、unsignedint、2字节指针R6、R7高字节在R6,低字节在R7long、unsignedlongR4、R5、R6、R7最高字节在R4,最低字节在R7floatR4、R5、R6、R732位IEEE格式通用指针R1、R2、R3存储类型在R1,高字节在R2,低字节在R3ThankYou!2023/10/13343.1C51对标准C的扩展3.1.1C51的数据类型数据是计算机操作的对象,包含常量和变量。C51扩展了ANSIC,以适应单片机的结构和特点。

数据类型就是数据的格式,它决定数据的值域范围、占用存储单元的个数及能参与哪种运算。

编写C51程序,先要确定数据类型、储存分区应尽可能采用无符号格式(unsigned)

C51中,多字节数据采用“大端对齐”格式数据起始字节置于高地址端2023/10/1335数据类型长度(位)取值范围字符型signedchar8-128~127unsignedchar80~255整型signedint16-32768~32767unsignedint160~65535长整型signedlong32-21474883648~21474883647unsignedlong320~4294967295浮点型float32±1.75494E-38~±3.402823E+38位型bit10,1sbit10,1访问SFRsfr80~255sfr16160~65535C51数据类型表2023/10/1336bit定义位变量名字,编译器在位寻址区自动分配该位变量;Sbit声明位变量的名字和地址,地址是确定的(SFR区确定位、位寻址区变量的某确定位)。几点说明:unsigned

charbdata

ibase;sbit

mybitf=ibase^0;sbitCY=0xD7;bitflag1=0;含义:赋值含义:声明2023/10/13373.1.2C51数据的存储分区存储器类型长度(位)对应单片机存储器bdata1片内RAM位寻址区,共128位。(亦能字节访问)data8直接寻址,共128字节。idata8间接寻址,共256字节。pdata8片外

RAM分页间址,共256字节。(MOVX@Ri)xdata16间接寻址,共64k字节。(MOVX@DPTR)code16ROM间接寻址,共64k字节。(MOVCA,@A+DPTR)经常使用的变量应该置于片内RAM中,要用bdata、data、idata来定义不常使用的变量或规模较大的变量应该置于片外RAM中,要用pdata、xdata来定义bitbdataflags;

//位变量flags定位在片内位寻址区chardatavar;

//字符变量var定位在片内RAM区floatidata

x,y;

//实型变量x,y定位在片内间址RAM区unsignedcharpdataz;

//无符号字符变量z定位在片外分页间址RAM区2023/10/1339编译模式默认存储分区特点SMALLdata小模式。变量默认在片内RAM。空间小,速度块。COMPACTpdata紧凑模式。变量默认在片外RAM的页(256字节,页号由P2口决定)。LARGExdata大模式。变量默认在片外RAM的64KB范围。空间大,速度慢。编译模式默认的变量存储分区3.1.3C51的编译模式未对变量存储分区定义时,C51编译器采用默认存储分区。例如:charvar;

//SMALL模式时,var定位于data存储区

//COMPACT模式时,var定位于pdata存储区

//LARGE模式时,var定位于xdata存储区2023/10/13413.1.4用_at_定义变量绝对地址用关键字“_at_”定义变量存放的首地址

idata

inty_at_0x30;//idata区域整型变量y的首地址为0x30例如:又如:xdatacharstring[20]_at_0x3000;//xdata中字符型数组string的首地址为0x3000

注意,C51编程时不要轻易使用绝对地址定位变量。

2023/10/13423.2

C51的指针对于一个变量a,利用&a表示变量a的地址。则语句

p=&a;表明把a的地址赋给了指针变量p,则“p指向了变量a”。

可以用*P表示变量a指针变量的定义

char*p;//定义指针变量P

p=30H;//指针变量赋值,30H为片内RAM地址x=*p;//30H单元的内容送给变量x*P指针变量数据变量3.2.1已定义数据存储分区的指针定义时就指定了所指向数据的存储分区。

该指针占1个字节(idata*,data*,pdata*)或2个字节(code*,xdata*)

示例:char

data*str;

//指针str指向的char型数据存于data空间int

xdata*num;

//指针num指向的int型数据存于xdata

空间

基于存储器的指针长度比通用指针短,可以节省存储器空间,运行速度快,但它所指对象具有确定的存储器空间,兼容性不好。数据数据分区2023/10/1344定义时未指定所指向的数据的存储分区。也称通用指针。3.2.2未定义数据存储分区的指针---通用指针通用指针占3个字节第一字节存放该指针的默认存储器类型编码(见表)第二字节存放该指针的高位地址偏移量第三字节存放该指针的低位地址偏移量

存储器类型编码存储器类型bdata/data/idataxdatapdatacode编码0x000x010xfe0xff2023/10/1345通用指针定义示例:char*xdata

strptr;

//指针本身存于xdata

空间,它指向char型数据int*datanumber;

//指针本身存于data空间,它指向int型数据由于指向对象的存储空间在编译时无法确定(运行时确定),因此必须生成通用代码以保证对任意空间的对象进行存取。所以通用指针生成的代码速度较慢。指针char型数据指针分区2023/10/13463.2.3利用指针进行绝对地址访问unsignedchardata*p;p=0x40;*p=0x55;

//数据0x55送入内部RAM的0x40单元

例如:

C51编译器提供了一组宏定义实现对80C51绝对地址的访问。这组宏定义原型放在absacc.h文件中,形如:

#defineDBYTE((unsignedcharvolatiledata*)0)从而使DBYTE用于以字节形式对data区访问,可以写成:*(DBYTE)=0x55H;或

DBYTE[0]=0x55H;

与此类似:CBYTE用于以字节形式对code区进行访问;PBYTE用于以字节形式对pdata区进行访问;XBYTE用于以字节形式对xdata区进行访问。CWORD、DWORD、PWORD和XWORD用于以字形式对code区、data区、pdata区和xdata区进行访问。

3.2.4C51程序编写示例【例3-1】将30H至3FH共16个RAM单元初始化为“55H”。#include<reg52.h>#include<absacc.h>voidmain(void){ unsignedchari; for(i=0;i<=15;i++) { DBYTE[0x30+i]=0x55; } while(1);}编译系统自动连接了startup.a51生成代码一是将内部RAM的00H~7FH清0;二是设置堆栈指针SP。

有全局变量赋值时编译系统会自动连接init.a51生成代码C:0x0000020011LJMPC:0011C:0x0003E4CLRAC:0x0004FFMOVR7,AC:0x00057430MOVA,#0x30C:0x00072FADDA,R7C:0x0008F8MOVR0,AC:0x00097655MOV@R0,#0x55C:0x000B0FINCR7C:0x000CBF10F6CJNER7,#0x10,C:0005C:0x000F80FESJMPC:000FC:0x0011787FMOVR0,#0x7FC:0x0013E4CLRAC:0x0014F6MOV@R0,AC:0x0015D8FDDJNZR0,C:0014C:0x0017758107MOVSP,#0x07C:0x001A020003LJMPC:0003反汇编如下:编译系统自动连接了startup.a51生成代码一是将内部RAM的00H~7FH清0;二是设置堆栈指针SP。

另:全局变量赋值时编译系统会自动连接init.a51生成代码2023/10/13513.3

C51的函数3.3.1C51函数的定义一般形式:返回值类型函数名(形式参数列表)[编译模式][reentrant][interrupt

n][usingn]{

函数体}编译模式为SMALL、COPACT或LARGEreentrant用于定义可重入函数interruptn用于定义中断函数,n为中断号,可以为0~31usingn确定工作寄存器组,取值为0~3

【例3-2】延时nMs函数示例(晶振11.0592MHz)。voidDelayMs(unsignedintn)//延时函数{ unsignedcharj; while(n--) { for(j=0;j<113;j++); }}调试:Registers窗口中的sec值。

3.3.2C51函数定义的选项编译模式

SMALL模式:变量默认在片内RAM;COMPACT模式:变量默认在片外RAM的页内;LARGE模式:变量默认在片外RAM的64KB范围。reentrant定义为重入函数

ANSIC中,函数默认都是可重入的

C51函数默认是不可重入的,使用可重入函数会消耗较多的存储器资源,应该尽量少用。interruptn定义中断函数常用的中断源对应的中断号usingn确定中断服务函数所使用的工作寄存器组中断源外中断0定时器0外中断1定时器1串行口定时器2中断号012345【例3-3】中断函数定义示例#include<reg51.h>sbitP10=P1^0;voidIntSrv(void)interrupt0

{ if(INT0==0) //测开关状态

{ P10=!P10; while(INT0==0); }}3.3.3C51的库函数常用的C51库函数参见附录B.2

【例3-4】C51库函数调用示例。#include“intrins.h”//在intrins.h中有对函数_nop_()的定义voidDelay(void){

inti=5000;

while(i--)_nop_();}【例3-5】C51标准输入输出函数调用示例。#include<reg51.h>#include<stdio.h>voidInitSPort(void){SCON=0x50;//串口方式1,允许接收TMOD=0x20;//T1方式2(自动重装)TH1=0xFD;//波特率9600 TR1=1;//启动T1TI=1;//发送中断置1}voidmain(void){

InitSPort();

printf("HelloWorld\n");while(1);}标准I/O的重定向!

在调试状态:ViewSerialWindowsUART#13.4

C51与汇编程序的接口3.4.1在C51程序中嵌入汇编指令【例3-6】利用预编译指令。#include"reg51.h"voidInit(void);voidmain(){while(1)

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论