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


作业讲解

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,那么就会取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--)要想执行完需要单步执行(即一次执行一句)50000次,要点50000次,很慢,所以我们可以设置断点。

断点就是前面出现了红色,有的版本是红色的圆,设置断点的方法就是在需要的语句前方灰色处用鼠标单击。

现在我们说一下上面的全速执行,全速执行就是一直执行,而且执行的很快,不需要你一下一下的点,但是你不知道执行到哪里了,所以我们要用到断点,这里我们不想点击50000次,所以我们在while(a--)后面那条语句设置断点,再开启全速执行,那么程序就会全速执行到断点的位置然后停止,不会执行断点那条语句。

这里执行完全速后,a变为了65535(也是满,unsigned int类型的最大值,满和空是一个概念),意思是减空了,从原本的50000,减到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;
 8 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 }