任务1 单灯闪烁控制
为了验证P1口的输出电平是不是由你编写的程序输出的电平,可以采用一个非常简单有效的办法,就是在想验证的端口位接一个发光二极管。当输出高电平时,发光二极管灭;输出低电平时,发光二极管亮。
在本任务中,使用P1端口的第一脚(记为P1_0)来控制发光二极管以1Hz的频率不断闪烁。
LED电路元件
(1)红色发光二极管2个;
(2)470Ω电阻2个。
LED电路搭建
按照图2-2上部分所示电路,在智能机器人教学板的面包板上搭建起实际电路。实际搭建好的电路参考图2-2下部分的照片。实际搭建电路时应注意:
图2-2 发光二极管与I/O脚P1_0的连接
● 确认发光二极管的短针脚(阴极)插入通过电阻与P1_0相连;
● 确认发光二极管的长针脚(阳极)插入“VCC”插口。
例程:HighLowLed.c
● 接通面包板上的电源;
● 输入、保存、下载并运行程序HighLowLed.c(整个过程请参考第1讲);
● 观察与P1_0连接的LED是否每隔一秒发光、关闭一次。
#include<BoeBot.h> #include<uart.h> int main(void) { uart_Init(); //初始化串口 printf("The LED connected to P1_0 is blinking!\n"); while(1) { P1_0=1; //P1_0输出高电平 delay_nms(500); //延时500ms P1_0=0; //P1_0输出低电平 delay_nms(500); //延时500ms } }
HighLowLed.c是如何工作的
与第1讲程序相比,本例程多使用了一个头文件BoeBot.h,在该头文件中定义了两个延时函数:void delay_nms(unsigned int i)与void delay_nus(unsigned int i)。
无符号整型数据unsigned int
与第1讲讲到的整型数据int相比,无符号整型数据unsigned int只有一个不同:数据的取值范围从-32768~+32767变为0~65535,也就是说它只能取非负整数。
delay_nms( )是毫秒级的延时,而delay_nus( )是微秒级的延时。如果想延时1s,可以使用语句delay_nms(1000);1ms的延时则用delay_nus(1000)来完成。
注意:上述的延时函数是在外部晶振为12MHz的情况下设计的,如果外部晶振频率不是12MHz,调用这两个函数所产生的真正延时就会发生变化。
晶振的作用
单片机要能工作,就必须有一个标准时钟信号,而晶振就为单片机提供标准时钟信号。
uart_Init();串口初始化函数,在头文件uart.h中实现,具体内容将在后面讲节介绍。
调用printf是为了在程序执行前给调试终端发送一条提示信息,告诉你现在程序开始执行了,并告诉你程序随后将开始干什么。这在以后的编程开发过程中形成一个良好的习惯,有助于提高程序的调试效率。代码段为:
while(1) { P1_0=1; //P1_0输出高电平 delay_nms(500); //延时500ms P1_0=0; //P1_0输出低电平 delay_nms(500); //延时500ms }
上述程序是本例程的功能主体。首先看两个大括号中的代码:先给P1_0脚输出高电平,由赋值语句P1_0=1完成,然后调用延时函数delay_nms(500),让单片机微控制等待500ms,再给P1_0脚输出低电平,即P1_0=0,然后再次调用延时函数delay_nms(500)。这样就完成了一次闪烁。在程序中,你没有看到P1_0的定义,它已经在由C语言为C51开发的标准库中定义好,由头文件uart.h包括进来。后续讲节中将要用到的其他引脚名称和定义都是如此。
注意:在所有计算机系统中,都用1表示高电平,0表示低电平,所以,P1_0=1就表示要向该端口输出高电平,而P1_0=0就表示给该端口输出低电平。
例程中两次调用延时函数,让单片机微控制器在给P1_0引脚端口输出高电平和低电平之间都延时500ms,即输出的高电平和低电平都保持500ms。
微控制器的最大优点之一就是它们从来不会抱怨不停地重复做同样的事情。为了让单片机不断闪烁,你需要把让LED闪烁一次的几个语句放在while(1){…}循环里。这里用到了C语言实现循环结构的一种形式——while语句。
while语句
while语句的一般形式如下:
while(表达式)循环体语句
当表达式为非0值时,执行while语句中的内嵌语句,其特点是先判断表达式,后执行语句。例程中直接用1代替了表达式,因此总是非0值,所以循环永不结束,也就可以一直让LED灯闪烁。
注意:循环体语句如果包含一个以上的语句,就必须用大括号(“{ }”)括起来,以复合语句的形式出现。如果不加大括号,则while语句的范围只到while后面的第一个分号处。例如,本例中while语句中如果没有大括号,则while语句的范围只到“P1_0=1;”。
也可以不要循环体语句,如第1讲例程中就直接用while(1),程序将一直停在此处。
在PBASIC编程语言中,需要循环的语句放在了DO⋯LOOP之间。
时序图简介
时序图反应的是高、低电压信号与时间的关系图。在图2-3中,时间从左到右增长,高、低电压信号随着时间在0~5V间变化。这个时序图显示的是刚才实验中的1000ms的高、低电压信号片段。右边的省略号表示这些信号是重复出现的。
图2-3 程序HighLowLed.c的时序图
该你了——让另一个LED闪烁
让另一个连接到P1_1管脚的LED闪烁是一件很容易的事情,把P1_0改为P1_1,重新运行程序即可。
参考下面的代码段修改程序:
uart_Init(); printf("The LED connected to P1_1 is blinking!"); while(1) { P1_1=1; //P1_1输出高电平 delay_nms(500); //延时500ms P1_1=0; //P1_1输出低电平 delay_nms(500); //延时500ms }
运行修改后的程序,确定能让LED闪烁。
你也可以让两个LED同时闪烁。参考下面代码段修改程序:
uart_Init(); printf("The LEDs connected to P1_0 and P1_1 are blinking!\n"); while(1) { P1_0=1; //P1_0输出高电平 P1_1=1; //P1_1输出高电平 delay_nms(500); //延时500ms P1_0=0; //P1_0输出低电平 P1_1=0; //P1_0输出低电平 delay_nms(500); //延时500ms }
运行修改后的程序,确定能让两个LED几乎同时闪烁。
当然,你可以再次修改程序,让两个发光二极管交替亮或灭,也可以通过改变延时函数参数n的值,来改变LED的闪烁频率。
尝试一下!