单片机C语言入门讲座
单片机内部资源编程

🏠 首页 《无线电》杂志 2004年 🔗 第5期 🔗 第39页 分类:电脑与单片机 🔗 周坚 🔗

通过前面课程的学习,我们已了解了“通用”的C语言特性,本文将介绍针对80C51单片机特性的C语言编程。

定时器编程

定时器编程主要是对定时器进行初始化以设置定时器工作模式,确定计数初值等,使用C语言编程和使用汇编编程方法非常类似,以下通过一个例子来分析。


例1:
用定时器实现P1所接LED每60ms亮或灭一次,设系统晶振为12M。

参考图1,在Keil软件中输入源程序,建立并设置工程,本例使用实验仿真板难以得到理想的结果,应使用硬件进行练习。

图1
图1 🔍原图 (532×278)

分析:
要使用单片机的定时器,首先要设置定时器的工作方式,然后给定时器赋初值,即进行定时器的初始化。这里选择定时器0,工作于定时方式,工作方式1,即16位定时/计数的工作方式,不使用门控位。由此可以确定定时器的工作方式字TMOD应为00000001B,即0x01。定时初值应为65536-60000=5536,由于不能直接给T0赋值,必须将5536转化为十六进制即为0\(_{x}\)15\(_{a}\)0,这样可以写出初始化程序:

TMOD=0x01;

TH0=0x15;

TL0=0xa0;

初始化定时器后,要定时器工作,必须将TR0置1,程序中用“TR0=1;”来实现。

可以用中断或查询的方式来使用定时器,本例使用查询方式。

由定时时间到后,TF0被置为1,因此,只需要查询TF0是否等于1即可得知定时时间是否到达,程序中用“if(TF0){...}”来判断,如果TF0=0,则条件不满足,大括号中的程序行不会被执行到,当定时时间到TF1=1后,条件满足,即执行大括号中的程序行首先将TF0清零,然后重置定时初值,最后是执行规定动作————取反P1.0的状态。

中断编程

C51编译器支持在C源程序中直接开发中断过程,使用该扩展属性的函数定义语法如下:

返回值 函数名 interrupt n

其中n对应中断源的编号,其值从0开始,以80C51单片机为例,编号从0~4,分别对应外中断0、定时器0中断、外中断1、定时器1中断和串行口中断。


1.中断应用实例

图2
图2 🔍原图 (535×306)

下面我们通过一个例子来说明中断编程的应用。


例2:
用中断法实现定时器控制P1.0所接LED以60ms闪烁。

参考图2输入源程序,设置工程,同样,本例用实验仿真板难以看到真实的效果,应使用硬件来完成这一实验。


分析:
本例与例1的要求相同,惟一的区别是必须用中断方式来实现。这里仍选用定时器T0,工作于方式1,无门控,因此,定时器的初始化操作与上例相同。要开启中断,必须将EA(总中断允许)和ET0(定时器T0中断允许)置1,程序中用“EA=1;”和“ET0=1;”来实现。在做完这些工作以后,就用for(;;){;}让主程序进入无限循环中,所有工作均由中断程序实现。

由于定时器0的中断编号为1,所以中断程序中这样写:

void timer0( ) interrupt 1

{...}

可见,用C51语言写中断程序是非常简单的,只要简单地在函数名后加上interrupt 关键字和中断编号就成了。


2.寄存器组切换

图3
图3 🔍原图 (176×426)

为进行中断的现场保护,80C51单片机除采用堆栈技术外,还独特地采用寄存器组的方式,80C51中有4组名称均为R0~R7的工作寄存器,通过设置RS0、RS1来切换工作寄存器组,这使得中断保护工作非常简单和快速。使用汇编语言编程时,内存使用均由编程者控制,编程时可直接设置RS0、RS1,但用C语言编程,内存由编译器分配和使用,因此,不能自行设置RS0、RS1,否则会造成内存使用的冲突。

在C51中,寄存器组选择取决于特定的编译器指令,即使用using n指定,其中n的值是0~3,对应使用4组工作寄存器。

例如上述例子中可以这么样来写:void timer0() interrupt 1 using 2

{...}

表示在该中断程序中使用第2组工作寄存器。

串行口编程

80C51系列单片机上有UART用于串行通信,80C51中有两个SBUF(缓冲器),一个用作发送缓冲器,一个用作接收缓冲器,在完成串口的初始化后,只要将数据送入发送SBUF,即可按设定好的波特率将数据发送出去,而在接收到数据后,可以从接收BUF中读到接收到的数据。下面通过一个例子来了解串行口编程的方法。


例3:
单片机P1口接8只发光二极管,P3.2~P3.5接有SK1~K4共4个按键,使用串行口编程,(1)由PC机控制单片机的P1口,将PC机送出的数以二进制形式显示在发光二极管上;(2)按下K1向主机发送数字0x55,按下K2向主机发送数字0xAA,使显示转下一行。

#define uchar unsigned char

#include “string.h”

#include “reg51.h”

void SendData(uchar Dat)

{ uchar i=0;

SBUF=Dat;

while(1){ if(TI)

{TI=0;

break;}}

€?€?}

void mDelay(unsigned int DelayTime)

{ unsigned char j=0;

for(;DelayTime>0;DelayTime——)

{for(j=0;j<125;j++)

{;}

€?€?}

€?€?}

uchar Key()

{ uchar KValue;

P3|=0x3e;//中间4位置高电平

if((KValue=P3|0xe3)!=0xff)

{mDelay(10);

if((KValue=P3|0xe3)!=0xff)

{for(;;)

if((P3|0xe3)==0xff)

return(KValue);

€?€?}

€?€?}

return(0);

€?€?}

void main()

{ uchar KeyValue;

P1=0xff; //关闭P1口接的所有灯

TMOD=0x20;//确定定时器工作模式

TH1=0xFD;

TL0=0xFD; //定时初值

PCON&=0x80;//SMOD=1

TR1=1; //开启定时器1

SCON=0x40; //串口工作方式1

REN=1; //允许接收

for(;;)

{if(KeyValue=Key())

{if((KeyValue|0xfb)!=0xff)//K1按下

SendData(0x55);

if((KeyValue|0xf7)!=0xff)

SendData(0xaa);

€?€?}

if(RI)

{P1=SBUF;

RI=0;

€?€?}

€?€?}

€?€?}


实现过程:
输入程序,命名为exam53.c,建立名为exam53的工程,将文件加入,设置工程,使用实验仿真板进行调试。正确编译连接后进入调试,打开实验仿真板(见今年第1期配刊光盘中提供的Dpj.dll文件),然后再点击view——>serial #1打开串行窗口,在窗口空白处点右键,在弹出式菜单中选择“Hex Mode”,如图3所示。

单击实验仿真板的K1键和K2键,即可看到串行窗口中分别出现55和AA;单击串行窗口的空白处,使其变为活动窗口,可接收键盘输入,按下键盘上不同的字符键,可见实验仿真板上的LED产生相应的变化。在实验仿真板上按下K1一次、K2连续两次、再按一次K1后,串行窗口中的状态如图4上部所示;在计算机键盘上按下“1”后实验仿真板显示的状态如图4下部所示。“0”使灯亮,“1”使灯灭,因此P1口的值为00110001,即0x31,这正是字符1的ASCII码值。


程序分析:
本程序使用T1作为波特率发生器,工作于方式2(8位自动重装入方式),波特率为19200,串行口工作于方式1,根据以上条件算出T1的定时初值为0xfd,TMOD应初始化为0x20,SMOD初始化为0x30,PCON中的SMOD位置1,主程序main的开头对这些初值进行了设置。设置好初值后,用“TR1=1;”开启定时器1,用“REN=1;”允许接收数据,然后进入无限循环中开始正常工作。在这个无限循环中首先调用键盘程序,检测是否有键按下及哪一个键被按下,如果K1被按下,则调用发送数据程序,将数0x55送出,如果K2被按下,则将数0xAA送出。接着检测RI是否等于1,如果RI等于1,说明接收到字符,清RI,准备下一次接收,并将接收到的数据送往P1口显示。一次循环结束,继续开始下一次循环。

发送函数SendData中有只有一个参数Dat,即待发送的字符,函数将该待发送的字符送入SBUF后,使用一个无限循环等待发送的结束,在循环中通过检测TI来判断数据是否发送完毕,发送完毕使用break语句退出循环。

该实验同样可用硬件实现,下面介绍使用前面课程中提到的仿真型实验板做实验的方法。由于该板占用了串口作为仿真机与PC机的通信,因此做串口通信类实验只能用下载后全速运行的方法,具体步骤如下:

1.设置工程,在Debug页中选择“Use Keil Monitor Drive”,点击Setting按钮,将通信的波特率设置为19200;

2.进入调试后全速运行程序,然后按Debug->Stop Runing,按提示退出调试状态,实际上这不并会中断硬件电路的工作;

3.在PC机上运行一个串口调试软件,这里以“串口调试助手”软件为例(读者可到www.skycn.com/soft/5480.html上下载该软件),按图5设置串口参数。按下实验板上的K1,串口调试助手的接收窗口即可接收到0x55和0xAA,在串口调试助手的输出窗口中键入数据,即可由实验板接收并由P1显示出来。

今后我们将通过一些综合性的例子的介绍,继续学习采用C语言编程的有关技术。

(周坚)