先介绍下C语言中的变量类型,简单的说有局部变量和全局变量两种。
变量的声明,就是告诉编译器,要在内存当中划出一块空间来存储该变量,而这个空间的大小跟变量的数据类型有关,比如char类型、int类型、long类型等等,不同的操作系统和编译器相应的数据类型占用空间可能会有不同。
变量的定义,就是声明变量之后内存当中已经有一块地址了,而赋予这块地址上内容就是对变量的定义。通俗理解变量的声明和定义,声明就是我在空地上造了一个房间(房间的大小跟我要存放的物体大小有关),房间的门牌号就是该变量的名称;变量的定义就是我把要存放的物体放进该房间。这样很好理解吧。
好,继续讲讲什么是局部变量和全局变量。大家先建立变量的作用域这个概念,也就是说变量在哪个代码段中是有效的(即内存中有对应的地址)。顾名思义,局部变量的作用域是局部的,比方说某一函数的定义中声明了变量i,那么这个变量i的作用域仅限于这一函数。对于全局变量而言,其作用域就是自这个全局变量声明开始,至整个代码段其都是存在的。
好了知道全局变量和局部变量的作用域之后,我们再了解下变量的初始值。对于全局变量,我们在声明之后即使没有赋值,编译器默认该全局变量的初始值是0;对于局部变量情况就不是这样了,如果我们声明一个局部变量之后并没有赋初值,那么该局部变量的初始值是随机的。因此大家在写程序的时候要养成好的习惯,就是变量声明之后就要赋初值,避免自己找不到程序的BUG。关于C语言的变量这一节就先讲这些,下一节我们再深入一点,讲讲变量名称之前的关键字比如static的作用。
好了,继续上一节遗留的内容,那就是写单片机中断程序时要注意的点。单片机的中断处理机制大家都清楚了,就是当有中断源激励中断时单片机停止正在执行的任务,转而去响应中断服务程序,等处理完中断服务程序之后继续之前的任务。那么这里就会有一个问题不知道大家想过没有,就是单片机在处理中断服务程序时,该中断源又申请中断,这个时候单片机怎么办?以上一节的LED灯间隔1s闪烁为例,定时器0的定时时间是50ms,如果超出50ms后中断服务程序还没处理完,定时器0又申请了一次中断。单片机会再去响应该中断,也就是说又重新执行中断服务程序。这样一来未执行的代码一累积程序就乱了套。大家可以用proteus做个仿真,比如在中断程序里加个延时函数,看看仿真结果,这样就更加明白了。
所以在写中断程序时,我们要有一个认识:能在主程序中写的代码,就不要在中断服务程序中写,若非要在中断服务程序中实现功能,那要高效简洁。基于此,我们对上一节的代码改进一下。
#include<reg52.h> //包含头文件
sbit led = P0^0;
unsigned char count = 0; //定时累计变量,我们需要1000ms定时,50 * 20 = 1000
//count是全局变量,通俗地说就是程序每次重新执行时值保持住最近一次的值
void main()
{
TMOD = 0x01; //设置定时器0工作方式1,16位计数
TH0 = (65536 - 45872) / 256; //晶振11.0592MHz,定时50ms时TH0初值
TL0 = (65536 - 45872) % 256; //晶振11.0592MHz,定时50ms时TL0初值
EA = 1; //开启总中断
ET0 = 1; //开启定时器0中断
TR0 = 1; //启动定时器0
while(1)
{
if(20 == count) //1000ms定时时间到
{
count = 0; //清零,使得可以再次定时1000ms
led = ~led; //P0.0电平取反,也就实现LED灯的熄灭或者点亮
}
//这部分代码放到主函数里,中断服务程序中只有定时器初值的重新赋值和count变量的累加
}
}
void T0_INT() interrupt 1 //大家对照着上述格式看看
{
TH0 = (65536 - 45872) / 256; //晶振11.0592MHz,定时50ms时TH0初值
TL0 = (65536 - 45872) % 256; //晶振11.0592MHz,定时50ms时TL0初值
//重装初值,这个很好理解,我们需要每次定时的时间相同
count++; //每进入一次中断,也就是说50ms时间到了,count变量进行累计
//中断服务程序简洁,高效
}
这一节的内容就先到这里,顺便提下在实际工程项目中涉及到的中断程序就复杂了,因为有时候中断服务程序中的功能实现就需要较多的代码,怎么办?还有一个办法就是进入中断之后,首先设置EA=0,也就是停止单片机的中断功能,让单片机安安心心的执行完中断服务程序,跳出中断服务程序之后再设置EA=1,当然这要根据实际工程项目,进行具体的代码编写。