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后再编译。
上一篇: Cargo, the Rust package manager, is not installed or is not on PATH. --windows解决方案
下一篇: BeanFactory 和 ApplicationContext 的区别
本文标签
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。