免费样片申请(暂时无用,不说了,很简单)
作业讲解
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 }