目录
1.点亮一个LED灯
2.LED灯闪烁
3.LED流水灯
3.1.最基础最原始的流水灯实现办法
3.2 移位法实现LED流水灯
左循环:
右循环 :
3.3 数组法 :
3.4 库函数法 :
1.define和sbit的区别
1.点亮一个LED灯
在keil中创建工程
遇到这个窗口是提示我们“是否把启动代码添加到工程中”,我们选择是。
右击source Group 1
选择c file,学C++的用C++,第三个汇编语言,第四个汇编与C合在一起的。
代码输入代码,
#include <reg52.h>sbit led0 = P2^0;sbit led1 = P2^1;sbit led2 = P2^2;sbit led3 = P1^7;sbit led4 = P3^1;void main(){while(1){led0 = 0;led1= 0;led2= 0;led3= 0;led4= 0;}}
编译:
看有无错误:0 Error说明程序是正确的
点击:(与上面步骤交换,先打√再编译)
勾选上如下东西
打开proteus,双击芯片,在Program file打开自己保存项目的文件夹,找到上一步生成的HEX文件
proteus我就不介绍了,左下角的一排控制按钮意思分别是运行
单步
暂停
结束
,我们点击运行就可以看到led灯被点亮
现象:
有单片机就在自己单片机烧录看看现象,不过要注意LED模块接的是51单片机的哪个I/O口,比如
所以只能用P2口,不能像上面的代码一样去用其他口子,否则会报错。
2.LED灯闪烁
我们要闪烁的话是不是要给个延迟,所以我们要写一个延迟函数
#include <reg52.h> //定义单片机的一些特殊功能寄存器sbit led=P2^0;//定义指定LED灯的管脚 void delay(unsigned int i)//延时函数。unsigned int定义无符号整型,范围0-655535{while(i--);//i=1时,大约延时10us} void main() //主函数,程序从这里开始执行{while(1){led=0; //0表示低电平,共阳极二极管点亮delay(50000); //大约延时450msled=1; //1表示高电平,LED熄灭delay(50000); //大约延时450ms}}
#include<reg52.h>和#include"reg52.h"区别两者来说区别不大,< >的引用是C51库函数里面的文件,而" "是引用我们自己创建的库函数里面的文件
在单片机中有两种延时方式,一种是软件延时,一种是硬件延时(计时器/计数器)。本知识点主要介绍软件延时函数。
我们发现其中多了_nop_()指令,该指令包含在头文件#include<intrins.h>中,所以我们需要专门调用一个文件#include <intrins.h>。_nop_()的作用是产生下一条指令,对于延时很短的,要求在us级的,采用“_nop_”函数,这个函数的作用是使程序执行完成后延时几微秒。nop指令为单周期指令,可由晶振频率算出延时时间,对于12M晶振,延时1us。
最后代码如下:
#include <REGX51.H>#include <intrins.h>sbit LED=P2^0;void Delay500ms()//@11.0592MHz{unsigned char i, j, k;_nop_();i = 4;j = 129;k = 119;do{do{while (--k);} while (--j);} while (--i);}int main(){while(1){LED=1;Delay500ms();LED=0;Delay500ms();}}
3.LED流水灯
3.1.最基础最原始的流水灯实现办法
8个LED灯的定义,让某一个灯点亮就是让这个LED灯为低电平。从左到右依次为01111111、10111111、11011111、11101111、11110111、11111011、11111101、11111110。其中1就是高电平、0位低电平,为低电平时LED点亮。
#include <reg52.h> sbit led1=P2^0;sbit led2=P2^1;sbit led3=P2^2;sbit led4=P2^3;sbit led5=P2^4;sbit led6=P2^5;sbit led7=P2^6;sbit led8=P2^7; void delay(unsigned int i){while(i--);//执行一次大约10us} void main() {while(1){led1=0; delay(5000); //5000*10us=50ms左右led1=1; delay(5000); led2=0; delay(5000); led2=1; delay(5000); led3=0; delay(5000); led3=1; delay(5000); led4=0; delay(5000); led4=1; delay(5000); led5=0; delay(5000); led5=1; delay(5000);led6=0; delay(5000); led6=1; delay(5000); led7=0; delay(5000); led7=1; delay(5000); led8=0; delay(5000); led8=1; delay(5000); }}
上面讲到了软件专门提供了delay函数,下面是1s的闪烁的代码,记住,8051指令集选STY_Y1
下面代码是多了,是因为我把P2口八个端口分开了,但是P2口可以整体赋值的,用16进制表示。
代码就会大大缩短,自己可以写一下。
#include <reg52.h>#include <intrins.h>sbit led1=P2^0;sbit led2=P2^1;sbit led3=P2^2;sbit led4=P2^3;sbit led5=P2^4;sbit led6=P2^5;sbit led7=P2^6;sbit led8=P2^7;void Delay500ms()//@11.0592MHz{unsigned char i, j, k;_nop_();i = 4;j = 129;k = 119;do{do{while (--k);} while (--j);} while (--i);}void main() {while(1){led1=0; Delay500ms();//亮灭500ms合起来一秒。led1=1; Delay500ms();led2=0; Delay500ms(); led2=1; Delay500ms(); led3=0; Delay500ms(); led3=1; Delay500ms(); led4=0; Delay500ms(); led4=1; Delay500ms(); led5=0; Delay500ms(); led5=1; Delay500ms();led6=0; Delay500ms(); led6=1; Delay500ms(); led7=0; Delay500ms(); led7=1; Delay500ms(); led8=0; Delay500ms(); led8=1; Delay500ms(); }}
3.2 移位法实现LED流水灯
左循环:
#include <reg51.h>#include <intrins.h>void Delay500ms()//@11.0592MHz{unsigned char i, j, k;_nop_();i = 4;j = 129;k = 119;do{do{while (--k);} while (--j);} while (--i);}void main(void) { int j; while(1) { P2=0xfe; //11111110, Delay500ms(); for(j=0;j<8;j++) { P2=P2<<1 | 0x01; //左移一位,变成1111 1100,与0000 0001或运算,得到1111 1101, //1111 1101左移一位 得到1111 1010,或运算后1111 1011 Delay500ms(); } } }
或运算应用场合, 某位置置1,其余为不变,左移时最后一位总产生0,所以或运算,使最后一位变1.
但是我们总是用软件生成延时函数是不是很不方便,每次还要让我们自己选择多少秒,生成后复制粘贴,很繁琐,能不能我们想延迟多少毫秒就是多少毫秒,而不是去软件重新生成一个新代码。所以我们写一个delay函数,
用软件先生成一个1ms的函数,
void Delay1ms(unsigned int xms)//@12.000MHz{unsigned char i, j; while(xms){i = 2;j = 239;do{while (--j);} while (--i);xms--; }}
这样的话我每次想改成多少毫秒就直接改x的数值就OK了,比如,我不想500ms,用100ms 就可以如下程序:
#include <reg51.h>void Delay1ms(unsigned int xms)//@12.000MHz{unsigned char i, j; while(xms){i = 2;j = 239;do{while (--j);} while (--i);xms--; }}void main(void) { int j; while(1) { P2=0xfe; //11111110, Delay1ms(100); for(j=0;j<8;j++) { P2=P2<<1 | 0x01; Delay1ms(100); } }}
右循环 :
#include <reg51.h>void Delay1ms(unsigned int xms)//@12.000MHz{unsigned char i, j; while(xms){i = 2;j = 239;do{while (--j);} while (--i);xms--; }}void main(void) { int j; while(1) { P2=0x7f; //0111 1111 Delay1ms(500); for(j=0;j<8;j++) { P2=P2>>1 | 0x80; //右移一位0011 1111,或1000 0000 变成1011 1111 Delay1ms(500); } } }
右移第一位总是0,或上1000 0000 让第一位变成1.
3.3 数组法 :
#include <reg51.h> unsigned char LED [8] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //??8?LED??? void Delay1ms(unsigned int xms)//@12.000MHz{unsigned char i, j; while(xms){i = 2;j = 239;do{while (--j);} while (--i);xms--; }} void main(void) { int j; for(j=0; j<8; j++) {P2 = LED[j]; Delay1ms(500);P2 = 0xff; Delay1ms(500); } }
3.4 库函数法 :
移位函数(最快实现流水灯程序)需要添加#include<intrins.h>库函数,其中_crol_表示左移(字符循环左移),_cror_表示右移(字符循环右移)。具体应用中_crol_(LED,1)表示把LED左移1位(例如:11111110执行完后为11111101),_cror_(LED,2)表示右移2位等(例如:10111111执行完后为11101111)。
_crol_循环左移
<<仅左移,后面补0;
比如
P1=0xfe;
P1=_crol_(P1,1) ; // 1111 1110、1111 1101、1111 1011,如同一条圆形纸带一样循环P1<<=1 ; // 1111 1110、 1111 1100、1111 1000 注意后面补0
代码如下
#include <reg51.h>#include <intrins.h> #define LED P2 //把P2口整体定义为LED,后面可以直接引用 void Delay1ms(unsigned int xms)//@12.000MHz{unsigned char i, j; while(xms){i = 2;j = 239;do{while (--j);} while (--i);xms--; }} void main() //主函数,程序从这里开始执行{int i;LED = 0xfe;for(i=0;i<7;i++) //LED左移一位{LED=_crol_(LED,1);Delay1ms(100); }for(i=0;i<7;i++)//LED右移一位{LED=_cror_(LED,1);Delay1ms(100); } }
#define LED P2 此句话意思为将P2口整体定义为LED,增加了程序的可读性。
1.define和sbit的区别
#define 就是通常说的宏定义,它可以将一个资源命名。
第一:将IO口换一个名字,如:#define LED P2 意思就是将P2口重新命名为LED;
第二:宏定义,将一个语句集合命名,例如:#define goto {ML1=1;ML2=0;MR1=1;MR2=0}
sbit特殊功能寄存器的一个位的声明,如:sbit LED0=P2^0;
#define是宏定义,是一个预编译指令。
如#define PI 3.14 在预编译阶段,会将PI替换为3.14
sbit是C51扩展的变量类型,一个在编译期替换,一个在运行期生效
首先,sbit led= P2,这个写法是错误的,虽然编译时不报错,但编译后执行程序时却是错误的。
sbit 是定义一个引脚的,注意,只是定义一个引脚,而 P2是一个并行口,有8个引脚,是不能sbit 来定义,可以用 sfr 定义。
#define 并不是定义引脚的,也不是定义并行口,只是一个宏替换,就是程序中的led 换成P2后再编译。
首先,sbit led= P2,这个写法是错误的,虽然编译时不报错,但编译后执行程序时却是错误的。
sbit 是定义一个引脚的,注意,只是定义一个引脚,而 P2是一个并行口,有8个引脚,是不能sbit 来定义,可以用 sfr 定义。
#define 并不是定义引脚的,也不是定义并行口,只是一个宏替换,就是程序中的led 换成P2后再编译。