单片机|51单片机学习总结

51单片机学习总结

一、串口

1.LED点亮(跑灯)
(1)亮

#include<reg52.h>
sbit led = P2^0;
void main()
{
	while(1)
	{
		led = 0;//必须是低电平才发光,看电路图
	}	
}

(2)跑灯

#include<reg52.h> 
#include<intrins.h>		   //记住此函数库,用于移位
typedef unsigned int u16;
typedef unsigned char u8;
#define led P2		  //此处用宏定义,sbit用于做单口的定义
void delay(u16 i)
{
	while(i--);
}
void main()
{
	u16 i;
	led = 0xfe;			//1111 1110,LED1亮,剩下的不亮
	delay(50000);		//此处一定要延时
	for(i=0;i<7;i++)
	{
		led = _crol_(led,1);    //左移一位灯
		delay(50000);			//延时闪烁,要不没有差距
	}
	for(i=0;i<7;i++)
	{
		led = _cror_(led,1);  	//右移一位灯
		delay(50000);
	}
}

2.独立键盘

#include<reg52.h>
typedef unsigned char u8;
typedef unsigned int u16;
sbit led = P2^0;
sbit k = P3^3;
void delay(u16 i)
{
	while(i--);
}
void jianpan()			  //最好重新构建函数
{
	if(k==0)			   //第一次判断k的值
	{
		delay(5000);		 //消抖
		if(k==0)		  //第二次判断k的值
		{
			led = ~led;		//令led取反,初始值为0
		}
		while(!k);			//判断按键是否松开
	}
}
void main()
{
	while(1)
	jianpan();
}

3.矩阵键盘(74HC245用于数码管,三态缓冲TTL门,P0控制A)

#include "reg52.h"
typedef unsigned int u16;	  
typedef unsigned char u8;
#define GPIO_DIG P0	  //数码管用到了P0口
#define GPIO_KEY P1	  //矩阵键盘用到了P1口
sbit LSA=P2^2;		  //38译码器的三个输入端
sbit LSB=P2^3;
sbit LSC=P2^4;
u8 KeyValue;	//用来存放读取到的键值,也就是哪一个被摁下
u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值此处是段选,一个数码管的各个段位亮
void delay(u16 i)  //延时函数,i=1时,延时1us
{
	while(i--);	
}
void KeyDown(void)
{
	char a=0;
	GPIO_KEY=0x0f; //初始化矩阵行和列的值,先行后列
	if(GPIO_KEY!=0x0f)//读取按键是否按下,如果按下就不是0x0f了
	{
		delay(1000);//延时10ms进行消抖
		if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
		{	
			//总共有16种组合,也就是16个键
			//测试列,先确定是哪一列
			GPIO_KEY=0X0F;
			switch(GPIO_KEY)
			{
				case(0X07):	KeyValue=0;break; //1列
				case(0X0b):	KeyValue=1;break;
				case(0X0d): KeyValue=2;break;
				case(0X0e):	KeyValue=3;break;
			}
			//测试行
			GPIO_KEY=0XF0;
			switch(GPIO_KEY)
			{
				case(0X70):	KeyValue=KeyValue;break;  //1行
				case(0Xb0):	KeyValue=KeyValue+4;break;
				case(0Xd0): KeyValue=KeyValue+8;break;
				case(0Xe0):	KeyValue=KeyValue+12;break;
			}
			while((a<50)&&(GPIO_KEY!=0xf0))	 //检测按键松手检测
			{
				delay(1000);
				a++;
			}
		}
	}
}
void main()
{	
	LSA=0; //给一个数码管提供位选,第一个数码管亮
	LSB=0;
	LSC=0;
	while(1)
	{	
		KeyDown();		   //按键判断函数
		GPIO_DIG=smgduan[KeyValue];	  
	}		
}

4.蜂鸣器

#include<reg52.h>
typedef unsigned char u8;
typedef unsigned int u16;
sbit beep = P1^5;//蜂鸣器连着单片机的15口
void delay(u16 i)
{
	while(i--);
}
void main()
{
	while(1)
	{
		beep = ~beep;
		delay(100);
	}
}

5.数码管显示数据(静态、动态,74hc573锁存器控制段选P0,也就是abcdefgdp的亮灭)
(1)静态(38译码器,三输入八输出,单片机22,23,24口输入)

#include<reg52.h>
typedef unsigned char u8;
typedef unsigned int u16;
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4; 
u8 code smg[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
				0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//分别代表0—F,其中0x3f=0011 1111(dp g f e d c b a段)
void main()
{
 	LSA=0;
	LSB=0;
	LSC=0;
	P0=smg[0];
	while(1);
}

(2)动态(38译码器,三输入八输出,单片机22,23,24口控制输入,分别可以显示Y0-Y7的输出,一定要消隐)

#include "reg52.h"
typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值
void delay(u16 i)
{
	while(i--);	
}
void DigDisplay()
{
	u8 i;
	for(i=0;i<8;i++)
	{
		switch(i)	 //位选,选择点亮的数码管,
		{
			case(0):
				LSA=0;LSB=0;LSC=0; break;//显示第0位
			case(1):
				LSA=1;LSB=0;LSC=0; break;//显示第1位
			case(2):
				LSA=0;LSB=1;LSC=0; break;//显示第2位
			case(3):
				LSA=1;LSB=1;LSC=0; break;//显示第3位
			case(4):
				LSA=0;LSB=0;LSC=1; break;//显示第4位
			case(5):
				LSA=1;LSB=0;LSC=1; break;//显示第5位
			case(6):
				LSA=0;LSB=1;LSC=1; break;//显示第6位
			case(7):
				LSA=1;LSB=1;LSC=1; break;//显示第7位	
		}
		P0=smgduan[i];//发送段码
		delay(100); //间隔一段时间扫描	
		P0=0x00;//消隐
	}
}
void main()
{	
	while(1)
	{	
		DigDisplay();  //数码管显示函数	
	}		
}

6.点阵(用74HC595,其中11、12管脚分别代表SRCLK(移位寄存器时钟输入P36),RCLK(存储寄存器时钟输入P35),SER(移位的时候应用P34))
位选:选定这个数码管或者点阵这一列LED灯
段选:选定具体数码管的哪个LED段(a-g)或点阵哪一个灯

#include "reg51.h"	
#include<intrins.h>
typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;
sbit SRCLK=P3^6;
sbit RCLK=P3^5;
sbit SER=P3^4;
u8 ledduan[]={0x00,0x00,0x3e,0x41,0x41,0x41,0x3e,0x00};
u8 ledwei[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
void delay(u16 i)
{
	while(i--);	
}
void hc595_sendbite(u8 bite)
{
	u8 a;
	SRCLK=0;	//数据移位和存储都是零
	RCLK=0;
	for(a=0;a<8;a++)
	{
		SER=bite>>7;		//移七位,代表Q7‘输出
		bite<<=1;//表示字节左移一位,分别表示移到前一位寄存器
		SRCLK=1;		//移位寄存器换成高电平有效
		_nop_();	//经过nop空指令,pc加一加一,做短暂延时调整
		_nop_();
		SRCLK=0;	//移位寄存器恢复低电平,为下一次循环移位做准备
	}
	RCLK=1;				 //存储寄存器始终有效
	_nop_();
	_nop_();
	RCLK=0;				 //最终手动软件清零
}
void main()
{			
	u8 i;
	while(1)
	{
		P0=0x7f;		  //初始化,第一列灯
		for(i=0;i<8;i++)
		{
			P0=ledwei[i];		  //位选,选中第一列灯
			hc595_sendbite(ledduan[i]);	//发送段选数据
			delay(100);		   //延时
			hc595_sendbite(0x00); //字节消隐 bite是一个16位字节数据
		}	
	}		
}

二、中断、定时/计数器、通信

1.系统中断
中断只需要考虑选择外部中断IT0(P32)或IT1(P33)是0(电信号触发方式)还是1(下降沿触发方式)
Eg:外部中断0
EA=1;//中断总开关
EX0=1;//开外部中断0
IT0=0/1;//外部触发方式,多为下降沿1触发
中断服务函数

void   int0   ()  interrupt   0    using  1(2)
{
	do anything that you want
}

(外部中断0和1)

#include "reg52.h"		
typedef unsigned int u16;	 
typedef unsigned char u8;
sbit k3=P3^2;  //定义按键K3
sbit led=P2^0;	 //定义P20口是led
void delay(u16 i)
{
	while(i--);	
}
void Int0Init()
{
	//设置INT0,初始化
	IT0=1;//跳变沿出发方式(下降沿)
	EX0=1;//打开INT0的中断允许。	
	EA=1;//打开总中断	
}
void main()		  //main函数里每次都调用函数加一个死循环,一般不改变,改变中断或定时器、初始化的内容
{	
	Int0Init();  //	设置外部中断0
	while(1);		
}
void Int0()	interrupt 0		//外部中断0的中断函数,外部中断1是2
{
	delay(1000);	 //延时消抖
	if(k3==0)
	{
		led=~led;
	}
}

2.定时器和计数器(高8位THx和低8位TLx两个8位寄存器控制,16位)
(1)TCON(控制启动或中断寄存器)
低4位控制外部中断、高4位控制定时器受中断影响开启或关闭的状态
TFx中断请求标志位(硬件自动清零)
TRx开启或断开定时/、计数器(用软件控制,置1时开启)
(2)TMOD(方式选择寄存器,其中M0M1表示四种方式)
低四位控制T0,高四位控制T1,GATE门控位(GATE=0,TRx为1才行)(GATE=1,TRx为1,外部中断INTx为1才行)
C/T位表示模式选择(0定时、1计数)
M1M0掌握(01 方式1 16位定时/计数)(10 方式2 8位自动重装定时/计数)
(3)初始化步骤

/*定时器0
实现现象:下载程序后D1小灯循环点亮1秒,熄灭1秒。使用单片机内部定时器可以实现准确延时。*/
#include "reg52.h"		
typedef unsigned int u16;	  
typedef unsigned char u8;
sbit led=P2^0;	 //定义P20口是led
void Timer0Init()
{
	TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动
	TH0=0XFC;	//给定时器赋初值,定时1ms
	TL0=0X18;	
	ET0=1;//打开定时器0中断允许,与上面中断有关
	EA=1;//打开总中断
	TR0=1;//打开定时器			
}
void main()
{	
	Timer0Init();  //定时器0初始化
	while(1);		
}
void Timer0() interrupt 1
{
	static u16 i;
	TH0=0XFC;	//给定时器赋初值,定时1ms
	TL0=0X18;
	i++;
	if(i==1000)
	{
		i=0;
		led=~led;	
	}	
}

3.定时器中断

/*定时器1											  
实现现象:下载程序后数码管最后一位间隔一秒循环显示0-F。使用单片机内部定时器可以实现准确延时。
数码管亮了,定时1ms后产生中断。
*/
#include "reg52.h"		
typedef unsigned int u16;	  
typedef unsigned char u8;
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值
u8 n=0;
void Timer1Init()
{
	TMOD|=0X10;//选择为定时器1模式,工作方式1,仅用TR1打开启动。
	TH1=0XFC;	//给定时器赋初值,定时1ms,FC18是固定1ms
	TL1=0X18;	
	ET1=1;//打开定时器1中断允许
	EA=1;//打开总中断
	TR1=1;//打开定时器			
}
void main()
{	
	LSA=0;
	LSB=0;
	LSC=0;
	Timer1Init();  //定时器1初始化
	while(1);		
}
void Timer1() interrupt 3 //定时/计数0是1,定时/计数1是3
{
	static u16 i;
	TH1=0XFC;	//还得给定时器赋初值,定时1ms
	TL1=0X18;
	i++;
	if(i==1000)
	{
		i=0;
		P0=smgduan[n++];
		if(n==16)n=0;	
	}	
}

4.串口通信
波特率:每秒传输的二进制代码位数(eg:每秒钟传送240个字符,而每个字符格式包含10位(1个起始位、1个停止位、8个数据位),这时的比特率为:10位×240个/秒 = 2400 bps)
SCON(控制寄存器,设定串口工作方式、接收发送控制以及设置状态标志):
SM0(7)、SM1(6)表示串行口工作方式(4种),SM2(5)表示多机通信控制位,REN(4)表示串行接收位(0时禁止接收、1时允许接收),TI表示发送中断标志位(必用软件清零),RI表示接收中断标志位(内部硬件置1,外部软件清零)。

中级实验

秒表(定时器+中断)

#include "reg52.h"			 
typedef unsigned int u16;	  
typedef unsigned char u8;
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值
u16 s;
u8 sec,mb[3];
void Timer0Init()
{
	TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
	TH0=0XFC;	//给定时器赋初值,定时1ms
	TL0=0X18;	
	TR0=1;//打开定时器			
}
void delay(u16 i)
{
	while(i--);	
}
void DigDisplay()
{
	u8 i;
	for(i=0;i<3;i++)
	{
		switch(i)	 //位选,选择点亮的数码管,
		{
			case(0):
				LSA=0;LSB=0;LSC=0; break;//显示第0位
			case(1):
				LSA=1;LSB=0;LSC=0; break;//显示第1位
			case(2):
				LSA=0;LSB=1;LSC=0; break;//显示第2位	
		}
		P0=smgduan[mb[i]];//发送段码
		delay(1); //间隔一段时间扫描	
		P0=0x00;//消隐
	}
}
void main()
{	
	Timer0Init();
	while(1)
	{
		if(TF0==1)
		{
			TF0=0;
			TH0=0XFC;	//给定时器赋初值,定时1ms
			TL0=0X18;
			s++;
		}
		if(s==1000)		 //到达1s时间
		{	
			s=0;
			sec++;
			if(sec==1000)sec=0;	 //计时到100秒后重新开始
		}
		mb[0]=sec%10;	   //秒表个位
	    mb[1]=sec/10%10;	   //秒表十位
		mb[2]=sec/100;
		DigDisplay();
	}
}
  • 18
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值