单片机应用技术0730 《C51单片机应用技术项目化教程》思考与习题详解.docx
《单片机应用技术0730 《C51单片机应用技术项目化教程》思考与习题详解.docx》由会员分享,可在线阅读,更多相关《单片机应用技术0730 《C51单片机应用技术项目化教程》思考与习题详解.docx(143页珍藏版)》请在冰豆网上搜索。
单片机应用技术0730《C51单片机应用技术项目化教程》思考与习题详解
C51单片机应用技术项目化教程
思考与习题详解
项目1设计信号灯控制系统
任务6能力拓展
1.6.1LED流水灯
【控制要求】P0、P2端口的LED先从右到左方向依次点亮,再从左到右方向依次点亮,如此循环形成流水灯效果。
【参考程序】
//**************************************************************
//项目名称:
LED左右移动流水灯
//功能描述:
P0、P2端口8位LED显示
//**************************************************************
#include
#include
unsignedcharscan_num;
charcodereserve[3]_at_0x3b;//保留0x3b开始的3个字节
//**********************************************************
//延时函数
//**********************************************************
voiddelayms(unsignedintms)
{
unsignedchark;
while(ms--)
{for(k=0;k<114;k++);}
}
//**********************************************************
//主函数
//**********************************************************
voidmain(void)
{
unsignedchari;
P0=0xff;//初始化端口
P2=0xff;
while
(1)
{
scan_num=0xfe;//扫描初始值
for(i=0;i<8;i++)//左移显示
{
P0=scan_num;//送显示
P2=scan_num;
scan_num<<=1;//左移一位
scan_num|=0x01;//最低位补"1"
delayms(300);//延时300ms
}
P0=0xff;//关闭LED显示
P2=0xff;
delayms(300);//延时300ms
scan_num=0x7f;//扫描初始值
for(i=0;i<8;i++)//右移显示
{
P0=scan_num;//送显示
P2=scan_num;
scan_num>>=1;//右移一位
scan_num|=0x80;//最高位补"1"
delayms(300);//延时300ms
}
P0=0xff;//关闭LED显示
P2=0xff;
delayms(300);//延时300ms
}
}
1.6.2LED灯精确定时闪烁
【控制要求】在单片机的P0.0端口上接一个发光二极管L1,使L1不停地一亮一灭,一亮一灭的时间间隔为1s(要求利用定时器T0实现精确的1s定时),循环往复。
【参考程序】
#include//reg51.h
sbitL1=P0^0;
unsignedchartime;//软计数器
voidtime0(void);//函数声明
//主函数
voidmain(void)
{
time=20;
TH0=0x4c;//定时50ms
TL0=0x00;
TMOD=0x01;
IE=0x82;
TR0=1;//timer0run
while
(1)//等待中断
{L1=0;}
}
//中断函数
voidtime0(void)interrupt1
{
TH0=0x4c;
TL0=0x00;
time--;
if(time==0)
{
L1=~L1;
time=20;
}
}
项目2设计数码管显示系统
任务6能力拓展
2.6.1数码管字幕显示
【控制要求】用8位数码管显示从右向左移动显示“--HELLO—”。
【参考程序】
//*************************************************************
//项目名称:
数码管字幕移动显示
//功能描述:
用8位数码管显示从右向左移动显示“--HELLO—”
//MCU:
AT89S52晶振:
11.0592MHz
//*************************************************************
#include//51芯片管脚定义头文件
#defineucharunsignedchar
#defineuintunsignedint
//--HELLO--
uchardisplay[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xBF,0xBF,0x89,0x86,0xC7,0xC7,0xC0,0xBF,0xBF,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
ucharshift,j=0;
charcodereserve[3]_at_0x3b;//保留0x3b开始的3个字节
//********************************************************
//ms延时子函数
//********************************************************
voiddelayms(uintms)
{
uchart;
while(ms--)
{for(t=0;t<114;t++);}
}
//*******************************************************
//函数名称:
显示函数
//函数功能:
显示
//*******************************************************
voidledplay(void)
{
uchari;
shift=0xfe;
for(i=8;i>0;i--)
{
P0=display[i+j];
P2=shift;
shift=(shift<<1)|0x01;
delayms
(1);
}
P2=0xff;
}
//*******************************************************
//函数名称:
主函数
//函数功能:
//*******************************************************
voidmain()
{
uchark;
P0=0xFF;
P2=0xFF;
while
(1)
{
for(j=0;j<17;j++)
{
for(k=0;k<125;k++)
ledplay();
}
}
}
2.6.2数码管左移右移显示
P0端口接动态数码管的字形码笔段,P2端口接动态数码管的数位选择端,P1.0接一个开关,当开关接高电平时,显示“12345678”字样;当开关接低电平时,显示“87654321”字样。
【硬件设计】
主控模块采用ATMEL公司生产的AT89S52单片机。
选用8段共阳极数码管,数码管的a、b、c、d、e、f、g、dp段分别与单片机P0口的P0.0、P0.1、P0.2、P0.3、P0.4、P0.5、P0.6、P0.7相连,用来控制显示数字的形状。
数码管的公共使能端COM连接三极管C8550的集电极,三极管C8550主要用于信号的放大,以驱动数码管工作。
三极管8550的基极通过限流电阻接到单片机P2口的P2.0,通过控制三极管C8550的基极电平来打开或关闭数码管的显示,起到“使能”作用。
三极管C8550的集电极接+5V电源。
动态数码显示模块与单片机的接口电路如图2-9所示。
图2-9动态数码显示模块与单片机的接口电路
【软件设计】
//*****************************************************
//项目名称:
动态数码显示
//功能描述:
当开关接高电平时,显示“12345678”;
//当开关接低电平时,显示“87654321”。
//******************************************************
#include
unsignedcharcodetable1[]={0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80};
unsignedcharcodetable2[]={0x80,0xf8,0x82,0x92,0x99,0xb0,0xa4,0xf9};
unsignedchari;
unsignedchart1,t2;
unsignedchartemp;
sbitK1=P1^0;
//主函数
voidmain(void)
{
while
(1)
{
temp=0xfe;
for(i=0;i<8;i++)
{
if(K1==1){P0=table1[i];}
else{P0=table2[i];}
P2=temp;
temp=(temp<<1)|0x01;
for(t1=0;t1<4;t1++)
{for(t2=0;t2<200;t2++);}
}
}
}
项目3设计按键识别系统
任务6能力拓展
3.6.1多路开关状态指示
【控制要求】单片机AT89S52的P0.0~P0.3连接4个发光二极管L1~L4,P1.0~P1.3连接4个按钮开关K1~K4,编程将开关的状态反映到发光二极管上:
开关闭合,对应的灯亮;开关断开,对应的灯灭。
【参考程序】
#include
sbitK1=P1^0;
sbitLED1=P0^0;
sbitK2=P1^1;
sbitLED2=P0^1;
sbitK3=P1^2;
sbitLED3=P0^2;
sbitK4=P1^3;
sbitLED4=P0^3;
//******************************************************
//主函数
//*******************************************************
voidmain(void)
{
while
(1)
{
if(K1==0){LED1=0;}//灯1亮
else{LED1=1;}//灯1灭
if(K2==0){LED2=0;}//灯2亮
else{LED2=1;}//灯2灭
if(K3==0){LED3=0;}//灯3亮
else{LED3=1;}//灯3灭
if(K4==0){LED4=0;}//灯4亮
else{LED4=1;}//灯4灭
}
}
3.6.2一键多功能按键识别技术
【控制要求】开关K1接在P1.0管脚上,在AT89S51单片机的P0端口接有四个发光二极管,上电的时候,L1接在P0.0管脚上的发光二极管在闪烁,当每一次按下开关K1的时候,L2接在P0.1管脚上的发光二极管在闪烁,再按下开关K1的时候,L3接在P0.2管脚上的发光二极管在闪烁,再按下开关K1的时候,L4接在P0.3管脚上的发光二极管在闪烁,再按下开关K1的时候,又轮到L1在闪烁了,如此轮流下去。
【参考程序】
#include
unsignedcharID;
//********************************************************
//延时函数
//********************************************************
voiddelay10ms(void)
{
unsignedchari,j;
for(i=20;i>0;i--)
for(j=248;j>0;j--);
}
//********************************************************
//延时函数
//********************************************************
voiddelay02s(void)
{
unsignedchari;
for(i=20;i>0;i--)
{delay10ms();}
}
//********************************************************
//主函数
//********************************************************
voidmain(void)
{
while
(1)
{
if(P1_0==0)
{
delay10ms();
if(P1_0==0)
{
ID++;
if(ID==4){ID=0;}
while(P1_0==0);
}
}
switch(ID)
{
case0:
P0_0=~P0_0;delay02s();break;
case1:
P0_1=~P0_1;delay02s();break;
case2:
P0_2=~P0_2;delay02s();break;
case3:
P0_3=~P0_3;delay02s();break;
}
}
}
项目4设计报警器系统
任务6能力拓展
4.6.1外部中断计数
【控制要求】利用单片机的外部中断功能进行计数,然后将计数值输出到数码管上显示。
按下K5键,计数值加1(外部中断0);按下K6键,计数值减1(外部中断1);采用3位数码管显示,最大计数值255。
【参考程序】
//************************************************************
//项目名称:
INT0、INT1中断计数
//功能:
通过连接在INT0和INT1的按键K5与K6实现程序
//对外部中断次数进行计//数,计数值显示在7段数码管上。
//INT0(K5):
计数值递增
//INT1(K6):
计数值递减
//*************************************************************
#include
#include
unsignedcharcodeLEDData[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff};
//段码
unsignedchardatadisplay[3];//显示缓存单元
unsignedcharcodescan_bit[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
//位码
unsignedcharcount;//计数单元
charcodereserve[3]_at_0x3b;//保留0x3b开始的3个字节
//********************************************************
//延时函数
//********************************************************
voiddelayms(unsignedintms)
{
unsignedchark;
while(ms--)
{for(k=0;k<114;k++);}
}
//********************************************************
//数据处理与显示函数
//********************************************************
voiddisp_count()
{
unsignedcharn,temp;
temp=count;
//数据处理
for(n=0;n<=1;n++)
{
display[n]=temp%10;
temp=temp/10;
}
display[2]=temp;//百位数据
//高位为0,不显示
for(n=2;n>0;n--)
{
if(display[n]==0)display[n]=0x0a;
elsebreak;
}
for(n=0;n<3;n++)
{
P0=LEDData[display[n]];//显示段码
P2=scan_bit[n];//输出位码
delayms
(1);
P2=0xff;//关闭显示
}
}
//********************************************************
//主函数
//********************************************************
voidmain(void)
{
P0=0xff;
P1=0xff;
P2=0xff;
IT0=0;//低电平触发;如IT0=1为下降沿触发
IT1=0;//低电平触发;如IT0=1为下降沿触发
EA=1;//总中断允许
EX1=1;//开启INT1中断
EX0=1;//开启INT0中断
while
(1)
{
disp_count();//数码管显示
}
}
//********************************************************
//INT0中断函数(加计数)
//********************************************************
voidINT0_ISR(void)interrupt0
{
unsignedcharx;
EX0=0;//关闭INT0中断
count++;//计数值加1
//用显示程序进行延时
for(x=0;x<70;x++)
{disp_count();}
EX0=1;//开启INT0中断
}
//********************************************************
//INT1中断函数(减计数)
//********************************************************
voidINT1_ISR(void)interrupt2
{
unsignedcharx;
EX1=0;//关闭INT1中断
count--;//计数值减1
//用显示程序进行延时
for(x=0;x<70;x++)
{disp_count();}
EX1=1;//开启INT1中断
}
4.6.2产生“叮咚”门铃声
【控制要求】当按下开关SP1(接P1.4)时,单片机产生“叮咚”声,从蜂鸣器(接P3.7)输出。
【参考程序】
#include
sbitP1_4=P1^4;
sbitP3_7=P3^7;
unsignedchart5hz;
unsignedchart7hz;
unsignedinttcnt;
bitstop;
bitflag;
//**********************************************************
//主函数
//**********************************************************
voidmain(void)
{
unsignedchari,j;
TMOD=0x02;//00000010—方式2
TH0=0x06;
TL0=0x06;
ET0=1;
EA=1;
while
(1)
{
if(P1_4==0)
{
for(i=10;i>0;i--)
for(j=248;j>0;j--);
if(P1_4==0)
{
t5hz=0;
t7hz=0;
tcnt=0;
flag=0;
stop=0;
TR0=1;
while(stop==0);
}
}
}
}
//**********************************************************
//中断程序
//**********************************************************
voidt0(void)interrupt1using0
{
tcnt++;
if(tcnt==200)
{
tcnt=0;
if(flag==0)
{
flag=~flag;
}
else
{
stop=1;
TR0=0;
}
}
if(flag==0)
{
t7hz++;
if(t7hz==3)
{
t7hz=0;
P3_7=~P3_7;
}
}
else
{
t5hz++;
if(t5hz==4)
{
t5hz=0;
P3_7=~P3_7;
}
}
}
4.6.3演奏音乐
【控制要求】演唱“两只老虎”:
单片机的P3.7外接扬声器,利用定时/计数器与中断唱出音乐“两只老虎”,其乐谱如下:
|1231|1231|345-|345-|
|565431|565431|151-|151-|
【参考程序】
#include
#defineuintunsignedint
#defineucharunsignedchar
sbitloudspeaker=P3^7;
//音阶musical_scale
uintcodemusical_scale[]={64580,64684,64777,64820,64898,64968,65030,
64260,65058};
//(65536-x)1us=1912us/2x=65536-856=64580
//乐谱music_score
//0x14,0x24,0x34,0x14;
//0x14,0x24,0x34,0x14
//0x34,0x44,0x58
//0x34,0x44,0x58
//0x52,,0x62,0x52,0x42,0x34,0x14
//0x52,,0x62,0x52,0x42,0