51单片机学习第二课---B站UP主江协科技

LCD1602

1、基本知识讲解

2、使用LCD1602

main.c函数

#include <REGX52.H>
#include"LCD1602.h"
void Delay(int xms)
{
	unsigned char i, j;
while(xms--)
{
	
		i = 2;
		j = 239;
		do
			{
		while (--j);
			} while (--i);
}
}
int result=0;
void main()

{
  while(1)
  {
  LCD_Init();
  result++;
  LCD_ShowChar(1,1,'A'); //显示单个字符,要加单引号
  
  LCD_ShowString(2,3,"girl");//显示字符串,要加双引号,从第二行第三列开始显示

  LCD_ShowNum(1,2,123,3);//显示十进制数字,此时显示2345,若为2,则显示45.
 
  LCD_ShowSignedNum(2,7,-66,2);//显示有符号十进制数字,此时只显示一个-号,也是从第七列开始;若为2,则显示-66

  LCD_ShowHexNum(2,10,0x0f,2); //显示十六进制
 
  LCD_ShowBinNum(1,5,0x0f,8)//显示二进制

  LCD_ShowNum(1,14,result,1);
  Delay(10000);//10s后开始加1 ,即1 2 3 4 .......9。
  }

}

lcd1602.c函数

#include <REGX52.H>
//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;

	
		i = 2;
		j = 239;
		do
			{
		while (--j);
			} while (--i);

}
/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}

LCD1602.h函数

#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif

矩阵键盘

1、矩阵键盘

matrixkey.h

#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__

unsigned char MatrixKey();

#endif

matrixkey.c

#include <REGX52.H>
#include "Delay.h"

unsigned char matrixkey()
{
	unsigned char keynumber=0; 
	 P1=0xff;
	 P1_7=0;  //这里用列显示,因为开发板IO口有限,用行扫描会与其他接口共用,蜂鸣器会响
	 //实际用行扫描也行。我这里改成了行扫描,因为我这个板子没有与蜂鸣器相撞
	 if(P1_3==0){Delay(20);while(P1_3==0);Delay(20); keynumber=1;}
	 if(P1_2==0){Delay(20);while(P1_2==0);Delay(20); keynumber=2;}
	 if(P1_1==0){Delay(20);while(P1_1==0);Delay(20); keynumber=3;}
	 if(P1_0==0){Delay(20);while(P1_0==0);Delay(20); keynumber=4;}

	 P1=0xff;
	 P1_6=0;
	 if(P1_3==0){Delay(20);while(P1_3==0);Delay(20); keynumber=5;}
	 if(P1_2==0){Delay(20);while(P1_2==0);Delay(20); keynumber=6;}
	 if(P1_1==0){Delay(20);while(P1_1==0);Delay(20); keynumber=7;}
	 if(P1_0==0){Delay(20);while(P1_0==0);Delay(20); keynumber=8;}

	 P1=0xff;
	 P1_5=0;
	 if(P1_3==0){Delay(20);while(P1_3==0);Delay(20); keynumber=9;}
	 if(P1_2==0){Delay(20);while(P1_2==0);Delay(20); keynumber=10;}
	 if(P1_1==0){Delay(20);while(P1_1==0);Delay(20); keynumber=11;}
	 if(P1_0==0){Delay(20);while(P1_0==0);Delay(20); keynumber=12;}

	 P1=0xff;
	 P1_4=0;
	 if(P1_3==0){Delay(20);while(P1_3==0);Delay(20); keynumber=13;}
	 if(P1_2==0){Delay(20);while(P1_2==0);Delay(20); keynumber=14;}
	 if(P1_1==0){Delay(20);while(P1_1==0);Delay(20); keynumber=15;}
	 if(P1_0==0){Delay(20);while(P1_0==0);Delay(20); keynumber=16;}
	 return keynumber;
}

main.c 

#include <regx52.h>
#include "LCD1602.h"
#include "delay.h"
#include "MatrixKey.h"


unsigned char keynum;

void main()
{
	LCD_Init();
	LCD_ShowString(1, 1,"Matrixkey:");
	
	while(1)
	{	
	    keynum=MatrixKey();
		if(keynum!0)//这里只要不是0,就执行下一步,也可以直接写keynum
		//因为keynum接收的是matrixkey()函数中返回值keynumber,而keynumber不会等于0
		{LCD_ShowNum(2,1,keynum,2);}
	
	}
}

2、矩阵键盘密码锁

main.c

#include <regx52.h>
#include "LCD1602.h"
#include "delay.h"
#include "MatrixKey.h"


unsigned char keynum;
unsigned int Password;
int count;
void main()
{
	LCD_Init();
	LCD_ShowString(1, 1,"Password:");
	
	while(1)
	{	
	    keynum=MatrixKey();
		if (keynum)//要先判断按键是否被按下,然后再确认是哪个按键被按下,这个是大前提
		{
		if(keynum<=10)//这里随便都行5、6、13都行
	 		{
		  		 if(count<4)//因为2^16=65536,按键只能按4次,如果5次最大值会超过65536,会显示乱码
		   			{
		   			Password*=10; //移位
		   			Password+=keynum%10;
		   			count++;
		   			}
		  		 LCD_ShowNum(2,1,Password,4); //显示密码
		  
			}
		if(keynum==11) //确认键,按下这个键对密码进行判断,正确输出ok,错误输出error
			{
		 		if(Password==2345)//判断是否输入正确密码
					{ 
		  				LCD_ShowString(1, 12,"ok");//密码正确,输出ok 
		  				
		 				Password=0;	//密码清0
		 				count=0;//按键次数清0
		  				LCD_ShowNum(2,1,Password,4);//LCD1602第二行显示0
					}
		 		else
					{ 
						LCD_ShowString(1, 12,"error"); //密码错误,输出error
		  			
		  				Password=0;
		  				count=0;
		  				LCD_ShowNum(2,1,Password,4);
					}
			}
		 if(keynum==12)	//取消键,输错了可以按这个键复位,这个复位没有复位掉第一行的ok和error
		 	{
		 	  Password=0;
		  	  count=0;
		  	 LCD_ShowNum(2,1,Password,4);

		 	}

		}
	}
	
}

定时器和中断系统

1、基本知识讲解

晶振周期是12MHZ,12次分频后脉冲周期是1MHZ,所以每过1us加一。

2、用中断来点亮LED灯

main.c

#include<regx52.h>
#include"Timer0.h"

/*void Timer0_Init()
{
  TMOD=0x01; //优化后写为TMOD &= 0xF0;高四位保持不变,低四位清0;TMOD |= 0x01;高四位保持不变,最低位赋值1;为什么要这样写,就是现在用的是定时器0,命令码是0x01,如果直接赋值0x01那么定时器1就用不了了,所以用这种方式,不影响定时器1的使用
  TF0=0;//这条指令也可以不写,写是为了防止开始中断就溢出了,相当于先初始化置为0,实际正常就是0
  TR0=1;
  //TH0=64535/256;//取出高八位	64535/256=252--十六进制为FC        252*256=64512,64535-64512=23--十六进制为17
  //TL0=64535%256;//取出低八位
  ET0=1;
  EA=1;
  PT0=0;

}*/
void main ()
{
  Timer0_Init();
 	while(1)
  {
  }
  	
		
}
void Timer0_Routine()        interrupt 1
{
	static unsigned  int count;	// 静态变量
   	TL0 = 0x18;				
	TH0 = 0xFC;
	count++;
if(count>=1000)
{
  count=0;
  P2_0=~P2_0;//上一次点亮,下一次熄灭,形成循环

}

}

Timer0.c

#include<regx52.h>
void Timer0_Init()		//1毫秒@12.000MHz  软件生成的代码
{
	//AUXR &= 0x7F;			//定时器时钟12T模式,旧版本单片机是12MHZ,不需要再设置为12T模式
	TMOD &= 0xF0;			//设置定时器模式
	TMOD |= 0x01;			//设置定时器模式
	TL0 = 0x18;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
    ET0=1;
 	EA=1;
  	PT0=0;


}
 /*void Timer0_Routine()        interrupt 1
{
	static unsigned  int count;	//
   	TL0 = 0x18;				
	TH0 = 0xFC;
	count++;
if(count>=1000)	//定时1s的代码 ,可直接复制
{
  count=0;
  P2_0=~P2_0;//上一次点亮,下一次熄灭,形成循环

}



}*/

3、用定时器和中断加独立按键实现LED流水灯方向的左移、右移

#include<regx52.h>
#include"Timer0.h"
#include"delay.h"
#include<intrins.h>
unsigned  char keynumber,num,LEDMODE;//注意要char类型,与IO口匹配都为8位,用int实现不了效果


unsigned char keynum()
{
if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);num=2;}
if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);num=1;}
if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);num=3;}
if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);num=4;}
return num;

}
/*void Timer0_Init()
{
  TMOD=0x01; //优化后写为TMOD &= 0xF0;高八位保持不变,低八位赋0;TMOD |= 0x01;高八位保持不变,最低位赋值1;
  TF0=0;//这条指令也可以不写,写是为了防止开始中断就溢出了,相当于先初始化置为0,实际正常就是0
  TR0=1;
  //TH0=64535/256;//取出高八位	64535/256=252--十六进制为FC        252*256=64512,64535-64512=23--十六进制为17
  //TL0=64535%256;//取出低八位
  ET0=1;
  EA=1;
  PT0=0;
																															
}*/
void main ()
{
 P2=0xfe;
 Timer0_Init();
 	while(1)
  {
  	keynumber=keynum();//把返回值赋给keynumber
	if(keynumber)
	{
	  if(keynumber==1)	//独立按键K1按第下,进入模式一,LED流水灯右移。再按下一次,ledmode=2,清0,进入模式0,	LED流水灯左移
	  {					  //注意这里只用了K1独立按键,按其他键对模式没有影响
	   LEDMODE++;
	   if(LEDMODE>=2)LEDMODE=0;

	  }
	 
	}
  }
  	
		
}
void Timer0_Routine()        interrupt 1
{
	static unsigned  int count;	// 静态变量
   	TL0 = 0x18;				
	TH0 = 0xFC;
	count++;
if(count>=500)
{
	count=0;
  if(LEDMODE==0)
  P2=_crol_    (P2, 1);//左移
  if(LEDMODE==1)
  P2=_cror_    (P2, 1);//右移
}

}

4、用定时器和中断来做电子时钟

#include<regx52.h>
#include<intrins.h>
#include"Timer0.h"
#include"delay.h"
#include"LCD1602.h"
unsigned int sec=55,min=58,hour=23;
void main ()
{
	LCD_Init();
	Timer0_Init();
	LCD_ShowString(1,1,"Clock:");
	LCD_ShowString(2,3,":  :");
	while(1)
	{
	 LCD_ShowNum(2,1,hour,2);
	 LCD_ShowNum(2,4,min,2);
	 LCD_ShowNum(2,7,sec,2);
		
	}
		
}
void Timer0_Routine()        interrupt 1
{
	static unsigned  int count;
	
   	TL0 = 0x18;				
	TH0 = 0xFC;
	count++;
if(count>=1000)	//定时1s的代码 ,可直接复制
{
  count=0;
  sec++;
  if(sec>=60)
  {
   min++;
   sec=0;
  }
  if(min>=60)
  {
   hour++;
   min=0;
  }
  if(hour>=24)
  {
   hour=0;
   
  }
}



}

 实际效果:

好的,以下是用51单片机代码实现闹钟的基本步骤: 1. 定义按键、LCD、蜂鸣器等硬件接口,初始化。 2. 定义闹钟时间变量,设置默认闹钟时间。 3. 进入主循环,等待用户设置闹钟时间。 4. 用户设置闹钟时间,将设置的时间与当前时间进行比对。 5. 如果时间到达,LCD显示“时间到了”,蜂鸣器响一段时间,关闭闹钟。 6. 如果时间未到达,继续等待。 下面是一个简单的代码示例: ```c #include <reg51.h> #define uchar unsigned char #define uint unsigned int sbit KEY1 = P1^0; sbit KEY2 = P1^1; sbit KEY3 = P1^2; sbit KEY4 = P1^3; sbit BEEP = P2^0; sbit RS = P3^0; sbit RW = P3^1; sbit E = P3^2; uchar code default_alarm[3] = {12, 0, 0}; // 设置默认闹钟时间 void delay(uint ms) // 延时函数 { uint i, j; for(i=0; i<ms; i++) for(j=0; j<120; j++); } void initLCD() // LCD初始化函数 { writeCommand(0x38); // 显示模式设置:16*2,5*7点阵,8位数据接口 writeCommand(0x0c); // 显示开关控制:显示开,光标关,光标闪烁关 writeCommand(0x06); // 光标/显示移位:光标移位,字符不移位 writeCommand(0x01); // 显示清屏 } void writeCommand(uchar com) // 写命令函数 { RS = 0; RW = 0; P0 = com; E = 1; delay(1); E = 0; delay(1); } void writeData(uchar dat) // 写数据函数 { RS = 1; RW = 0; P0 = dat; E = 1; delay(1); E = 0; delay(1); } void writeStr(uchar *str) // 写字符串函数 { while(*str != '\0') { writeData(*str++); } } void displayTime(uchar hour, uchar minute, uchar second) // 显示时间函数 { writeCommand(0x80); // 第一行第一列 writeData(hour/10 + '0'); writeData(hour%10 + '0'); writeData(':'); writeData(minute/10 + '0'); writeData(minute%10 + '0'); writeData(':'); writeData(second/10 + '0'); writeData(second%10 + '0'); } void main() { uchar hour, minute, second; // 时间变量 uchar alarm_hour, alarm_minute, alarm_second; // 闹钟时间变量 uchar i; initLCD(); // 初始化LCD hour = 12; // 设置默认时间 minute = 0; second = 0; while(1) { displayTime(hour, minute, second); // 显示当前时间 if(KEY1 == 0) // 检测按键1是否按下 { hour++; // 每按一次,小时加1 if(hour > 23) // 超过23就从0开始 hour = 0; delay(100); // 延时去抖 } if(KEY2 == 0) // 同理检测按键2、3 { minute++; if(minute > 59) minute = 0; delay(100); } if(KEY3 == 0) { second++; if(second > 59) second = 0; delay(100); } if(KEY4 == 0) // 设置闹钟时间 { alarm_hour = hour; alarm_minute = minute; alarm_second = second; writeCommand(0xc0); // 显示“设置成功” writeStr("Alarm Set OK!"); BEEP = 1; // 蜂鸣器响一声 delay(500); BEEP = 0; delay(500); writeCommand(0x01); // 清屏 } if(hour==alarm_hour && minute==alarm_minute && second==alarm_second) // 比对时间 { writeCommand(0xc0); // 显示“时间到了” writeStr("Time is up!"); BEEP = 1; // 蜂鸣器响一段时间 for(i=0; i<50; i++) { delay(100); BEEP = !BEEP; } BEEP = 0; delay(500); writeCommand(0x01); // 清屏 } delay(1000); // 延时1秒 second++; // 秒数加1 if(second > 59) // 超过59就进位 { second = 0; minute++; if(minute > 59) { minute = 0; hour++; if(hour > 23) hour = 0; } } } } ``` 注意:以上代码只是一个简单的示例,实际应用中还需要考虑一些异常情况,例如设置不合法的闹钟时间、闹钟响了但用户没有关闭等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值