51单片机学习笔记

学习单片机-

stc89c52单片机。

原理图如图:51单片机学习笔记_第1张图片
编程工具:Keil uVision4
烧录软件:stc-isp-15xx-v6.86I
编译语言:c51

创建51单片机工程:

1.打开软件,点击project新建工程,命名为英文(使用中文会出现一些奇怪的错误)。
2.选择单片机型号为AT89C52。
3.新建main.c文件添加进工程。
4.配置魔术棒工具卡,在output选项卡勾选crete hex,这样在程序运行完成就会产生一个hex文件用于烧录。

烧录软件的使用:

1.选择单片机型号stc89c52。
2.点击打开程序文件,在工程中找到hex文件。
3.点击下载编程,按下单片机开关。

关于LED流水灯模块

51单片机学习笔记_第2张图片
阴极管教为低电平时,Led导通。即0亮1灭。

点亮D1

要点亮D1,就要把P20置0.
代码如下
51单片机学习笔记_第3张图片
reg52.h是51单片机的头文件。

使D1灯闪烁

延时问题:可以让程序进入一个i–的循环,通过设置i的大小来控制延时的时间。
51单片机学习笔记_第4张图片
这个i设置的值要大一点。。我开始设置在100,1000观察不到闪烁现象。。调整到5000可以观察到很快的闪烁。

LED流水灯

要实现的是D1到D8逐渐亮起,每当后一个灯点亮,前一个灯熄灭。
当对P2口赋值时,以十六进制赋值,比如赋0x01,转化为二进制就是00000001,1在P2的最低位即为P2.0,此时D1亮,其他都灭。
第一个灯亮了之后,给他一定的延时,然后下一个灯亮,这个时候可以可以设置P2为二级制值为00000010的16进制,之后逐个设置。。但还有一个简单的方法,使用左右移函数。
51单片机学习笔记_第5张图片
crol(led,1)即为左移函数,使用后小灯从最低位向高位移动,右移函数将crol改为cror即可。

蜂鸣器模块

**51单片机学习笔记_第6张图片
51单片机学习笔记_第7张图片
直接用单片机的io口驱动蜂鸣器很困难,这里通过三极管将电流放大后再进行驱动。
51单片机学习笔记_第8张图片
单片机的蜂鸣器是无源蜂鸣器,需要一个有一定频率的脉冲信号(高低电平不断转换)使他发声。
51单片机学习笔记_第9张图片

动态数码管模块

51单片机学习笔记_第10张图片
51单片机学习笔记_第11张图片
51单片机学习笔记_第12张图片
51单片机学习笔记_第13张图片
动态显示分为段选和位选。这里使用74HC245驱动实现段选,由于数码管是共阴极接法当输入是高电平时对应位置亮。使用74HC318扩展io口实现位选,将输入的三位二进制转换为十进制即可得到位置,例如输入为101转化为二进制即为5对用Y5输出选中LED6为低电平。

#include 

typedef unsigned int u16;
typedef unsigned char u8;

sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

u8 code smgduan[9]={0x06,0x4f,0x06,0x66,0x40,0x6d,0x5b,0x3f
					};


void delay(u16 i)
{
	while(i--);	
}
void DigDisplay()
{
	u8 i;
	for(i=0;i<8;i++)
	{
		switch(i)	 //位选,选择点亮的数码管,
		{
		   case(0):
				LSA=1;LSB=1;LSC=1; break;//显示第0位
			case(1):
				LSA=0;LSB=1;LSC=1; break;//显示第1位
			case(2):
				LSA=1;LSB=0;LSC=1; break;//显示第2位
			case(3):	
				LSA=0;LSB=0;LSC=1; break;//显示第3位
			case(4):
				LSA=1;LSB=1;LSC=0; break;//显示第4位
			case(5):
				LSA=0;LSB=1;LSC=0; break;//显示第5位
			case(6):
				LSA=1;LSB=0;LSC=0; break;//显示第6位
			case(7):
				LSA=0;LSB=0;LSC=0; break;//显示第7位	
		}
		P0=smgduan[i];//发送段码
		delay(100); //间隔一段时间扫描	
		P0=0x00;//消隐
	}
}


void main()
{	
	while(1)
	{	
		DigDisplay();  //数码管显示函数	
	}		
}

数码管显示1314-520,如果把延迟调大到24ms左右可以观察到逐个显示,我直接调到10000观察到很明显的逐个显示现象。

独立按键模块

#include

typedef unsigned int u16;
typedef unsigned char u8;

sbit k1=P3^1;
sbit led=P2^0;

void delay(u16 i)
{
   while(i--);
}
void krun()
{
 if(k1==0)
 {
 delay(1000); //防抖动
 if(k1==0)
 {
  led=~led;
 }
 }
 while(!k1);//检查是否松开
}
void main()
{
  while(1)
  {
  krun();
  }
}

按键防抖动和检查按键是否松开是应该注意的地方;烧录后,按下k1小灯状态改变。

矩阵按键模块

51单片机学习笔记_第14张图片
要实现判断哪个按键被按下并返回他的序号到数码管上。
采用行列扫描法检测,先行后列或先列后行确定按键位置。

#include

typedef unsigned int u16;
typedef unsigned char u8;

#define key P1

sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

u8 keyvalue;
u8 code duan[17]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
                  0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};

void delay(u16 i)
{
 while(i--);
}
void DigDisplay()
{
	u8 i;
	for(i=0;i<2;i++)
	{
	if(i==1)
	{
				LSA=1;LSB=1;LSC=1; 
				P0=~duan[1];//发送段码
				delay(100); //间隔一段时间扫描		
				P0=0x00;//消隐	
	}
	else
	{			

				LSA=0;LSB=1;LSC=1; 	 
				P0=~duan[keyvalue-10];//发送段码
				 delay(100); //间隔一段时间扫描
				 	P0=0x00;//消隐
					}	
				 
					}
		}

void find()
{   
u16 a=0;
  key=0x0f;
  if(key!=0x0f)
  {
 
	  delay(1000);
	    if(key!=0x0f)
		{
		key=0x0f;
		switch(key)
		{
		case(0x07): keyvalue=1;break;
		case(0x0b): keyvalue=2;break;
		case(0x0d): keyvalue=3;break;
		case(0x0e): keyvalue=4;break;
		}
		key=0xf0;
		switch(key)
		{
		case(0x70): keyvalue=keyvalue;break;
		case(0xb0): keyvalue=keyvalue+4;break;
		case(0xd0): keyvalue=keyvalue+8;break;
		case(0xe0): keyvalue=keyvalue+12;break;
		}
		}
  }
   while((key!=0xf0)&&(a<50))
   {
   delay(10);
   a++;
   }
 
}
void main()
{
 while(1)
 {
  find();
  if(keyvalue>=10)
  {
     DigDisplay();
  }
  else
  {
  P0=~duan[keyvalue];//因为上面的段码用的是共阳。。所以这里取反
  }
 }
}

原先设置的检测松手为每次延时100,发现这样当显示10以上位置时会闪烁。。在松手检测中设置a=50时跳出是为了防止程序陷入死等待机。。对为什么要做松手检测有些迷惑。。查找资料
在这里插入图片描述
烧录后,按下按键,1-9在数码管第一位显示,10-16在数码管第一第二位显示。

你可能感兴趣的:(51单片机学习笔记)