资讯详情

51单片机学习笔记(郭天祥版)(2)——第一课作业、流水灯、蜂鸣器

免费样品申请(暂时无用,不说,很简单)


作业讲解

1-5点亮灯太简单了,别说了

6:试着让第一个发光管闪烁

闪烁,就是亮,灭,再亮,再灭这样一个循环的过程,就是写程序控制某个循环IO口先输出低电平,然后输出高电平,然后输出低电平。在这样的循环中,它将持续一段时间而不改变状态(即延迟)。使用简单的延迟while或者for循环就可以了。

 1 #include<reg52.h>  2 sbit p1_1=P1^0;  3 unsigned int a;  4 void main()  5 {  6     a=50000;  7     p1_1=0;  8     while(a--);  9     a=50000; 10     p1_1=1; 11     while(a--); 12 } 

定义一个unsigned int变量类型(无符号整形)a,其范围为0-65535,如果超过此值,则取余,如70000-65535后。

这择这两个,这样如果一直插入单片机,然后更改代码并编译,就会自动下载到单片机。

你可能会遵循上述方法,但这是错误的,不标准的。因为在正常执行c语言代码时,从进入main函数开始,执行完main内部代码已经结束,但这里重新执行,因为单片机会已经重复执行main函数,但有时会出错。

正确的写法

 1 #include<reg52.h>  2 sbit p1_1=P1^0;  3 unsigned int a;  4 void main()  5 {  6     while(1)  7     {  8         a=50000;  9         p1_1=0; 10         while(a--); 11         a=50000; 12         p1_1=1; 13         while(a--); 14     } 15 } 

在main再写一个函数内部while(1)将需要循环执行的代码放入while(1)花括号内,使单片机始终循环while(1)内部内容不出错。


学习软件调试

像放大镜一样点击打开调试,调试前先编译。再次单击并关闭。

黄色箭头指着下一个要执行的句子

这是复位,让调试重新开始。

全速执行。

停止全速执行,只有在全速执行后才会变红,才能使用。

进入函数内部。

执行下一调语句。

点击Peripheral(硬件)

Interrupt:中断

I/O-Ports:IO口

Serial:串行端口

Timer:定时器

选择我们现在使用的东西IO口的P1口Port 1

可以看到P1上电后为oxFF,上电后一切IO口为高电平(IO口上电后为1,其他寄存器上电后为0,上电后会自动复位,所以这里软件的复位可以作为上电),相应的后8位都打了√,如果√不,相应的一个变成了0。操作单片机是内部寄存器(P1)操作。

点击View,选上call stack window

看,执行的句子变绿了,没有执行的是灰色,这里while(a--)要完成执行,需要单步执行5万次(即一次执行一句),重点是5万次,非常慢,所以可以设置断点。

断点是红色出现在前面,有些版本是红色的圆,设置断点的方法是用鼠标单击所需句子前的灰色部分。

现在让我们谈谈上述全速执行。全速执行总是执行的,而且执行速度很快。你不需要一个点,但你不知道在哪里执行,所以我们需要使用断点。我们不想在这里点击5万次,所以我们在while(a--)后面的句子设置断点,然后打开全速执行,然后程序将全速执行到断点位置,然后停止,而不是断点句子。

在这里执行完全速后,a变成65535(也是满的,unsigned int类型的最大值,满和空是一个概念),意思是减空,从原来的5万,减到0后再减一次就是65535。


硬件调试(在线调试)(模拟芯片) 不买,先不看

仿真芯片有助于您了解程序是如何执行的

点开设置

点到debug这一栏。

原本是use Simulator,现在我们点击右边的Use,选择keil Monitor-51 Driver,再点击Settings设置

选择com用于下载程序com这里就选几个com然后点击ok。

之后这里全部打钩,再确定。

模拟时必须先接通电源

然后点击debug调试

连接将显示在下面(Connected to Monitor-51)

然后按照刚才的方法调试。不同的是,在这里调试时,单片机会一步一步地跟着。

您可以知道每个指令何时执行,每个变量如何变化。

调制结束时,先按下单片机上的复位按钮,然后点击debug结束


接下来,学习如何设置更准确的延迟时间

首先,实验板的晶振频率为11.0592MHz,计算机单片机的运行速度由其决定

以下内容只需要知道一个机器周期是12个时钟周期,一个时钟周期是冲击源周期。

调整时间时,需要调整时间keil晶振频率与单片机相同

打开调试状态

当程序在这里运行时,你会看到0.00042209s,运行到灯亮

0.00042752s,然后我们运行到它熄灭之前,看看中间有多长时间。这是我们想要的延迟时间。在这里设置断点,否则while(a--)我们需要手动50000次...

时间变为了0.48893555s,离500ms最近,在我们的微调下,把a变成51000,然后运行到这里几乎是一样的。下面也改了。

让我们看看如果没有11.0592MHz晶振频率,默认24MHz会怎么样

频率24是11的2倍左右,所以时间几乎是1/2。

但这里只是模拟,对单片机没有影响,单片机本身仍然使用11.0592来计算,但这样你就不准了。


接下来学习子函数(以后写程序都写在函数里,然后main全是调用)

首先介绍宏定义define,相当于一个新名字,用法#define new_name old_name

 1 #include<reg51.h>  2 #define uint unsigned int//宏定义  3 #define uchar unsigned char  4   5 void delay();//声明函数  6 sbit D1=P1^0;  7 void main()  8 {  9     while(1) 10     { 11         D1=0; 12         delay(); 13         D1=1; 14         delay(); 15     } 16 } 17  18 void delay()//定义函数,大约是500ms的延时, 19 { 20     uint x,y; 21     for(x=100;x>0;x--) 22     { 23         for(y=600;y>0;y--) 24         { 25              26         } 27     } 28 } 

这里for上面还出现了循环while循环,当没有内部句子时,可以省略{},直接写分号

1 void delay(uint n) 2 { 3     uint x,y; 4     for(x=n;x>0;x--) 5     { 6         for(y=600;y>0;y--); 7     } 8 } 

其他人自己理解,不再重复

子函数带参数

 1 #include<reg51.h>  2 #define uint unsigned int  3 #define uchar unsigned char  4   5 void delay(uint n);  6 //void delay(uint );这里的声明也可以写成这样(不写)n),但建议写上面的,方便,上面的只需要复制函数定义,不会出错。  7 sbit D1=P1^0;   void main()
 9 {
10     while(1)
11     {
12         D1=0;
13         delay(100);
14         D1=1;
15         delay(100);
16     }
17 }
18 
19 void delay(uint n)
20 {
21     uint x,y;
22     for(x=n;x>0;x--)
23     {
24         for(y=600;y>0;y--)
25         {
26             
27         }
28     }
29 }

函数定义和函数声明的参数叫做形参(形式参数),函数调用时给的数值是实参(实际参数),因为函数定义时函数是不执行的,而只有调用时,函数才执行,其中的参数会使用你传的参数,也就是实参。


接下来我们用stc-isp来生成延时函数

打开后点击红框内的三角箭头,找到软件延时计算器

先选择晶振频率,再设置延时的时间,再选择指令集STC-Y1,然后生成c代码,最后复制就可以了

 1 #include<reg51.h>
 2 #define uint unsigned int
 3 #define uchar unsigned char
 4     
 5 void Delay1ms();
 6 void delay(uint n);
 7 sbit D1=P1^0;
 8 void main()
 9 {
10     while(1)
11     {
12         D1=0;
13         delay(200);
14         D1=1;
15         delay(200);
16     }
17 }
18 
19 void delay(uint n)
20 {
21     while(n--)
22     {
23         Delay1ms();
24     }
25 }
26 void Delay1ms()        //@12.000MHz
27 {
28     unsigned char i, j;
29 
30     i = 2;
31     j = 239;
32     do
33     {
34         while (--j);
35     } while (--i);
36 }

定义一个延时1ms的函数,然后再定义一个带参数的函数,调用延时1ms的函数n次,就产生了延时n ms的函数了


接下来是流水灯

找到C51文件夹中Hlp文件夹下的c51帮助文档,在Reference里能看到库函数,都是写好的可以直接调用的函数

这里我们要用到_crol_

点开后可以看到介绍和例子,需要用到头文件intrins.h,将变量c循环左移b位,返回移动后的结果。a=0xA5(1010 0101),循环左移一位变成(0100 1011),循环左移第二位(1001 0110),循环左移第三位(0010 1101)即0x2D,循环左移一次就是整体左移一次,把最高位的放到最低位。

 1 #include<reg51.h>
 2 #include<intrins.h>
 3 
 4 #define uint unsigned int
 5 #define uchar unsigned char
 6 
 7 uchar temp;//为什么用uchar而不用uint?
 8 
 9 void Delay1ms();
10 void delay(uint n);
11 
12 void main()
13 {
14     temp=0xfe;
15     P1=temp;//因为uchar有8位,而uint有16位,每组IO口也是8位,所以如果我们要用uchar
16     while(1)//先让P1=0xfe(1111 1110)
17     {
18         delay(300);//延时300ms
19         temp=_crol_(temp,1);//改变temp的值
20         P1=temp;//改变P1的值
21     }
22 }
23 
24 void delay(uint n)
25 {
26     while(n--)
27     {
28         Delay1ms();
29     }
30 }
31 void Delay1ms()        //@12.000MHz
32 {
33     unsigned char i, j;
34 
35     i = 2;
36     j = 239;
37     do
38     {
39         while (--j);
40     } while (--i);
41 }

其实temp这里多余,只是想让你知道定义变量要注意的地方,比如为什么不用unsigned int而用unsigned char

 1 void main()
 2 {
 3     P1=0xfe;
 4     while(1)//先让P1=0xfe(1111 1110)
 5     {
 6         delay(300);//延时300ms
 7         P1=_crol_(temp,1);//改变P1的值
 8 
 9     }
10 }

main可以直接改成这样


课后作业


补充一下蜂鸣器

蜂鸣器原理图

   

(我的板子是第二种)(继电器也挺重要,但暂时不说了)

FM就是P2^3口,然后接一个电阻,这里用了一个三极管,用了它的开关作用(它还有放大作用),(蜂鸣器内阻很小(忽略)),当给P2^3低电平时,ce就导通了,就有从VCC流经蜂鸣器然后经过ce的电流。

因此蜂鸣器的使用也很简单,0就响,1就停止。

 1 #include<reg51.h>
 2 
 3 sbit beep=P2^3;
 4 
 5 void main()
 6 {
 7 
 8     while(1)
 9     {
10             beep=0;
11     }
12 }

这样就响了

接下里是响、停循环进行

 1 #include<reg51.h>
 2 
 3 #define uint unsigned int
 4 #define uchar unsigned char
 5 
 6 sbit beep=P2^3;
 7 
 8 void Delay1ms();
 9 void delay(uint n);
10 
11 void main()
12 {
13 
14     while(1)
15     {
16             beep=0;
17             delay(300);
18             beep=1;
19             delay(300);
20     }
21 }
22 
23 void delay(uint n)
24 {
25     while(n--)
26     {
27         Delay1ms();
28     }
29 }
30 void Delay1ms()        //@12.000MHz
31 {
32     unsigned char i, j;
33 
34     i = 2;
35     j = 239;
36     do
37     {
38         while (--j);
39     } while (--i);
40 }

这里在提一下前面说到的~(取反),原本是0,取反就是1,原本是1,取反就是0,用这个会很简单。

 1 #include<reg51.h>
 2 
 3 #define uint unsigned int
 4 #define uchar unsigned char
 5 
 6 sbit beep=P2^3;
 7 
 8 void Delay1ms();
 9 void delay(uint n);
10 
11 void main()
12 {
13 
14     while(1)
15     {
16             beep=~beep;
17             delay(300);
18     }
19 }
20 
21 void delay(uint n)
22 {
23     while(n--)
24     {
25         Delay1ms();
26     }
27 }
28 void Delay1ms()        //@12.000MHz
29 {
30     unsigned char i, j;
31 
32     i = 2;
33     j = 239;
34     do
35     {
36         while (--j);
37     } while (--i);
38 }

标签: d1o47三极管参数y1三极管电流

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台