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

目录

1.点亮一个LED灯

 2.LED灯闪烁

3.LED流水灯

3.1.最基础最原始的流水灯实现办法

3.2 移位法实现LED流水灯 

左循环:

右循环 :

3.3 数组法 :

3.4 库函数法 :

1.define和sbit的区别


1.点亮一个LED灯

51单片机编程应用(C语言):LED灯_第1张图片

 在keil中创建工程

51单片机编程应用(C语言):LED灯_第2张图片

51单片机编程应用(C语言):LED灯_第3张图片

遇到这个窗口是提示我们“是否把启动代码添加到工程中”,我们选择是。 

51单片机编程应用(C语言):LED灯_第4张图片

右击source Group 1 

51单片机编程应用(C语言):LED灯_第5张图片

选择c file,学C++的用C++,第三个汇编语言,第四个汇编与C合在一起的。 

51单片机编程应用(C语言):LED灯_第6张图片

代码输入代码, 

#include 
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说明程序是正确的

点击:(与上面步骤交换,先打√再编译)

51单片机编程应用(C语言):LED灯_第7张图片

勾选上如下东西

51单片机编程应用(C语言):LED灯_第8张图片

打开proteus,双击芯片,在Program file打开自己保存项目的文件夹,找到上一步生成的HEX文件

51单片机编程应用(C语言):LED灯_第9张图片  

proteus我就不介绍了,左下角的一排控制按钮意思分别是运行 单步 暂停 结束,我们点击运行就可以看到led灯被点亮

现象:

51单片机编程应用(C语言):LED灯_第10张图片

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

51单片机编程应用(C语言):LED灯_第11张图片

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

 2.LED灯闪烁

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

#include 			 //定义单片机的一些特殊功能寄存器
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和#include"reg52.h"区别
  • 两者来说区别不大,< >的引用是C51库函数里面的文件,而" "是引用我们自己创建的库函数里面的文件

在单片机中有两种延时方式,一种是软件延时,一种是硬件延时(计时器/计数器)。本知识点主要介绍软件延时函数。

51单片机编程应用(C语言):LED灯_第12张图片

我们发现其中多了_nop_()指令,该指令包含在头文件#include中,所以我们需要专门调用一个文件#include 。_nop_()的作用是产生下一条指令,对于延时很短的,要求在us级的,采用“_nop_”函数,这个函数的作用是使程序执行完成后延时几微秒。nop指令为单周期指令,可由晶振频率算出延时时间,对于12M晶振,延时1us。

最后代码如下:

​
#include 
#include 
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 			
 
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 			
#include 
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 
#include 
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 
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 
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 
 
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库函数,其中_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 
    #include 
     
    #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后再编译。
 

你可能感兴趣的:(51单片机编程应用,51单片机,c语言,嵌入式硬件)