第3章 C51入门例题.docx
- 文档编号:5367908
- 上传时间:2022-12-15
- 格式:DOCX
- 页数:14
- 大小:74.20KB
第3章 C51入门例题.docx
《第3章 C51入门例题.docx》由会员分享,可在线阅读,更多相关《第3章 C51入门例题.docx(14页珍藏版)》请在冰豆网上搜索。
第3章C51入门例题
第3章51单片机入门实验
本章的实验都是简单C语言程序,实验中没有复杂的C语言语法与难以理解的数据结构,因此特别适合入门学习C语言。
本章所有实验都在实验板上实验过,实验用51单片机电路板的接线图如图3-1所示。
图3-1实验电路接线图
图中单片机为AT89S51或是STC89C51RC,其P0、P1口连接共阳极数码管,P2口连接8个低电平有效的LED灯(发光二极管),P3口连接8个低电平有效的按钮。
若是采用STC89C51RC单片机,由于ISP需要占用串行口,若是不切换引脚,则与P3.0和P3.1相连的按钮不能使用。
若是采用AT89S51,由于SPI编程需要P1.5、P1.6和P1.7引脚通信,所以编程后,需要切换引脚,才能使P1口连接的数码管正常显示。
3.1简单C51实验
[实验3-1]如下程序实现流水灯的方法是,依次灭掉前一个灯,然后点亮后一个灯,再延时一会,不断循环,就可以看到流水灯的效果了。
本实验使用P2.0~P2.3引脚。
源程序如下:
#include"AT89X51.H"//头文件
voidmain(void)//主程序
{
unsignedintn;
while
(1)
{
P2_3=1;P2_0=0;//灭掉P2_3,点亮P2_0=0
for(n=0;n<20000;n++);//循环延时
P2_0=1;P2_1=0;//灭掉P2_0,点亮P2_1=0
for(n=0;n<20000;n++);//循环延时
P2_1=1;P2_2=0;//灭掉P2_1,点亮P2_2=0
for(n=0;n<20000;n++);//循环延时
P2_2=1;P2_3=0;//灭掉P2_2,点亮P2_3=0
for(n=0;n<20000;n++);//循环延时
}}
[实验3-2]花样LED灯闪烁。
在表格中预先存入LED灯的各种闪烁组合,然后利用查表读出表格中的数据,并输出到P2口,这种方法经常用于霓虹灯的控制。
源程序如下:
#include
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口的流水灯的流动。
源程序如下:
#include"reg51.h"//通用51头文件
#include"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;//定义输出数据与初值
for(;;)//无限循环
{
P2=OutData;//将OutData输出到P2口,使P2口中的一个LED灯亮
OutData=_crol_(OutData,1);//使OutData循环左移,使亮的LED灯左移一位
mDelay(100);//调用延时函数
}}
[实验3-4]P3_2引脚连接的按键控制的流水LED灯
该实验中的按键控制P2口连接的流水LED灯是否流水,如果按键按下,使流水灯流水,否则流水灯全灭。
源程序如下:
#include"reg51.h"
#include"intrins.h"//该文件包含有_crol_()函数的定义
voidmDelay(unsignedintDelayTime)//延时函数
{unsignedintj=0;
for(;DelayTime>0;DelayTime--)
{for(j=0;j<125;j++);}
}
voidmain()//主函数
{
unsignedcharOutData=0xfe;//定义变量为0xfe
while
(1)//无限循环
{
P3|=0x3c;//00111100将P3口中间4位置1
while((P3|0xfb)!
=0xff)//11111011=0xfb若是P3_2引脚为1,则该循环条件不成立
{//若是P3_2引脚为0(按键按下),则该循环条件成立
P2=OutData;//将OutData输出到P2口相连的LED灯
OutData=_crol_(OutData,1);//将OutData循环左移1位
mDelay(100);//调用延时函数
}
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顺序点亮,重复循环。
源程序如下:
#include
unsignedchari;//定义循环次数变量
unsignedchartemp;//定义被循环的变量
unsignedchara,b;//定义循环中间值变量
voiddelay(void)//定义延时函数
{
unsignedcharm,n,s;
for(m=20;m>0;m--)
for(n=20;n>0;n--)
for(s=248;s>0;s--);
}
voidmain(void)//主函数
{while
(1)
{
temp=0xfe;//设置循环初值
P2=temp;//送P2口显示
delay();//调用延时函数
for(i=1;i<8;i++)//正向循环流水
{
a=temp<
b=temp>>(8-i);//如果i=1,b=00000001,i=2,b=00000011
P2=a|b;//如果i=1,P2=11111101,i=2,P2=11111011
delay();//调用延时函数
}
for(i=1;i<8;i++)//反向循环流水
{
a=temp>>i;
b=temp<<(8-i);
P2=a|b;
delay();
}}}
[实验3-6]用查表法控制P2口连接的8个LED灯。
可以按照需要自行加入表格元素,编辑表格元素时,应该先画显示的LED灯点亮图形,方法如下:
图型(0表示灯亮)
十六进制编码
01111110
7e
10111101
bd
11011011
db
11100111
e7
等等
源程序如下:
#include
unsignedcharcodetable[]={0xfe,0xfd,0xfb,0xf7,
0xef,0xdf,0xbf,0x7f,
0xfe,0xfd,0xfb,0xf7,
0xef,0xdf,0xbf,0x7f,
0x7f,0xbf,0xdf,0xef,
0xf7,0xfb,0xfd,0xfe,
0x7f,0xbf,0xdf,0xef,
0xf7,0xfb,0xfd,0xfe,
0x00,0xff,0x00,0xff,
0x7e,0xbd,0xdb,0xe7,
0x7e,0x3c,0x18,0x00,0x01};
//元素中只能有一个0x01,因为0x01是最后一个元素标志。
unsignedchari;
voiddelay(void)//定义延时函数
{unsignedcharm,n,s;
for(m=20;m>0;m--)
for(n=20;n>0;n--)
for(s=248;s>0;s--);
}
voidmain(void)//主函数
{
while
(1)//无限循环语句
{
if(table[i]!
=0x01)//判断是否是表格的最后一个元素
{
P2=table[i];//将表格元素赋予P2口,在与P2口相连的LED灯上显示
i++;//准备显示下一个表格元素
delay();//调用延时函数延时
}
else//如果是最后一个元素,使循环次数变量为0
{i=0;}}}
3.2具有定时器的C51程序实验
[实验3-7]定时器中断控制LED闪烁。
由于51单片机从中断发生到进入中断的时间不定,是3至8个机器周期,在进入了中断后,软件才重新置定时器初始值,这样就会存在定时误差。
不是精确定时,如果要精确定时,需要使用定时器自动装载方式,也就是在定时器溢出的同时,硬件逻辑就自动把定时器初始值装载进去,而不是在中断服务程序里赋初始值,只有这样才可以实现精确定时,在精确定时的情况下,定时误差由晶振的频率不稳定引起。
中断引起P2.0引脚连接的LED灯闪烁。
源程序如下:
#include"AT89X51.H"
voidmain(void)//主程序
{
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灯亮灭一次。
源程序如下:
#include"AT89X51.H"
voidmain(void)//主程序
{
TMOD=0x02;//定时器0,工作模式2(0000,0010),8位定时模式
//GATE=0,C/T=0,
TH0=0x06;//写入预置初值到定时器TH,预置6,使250微秒溢出一次(12MHz)
TL0=0x06;//写入预置值
TR0=1;//启动定时器
ET0=1;//允许定时器中断
EA=1;//允许总中断
while
(1);//无限循环
}
timer0()interrupt1//定时器0中断服务程序
{
staticunsignedintkk;//设置局部静态变量
kk++;//每中断一次加1
if(kk==2000)//当中断2000次后,相当于0.5秒0.25ms*2000=0.5s
{kk=0;
P2_0=~P2_0;//闪烁LED
}}
[实验3-9]精确定时的流水灯。
所有的中断都要尽快的运行和退出,中断服务程序越短越好,这样才不至于干扰主程序的工作和其他中断的运行。
所以应该尽量把程序代码从中断服务函数里搬到主程序中运行。
对于定时器的中断的工作方式,可以建立一个全局变量的标记,在中断服务程序中置位这个标记,然后就退出中断服务。
在主程序里检查到这个全局变量标记之后,就运行相关的程序。
对于CPU任务比较多的程序来说,这种工作方式可以获得较好的工作效率。
采用查表的方式,将要点亮LED灯的顺序预先设置好,到了指定的时间,就一起将LED灯亮灭信息送到P2口。
源程序如下:
#include"AT89X51.H"
unsignedintldelay=0;//长定时溢出标记ldelayt,预置值是0
voidmain(void)//主程序
{
unsignedcharcodeledp[4]={0xfe,0xfd,0xfb,0xf7};//预定的灯亮灭顺序,写入P2
unsignedintledi;//用来确定表格位置的变量
TMOD=0x02;//定时器0,工作模式2(0000,0010),8位定时模式
//GATE=0,C/T=0,
TH0=0x06;//写入预置初值到定时器TH,预置6,250微秒溢出一次(12MHz)
TL0=0x06;//写入预置值
TR0=1;//启动定时器
ET0=1;//允许定时器中断
EA=1;//允许总中断
while
(1)//无限循环
{
if(ldelay==1)//时间溢出标记为1,处理如下事件
{
ldelay=0;//清除溢出标记
P2=ledp[ledi];//读出一个表格值送到P2口
ledi++;//指向下一个表格值
if(ledi==4)//如果表格查过一遍
ledi=0;//指向第一个表格值
}}}
timer0()interrupt1//定时器0中断服务程序
{
staticunsignedintkk;//定义静态局部变量
kk++;//每次中断服务程序执行,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),源程序如下:
#include"reg_c51.h"
unsignedcharhex[16]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,
0x88,0x83,0xC6,0xA1,0x86,0x8E};//数码管十六进制译码表
unsignedcharn,nn;//定义中断次数变量
voidmain(void)//主函数
{
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
ET0=1;//允许定时/计数器0中断
EA=1;//允许总中断
TR0=1;//启动定时/计数器0
while
(1)//无限循环
{
P1=hex[nn/10];//显示中断次数变量n的高位
P0=hex[nn%10];//显示中断次数变量n的低位
}}
voidit_timer0(void)interrupt1//定时/计数器0中断服务函数
{
TH0=0x3C;//重设初值
TL0=0xb0;//重设初值
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占空比控制示意图
源程序如下:
#include"AT89X51.H"//模拟PWM输出控制灯的10个亮度级
unsignedintscale;//占空比控制变量
voidmain(void)//主程序
{
unsignedintn;//延时循环变量
TMOD=0x02;//定时器0,工作模式2(0000,0010),8位定时模式
TH0=0x06;//写入预置初值6到定时器0,使250微秒溢出一次(12MHz)
TL0=0x06;//写入预置值
TR0=1;//启动定时器
ET0=1;//允许定时器0中断
EA=1;//允许总中断
while
(1)//无限循环,实际应用中,这里是做主要工作
{
for(n=0;n<50000;n++);//每过一段时间,就自动加一个档次的亮度
scale++;//占空比控制变量scale加1
if(scale==10)scale=0;//如果scale=10,使scale为0
}
}
timer0()interrupt1//定时器0中断服务程序
{
staticunsignedinttt;//tt用来保存当前时间在一秒中的比例位置
tt++;//每250微秒增加1
if(tt==10)//2.5毫秒的时钟周期
{
tt=0;//使tt=0,开始新的PWM周期
P2_0=0;//使LED灯亮
}
if(scale==tt)//按照当前占空比切换输出为高电平
P2_0=1;//使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机串口相连。
源程序如下:
#include"reg_c51.h"
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;//启动定时器
while
(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,串口助手收到并显示在接收区中。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第3章 C51入门例题 C51 入门 例题