2.MCS-51单片机C语言程序设计_第1页
2.MCS-51单片机C语言程序设计_第2页
2.MCS-51单片机C语言程序设计_第3页
2.MCS-51单片机C语言程序设计_第4页
2.MCS-51单片机C语言程序设计_第5页
已阅读5页,还剩52页未读 继续免费阅读

下载本文档

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

文档简介

MCS-51单片机

C语言程序设计1单片机C语言概述1.1C51程序开发过程1.2C51程序结构2C51的数据类型与运算2.1C51的数据类型2.2C51数据的存储器类型2.3MCS-51硬件结构的C51定义2.4C51的运算符和表达式MCS-51单片机C语言程序设计23C51流程控制语句3.1C51选择语句3.2C51循环语句4C51的指针类型4.1一般指针4.2基于存储器的指针5C51的函数6C51编程实例6.1MCS-51内部资源的编程6.2MCS-51扩展资源的编程31.1C51程序开发过程1.采用C51的优点用C51进行程序设计可大大提高实际工程的开发效率。1单片机C语言概述 在编程方面,使用C51较汇编语言有诸多优势: 1)编程容易 2)容易实现复杂的数值计算 3)容易阅读与交流 4)容易调试与维护程序 5)容易实现模块化开发 6)程序可移植性好42.

C51程序开发过程5C语言与ANSI的区别

用汇编语言编写单片机程序时,必须要考虑其存储器的结构,尤其要考虑其片内数据存储器、特殊功能寄存器是否正确合理的使用。 用C51编写程序,虽然不像汇编语言那样需要具体地组织、分配存储器资源,但是C51对数据类型和变量的定义,必须要与单片机的存储结构相关联,否则编译器不能正确地映射定位。

6 用C51编写单片机程序,与用ANSIC编写程序的不同之处是,需要根据单片机存储器结构及内部资源,定义相应的数据类型和变量。 其它的语法规定、程序结构及程序设计方法,都与ANSIC相同。C语言与ANSI的区别71.2C51程序结构C51程序由一个或多个函数构成,其中至少应包含一个主函数main。程序从主函数开始执行,调用其他函数后又返回主函数。被调用函数如果位于主函数前面,可以直接调用,否则应先说明后调用。被调用函数可以是用户自编的函数,或是C51编译器提供的库函数。C语言程序的基本结构如下。8全局变量说明/*可被程序中所有函数引用的变量*/main() /*主函数,程序入口*/{局部变量说明 /*只能在本函数体内引用的变量*/C执行语句,包括可能的函数调用语句等}}function1(形参列表)/*函数l*/形参说明{局部变量说明C执行语句,包括可能的函数调用语句等}functionN(形参列表)/*函数N*/形参说明{局部变量说明C执行语句,包括可能的函数调用语句等}9①变量必须先说明后引用,所有符号对大小写敏感。②每条语句必须以分号“;”结尾,一行可以写多条语句,一条语句也可以写多行。③注释用/*……*/表示。④花括号必须成对出现,书写位置不限。C语言的规则如下:典型示例如下。10#include<reg52.h>#include<stdio.h>voiddelayms(unsigned);voidmain(void){unsignedchari;P1=0x01;do {for(i=0;i<=7;i++) { delayms(5000); P1=P1<<1; if(P1==0x00){P1=0x01;} } }while(1);}11voiddelayms(unsignedx){unsignedcharj;while(x――) { for(j=0;j<123;j++){;} }}122.1C51的数据类型与标准C语言一样,C51的数据也分为常量和变量。常量是在程序的运行过程中不能被改变的量。可以是字符、十进制数或十六进制数。十六进制数的开始以“0x”表示。变量是在程序运行过程中可以被改变的量。变量由变量名和变量的内容构成。变量名指出了变量的存放位置,其内容就是变量的值。2C51的数据类型与运算C51编译器支持的常用数据类型见表

13数

型长度/位取

围字符型signedchar8-128~+127unsignedchar80~255整型signedint16-32768~+32767unsignedint160~65535signedlong32-2147483648~+2147483647unsignedlong320~4294967295浮点型float32±1.175494E-38~±3.402823E+38位型bit10或1sbit10或1访问SFRsfr80~255sfr16160~6553514注意:通常情况下,应尽可能采用无符号格式unsigned。使用有符号格式signed时,编译器要进行符号位检测并需要调用库函数,生成程序代码长,程序运行速度慢。默认值为有符号格式。C编译器在编译时自动进行类型转换。15位变量必须定位在MCS-51单片机片内RAM的位寻址空间中,但应注意区别bit与sbit的不同用法:bit用于定义位变量的名字,编译器会对其分配地址。位变量分配在内部RAM的位寻址区,位地址范围为00H~7FH。sbit用于定义位变量的名字和地址,地址是确定的且不用编译器分配。定义范围为整个位寻址空间。162.2C51数据的存储器类型C51编译器支持的存储器类型见表存储器类型长度/位对应单片机存储器bdata8片内RAM位寻址区,共128b(亦能字节访问)data8直接寻址,共128Bidata8间接寻址,共256Bpdata8片外RAM分页间址,共256B(用“MOVX

@Ri”指令访问)xdata16间接寻址,共64KB(用“MOVX

@DPTR”指令访问)code16ROM间接寻址,共64KB(用“MOVC

A,@A+DPTR”指令访问)17注意:访问片内RAM比访问片外RAM的速度快的多,所以经常使用的变量应置于片内RAM中。bitbdataflags;/*位变量flags定位在片内RAM的位寻址区*/chardatavar;/*字符变量var定位在片内RAM区*/floatidatax,y;/*实型变量x,y定位在片内间址RAM区*/unsignedcharpdataz;/*无符号字符变量z定位在片外分页间址RAM区*/unsignedintxdatareceiv_buf[50];unsignedcharcodedis_code[10]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07,0x7f,0x6f};

//定义共阴极数码管段码数组18C51支持的存储模式存储模式默认存储器类型特

点SMALLdata小模式,变量默认在可直接寻址的片内RAM。空间小,速度快COMPACTpdata紧凑模式,变量默认在片外RAM的页(256B,页号由P2口决定)LARGExdata大模式,变量默认在片外RAM的64KB范围。空间大,速度慢在Keil中,执行Project|OptionsforTarget‘Target1’命令,弹出OptionsforTarget‘Target1’对话框,在MemoryModel中指定存储模式。存储模式:如果在定义变量时缺省了存储区属性,则编译器会自动选择默认的存储区域,也就是存储模式。192.3MCS-51硬件结构的C51定义C51是对标准C语言(ANSIC)进行了扩展,从而具有对MCS-51单片机硬件结构的支持与操作能力。

sfr 特殊功能寄存器名=地址常数

地址常数范围:0x80~0xff。 特殊功能寄存器定义例子(见reg51.h、reg52.h等文件): sfr P0=0x80; //定义P0寄存器 sfr P1=0x90; //定义P1口寄存器 sfr PSW=0xd0; //定义PSW sfr IE=0xa8; //定义IE

1.特殊功能寄存器的声明2016位特殊功能寄存器的定义

定义的一般格式为:

sfr16 特殊功能寄存器名=地址常数 地址常数范围:0x80~0xff。 例如(见reg51.h、reg52.h等文件):

sfr16DPTR=0x82; sfr16T2=0xcc; //含TL2和TH2

21

几点说明:

1)定义特殊功能寄存器中的地址必须在0x80~0xff范围内。 2)定义特殊功能寄存器,必须放在函数外面作为全局变量。 3)用sfr或sfr16每次只能定义一个特殊功能寄存器。 4)像sbit一样,用sfr或sfr16定义的是绝对定位的变量(因为名字是与确定地址对应的),具有特定的意义,在应用时不能像一般变量那样随便使用。

222.特殊功能寄存器中特定位的声明(1)

sbit位变量名=特殊功能寄存器名^位的位置(2)

sbit位变量名=字节地址^位的位置(3)

sbit位变量名=位地址sbit OV=PSW^2; //定义PSW的第2位sbit AC=0xD0^6; //定义PSW的第6位sbit OV=PSW^2; //定义PSW的第2位23

几点说明: 1)用sbit定义的位变量,必须能够按位操作,而不能够对无位操作功能的位定义位变量。 2)用sbit定义位变量,必须放在函数外面作为全局位变量,而不能在函数内部定义。 3)用sbit每次只能定义一个位变量。 4)对其它模块定义的位变量(bit型或sbit型)的引用声明,都使用bit。 5)用sbit定义的是一种绝对定位的位变量(因为名字是与确定位地址对应的),具有特定的意义,在应用时不能像bit型位变量那样随便使用。243.内部RAM中可位寻址对象的定义当位对象位于MCS-51单片机内部RAM的20H~2FH单元时,可以利用C51编译器提供的bdata存储器类型进行定义,还可以用sbit声明bdata变量的相应位。intbdataibase;sbitmybit0=ibase^0;254.对存储器和外接I/O接口地址的访问对存储器的访问CBYTE(访问code区字符型) CWORD(访问code区int型)DBYTE(访问data区字符型) DWORD(访问data区int型)PBYTE(访问pdata或I/O区字符型) PWORD(访问pdata区int型)XBYTE(访问xdata或I/O区字符型) XWORD(访问xdata区int型)这些宏定义原型放在absacc.h文件中,使用时需要用预处理命令把该头文件包含到文件中,形式为:#include<absacc.h>。26对外部I/O接口的访问MCS-51单片机I/O接口与外部数据存储区是统一编址的,因此对I/O接口地址可用XBYTE或PBYTE。例如:XBYTE[0x7fff]=0x30将30H输出到地址为7FFFH的接口。#include<absacc.h>DBYTE[0x30]=48; //给片内RAM送数据XBYTE[0x0002]=0x36; //给片外RAM送数据dis_buf[0]=CBYTE[TABLE+5];

//从CODE区读数据272.4C51的运算符和表达式C51具有十分丰富的运算符,对数据具有极强的表达能力。由运算符及运算对象组成的具有特定含义的表达式,在任意一个表达式的后面加一个分号“;”就构成了一个表达式语句。运算符和表达式构成了C51程序的各种语句。算术运算符和算术表达式基本算术运算符自增、自减运算符类型转换

282.关系运算符和关系表达式关系运算符关系表达式

关系运算即比较运算。其优先级低于算术运算,高于赋值运算。293.逻辑运算符和逻辑表达式逻辑运算符

逻辑表达式C51提供6种位运算符,如下所述。&按位与;︱按位或;^按位异或;~按位取反;<<左移;>>右移。如P1=P1<<1表示对P1口的所有位左移1位。位运算的优先级顺序为:位取反、左移和右移、位与、位异或,位或。4.位运算符30符号“=”称为赋值运算符,其作用是将1个数据的值赋给1个变量。在赋值运算符的前面加上其他运算符可以构成复合赋值运算符。在C51中共有10种复合运算符。+=加法赋值; -= 减法赋值; *=乘法赋值;/=除法赋值;%=取模赋值; <<= 左移位赋值;>>=右移位赋值;&=逻辑与赋值;︱=逻辑或赋值;^= 逻辑异或赋值;~=逻辑非赋值。例如:a*=5相当于a=a*5;b&=0x80相当于b=b&0x80。注意:C51运算符的优先级由高到低顺序为:逻辑非、算术运算符、关系运算符、逻辑与和逻辑或、赋值运算符。5.赋值和复合赋值运算符313.1C51选择语句

C51的程序结构分为顺序结构、选择结构和循环结构1.条件语句1)

if(条件表达式)语句2)

if(条件表达式)语句1else语句23)if(条件表达式1)语句1elseif(条件表达式2)语句2…3C51流程控制语句322.开关语句开关语句主要用于多分支的场合。一般形式如下。switch(表达式){case常量表达式1:语句1;break;case常量表达式2:语句2;break;

case常量表达式n:语句n;break;default:语句n+1;}开关语句执行时,将switch后面表达式的值与case后面各个常量表达式的值逐个进行比较,若匹配则执行相应case后面的语句333.2C51循环语句1.

while语句2.

do-while语句3.

for语句在C51程序中,实现循环的方法有以下4种。while(条件表达式)语句;do语句while(条件表达式);(1)当型循环for([初值表达式];[条件表达式];[更新表达式])语句

4.

if语句与goto语句结合(2)直到型循环loop:if(表达式) {语句gotoloop;}loop:{语句if(表达式)gotoloop;}341.

while语句指针为变量的访问提供了一种特殊的方式。如果有一个变量a,则可以利用&a表示变量a的地址。为了获得指针所指向对象的内容,可以利用指针运算符“*”来实现,C51编译器支持两种指针类型:一般指针和基于存储器的指针。4C51的指针类型chardata*p;//定义指针变量p=30H;//为指针变量赋值x=*p;354.1一般指针定义时未指定它所指向的对象的存储器类型时,该指针变量就被认为是一般指针。C51编译器支持两种指针类型:一般指针和基于存储器的指针一般指针可用于存取任何变量而不必考虑变量在MCS-51单片机存储空间的位置,许多C51库函数采用了一般指针。char*xdatastrptr; /*指针本身存于xdata空间,它指向char型数据*/int*datanumber; /*指针本身存于data空间,它指向int型数据*/364.2基于存储器的指针基于存储器的指针在定义时就指定了所指向对象的存储类型。指针的长度可以为1个字节(idata*,data*,pdata*)或2个字节(code*,xdata*)。

例如:chardata*str;/*指针指向的char型数据存于data空间*/intxdata*num;/*指针指向的int型数据存于xdata空间*/longcode*pow;/*指针指向的long型数据存于code空间*/还可以在定义时指定指针本身的存储器空间位置。例如:chardata*xdatastr; /*指针本身在xdata空间*/intxdata*datanum; /*指针本身在data空间*/longcode*idatapow; /*指针本身在idata空间*/37

注意:(1)要区分指针变量指向的空间区域和指针变量本身所存储的区域;(2)定义时,前者不能缺省,而后者可以缺省;(3)指针变量的长度:指向不同的区域,占用的字节数不同。

说明:指针变量本身所存储的区域,在定义指针时一般都省略了,指针变量本身保存在缺省存储的区域中。38

例:编写程序,将单片机片外数据存储器中地址从0x1000开始20个字节数据,传送到片内数据存储器地址从0x30开始的区域。

程序段如下: unsignedchardata i,*dcpt; unsignedcharxdata *xcpt; dcpt=0x30; //给指针赋地址 xcpt=0x1000; for(i=0;i<20;i++) *(dcpt+i)=*(xcpt+i);

dcpt和xcpt两个指针变量存储在什么地方?391.

C51函数的定义5C51的函数 在C51中,函数的定义与ANSIC中是相同的。唯一不同的就是在函数的后面需要带上若干个C51的专用关键字。C51函数定义的一般格式如下: 返回类型函数名(形参表)[函数模式][reentrant][interruptm][usingn] { 局部变量定义 执行语句 }

40

各属性含义如下:

函数模式:也就是编译模式、存储模式,可以为small、compact和large。缺省时则使用文件的编译模式。

reentrant:表示重入函数。所谓可重入函数,就是允许被递归调用的函数。是C51定义的关键字。在编译时会为重入函数生成一个堆栈,通过这个堆栈来完成参数的传递和存放局部变量。 重入函数不能使用bit型参数;函数返回值也不能是bit型。41

interruptm:中断关键字和中断号。interrupt是C51定义的。C51支持32个中断源

单片机中断源与中断号的关系中断源外中断0T0中断外中断1T1中断串行中断T2中断中断号012345中断入口地址0x00030x000b0x00130x001b0x00230x002b42

usingn:选择工作寄存器组和组号, n可以为0~3,对应第0组到第3组。关键字using是C51定义的。

如果函数有返回值,不能使用该属性,因为返回值是存于寄存器中,函数返回时要恢复原来的寄存器组,导致返回值错误。

43C51中断函数的定义 C51函数的定义实际上已经包含了中断服务函数,但为了明确起见,下面专门给出中断处理函数的具体定义形式: void函数名(void)[函数模式]interruptm[usingn] { 局部变量定义 执行语句 }

44

中断服务函数需要注意以下几点: 1)中断服务函数不传递参数; 2)中断服务函数没有返回值; 3)中断服务函数必须有interruptm属性; 4)进入中断服务函数,ACC、B、PSW会进栈,根据需要,DPL、DPH也可能进栈,如果没有usingn属性,R0~R7也可能进栈,否则不进栈; 5)在中断服务函数中调用其它函数,被调函数最好设置为可重入的,因为中断是随机的,有可能中断服务函数所调用的函数出现嵌套调用; 6)不能够直接调用中断服务函数。

45

例编写程序,使用定时器/计数器0定时1ms并产生中断,实现从P1.7产生方波的功能。

程序如下:#include<reg52.h>#define TIMER0L 0x18 //设振荡频率为12MHz#define TIMER0H 0xfc //定时1ms(1000微秒)voidtimer0_int(void)interrupt1{ TL0=TIMER0L;

TH0=TIMER0H;

P1_7=~P1_7; //产生的方波频率为500Hz}

46void main(void){ TMOD=0x01; //设置T1模式1定时

TL0=TIMER0L; //设置T0低8位初值

TH0=TIMER0H; //设置T0高8位初值

IE=0x82; //开T0中断和总中断

TR0=1; //开T0运行 while(1); //等待中断,产生方波}

47若被调函数是有参函数,则主调函数必须把被调函数所需的参数传递给被调函数。传递给被调函数的数据称为实际参数,即实参。实参向形参的传递是单向的,即只能将实参传递给形参。参数传递可以采用寄存器、固定存储器位置传递方式。寄存器参数传递使用的寄存器见表:2.

C51函数的调用与参数传递传递的参数char、1字节指针int、2字节指针long、float一

针参数1R7R6、R7R4~R7R1、R2、R3参数2R5R4、R5R4~R7R1、R2、R3参数3R3R2、R3R1、R2、R348

3.

C51的库函数C51编译器提供了丰富的库函数,使用这些库函数可以大大提高编程的效率。每个库函数都在相应的头文件中给出了函数的原形,使用时只需在源程序的开始用编译命令#include将头文件包含进来即可。496.1MCS-51内部资源的编程

1.中断服务函数示例中断函数的定义形式如下。void函数名(void)interruptn[usingm]{函数体}6C51编程实例50常用的中断源对应的中断号见表:中

源外中断0定时器0外中断1定时器1串

口中断号01234关键字using用于指定使用的工作寄存器区,m的范围是0~3。指定工作寄存器区后,所有被中断调用的过程都必须使用同一个寄存器区,否则参数传递就会发生错误。不设定工作寄存器区时,编译系统会将当前工作寄存器区的8个寄存器都压入堆栈。注意:应用程序中任何函数都不能调用中断服务函数,它是供系统调用的。51【例1】在一个MCS-51单片机应用系统中,外中断0引脚接一个开关,并行端口线P1.0接一个发光二极管。要求系统的功能是开关闭合一次发光二极管的状态改变一次。试编写程序。#include<reg51.h>#include<intrins.h> /*在intrins.h中有对函数*/

温馨提示

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

评论

0/150

提交评论