《中学生C51单片机易学实战入门教程》
实验准备
课程内容
第三课 8 LED玩花样
实验准备:
使用第一课已装配好的实验板
LED 增加7只
电阻 10k ,增加7只
课程内容:
一、 接完整8只LED 电路
参照原理图,类似在P1.0上接LED的方法,把P1.1到P1.7的7只LED和电阻也接好。
这时,为实验板加电,可见到只有P1.0对应的D1这只LED在闪,如果按之前的编程思路,就是使用如下的程序方式:
sbit P10= P1^0;
sbit P11= P1^1;
sbit P12= P1^2;
sbit P13= P1^3;
sbit P14= P1^4;
sbit P15= P1^5;
sbit P16= P1^6;
sbit P17= P1^7;
同时main()程序中使用
P10=!P10;
P11=!P11;
P12=!P12;
P13=!P13;
P14=!P14;
P15=!P15;
P16=!P16;
P17=!P17;
这方式可行吗?当然可行,只要能达到效果,哪一种方式都行,其实这也是编程最先采用的方法,就是先用最容易理解,最简单的实现方法去编程,达到要求结果后,再去做程序优化,否则没达到结果 什么精简高效的程序都是没用的。
好了,现在可以同时控制8 LED了,但看上去很繁,那么就做优化。
单片机虽然只认0与1,但可以一次同时处理多个位,例如C51系列就是8位单片机,同时可以处理8位,更高级的处理器可以同时处理16位、32位、64位或128位等等。
89C52单片机可一次同时处理8位,这单片机把控制数据输入输出的管脚(简称IO口)分成4组,每组8个IO口,分别命名为P1、P2、P3、P4,这在 reg52.h 文件中预先做好定义,方便我们直接操控。
本次实验中8 只LED接在P1的8个IO口处,所以,可以直接一次性控制8只LED。
修改控制,只须改到一行代码。
主程序main()中,把
P10=!P10;
改成
P1=~P1;
下载,观看实验效果,可以见到8只LED同时闪动。
上一课中所用的运算符号!,只对一位数起效,不能同时控制8位,如果把
P1=~P1;
改成
P1=!P1;
那么只有LED1闪,其他不闪,这个可以下载实践下。
而运算符~则是8位同时运算
00000000 做~取反,对每个位取反,结果就是11111111
同理,11111111 做~取反,对每个位取反,结果就是00000000
二、十六进制与二进制
如果8个LED灯想玩下花样,做出特效,有的LED发光,有的不发光,或者做流水灯等广告效果,这时,需要对不同的LED控制它所在位设0或设1,于是 11110000,10101010等这样的结果就出现了,这些数不方便记忆,也不方便编程,于是采用『数制』来实验简化。11110000或10101010这纯机器码表现形式你为二进制数,每位只能是0或1,逢2进1,与平常用的10进制数类似,10进制每位可用0至9个数,逢10进1。还有十六进制的数,成语『半斤八两』中所用的是十六进制,中国古代的重量计量方式是一斤是十六两。
二进制数太长不好写不好记,一般采用十六进制方式表示,
二进制11110000 ---> 十六进制 0xF0
二进制10101010 ---> 十六进制 0xAA
注意,每个十六制数前要加 0x,如果不加,是当成10进制数的。
如果转换,很简单,电脑中有只工具软件『计算器』能帮我们。
在电脑程序附件中可以找到『计算器』这个工具软件。
可以通过 查看 – 科学型 ,切换到 数制转换模式
点二进制,输入11110000,再点十六进制,就自动显示F0
三、8 LED 花样控制
现在,可以实验LED花样特效了,
间闪效果一:(这里仅修改主程序main())
void main()
{
P1=0xAA;//二进制对应是 10101010
mDelay(200);
P1=0x55;//二进制对应是 01010101
mDelay(200);
}
间闪效果二:(这里仅修改主程序main())
void main()
{
P1=0x36;//二进制对应是 01101101
mDelay(200);
P1=0x5B;//二进制对应是 10110110
mDelay(200);
P1=0xDB;//二进制对应是 11011011
mDelay(200);
}
四、 新花样:单点LED轮转
#include "reg52.h"
#define uchar unsigned char
#define uint unsigned int
sbit P10=P1^0;
void mDelay(uint Delay)
{
uint i;
for(;Delay>0;Delay--)
for(i=0;i<124;i++);
}
void main()
{
uchar a = 0x01; // 二进制00000001
for(;;)
{
P1 = ~a; // 首次循环时把a取反的值给P1,11111110
//控制P1.0的LED,注意这时 a 值本身是没有变化的
a = a << 1; // 首次循环时 a左移一位,a值变成 00000010
if (a==0x00) a=0x01; //如果 a 变成了00000000,那么设成00000001
mDelay(200); //延时,之后继续循环 分别控制 各只LED
}
}
程序分析:
第一:uchar 定义的数据,刚好是8位,直接适用于IO的控制。
第二:<< 左移运算符,a中的8个位同时向左移,最后一个用0补上。(同理>>右移运算类似), a=a<<1; 是先计算右边的式子,即左移一位,然后把结果放回a保存。
第三:if (a==0x00) a=0x01;这是判断结构,if 就是『如果』,由于循环结构for(;;)是无限循环,所以其中 a 每左移8次后会变成0,这时让a设成0x01,可以让重新让第一位的LED受控。
注意if (a==0x00)中的 a==0x00 是两个等于号,这是C语言中的,判断运算符中的一个,类似,还有 >=(小于或等于)、<=(大于或等于)、<(小于)、>( 大于)、!=(不等于) 这些运算符。
五、 程序优化
C51单片机开发的前辈已编有一些方便我们使用的功能模块,我们直接按需调用,于是程序可以再简化。在文件in中定义有循环左移位函数_crol_(),使用方法直接看以下修改后的程序。(类似有循环右移位函数_cror_())
#include "reg52.h"
#include "in"
#define uchar unsigned char
#define uint unsigned int
sbit P10=P1^0;
void mDelay(uint Delay)
{
uint i;
for(;Delay>0;Delay--)
for(i=0;i<124;i++);
}
void main()
{
uchar a = 0x01; // 二进制00000001
for(;;)
{
P1 = ~a; // 首次循环时把a取反的值给P1,11111110
//控制P1.0的LED,注意这时 a 值本身是没有变化的
a = _crol_(a,1); // a 循环左移位,左边移出的放回右边的移空位
mDelay(200); //延时,之后继续循环 分别控制 各只LED
}
}
注意:
1.增加了 #include "in" 这一行,
2.循环左移位函数 _crol_(),函数名前面与后面是下划线。