实验要求:
《单片机原理与接口技术》实验(8051RC)
实验一 流水灯设计/报警产生器设计
实验要求:
- 修改程序,实现 4 个按键控制,自上至下、自下至上、自中间至两边、自两边至中间循环 点亮 LED,循环次数均为 3 圈,3 圈结束后恢复到所有 LED 熄灭的正常状态。请编写程序并调试。
- 编写程序,实现 8 个发光二极管同时点亮,但亮度从上到下由亮变暗(选做)。
- 简述你在本实验中遇到过哪些问题?这些问题是解决的?有何收获和体会?
- 扬声器音量大小如何调节,是否和LED亮度调节类似呢?
实验内容:
一、流水灯设计
通过了解 P1 口连接 3-8 译码器进行 LED 选通电路图及数码管位选电路、P0 的控制 74HC245 驱动 LED 的电路,见下图。本实验要求实现 4 个按键控制,自上至下、自下至上、自中间至两边、自两边至中间循环 点亮 LED,循环次数均为 3 圈,3 圈结束后恢复到所有 LED 熄灭的正常状态。请编写程序并调试。实现 8 个发光二极管同时点亮,但亮度从上到下由亮变暗(选做)。
代码思路:
运用判断语句判断独立按键是否摁下
流水灯右移部分可以采用右移来实现。由于数据右移之后高位补的是0,故可以采用将数据右移运算之后与0X80进行与运算,使得高位补1.例如0X7f=0111 1111>>1=0011 1111,0x80=1000 0000,0011 1111|1000 0000=1011 1111。
同理流水灯左移部分同样可以采用左移运算之后进行与运算。但是此时是低位补0。所以应该用0000 0001=0x01进行与运算。从中间到两边和从两边到中间采用分别显示的办法。较为简单,故不再赘述。
要求1代码如下:
#include <reg51.h>
sbit LSA=P1^5;
sbit LSB=P1^6;
sbit LSC=P1^7;
sbit key1=P3^2;
sbit key2=P3^3;
sbit key3=P3^4;
sbit key4=P3^5;
void delayms(unsigned int xms);
void main()
{
unsigned int i,j;
LSA=0;
LSB=0;
LSC=0;
P0=0xff;
while(1)
{
if(key1 == 0)//按键1按下
{
for(j = 0;j < 3;j++)
{
P0 = 0x7f;
for(i=0;i<8;i++)
{
delayms(500);
P0=P0>>1|0x80;//右移运算之后和0x80与运算
}
}
P0=0xff;//熄灭流水灯
}
if(key2 == 0)//按键2按下
{
for(j=0;j<3;j++)
{
P0=0xfe;
for(i=0;i<8;i++)
{
delayms(500);
P0=P0<<1|0x01;//左移运算之后和0x01与运算
}
}
P0=0xff;//熄灭流水灯
}
if(key3 == 0)
{
for(j=0;j<3;j++)
{
P0=0xe7;
delayms(500);
P0=0xdb;
delayms(500);
P0= 0xbd;
delayms(500);
P0=0x7e;
delayms(500);
}
P0=0xff;//熄灭流水灯
}
if(key4 == 0)
{
for(j=0;j<3;j++)
{
P0=0x7e;
delayms(500);
P0=0xbd;
delayms(500);
P0= 0xdb;
delayms(500);
P0=0xe7;
delayms(500);
}
P0=0xff;//熄灭流水灯
}
}
}
void delayms(unsigned int xms)//延时函数
{
unsigned int i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
调试结果如下:
单片机按键控制流水灯
第二个要求:编写程序,实现 8 个发光二极管同时点亮,但亮度从上到下由亮变暗(选做)。
代码思路:众所周知,灯的亮度与电压的大小有关,所以利用pwm方波占空比来实现对有效电压大小的控制,进而控制小灯的亮暗程度。由于51单片机没有pwm产生模块,所以采用定时器来产生pwm信号。进而通过I/O口输出我们设置pwm大小的有效电压来实现控制小灯亮度。
参考代码如下:
#include <reg51.h>
#define uchar unsigned char
sbit LSA = P1^5;
sbit LSB = P1^6;
sbit LSC = P1^7;
sbit led1=P0^0;
sbit led2=P0^1;
sbit led3=P0^2;
sbit led4=P0^3;
sbit led5=P0^4;
sbit led6=P0^5;
sbit led7=P0^6;
sbit led8=P0^7;
int X ;
int duty;
int pwm1,pwm2,pwm3,pwm4,pwm5,pwm6,pwm7,pwm8;
void delayms(unsigned int xms);
void main()
{
LSA = 0;
LSB = 0;
LSC = 0;
X=2000;
TMOD=0x01;//系统初始化设置
EA=1;//打开总中断
ET0=1;
TH0=0xff; //装载定时器初值
TL0=0xf6;
TR0=1;
while(1)
{
pwm1=100;
pwm2=90;
pwm3=80;
pwm4=70;
pwm5=60;
pwm6=50;
pwm7=40;
pwm8=80;
};
}
void timer1_isr() interrupt 1
{
static uchar clk=0;
TH0=0xff;
TL0=0xf6;
++clk;
if(clk>=101)//设置pwm总值为100,每当达到101,clk值归0
clk=0;
if(clk>=pwm1)//pwm1输出给led1
led1=0;
else
led1=1;
if(clk>=pwm2)//pwm2输出给led2
led2=0;
else
led2=1;
if(clk>=pwm3)//pwm3输出给led3
led3=0;
else
led3=1;
if(clk>=pwm4)//pwm4输出给led4
led4=0;
else
led4=1;
if(clk>=pwm5)//pwm5输出给led5
led5=0;
else
led5=1;
if(clk>=pwm6)//pwm6输出给led6
led6=0;
else
led6=1;
if(clk>=pwm7)//pwm7输出给led7
led7=0;
else
led7=1;
if(clk>=pwm8)//pwm8输出给led8
led8=0;
else
led8=1;
}
调试结果如下:
要求3:报警器的设计
用P4.4输出1KHz和500Hz的音频信号驱动扬声器,作报警信号,要求1KHz信号响100ms,500Hz信号响200ms,交替进行,P1.7接一开关进行控制,当开关合上响报警信号,当开关断开报警信号停止,请按流程图编出程序。电路图如下:
代码思路:
串口P4_4不可以直接运用,最后百度得到解决办法。晶振频率为11.0592MHZ,一个机器周期为十二个晶振周期,也就是说机械周期的频率为0.9216MHZ=921.6KHZ,所以若要产生1KHZ的信号需要大约460个机械周期的高电平和460个机械周期的低电平。同理若要产生500HZ的信号需要大约920个机械周期的高电平和920个机械周期的低电平。1KHZ每个周期为1ms,所以循环200次就是蜂鸣器工作了200ms。注意:C语言中没有_nop_()函数。在51C中一般包含在#include “intrins.h” 头文件中。该函数是在51单片机中用的延时函数,表示执行一条没有什么意义的指令,延时一个指令周期,有的指令周期是两个或两个以上的机械周期,但是_nop_();指令需要的只是一个机械周期也就是12个时钟周期(震荡周期)。51单片机中,1个机械周期 = 12个时钟周期 = 12 * ( 1 / f)。(f 为晶振频率)。
参考代码:
#include <reg51.h>
#include <intrins.h>
sfr P4 = 0xe8;
sbit beep=P4^4;
sbit key1=P3^2;
sbit key2=P3^3;
unsigned char count;
void delay500(void)
{
unsigned char i;
for(i=460;i>0;i--)
{
_nop_();//空指令
}
}
void main(void)
{
while(1)
{
if(key1==0)
{
for(count=200;count>0;count--)//1KHZ每周期为1ms,循环200次,工作200ms
{
beep=1;
delay500();
beep=0;
delay500();
}
for(count=200;count>0;count--)//500HZ每周期为2ms,循环200次,工作200ms
{
beep=1;
delay500();
delay500();
beep=0;
delay500();
delay500();
}
}
else
beep=1;
}
}
4.扬声器音量大小如何调节,是否和LED亮度调节类似呢?
起初,我根据第二个要求的方法,利用定时器产生的PWM方波信号。但是将程序下载进去之后发现蜂鸣器根本不响!看来老师给这个思考题也是有原因的。后来我利用延时函数加上循环手动做了一个PWM方波信号,发现可行。
代码如下:
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sfr P4 = 0xe8;
sbit beep=P4^4;
sbit key1=P3^2;
unsigned char count;
int pwm1,pwm2,pwm3;
void delay500(void)
{
unsigned char i;
for(i=460;i>0;i--)
{
_nop_();
}
}
void timer1_isr() interrupt 1
{
static uchar clk=0;
TH0=0xff;
TL0=0xf6;
++clk;
if(clk>=101)
clk=0;
if(clk>=pwm1)
beep=1;
else
beep=0;
if(clk>=pwm2)
beep=1;
else
beep=0;
if(clk>=pwm3)
beep=1;
else
beep=0;
}
void main(void)
{
while(1)
{
if(key1==0)
{
for(count=2000000;count>0;count--)
{
beep=1;
delay500();
delay500();
delay500();
delay500();
delay500();
delay500();
delay500();
delay500();
beep=0;
delay500();
delay500();
}
for(count=2000000;count>0;count--)
{
beep=1;
delay500();
delay500();
delay500();
delay500();
delay500();
delay500();
beep=0;
delay500();
delay500();
delay500();
delay500();
}
for(count=2000000;count>0;count--)
{
beep=1;
delay500();
delay500();
delay500();
delay500();
beep=0;
delay500();
delay500();
delay500();
delay500();
delay500();
delay500();
}
for(count=2000000;count>0;count--)
{
beep=1;
delay500();
delay500();
beep=0;
delay500();
delay500();
delay500();
delay500();
delay500();
delay500();
delay500();
delay500();
}
for(count=2000000;count>0;count--)
{
beep=0;
delay500();
delay500();
delay500();
delay500();
delay500();
delay500();
delay500();
delay500();
delay500();
delay500();
}
}
else
beep=1;
}
}
总结
第一次写博客,耗费了大概一天的时间,但是学到了很多东西。以前在大一的时候学习过51单片机,但是这次的感觉和以前的感觉不一样。要求一中的左右移之后的与运算以及要求二的运用定时器产生pwm信号,要求三中P4_4口的使用,要求四中手动产生PWM都让我学到很多。