51单片机——C51

目录

前言

一、C51与标准C的区别

二、C51数据类型

三、C51变量的特殊属性

存储器类型      

存储模式

绝对地址访问

四、C51中断函数和输入输出

中断函数

输入输出

完结



前言

        通过使用C语言可以进行对MCS—51单片机的开发,实现各种外设功能,我们称用来开发51单片机的“C语言”为C51。C51是基于标准C、专门为开发51单片机而设计的,与标准C有一定区别,有很多内容是专门为51单片机设定的。

       本文主要介绍C51的特别之处, 由于C51的很多特有内容与51单片机的内部硬件结构是息息相关的,所以在阅读之前有必要先熟悉一下51单片机的硬件结构,可以参考下面内容:

51单片机内核及其工作原理-CSDN博客

一、C51与标准C的区别

异:

①库函数不同。标准C的库函数是PC来定义的,而C51的库函数是按照51单片机相应情况来制定的。

②数据类型的区别。C51中增加了几种特有的数据类型。

③变量的存储模式区别。C51中变量的存储模式与51单片机的存储结构紧密相关。

④输入输出处理不同。C51中的输入输出往往是通过串口实现的。

⑤函数使用方面不同。C51有特定的中断函数,以及main()函数无限循环。

同:

其他语法、程序结构及程序设计等方法与标准C语言一致,所以,在第一次玩51单片机时,就会认为它和所学的标准C语言一样。

二、C51数据类型

C51与标准C中的数据类型基本相同,主要不同在于C51中有专门针对51单片机的特殊功能寄存器(SFR)型和位类型。

基本数据类型长度取值范围
bit1位0或1
sbit1位0或1
sfr1字节0~255
sfr162字节0~65535
unsigned char1字节0~255
(signed)char1字节-128~+127
unsigned int2字节0~65535
(signed)int2字节-32768~+32767
unsigned long4字节0~4294967295
(signed)long4字节-2147483648~+2147483647
float4字节\pm1.175494E-38~\pm3.402823E+38

bit类型:位变量,要么是0,要么是1。

如:bit  flag = 0;

sfr类型:将特殊功能寄存器的地址重定义,之后便可以把它当作变量直接操作(下面的数据类型也相同)。

如:sfr  P1 = 0x90;

例:P1 = 0xFF; //将P1端口的8个引脚全部输出高电平(1)。

sfr16类型:给16位的特殊功能寄存器的地址重定义。

如:sfr16  DPTR = 0x82;

sfr或sfr16:51单片机内的SFR,用于控制单片机的内部定时器/计数器、串口、I/O及其他功能部件,每一个特殊功能寄存器在片内RAM中都对应一个字节单元或两个字节单元。C51提供了一种自主定义的方法,其与标准C不兼容,只适用与51系列单片机。

sbit类型:给特殊功能寄存器的位地址重定义。

如:sbit  P1_1 = 0x91;

//另外一种定义方式。

sfr   P1 = 0x90;

 sbit  P1_1  = P1^1;

C51中为了用户处理方便,C51编译器把MCS—51单片机的常用的特殊功能寄存器和特殊位进行了定义,放在一个“reg51.h”或“reg52.h”的头文件中,当用户使用时,只需要包含该头文件即可。如下: 

/*--------------------------------------------------------------------------
REG52.H

Header file for generic 80C52 and 80C32 microcontroller.
Copyright (c) 1988-2002 Keil Elektronik GmbH and Keil Software, Inc.
All rights reserved.
--------------------------------------------------------------------------*/

#ifndef __REG52_H__
#define __REG52_H__

/*  BYTE Registers  */
sfr P0    = 0x80;
sfr P1    = 0x90;
sfr P2    = 0xA0;
sfr P3    = 0xB0;
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 Extensions  */
sfr T2CON  = 0xC8;
sfr RCAP2L = 0xCA;
sfr RCAP2H = 0xCB;
sfr TL2    = 0xCC;
sfr TH2    = 0xCD;


/*  BIT Registers  */
/*  PSW  */
sbit CY    = PSW^7;
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 only

/*  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 PX0   = 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^0; // 8052 only
             
/*  T2CON  */
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;

#endif

三、C51变量的特殊属性

        变量在使用前必须进行定义,其中,可以对变量设置C51特有的存储器模式,以便编译器为它分配相应的存储单元。一般格式为:

[存储种类]   数据类型  [存储器类型]   变量1[可以赋初值],变量2[可以赋初值]......;

其中存储种类和存储器类型可以省略,系统会有默认的存储种类和存储器类型,如下例子:

const    char                     a=0x10;
extern   unsigned int             b=0x1234;
static   float         xdata      c=123.456;
         float         code       d=123.456;  

存储器类型      

        C51变量所处的单片机的存储器区域,由其变量定义中特殊的存储器类型决定。C51的存储器类型有一下几种:

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

如下,几个实例:

unsigned char   data   a;//在片内RAM低128B内定义字符型变量a。

unsigned int    idata  a;//在片内RAM256B内定义整型变量a。

float           xdata a;//在片外RAM64kB空间定义浮点型变量a。

unsigned int   code  a;//在ROM空间内定义整型变量a。

unsigned char  bdata a;//在片内RAM位寻址区定义可字节处理和位处理的无符号字符型变量a。

当存储器类型缺省时,C51编译器将按照存储模式默认的存储器类型。

存储模式

        C51编译器支持三种存储模式:SMALL模式、COMPACT模式和LARGE模式不同的存储模式对变量默认的存储器类型不一样。

SMALL模式函数参数和变量被默认在片内RAM中,存储器类型为data
COMPACT模式函数参数和变量被默认在片外RAM的低256B空间,存储器类型为pdata
LARGE模式函数参数和变量被默认在片外RAM的64kB空间,存储器类型为xdata

在程序中变量的存储模式的指定通过#pragma预处理命令来实现。函数的存储模式可以通过在函数定义时后面带存储模式说明。如果没有指定,则系统都隐含为SMALL模式。如下:

/***变量***/
#pragma  small        //变量的存储模式为SMALL    
char a;               //存储器类型为:data
int xdata b;          //存储器类型为:xdata

#pragma compact       //变量的存储模式为COMPACT
char c;               //存储器类型为:pdata
int xdata d;          //存储器类型为:xdata

/***函数***/
int fun1(int x1,int x2)  large   //函数的存储器模式为LARGE,形参x1和x2的存储器类型为:xdata
{
return(x1+x2);
}

int fun2(int y1,int y2)         //函数的存储器模式隐含为SMALL,形参y1和y2的存储器类型为:data
{
retrun(y1+y2);
}

绝对地址访问

        C51通过三种方式实现绝对地址访问,即通过地址来访问存储空间的内容。

1、使用C51运行库中预定义宏

        C51编译器提供了一组宏定义对5系列单片机的code、data、pdata和xdata空间进行绝对寻址。规定只能以无符号数的方式访问,定义了8个宏定义,其函数原型如下:

#include <absacc.h>   //宏定义所在的头文件,使用时需要引用该头文件。

//如下,8个宏定义为:
#define CBYTE((unsigned char volatile code *)0)
#define DBYTE((unsigned char volatile data *)0)
#define PBYTE((unsigned char volatile pdata *)0)
#define XBYTE((unsigned char volatile xdata *)0)

#define CWORD((unsigned int  volatile code  *)0)
#define DWORD((unsigned int  volatile data *)0)
#define PWORD((unsigned int  volatile pdata  *)0)
#define XWORD((unsigned int  volatile xdata *)0)

如下例子:

#include <absacc.h>
#include <reg52.h>

#define uchar unsigned char
#define uint  unsigned int

void main(void)
{
uchar a;
uint b = 2024;
a = XBYTE[0xF005];//读片外RAM的F005H字节单元。
XWORD[0xD002] = b;//写片外RAM的D002H字单元。

while(1){}
}

2、通过指针访问

        在C语言中,指针可以用来代表地址。采用指针的方法,可以实现对任意指定存储器单元进行访问。如下:

#define uchar unsigned char
#define uint  unsigned int

void fun(void)
{
uchar data a;      //定义一个data区的变量a。
uchar pdata *p1;   //定义一个指向pdata区的指针p1。
uint  xdata *p2;   //定义一个指向xdata区的指针P2。
uchar data  *p3;   //定义一个指向data区的指针p3。

p1 = 0x30;         //给指针p1赋值,指向pdata区的30H单元
p2 = 0x1000;       //给指针p2赋值,指向xdata区的1000H单元
p3 = &a;           //给指针p3赋值,指向data区的a变量的地址单元

*p1 = 0x12;        //将数据0x12送到片外RAM30H单元
*p2 = 0x1234;      //将数据0x234送到片外RAM1000H单元
*p3 = 0x12;        //将变量a赋值为0x12

}

3、使用C51扩展关键字:_at_

        使用_at_对指定存储器空间的绝对地址进行访问,一般格式如下:

[存储器类型]  数据类型   变量名   _at_   绝对地址(地址常数

使用_at_定义的变量必须为全局变量,如下实例:

#define uchar unsigned char
#define uint  unsigned int

data uchar a  _at_ 0x40; //在data区中定义字节变量a,地址为40H
xdata uint b  _at_ 0a2000; //在xdata区中定义字节变量b,地址为2000H

void main(void)
{
a = 0x12;                   //对片内40H单元赋值
b = 0x1234;                 //对片外2000H单元赋值

while(1){}

} 

四、C51中断函数和输入输出

中断函数

中断函数的特点:

①中断函数不能使用参数传递。若进行参数的申请将产生编译错误。

②中断函数没有返回值。定义时应将该函数定义为void类型。

③中断函数只有相应的中断产生时才能由系统自动调用。其他函数不能调用,否则产生编译错误。

④中断函数最好不要调用别的函数,如需调用,要保证其能尽快执行完,同时被调用函数将使用相同的寄存器组。

中断函数中禁止使用extern存储类型说明

中断函数的定义格式为:

函数类型  函数名(形式参数表) [interrupt  m]  [using  n]

interrupt  m选项(重点):指明定义的函数为中断响应函数,其中m为中断号。

using   n选项:指定本函数中使用的寄存器组号(0~3)。

void time0() interrupt 1 using 1 //定时器0中断函数。
{
//中断处理内容。
}

但在平时使用中往往省略[using   n]选项。

输入输出

        单片机系统的输入、输出(如键盘、显示器、打印机等)往往是通过接口扩展实现的,访问时常采用“绝对地址访问”方式进行。51单片机还提供了一种“串口打印”输入输出方式:需引用头文件“stdio.h”,并配置串口(中断方式)。然后就可以用printf语句通过串口输入和输出数据了。

stdio.h:是标准C的输入输出库,但在C51中,将其制定为通过串口输入输出的相关函数。


完结

可以查阅相关内容:

51单片机内核及其工作原理-CSDN博客

有误之处望指正

  • 21
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

画凉ZL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值