51单片机编程应用(C语言):LED灯

爱学C语音的猫 2024-10-26 08:35:02 阅读 86

目录

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合在一起的。 

代码输入代码, 

<code>#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我就不介绍了,左下角的一排控制按钮意思分别是<code>运行 单步 暂停 结束,我们点击运行就可以看到led灯被点亮

现象:

有单片机就在自己单片机烧录看看现象,不过要注意LED模块接的是51单片机的哪个I/O口,比如

所以只能用P2口,不能像上面的代码一样去用其他口子,否则会报错。 

 2.LED灯闪烁

我们要闪烁的话是不是要给个延迟,所以我们要写一个延迟函数

<code>#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); //大约延时450ms

led=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。

最后代码如下:

<code>​

#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后再编译。

 



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。