目录
前言:此篇文章仅仅写出了C51和标准C之间的差异,具体C语言知识请见C语言专栏。
C51与标准C的差异
- C51中的数据类型与标准C语言的数据类型也有一定的区别
- C51在变量的定义与使用上与标准C语言不一样
- 为了方便对51单片机硬件资源进行访问,C51在绝对地址访问上对标准C语言进行了扩展
- C51中函数的定义与使用与标准C语言不完全相同
C51的数据类型
位类型
前言:访问MCS-51单片机的可寻址的位单元在内存中只占一个二进制位,其值可以是1或0
支持两种位类型:bit型和sbit型
- bit定义的位变量在用C51编译器编译时,不同的时候分配的位地址不一样
- sbit定义的位变量必须与MCS-51单片机的一个可以位寻址的位单元联系在一起,在C51编译器编译时,其位地址是不可变化的
#include "reg51.h"
//a的地址和P3^1的地址不一样,只与P3^1的值一样
bit a=P3^1;
//a的地址和P3^1的地址一样
sbit a=P3^1;
sbit OV=0xd2;
注意:定义的位变量bit必须位于片内数据存储器的位寻址区;
bit data a1; //正确
bit xdata a2; //错误
特殊功能寄存器型
前言:访问MCS-51单片机的特殊功能寄存器分为sfr和sfr16
- sfr为字节型特殊功能寄存器类型,占一个内存单元,可以访问MCS-51内部的所有特殊功能寄存器
- sfr16为双字节型特殊功能寄存器类型,占2个字节单元,可以访问MCS-51内部的所有2个字节的特殊功能寄存器
注意:为了与一般的变量相区别,特殊功能寄存器变量名一般用大写字母表示。地址一般用直接地址行式。为了使用方便,特殊功能寄存器变量名取名时一般与相应的特殊功能寄存器名称相同
//访问8位寄存器
sfr PSW=0xd0;
//访问16位寄存器
sfr16 T0=0x8A;
C51变量和存储器类型
格式:[存储种类] 存储类型说明符 [存储器类型] 变量名1[=初值],变量名2[=初值];
存储种类:分别是自动(auto)、外部(extern)、静态(static)和寄存器(register)
数据类型说明符:char、int等
存储器类型
前言:存储器类型指明变量所处的单片机的存储区域与访问方式。
//在片内RAM低128B定义,用直接寻址的方式访问字符型变量var1
char data var1;
//在片外RAM64KB空间定义用间接寻址的方式访问外部实型变量var4
extern float xdata var4;
变量名:变量名的定义规则请详见C语言基础知识。
存储模式
- SMALL模式:SMALL模式称为小编译模式,在该模式下,编译时变量被默认在片内RAM中,存储器类型为data(默认的情况下采用的就是该种模式)
- COMPACT模式:COMPACT为紧凑编译模式,在该模式下,编译时变量被默认在片外RAM的低256B空间,存储器类型为pdata
- LARGE模式:LARGE模式被称为大编译模式,在该模式下,编译时变量被默认在片外RAM的64B空间,存储器类型为xdata
注意:存储模式可以通过#pragma预处理命令来定义
//变量的存储模式默认为SMALL
char k1; //k1变量的存储器类型为data
int xdata m1; //m1变量的存储器类型为xdata
//预处理使存储模式为compact
#pragma compact
char k2; //k2变量的存储器类型为pdata
int xdata m2; //m2变量的存储器类型为xdata
使用C51运行库中预定义宏
使用前导库:#include <absacc.h>
- CBATE:以字节的行式对code区寻址
- DBYTE:以字节的行式对data区寻址
- PBYTE:以字节的行式对pdata区寻址
- XBYTE:以字节的行式对xdata区寻址
- CWORD:以字的行式对code区寻址
- DWORD:以字的行式对data区寻址
- PWORD:以字的行式对pdata区寻址
- XWORD:以字的行式对xdata区寻址
访问方式:宏名[地址]
案例举例
#include <absacc.h>
//向0x0005里面取var1变量
var1=XBYTE[0x0005];
//向0x0002里面取var2变量
var2=XWORD[0x0002];
C51的指针变量
前言:使用指针可以很方便有效的表达复杂的数据结构;可以动态的分配存储器,直接处理内存地址
分为存储器型指针和一般指针两种
- 存储器型指针:定义时指明了所指向数据的存储器类型——char xdata *p2
- 一般指针:定义时没有指明所指向的数据的存储器类型
指针简单操作
#include <stdio.h>
int main() {
int a = 56;
printf("%p\n",&a);
//通过指针获取a的地址
int* pa = &a;
//取出该地址的内容
*pa = 20;
printf("%d\n", a);
return 0;
}
位寻址
前言:在单片机系统中,操作任意寄存器或者某一位的数据时,必须给出其物理地址,又因为一个寄存器里有8位,所以,位的数量是寄存器数量的8倍,单片机无法对所有的位进行编码,故每8个寄存器中,只有一个是可以位寻址的。对不可位寻址的寄存器,若只要操作其中一位而不影响其他位时,可用“&=”、“|=”、“^=”的方法进行位操作。
- &=:其一般作用为对某一位进行清零,若想要对a的第0位清零,则就可以a&=0xFE
- |=:其一般作用为对某一位数据进行置1,若想对a的第0位置1,则就可以a|=0x01
- ^=:将某位数据与1进行异或,相同置1,相异为0
位寻址与不可位寻址寄存器
C51的扩展关键字_at_
格式:[存储器类型] 数据类型说明符 变量名 _at_ 地址常数;
作用:指定变量到哪个地址存放。
//指定变量x1到0x40地址存放
data unsigned char x1 _at_ 0x40;
C51中的函数
前言:C51程序与标准C语言类似,程序也由若干函数构成,程序也由主函数main()开始,并在主函数中结束,除了主函数外,也有标准库函数和用户自定义函数。标准库函数是由C51编译器提供的,不需要用户进行定义,可以直接调用。用户也可以自己定义函数。他们的使用方法与标准C语言基本相同。但C51针对的是51系列单片机,C51的函数在有些方面还是和标准C语言不同,参数传递和返回值与标准C语言中是不一样的,而且C51又对标准C语言做了相应的扩展。扩展有:选择存储模式;指定一个函数作为一个中断函数;选择所用的寄存器组等。
C51函数的参数传递
- 一种是通过寄存器R0-R7传递参数
- 第二种是通过固定的存储区传递
C51函数的返回值
前言:函数的返回值通常用寄存器传递。
C51函数的存储模式
- SMALL模式:小编译模式,在该模式下,编译时函数参数和变量被默认在片内RAM中,存储器类型为data(默认模式)
- COMPACT模式:紧凑编译模式;在该模式下编译时函数参数和变量被默认在片外RAM的低256B空间中,存储类型位pdata
- LARGE模式:大编译模式;在该模式下,编译时函数参数和变量被默认在片外RAM的64B空间,存储类型位xdata
注意:函数定义时后面再相应的参数(small,compact或large)来指明,系统隐含为SMALL模式
//函数的存储模式为large,x1,y1,z1变量的存储器类型为xdata
int func1(int x1,int y1) large
{
int z1;
z1=x1+y1;
return(z1);
}
C51中的中断函数
前言:定义函数时后面用了interrupt m修饰符,则把该函数定义成中断函数。系统对中断函数编译时会自动加上程序头段和尾段,并按照MCS-51系统中断的处理方式把他安排在程序存储器的相应位置
注意:m的取值为0-31,对应的中断情况如下
- 0:外部中断0
- 1:定时/计数器T0
- 2:外部中断1
- 3:定时/计数器T1
- 4:串行口中断
- 5:定时/计数器T2(52扩展的)
中断函数注意事项
- 中断函数不能进行参数传递(若要传递需要用全局变量)
- 中断函数没有返回值
- 在任何情况下都不能直接调用中断函数
- 若在中断函数中调用了其他函数,则被调用函数所使用的寄存器必须与中断函数相同
- C51编译器对中断函数编译时会自动在程序开始和结束处加上相应的内容
- C51编译器从绝对地址8m+3处产生一个中断向量
- 中断函数最好写在文件的尾部,并且禁止使用extern存储类型说明
extern int x;
//外部中断
void int0() interrupt 0 using 1
{
x++;
}
C51函数的寄存器组
前言:定义时带using n修饰符,其中n的取值为0——3
void func3(void) using 1
{……}
对于using n修饰符的使用,应注意以下几点
- using n修饰符不能用于有返回值得函数
- 加入using n后,C51在编译时自动在函数得开始处和结束处加以下指令
{
PUSH PSW
MOV PSW //与寄存器组号n相关的常量
……
POP PSW
}