51单片机的学习思考(1)

实验要求:

《单片机原理与接口技术》实验(8051RC)
实验一 流水灯设计/报警产生器设计
实验要求:

  1. 修改程序,实现 4 个按键控制,自上至下、自下至上、自中间至两边、自两边至中间循环 点亮 LED,循环次数均为 3 圈,3 圈结束后恢复到所有 LED 熄灭的正常状态。请编写程序并调试。
  2. 编写程序,实现 8 个发光二极管同时点亮,但亮度从上到下由亮变暗(选做)。
  3. 简述你在本实验中遇到过哪些问题?这些问题是解决的?有何收获和体会?
  4. 扬声器音量大小如何调节,是否和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;
}

调试结果如下:
pwm控制小灯
要求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都让我学到很多。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值