第3章 C51入门例题Word文档下载推荐.docx
《第3章 C51入门例题Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《第3章 C51入门例题Word文档下载推荐.docx(14页珍藏版)》请在冰豆网上搜索。
AT89X51.H>
voidmain(void)
constunsignedchardesign[32]={0xFF,0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F,
0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0xFE,0xFF,
0xFF,0xFE,0xFC,0xF8,0xF0,0xE0,0xC0,0x80,0x0,
0xE7,0xDB,0xBD,0x7E,0xFF};
//定义花样数据
unsignedinta;
//定义循环用的变量
unsignedcharb;
//因内存有限,在C51编程中要注意变量类型的使用
do{//dowhile型循环
for(b=0;
b<
32;
b++)
for(a=0;
a<
30000;
a++);
//延时一段时间
P2=design[b];
//读已经定义的花样数据并写花样数据到P2口
}
}while
(1);
[实验3-3]调用延时函数的流水灯程序。
如下程序中将延时循环语句单独编写成延时函数,并利用循环移位指令实现P2口的流水灯的流动。
reg51.h"
//通用51头文件
intrins.h"
//C51函数库,具有移位函数
#defineucharunsignedchar//重新定义unsignedchar类型名为uchar
#defineuintunsignedint//重新定义unsignedint类型名为uint
voidmDelay(unsignedintDelay)//具有延时参数的延时函数
{unsignedinti;
for(;
Delay>
0;
Delay--)
{for(i=0;
i<
124;
i++);
voidmain()//主函数
{unsignedcharOutData=0xfe;
//定义输出数据与初值
;
)//无限循环
P2=OutData;
//将OutData输出到P2口,使P2口中的一个LED灯亮
OutData=_crol_(OutData,1);
//使OutData循环左移,使亮的LED灯左移一位
mDelay(100);
//调用延时函数
[实验3-4]P3_2引脚连接的按键控制的流水LED灯
该实验中的按键控制P2口连接的流水LED灯是否流水,如果按键按下,使流水灯流水,否则流水灯全灭。
#include"
//该文件包含有_crol_()函数的定义
voidmDelay(unsignedintDelayTime)//延时函数
{unsignedintj=0;
DelayTime>
DelayTime--)
{for(j=0;
j<
125;
j++);
{
unsignedcharOutData=0xfe;
//定义变量为0xfe
while
(1)//无限循环
P3|=0x3c;
//00111100将P3口中间4位置1
while((P3|0xfb)!
=0xff)//11111011=0xfb若是P3_2引脚为1,则该循环条件不成立
{//若是P3_2引脚为0(按键按下),则该循环条件成立
//将OutData输出到P2口相连的LED灯
//将OutData循环左移1位
P2=0xff;
//将连接在P2口的LED灯熄灭
[实验3-5]采用移位指令实现的流水灯。
八个LED灯L1-L8分别接在单片机的P2.0-P2.7引脚上,输出“0”时,LED灯亮,按照P2.0→P2.1→P2.2→P2.3→┅→P2.7→P2.6→┅→P2.0顺序点亮,重复循环。
源程序如下:
unsignedchari;
//定义循环次数变量
unsignedchartemp;
//定义被循环的变量
unsignedchara,b;
//定义循环中间值变量
voiddelay(void)//定义延时函数
unsignedcharm,n,s;
for(m=20;
m>
m--)
for(n=20;
n>
n--)
for(s=248;
s>
s--);
}
voidmain(void)//主函数
{while
(1)
temp=0xfe;
//设置循环初值
P2=temp;
//送P2口显示
delay();
for(i=1;
8;
i++)//正向循环流水
a=temp<
<
i;
//如果i=1,a=1111,1100,i=2,a=11111000
b=temp>
>
(8-i);
//如果i=1,b=00000001,i=2,b=00000011
P2=a|b;
//如果i=1,P2=11111101,i=2,P2=11111011
i++)//反向循环流水
a=temp>
b=temp<
}}}
[实验3-6]用查表法控制P2口连接的8个LED灯。
可以按照需要自行加入表格元素,编辑表格元素时,应该先画显示的LED灯点亮图形,方法如下:
图型(0表示灯亮)
十六进制编码
01111110
7e
10111101
bd
11011011
db
11100111
e7
等等
unsignedcharcodetable[]={0xfe,0xfd,0xfb,0xf7,
0xef,0xdf,0xbf,0x7f,
0xfe,0xfd,0xfb,0xf7,
0x7f,0xbf,0xdf,0xef,
0xf7,0xfb,0xfd,0xfe,
0x00,0xff,0x00,0xff,
0x7e,0xbd,0xdb,0xe7,
0x7e,0x3c,0x18,0x00,0x01};
//元素中只能有一个0x01,因为0x01是最后一个元素标志。
voiddelay(void)//定义延时函数
{unsignedcharm,n,s;
voidmain(void)//主函数
while
(1)//无限循环语句
if(table[i]!
=0x01)//判断是否是表格的最后一个元素
P2=table[i];
//将表格元素赋予P2口,在与P2口相连的LED灯上显示
i++;
//准备显示下一个表格元素
//调用延时函数延时
else//如果是最后一个元素,使循环次数变量为0
{i=0;
}}}
3.2具有定时器的C51程序实验
[实验3-7]定时器中断控制LED闪烁。
由于51单片机从中断发生到进入中断的时间不定,是3至8个机器周期,在进入了中断后,软件才重新置定时器初始值,这样就会存在定时误差。
不是精确定时,如果要精确定时,需要使用定时器自动装载方式,也就是在定时器溢出的同时,硬件逻辑就自动把定时器初始值装载进去,而不是在中断服务程序里赋初始值,只有这样才可以实现精确定时,在精确定时的情况下,定时误差由晶振的频率不稳定引起。
中断引起P2.0引脚连接的LED灯闪烁。
TMOD=0X01;
//定时器0,工作模式1,16位定时模式,GATE=0,C/T=0
TR0=1;
//启动定时器
ET0=1;
//允许定时器中断
EA=1;
//允许总中断
while
(1);
//无限循环
timer0()interrupt1//定时器0中断服务程序
TH0=0X00;
//写入定时器TH初值00H
TL0=0X06;
//写入定时器TL初值06H,计数器溢出值为65530
P2_0=~P2_0;
//闪烁LED
[实验3-8]精确定时0.5s。
在定时器中断服务函数里,设置了一个静态变量kk,静态变量kk的值在进入函数时是不会被初始化的,而是保持上次的值。
它用来计数定时器的溢出次数,也就是T0中断服务函数进入的次数,每溢出2000次,就是间隔0.5秒,使P2.0连接的LED灯亮灭一次。
TMOD=0x02;
//定时器0,工作模式2(0000,0010),8位定时模式
//GATE=0,C/T=0,
TH0=0x06;
//写入预置初值到定时器TH,预置6,使250微秒溢出一次(12MHz)
TL0=0x06;
//写入预置值
staticunsignedintkk;
//设置局部静态变量
kk++;
//每中断一次加1
if(kk==2000)//当中断2000次后,相当于0.5秒0.25ms*2000=0.5s
{kk=0;
//闪烁LED
[实验3-9]精确定时的流水灯。
所有的中断都要尽快的运行和退出,中断服务程序越短越好,这样才不至于干扰主程序的工作和其他中断的运行。
所以应该尽量把程序代码从中断服务函数里搬到主程序中运行。
对于定时器的中断的工作方式,可以建立一个全局变量的标记,在中断服务程序中置位这个标记,然后就退出中断服务。
在主程序里检查到这个全局变量标记之后,就运行相关的程序。
对于CPU任务比较多的程序来说,这种工作方式可以获得较好的工作效率。
采用查表的方式,将要点亮LED灯的顺序预先设置好,到了指定的时间,就一起将LED灯亮灭信息送到P2口。
unsignedintldelay=0;
//长定时溢出标记ldelayt,预置值是0
voidmain(void)//主程序
unsignedcharcodeledp[4]={0xfe,0xfd,0xfb,0xf7};
//预定的灯亮灭顺序,写入P2
unsignedintledi;
//用来确定表格位置的变量
//定时器0,工作模式2(0000,0010),8位定时模式
//GATE=0,C/T=0,
//写入预置初值到定时器TH,预置6,250微秒溢出一次(12MHz)
//启动定时器
//允许定时器中断
while
(1)//无限循环
if(ldelay==1)//时间溢出标记为1,处理如下事件
ldelay=0;
//清除溢出标记
P2=ledp[ledi];
//读出一个表格值送到P2口
ledi++;
//指向下一个表格值
if(ledi==4)//如果表格查过一遍
ledi=0;
//指向第一个表格值
}}}
//定义静态局部变量
//每次中断服务程序执行,kk增加1
if(kk==2000)//T0的预置值0x06,溢出2000次就是0.5秒钟,晶振12MHz
kk=0;
//如果中断服务程序执行2000次,则执行下一个语句
ldelay=1;
//将该标记置1,以便主程序处理
[实验3-10]定时/计数器工作在模式1,设置定时/计数器0初值为15536,因此计数溢出值为50000,在时钟频率为12MHz时,中断周期为50ms,每20次中断使P2.0引脚取反,使相连的LED灯闪烁;
每20次中断使变量nn加1,用连接在P1和P0口的数码管显示nn值(范围0~59),源程序如下:
reg_c51.h"
unsignedcharhex[16]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,
0x88,0x83,0xC6,0xA1,0x86,0x8E};
//数码管十六进制译码表
unsignedcharn,nn;
//定义中断次数变量
TMOD&
=0xF0;
//定时/计数器0运行在模式1,16位模式
TMOD|=0x01;
//GATE0=0;
C/T0#=0;
M10=0;
M00=1;
TH0=0x3c;
//设初值,初值=(65536-15536)/256=3cH
TL0=0xb0;
//设初值,初值=(65536-15536)%256=b0H,,50ms
//允许定时/计数器0中断
//允许总中断
//启动定时/计数器0
P1=hex[nn/10];
//显示中断次数变量n的高位
P0=hex[nn%10];
//显示中断次数变量n的低位
voidit_timer0(void)interrupt1//定时/计数器0中断服务函数
TH0=0x3C;
//重设初值
n++;
//每中断一次,n加1
if(n==20)//如果中断20次,则执行如下语句
n=0;
//将n清0
nn++;
//使nn加1
if(nn==60)//如果nn=60,执行如下语句
{nn=0;
}//将nn清0
P2_0=~P2_0;
//将P2_0引脚的状态取反,使相连的LED灯闪烁
P2_1=~P2_1;
//每次中断都取反P2_1引脚,使相连的LED灯闪烁
[实验3-11]脉冲宽度调制(PWM)方式控制LED灯亮度。
在一定的频率的方波中,调整高电平和低电平的占空比,即可实现LED灯亮度控制。
如图4-7所示,程序中使用定时器0产生2.5ms周期脉冲,使用占空比控制变量scale控制占空比,在低电平期间使LED灯亮,在高电平期间使LED灯灭,改变scale就改变了高电平与低电平的时间,因此也就控制了LED灯(连接在P2.0引脚)的亮度。
图4-7PWM占空比控制示意图
//模拟PWM输出控制灯的10个亮度级
unsignedintscale;
//占空比控制变量
voidmain(void)//主程序
//延时循环变量
//定时器0,工作模式2(0000,0010),8位定时模式
//写入预置初值6到定时器0,使250微秒溢出一次(12MHz)
//写入预置值
//启动定时器
//允许定时器0中断
//允许总中断
while
(1)//无限循环,实际应用中,这里是做主要工作
50000;
//每过一段时间,就自动加一个档次的亮度
scale++;
//占空比控制变量scale加1
if(scale==10)scale=0;
//如果scale=10,使scale为0
staticunsignedinttt;
//tt用来保存当前时间在一秒中的比例位置
tt++;
//每250微秒增加1
if(tt==10)//2.5毫秒的时钟周期
tt=0;
//使tt=0,开始新的PWM周期
//使LED灯亮
if(scale==tt)//按照当前占空比切换输出为高电平
//使LED灯灭
程序中从tt=0开始到scale为低电平,从scale开始到tt=10为高电平,由于scale是变量,所以改变scale就可以改变占空比。
3.3串行通信实验
[实验3-12]51单片机串口与PC机通信
单片机采用模式1(8位),定时器1采用模式2产生波特率,晶体频率11.0592MHz,9600波特率,PC机上运行的串口助手向单片机发送16进制数据,然后单片机将接收到的数据(16进制)返回串口助手。
单片机用P2口连接的LED灯和P1和P0口连接的数码管显示接收到的数据。
单片机串口通过电平转换芯片与PC机串口相连。
unsignedcharuart_data;
unsignedcharcodetable[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,
0x08,0x03,0x46,0x21,0x06,0x0e};
//十六进制-7段译码表
unsignedcharng,ns,temp;
//ng是接收到数据的低4位,ns是高四位,temp是暂存接收数据的变量
voidmain(void)
SCON=0x50;
//8位串行口模式1,允许接收,REN=1
TMOD=TMOD|0x20;
//定时器1,在模式2
TH1=0xFD;
//波特率为9600,晶体频率为11.059MHz
TL1=0xFD;
//波特率为9600,晶体频率为11.059MHz
ES=1;
//使能串行口中断
EA=1;
//使能全局中断
TR1=1;
//无限循环
voidserial_IT(void)interrupt4//串口中断服务程序
{if(RI==1)//如果是接收中断,则执行如下语句
RI=0;
//清除接收中断标志
uart_data=SBUF;
//接收数据
SBUF=uart_data//将接收的数据发送
temp=uart_data;
//暂存接收到的数据
P2=~temp;
//将接收的数据求反后送P2口,用LED灯显示
ng=temp&
0x0f;
//取低4位,ng是接收到数据的低4位
ns=temp>
4;
//将高4位右移4位
ns&
=0x0f;
//取低4位。
ns是接收到数据的高4位
P0=table[ng];
//将低4位送P0口,用数码管显示低4位
P1=table[ns];
//将高4位送P1口,用数码管显示高4位
elseTI=0;
//清除发送标志
图3-2串口助手与实验3-12的程序通信
图3-2显示的是串口助手软件与实验3-12程序通信的情况,串口助手发送55H,51单片机收到后,向串口助手转发55H,串口助手收到并显示在接收区中。