本文章来自www.zyxmcu.com(张彦欣单片机),这里你有更多的教程。
今天,我们来进行MCS51的第一堂课,这才是真正的写程序。既然要学习MCS51的端口,我们就闲来温习一下MCS51的几个IO口。
P0端口:具有8 位漏极开路的双向IO口。每位可以驱动8个TTL逻辑电平。
P1端口:具有内部上拉电阻的双向IO口。每位可驱动4个TTL逻辑电平。
P2端口:具有内部上拉电阻的双向IO口。每位可驱动4个TTL逻辑电平。
P3端口:具有内部上拉电阻的双向IO口。每位可驱动4个TTL逻辑电平。
今天,我们就来控制这些IO口,让他们输出一定的内容。这是基础,以后各种芯片的使用,其实都是通过控制IO输出各种有时序的电平(就是输出一定的波形),来控制芯片的。
这些IO口,输出什么电平(高电平还是低电平)是通过我们的程序来控制的。在C语言中,控制端口的输出极其的简单,我们闲来看几个例子:
P0 = 0x01; //将P0口(这个P0在REG51.H头文件中已经定义,可以直接使用)赋值为0x01;
//我们知道,0x01是16进制,转换成二进制是0B0000 0001。
//我们知道,P0口是8位的,分别是P0.0 P0.1 P0.2 P0.3 P0.4 P0.5 P0.6 P0.7
//这个赋值,其实就是对应的将P0.0输出高电平,其他的输出低电平。
P1 = 0xFF; //这个和上面是一样的,0xFF的二进制是0B1111 1111。意思就是将P1的八个引
//脚,全部输出为高电平。
那如何给某一个特定的引脚赋值呢?比如,我就是想让第40个引脚输出高电平,不想改变其他引脚的状态。这个简单,我们看看MCS51的管脚图,第40个引脚是P0.0口。
那么用C语言的思维方式是不是应该这么写:
P0^0 = 1; //注意,P0.0只是一位,他的状态只能是0或者1。不能出现P0^0=0x12这样的语句。
//当然,这么写也是不对的。因为C语言中“^”是一个“异或”运算符。机器会
//以为你这里进行的是P0和0的异或运算。所以出错。
应该这样来表达:
sbit MyBit = P0^0; //将P0^0定义成一个“位变量”,这个变量的名字叫MyBit(你可以起任何的名字--但不能和REG51.H头文件里面的重合)
MyBit="1"; //再给这个位变量赋值。
怎么样,给端口赋值是不是很简单啊?你也看出来了吧,其实在C语言中,一个语句可以有很多中表达方式,比如给P0.0赋值的这个例子,我还可以这么写:
P0 |= 0x01; //这个你现在如果看不懂,不要紧,后来你就会知道了。
//“|”是一个“或运算”符。而且这个句子等价于P0 = P0 | 0x01 ;明白了吧。
好了,你也应该大体明白端口赋值的道理了。接下来,我们就开始写一个我们自己的程序吧~~
1.打开我们的编程软件Keil。建立一个工程。(如果你还不明白这一步怎么操作,你可以看看教程中的“KEIL的使用”)
2.我们先来写一个极其简单的程序: #include <REG51.H> //先将CPU的头文件包含到工程中来。这其中定义了CPU所有的寄存器。
void main() //main()函数,是一个工程中的主函数,程序就是从这里开始运行的,是必须有的。
{
for(;;) //你没有看错,这个for(;;)里面的确没有变量和控制条件.
//就是为了无限循环,也可以使用while(1)。
{
P0 = 0x01; //在这个不断循环中,一直执行一句话,就是P0 = 0x01。
}
}
3.编译一下,链接一下,OK,程序没有错误“0个错误,0个警告”。
4.把程序下载到我们的开发板L-20上,看看CPU运行的结果是什么吧?哈哈,不用说,你会看到流水灯除了第一个,其他7个都是亮的。说到了流水灯,我看我们有必要来看看流水灯的电路:
从照片上,我们就可以看到,L-20系统有8个发光二极管,这一排发光二极管的连接方式如右面的这个电器连接示意图所示,发光二极管是这样连接到CPU的。(图中只是画出了链接到P0.7的那个LED放光二极管,还有7个没有画出,他们分别连接到P0的其他端口)。你也许已经注意到了,这个发光二极管是反着接到CPU上的,也就是说,当CPU的P0.7口输出高电平的时候,D7这个发光二极管是不亮的(因为两端的电压相等,不会有电流流过);当CPU的P0.7口输出为低电平的时候,+5V端有电流流想CPU的P0.7端口,这时LED放光二极管点亮。
有人问了,为什么要向相应的端口写“0”的时候才亮;写“1”的时候就不亮,这和我们平时的思维方式不同啊,电路为什么要这么连接啊?哈哈,我这样链接是有原因的:CPU的端口,往外提供电流的能力很小,一般才零点几MA左右,根本就不能是LED发光;但是灌电流却比较大,可达到20MA左右,完全可以使LED发光。现在明白为什么要这么链接了吧?就是为了能让lED在不使用功率发达器件的情况下,直接点亮。
好了,既然知道L-20系统的流水灯电路和原理了,接下来,我们就写个程序来控制这些灯的亮灭吧~~
#include <REG51.H>
void main()
{
for(;;)
{
P0 = 0x00; //把P0口上的LED灯全部打开。
P0 = 0xFF; //把P0口上的LED灯全部熄灭。
}
}
好了,在CPU的无限循环运行中,我们让它关掉LED,再打开LED。是不是就是让L-20上的八个LED灯不断的闪烁啊?哼哼~~赶紧把这个程序下载到L-20上看看运行的结果吧~~
什么,不对?LED灯没有闪烁,而是一直在亮?怎么可能,我们程序中明明是让P0口上的灯先打开,后关闭啊?问题出在哪里?哈哈,问题就处在我们低估CPU的运行速度了。CPU的运行速度非常的快,它不断的开关LED,但是频率相当的高(达到500 000 HZ),由于我们的眼睛有视觉暂留效应,所以我们根本就看不出来LED灯在闪烁(事实上,他的确在闪烁)。
那该怎么办啊?哈哈,当然是让他闪烁的慢一点了:
#include <REG51.H>
void main()
{
unsigned int i;
for(;;)
{
P0=0x00; //打开所有的LED灯。
for(i=0;i<60000;i++); //打开后,让CPU数数,数到60000后再执行下面的语句。这就是延时的原理。
P0=0xFF; //关闭所有的LED灯。
for(i=0;i<60000;i++); //延时的原理其实就是让CPU执行空语句,浪费CPU的时间。
}
}
赶紧把这个程序下载到L-20上看看效果吧~~哈哈,是不是看到L-20实验板上的发光二极管在一闪一闪的?对了,这就是我们要的效果!
注意:
到了这里,有些朋友想发挥一下了。他想让灯闪烁的再慢一点,所以他在延时那部分是这么写的:for(i=0;i<100000;i++);结果呢,他发现这个灯根本就不闪烁了,而是一直亮。大家知道问题出在哪里吗?对了,问题就出在“变量溢出”了。你看看“i”这个变量,是unsigned int型的,这中型号的变量的范围是0 ~ 65535。当i=65535以后,再加1,就是0了,怎么可能大于100000?所以,第一个for()循环就通过不了了,就一直卡在那里了。所以说,大家在以后的项目中,一定一定要注意变量溢出问题!!
有些朋友还是不满足让这些LED只是这样一闪一闪的,他希望这些LED也和马路边上的霓虹灯一样,不断的交替闪动,就仿佛流水一样,来来回回,十分好玩。还是那句话“没有问题哇!”Come on~~
#include <REG51.H>
void main()
{
unsigned int i;
for(;;)
{
P0=0xFF; //全部关闭LED。
for(i=0;i<20000;i++); //延迟一段时间。
P0 = 0xFE; //打开第一个灯。 0B1111 1110
for(i=0;i<20000;i++);
P0 = 0xFD; //打开第二个灯。 0B1111 1101
for(i=0;i<20000;i++);
P0 = 0xFB; //打开第三个等。 0B1111 1011
for(i=0;i<20000;i++);
P0 = 0xF7; //打开第四个灯。 0B1111 0111
for(i=0;i<20000;i++);
P0 = 0xEF; //打开第五个灯。 0B1110 1111
for(i=0;i<20000;i++);
P0 = 0xDF; //打开第六个灯。 0B1101 1111
for(i=0;i<20000;i++);
P0 = 0XBF; //打开第七个灯。 0B1011 1111
for(i=0;i<20000;i++);
P0 = 0x7F; //打开第八个灯。 0B0111 1111
}
}
好啦!怎么样,能看的懂吧?原理非常的简单,就是先让第一个灯亮,过一段时间,再让第二个灯亮,再第三个,第四个……这样以来,这些灯就像流水一样不断的来回循环,是不是很有意思。
当然,你自己也可以规定不同的流动方式,赶紧动手制作你自己的流水灯吧!!最后,请你欣赏我自己做的几个简单的流水灯运行结果吧!~
文章评论(0条评论)
登录后参与讨论