
1.3 C51编程举例
下面通过MCS-51内部功能部件的简单应用的例子,加深对C51程序结构及单片机的C语言编程的理解。
【例1-5】 Proteus仿真电路如图1-2所示,8个发光二极管D1~D8经限流电阻分别接至P1口的8个引脚,阳极共同接高电平。编程实现发光二极管的流水点亮,即按照D1→D2→…→D8的顺序,每次点亮一个发光二极管,一段时间后熄灭该发光二极管,然后点亮下一个发光二极管,重复循环。

图1-2 例1-5的Proteus仿真电路图
C51源程序如下:
#include<reg51.h> #include<intrins.h> //移位库函数包含于此头文件中 void delay(unsigned int d) //定义延时子函数 { while(--d>0); } void main() { unsigned char i,sel; while(1) { sel=0xfe; for(i=0;i<8;i++) { P1=sel; //显示变量赋给P1口 delay(50000); //延时 sel=_crol_(sel,1); //改变显示变量 } } }
也可以这样编程:
#include<reg51.h> void delay(unsigned int d) { while(--d>0);} void main() { unsigned char i,sel,a;
while(1) { sel=0xfe; for(i=0;i<8;i++) { P1=sel; delay(50000); a=a<<1; sel=sel|0x01; } } }
【例1-6】 单片机的P1口接8个发光二极管,P0口接8个开关,编程实现当开关动作时,对应的发光二极管亮或灭。
只需把P0口的内容读出后,通过P1口输出即可。
汇编语言源程序如下:
ORG 0000H MOV P0,#0FFH LOOP: MOV A,P0 MOV P1,A SJMP LOOP
C51语言源程序如下:
#include<reg51.h> void main(void) { unsigned char i; P0=0xff; for(;;) { i=P0; P1=i; } }
【例1-7】 单片机外接12 MHz晶振,用P1.7输出1 kHz和500 Hz的音频信号驱动扬声器,作为报警信号,要求1 kHz信号与500 Hz信号交替进行,P1.0接一个开关S进行控制,当开关合上时,响报警信号,当开关断开时,报警信号停止,Proteus仿真电路如图1-3所示。

图1-3 例1-7的Proteus仿真电路图
C51源程序如下:
#include<reg51.h> #include<intrins.h> //空操作库函数包含于此头文件 sbit S=P1^0; //定义位变量 sbit BUZ=P1^7; //定义位变量 unsigned char k; //定义循环变量 void delay(void) //定义延时子函数 { unsigned char i; for(i=250;i>0;i--) { _nop_(); //空操作 } } void main(void) { while(1) { BUZ=0; //关闭声音 S=1; if(S==0) //判断开关是否闭合 { BUZ=0; delay(); BUZ=0; delay(); BUZ=1; delay(); delay(); BUZ=0; delay(); delay(); } } }
注意:此例中的定时和音频信号频率不是很准确,如果实际使用中对周期或定时要求精确度较高,可以采用定时/计数器来实现。
【例1-8】 使用定时/计数器以工作方式2产生100 μs定时,在P1.0口输出周期为200 μs的连续方波,已知晶振频率为6 MHz。
机器周期频率:fcy = f /2/6 = 0.5 MHz,Tcy = 2 μs
定时器预置值(初值)N:28 - N = T/Tcy = T × fcy = 50
N = 206 = 0CEH
定时/计数器0工作于方式2,定时方式,其方式控制字:TMOD=02H。
在程序中,头文件reg51.h中定义了8051的I/O端口、特殊功能寄存器和特殊功能位等符号,这些符号可以像用户变量一样在程序中直接使用。主函数main( )完成定时/计数器0的初始化,CPU开中断,然后进入一无限循环,等待P1.0引脚上的方波输出。
方波输出由中断服务函数timer0( )产生。函数属性interrupt 1将timer0( )声明为定时/计数器0的中断服务函数,而函数属性using 3使中断发生时切换到寄存器组3,这样可以减少中断现场保护的时间,提高中断服务的实时性。
C51源程序清单如下:
/***********200μs周期方波发生程序**************/ #define T0_VALUE 0xCE #define TMOD_VALUE 0x02 /*定时/计数器0方式控制字*/
#include<reg51.h> void main() { TMOD=TMOD_VALUE; /*T0按定时方式2*/ TH0=T0_VALUE; /*置定时器重装初值寄存器*/ TL0=T0_VALUE; /*装计数初值到定时器的8位加法计数器*/ EA=1; /*CPU开中断*/ ET0=1; /*T0允许中断*/ TR0=1; /*启动T0*/ while(1); /*等待P1.0引脚上输出方波信号*/ } void timer0(void) interrupt 1 using 3 { P1=P1^0x01; /*将P1.0取反后输出*/ }