C51简介及Keil的使用

C51简介及Keil的使⽤
前⾔
此⽂档主要是针对有⼀定C/C++编程基础,并打算⽤Keil从事C51开发的开发⼈员。C51涉及的知识⽐较多,但是⼊门基本的开发,还是容易的。
C51简介
1.  C51概念
C51继承于C语⾔,主要运⾏于51内核的单⽚机平台。单⽚机,单⽚微型计算机器(SingleChipMicrocomputer)的简称,⼜称微控制单元(MicroControllerUnit,MCU)。MCU由CPU、RAM、ROM、I/O、中断系统、晶振等组成。51内核的单⽚机都是8位的,因为数据I/O是8位的,但是地址总线是16位的。基于51内核的单⽚机有很多种,如8051、80515等。
存储器:包括⽚内存储器、⽚外存储器。⽚内存储器⼀般包括256字节的⽚内RAM,和8K字节的程序存储器ROM。⽚外储存器XRAM可达64K字节。⽚外存储器是相对于51内核⽚内存储器⽽⾔的,基于51内存开发的单⽚机,⼀般是将⽚外存储器集成到MCU中去了。声明为XDATA的内存,MCU就知道是XRAM,会使⽤XRAM总线协议来操作XRAM内存,这⼀过程在⽤户层⾯是看不到的。51内核的数据Pin
是8位,地址Pin是16位的,所以可以操作最多64K的⽚外存储器。
256字节的⽚内RAM:
名称地址范围备注
⼯作寄存器组00x00—0x07此组⽤作默认的寄存器
⼯作寄存器组10x08—0x0F此组常⽤作中断函数寄存器
⼯作寄存器组20x10—0x17⼯作寄存器若未使⽤,可⽤作堆栈计算
⼯作寄存器组30x18—0x1F
位寻址区0x20—0x2F此区域可位寻址(bit)
堆栈区0x30—0x7F此区域可⽤于堆栈计算
0x80—0xFF地址为8倍数SFR可位寻址
引脚:51单⽚机的管脚⼀般主要包括电源、时钟、控制和I/O脚。
电源:VCC,接电源;VSS接地。
时钟:接晶振。
控制线:ALE、EA等控制脚。
I/O线:4个8位并⾏I/O端⼝,分别为P0、P1、P2、P3⼝,每个⼝8个引脚共32引脚。
2. C51语法
1. 数据类型
基本数据类型名称长度取值范围
unsigned char⽆符号类型1byte0~255shuangwang
signed char有符号类型1byte-128~127
unsigned int⽆符号类型2byte0~65536
signed int有符号类型2byte-32768~32767
unsigned long⽆符号类型4byte0~4294967295
signed long有符号类型4byte-2147483648~2147483647
float浮点类型4byte+-1.75494E-38~+-3.402834E+38
bit位类型1bit0/1
Sfr8位特殊功能寄存器1byte0~255
sfr1616位特殊功能寄存器2byte0~65536
sbit可寻址位类型1bit0/1
定义:临时变量只能定义在代码块的最开始,即”{“后⾯,且变量定义前不能有⾮定义语句。因为Keil能够在编译时就⽐较好确定栈内存,如果超过限定内存会报编译错误。(此处基于C89规范,C99没有此限制。)
申明:如果外部⽂件需要使⽤全局变量,使⽤extern来限定。
初始化:全局变量和局部变量,如果没有指定初始化值,默认为0。
bit:位类型,bit指定的变量可以直接按拉寻址,所以需要特殊的内存匹配,即位寻址区(0x20—0x2F),可申明最多128个bit类型的变量。
sfr:特殊功能寄存器(special function register),只能定义在函数体外,且必须指定特殊功能寄存器地址。
sfr16:16位的特殊功能寄存器,可以完成⼀些需要16位的特殊功能。
sbit:特殊功能寄存器位变量,是针对sfr的。但是因为位寻址效率的问题,所以只有地址为8倍数的sfr才可以被位寻址。sbit也只能定义在函数体外。⽤法如下:
sfr IE = 0xA8;
sbit EXO = IE^0; // 0xA8的第1位,相当于IE⼝的第0管脚
sbit EX7 = IE^7; // 0xA8的第8位,相当于IE⼝的第7管脚
sbit EX01 = 0xA8;// 0xA8的第1位,相当于IE⼝的第0管脚
sbit EX71 = 0xAF;// 0xA8的第8位,相当于IE⼝的第7管脚
sbit EXO2 =0xA8^0; // 0xA8的第1位,相当于IE⼝的第0管脚
sbit EX72 =0xA8^7; // 0xA8的第8位,相当于IE⼝的第7管脚
注:80C51的特殊功能寄存器只有21字节可以使⽤,其他的字节⽆定义,也不能进⾏读写操作。
2. 储存器类型和指针
存储器类型描述
data直接寻址的⽚内RAM低128Byte,访问速度快
badta⽚内RAM的可位寻址区(20H~2FH),允许字节和位混合访问
idata间接寻址访问的⽚内RAM,允许访问全部⽚内RAM
pdada⽤Rn间接访问的⽚外低256Byte
xdata⽤DPTR间接访问⽚外RAM,允许访问全部64KB的⽚外RAM
code程序存储器64KB ROM
char* pStr;  // 指针占3个字节,第1字节标识存储器类型,第2字节为指针存储地址的⾼字节,第3字节为指针存储地址的低字节。(未注明存储器类型即为默认存储器类型,由Keil的编译环境控制,且默认的存储器类型是修饰指针的)
char* idatapStr1; // 指针占3个字节,此处指定指针值的存储器类型为idata。
char* xdatapStr2; // 指针占⽤3个字节
char* codepStr3; // 指针占⽤3个字节,code的作⽤类似于const
char idata *pStr4; // 指针占⽤1个字节,idata是修饰pStr4指向的内容。idata表⽰的⽚内RAM最多只256字节,所以pStr4也只需要1个字节即可表⽰。
char xdata *pStr5; // 指针占⽤2个字节,xdata修饰的是pStr5指向的内容,⽽xdata表⽰的⽚外内存最多64K,所以2个字节⾜够。
char code *pStr6; // 指针占⽤2个字节
char idata *xdata pStr7; // 指针占⽤1个字节,因为pStr7指向的内容是idata
char xdata *idata pStr8; // 指针占⽤2个字节,因为pStr8指向的内容是xdata
综上所述,指针的⼤⼩分两类,未指明指向内容的存储器类型,此类指针⼤⼩为3字节。
指明了指针指向内容的存储器类型的指针⼤⼩为内容存储器的⼤⼩。
注:因为指针的⼤⼩及类型不是固定的,所以指向两个不同类型的指针不能赋值,只能通过解引⽤间接赋值。
3.  volatile
volatile是⽤来限定变量告诉编译器,此变量可能会被特殊的情况修改,所以对此变量的操作不要做优化,直接从内存上存取。Keil编译器为了执⾏效率,都是将变量存放到寄存器上再来操作的,这就导致第⼆次取变量值时,可能是直接从寄存器中取值,⽽不是从内存上读取。那么有⼀些特殊操作可能发⽣在⼆次取值过程中,导致第⼆次取值没有更新到。
char xdata g_value1;
char volatile xdatag_value2;
int main()
{
char cArg = g_value1; // 1
900000 MOV DPTR, #C_STARTUP(0x0000)
E0  MOVX    A, @DPTR
FE    MOV    R6, A
if (g_value1 != cArg) // 2
6E      XRL      A, R6  // g_value1此刻是直接从寄存器中取值
cArg = 6;
cArg = g_value2;
900001  MOV    DPTR, #g_value2(0x0001)
E0      MOVX    A, @DPTR
FE      MOV    R6, A
if (g_value2 != cArg)
E0      MOVX    A, @DPTR // g_value2此刻是从内存中取值
6E      XRL    A, R6
cArg = 5;
return 0;
}
上⾯的代码很好的体现了volatile的特殊作⽤。如果在1和2之间有⼀些特殊情况修改了变量g_value1将导致错误。所以这样的⼀些特殊情况涉及到的变量,必须⽤volatile修饰,具体如下:
汇编代码修改的变量(⼀般情况下汇编代码不要修改外部变量)
硬件寄存器修改的变量(即指硬件寄存器值本⾝)
中断函数修改的全局变量
4. 中断函数
中断,顾名思义就是中断当前代码的执⾏流。中断函数即中断之后响应的函数。中断根据中断源类型不同,主要分为:外部中断,定时器中
断、串⼝中断等。中断的实现原理是,CPU执⾏每条代码前,都会去检查中断标志位,如果中断标志位有信号,即响应中断函数。函数的执
⾏是需要堆栈和寄存器的,那么中断函数的执⾏如何不破坏当前函数的堆栈和寄存器呢?C51有⼀个特殊的实现⽅式,即提供多套⼯作寄存
器器,且堆栈和当前代码共⽤。这样当中断函数执⾏时,原有代码的运⾏环境就得以保存,中断函数结束后,就可以恢复当前代码执⾏流
程。
甲烷制氢
中断函数的格式如下:void ExternINT0(void) interrupt 0 using 1
interrupt 0表⽰0号中断。using 1表⽰使⽤⼯作寄存器组1,如果不指定则使⽤默认⼯作寄存器组0,可能会与通⽤函数的⼯作寄存器冲
突。另外中断函数中的使⽤的全局变量如果和主流存在同时写操作,那么在主流写时,需要关闭中断防⽌写冲突,等写完成之后再开启中
断。
寒冬料峭
void ExternINT0(void) interrupt 0 using 1
{
g_value1++;
}
int main()
{
EA = 1;  // 开启所有中断
EX0 = 1;  //开启外部中断0,对应0号中断
IT0 = 1; // 外部中断0触发⽅式
IE0 = 1; // ⼿动触发中断0,中断函数执⾏后,此标志变为0
return 0;
}
5. 绝对地址
因为C51是直接与硬件交互,为了提⾼代码的执⾏效率,硬件的⼀些特殊功能可能会直接访问指定地址的变量和执⾏指定地址的函数。这些
指定地址是固定不变的,是绝对地址。
变量绝对地址定位
char idata myVar_at_ 0x40; // _at_关键字,指定idata区域的绝对地址0x40;编译链接之后在MAP⽂件中可以到如下信息00000040H  IDATA  BYTE      myVar,即表明char xdata myVal _at_ 0x400; // 指定xdata区域的0x400;
struct link list idata _at_ 0x40; // list at idata 0x40
char xdata text[256]  _at_ 0xE000; // array at xdata 0xE000
在Options for target->LX51 Locate->User Segments编译框中添加:
COtext(x:0xE000)
CO表⽰Code,全局数组定义之后,是会被放在Code中
text表⽰变量名
x:0xE000,表⽰指定的内存为xdata类型,地址为0xE0000
函数绝对地址定位
在Options for target->LX51 Locate->User Segments编译框中添加:
PRMyTestMAIN(0x4000)
2011江苏高考数学
PR表⽰program  Executable program code
MyTest表⽰函数名
MAIN表⽰所在⽂件名哈尔滨学院图书馆
0x4000表⽰函数绝对地址
绝对地址的访问
1. 可以通过汇编直接访问绝对地址变量及函数
2. 可以通过将绝对地址赋值给指针访问变量及函数
6. 可重⼊(reentrant)
⼀个函数如果被主流程调⽤,另外⼜被中断函数调⽤,那么这个函数即重⼊了。这样的函数可能存在问题。如下列,主流程执⾏到2,然后触发中断函数了,并同样执⾏了下列函数,那么寄存器Exam可能已经被修改。即使此时退回到主流执⾏2,结果可能是错误的。这个时候Keil引⼊了reentrant,通⽤模拟堆栈⽤来避免此类问题。因为是模拟的,效率低,⾮必须不要使⽤。
unsigned int Test(int nVal) reentrant
{
unsigned int nRet = 0;
Exam = nRet;            // 1
中铁航空港nRet =Square_Exam( );  // 2
return nRet;
}
7. 看门狗
看门狗(Watch Dog),其作⽤是监控单⽚机程序的运⾏,如果程序跑飞或者进⼊死循环等意外状态,看门狗则将单⽚机进⾏复位,让程序重新开始运⾏。看门狗的实现⽅式,有硬件⽅式和软件⽅式。硬件⽅式是通过外部芯⽚来监控,并由外部芯⽚来控制复位。软件⽅式,即单⽚机本⾝通过定时器来对程序运⾏状态进⾏定时监控,如果在发现状态则将单⽚机复位。因为看门狗主要是通过定时器实现,所以看门狗定时器(Watch Dog Timer,WDT)⼀般会作为⼀个独⽴的组成部分。
看门狗(WDT)设计原理是,⼀个定时器模块,⼀个输⼊端(叫喂狗,kicking the dog or servicethe dog),还有⼀个控制单⽚机的RST 端。每隔⼀段时间必须喂狗将WDT清0。如果指定时间没有检测到喂狗,看门狗定时器即会超时,然后重置RST端让单⽚机复位。
89C51默认是不带看门狗的。89S51是在89C51的基础上进⾏的扩展,添加了看门狗功能,此处⽤89S51为例说明看门狗具体⽤法。以下资料来⾃89C51的Datasheets。

本文发布于:2024-09-25 10:37:37,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/445717.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:中断   函数   变量   类型   内存   地址
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议