(51单片机)LCD显示数据存储(DS1302时钟模块教学)(LCD1602教程)(独立按键教程)(延时函数教程)(I2C总线认识)(AT24C02认识)

目录

演示视频:

源代码

main.c

LCD1602.c

LCD1602.h

AT24C02.c

AT24C02.h

Key.c

Key.h

I2C.c

I2C.h

Delay.c

Delay.h

代码解析与教程:

Dealy模块

LCD1602模块

Key模块

I2C总线模块

[AT24C02模块 /E2PROM模块](#AT24C02模块 /E2PROM模块)

main模块


演示视频:

E2PROM数据存储

源代码

如上图将11个文放在Keli5 中即可,然后烧录在单片机中就行了

烧录软件用的是STC-ISP,不知道怎么安装的可以去看江科大的视频:

【51单片机入门教程-2020版 程序全程纯手打 从零开始入门】https://www.bilibili.com/video/BV1Mb411e7re?p=2\&vd_source=ada7b122ae16cc583b4add52ad89fd5e

源代码:

++头文件要记得宏定义和重定义,避免重复调用:++

cpp 复制代码
#ifndef _Timer0_h_//名字根据文件名定义即可
#define _Timer0_h_

//声明函数......

#endif

main.c

cpp 复制代码
#include <STC89C5xRC.H>
#include "LCD1602.h"
#include "Key.h"
#include "Delay.h"
#include "AT24C02.h"

//获取按键值
unsigned char KeyNum;
//16位的int类型的数
unsigned int Num;

//主函数
void main()
{
	LCD_Init();//初始化LCD
	LCD_ShowNum(1,1,Num,5);//初始化显示
	while(1)
	{
		KeyNum=Key();//获取按键值
		if(KeyNum==1)	//K1按键,Num自增
		{
			Num++;
			LCD_ShowNum(1,1,Num,5);//LCD显示当前Num
		}
		if(KeyNum==2)	//K2按键,Num自减
		{
			Num--;
			LCD_ShowNum(1,1,Num,5);//LCD显示当前Num
		}
		if(KeyNum==3)	//K3按键,向AT24C02写入数据
		{
			AT24C02_WriteByte(0,Num%256);//获取高8位,存到0字节地址
			Delay(5);//注意写周期5ms
			AT24C02_WriteByte(1,Num/256);//获取低8位,存到1字节地址
			Delay(5);
			LCD_ShowString(2,1,"Write OK");//LCD显示
			Delay(1000);//显示1秒后消失
			LCD_ShowString(2,1,"        ");//显示1秒后消失
		}
		if(KeyNum==4)	//K4按键,从AT24C02读取数据
		{
			Num=AT24C02_ReadByte(0);//返回值Data赋值给Num,获取0字节地址的高8位
			Num|=AT24C02_ReadByte(1)<<8;//返回值Data赋值给Num,获取1字节地址的低8位,因为Num是16字节,先左移8将前8位变成0,再|(有1即1)将低8位获取出来
			LCD_ShowNum(1,1,Num,5);//LCD显示当前Num(Data)
			LCD_ShowString(2,1,"Read OK ");//LCD显示
			Delay(1000);//显示1秒后消失
			LCD_ShowString(2,1,"        ");//显示1秒后消失
		}
	}
}

LCD1602.c

cpp 复制代码
#include <STC89C5xRC.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()		//@11.0592MHz
{
	unsigned char i, j;

	i = 11;
	j = 190;
	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

cpp 复制代码
#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

AT24C02.c

cpp 复制代码
//AT24C02.c

#include <STC89C5xRC.H>
#include "I2C.h"

#define AT24C02_ADDRESS 0xA0

/**
  * @brief  AT24C02写入一个字节
  * @param  WordAddress 要写入字节的地址
  * @param  Data 要写入的数据
  * @retval 无
  */

void AT24C02_WriteByte(unsigned char WordAddress,Data){
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(WordAddress);
	I2C_ReceiveAck();
	I2C_SendByte(Data);
	I2C_ReceiveAck();
	I2C_Shop();
}

/**
  * @brief  AT24C02读取一个字节
  * @param  WordAddress 要读出字节的地址
  * @retval 读出的数据
  */

unsigned char AT24C02_ReadByte(unsigned char WordAddress){
	unsigned char Data;
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(WordAddress);
	I2C_ReceiveAck();
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS|0x01);
	I2C_ReceiveAck();
	Data=I2C_ReceiveByte();
	I2C_SendAck(1);
	I2C_Shop();
	return Data;
}

AT24C02.h

cpp 复制代码
//AT24C02.h

#ifndef __AT24C02_H__
#define __AT24C02_H__

void AT24C02_WriteByte(unsigned char WordAddress,Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress);
#endif

Key.c

cpp 复制代码
#include <STC89C5xRC.H>
#include "Delay.h"

unsigned char Key()//获取独立按键
{
	unsigned char KeyNumber=0;
	//进行判断是否摁下按键和防抖操作
	if(P31==0){Delay(20);while(P31==0);Delay(20);KeyNumber=1;}
	if(P30==0){Delay(20);while(P30==0);Delay(20);KeyNumber=2;}
	if(P32==0){Delay(20);while(P32==0);Delay(20);KeyNumber=3;}
	if(P33==0){Delay(20);while(P33==0);Delay(20);KeyNumber=4;}
	return KeyNumber;
}

Key.h

cpp 复制代码
#ifndef _Key_h_
#define _Key_h_

unsigned char Key();

#endif

I2C.c

cpp 复制代码
//I2C.c

#include <STC89C5xRC.H>

sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;

//I2C开始
void I2C_Start(){
	I2C_SDA=1;
	I2C_SCL=1;
	I2C_SDA=0;
	I2C_SCL=0;
}

//I2C停止
void I2C_Shop(){
	I2C_SDA=0;
	I2C_SCL=1;
	I2C_SDA=1;
}

//I2C发送一个字节
void I2C_SendByte(unsigned char Byte){
	unsigned char i;
	for(i=0;i<8;i++){
		I2C_SDA=Byte&(0x80>>i);
		I2C_SCL=1;
		I2C_SCL=0;
	}
}

//I2C接收一个字节
unsigned char I2C_ReceiveByte(){
	unsigned char i,Byte=0x00;
	I2C_SDA=1;
	for(i=0;i<8;i++){
		I2C_SCL=1;
		if(I2C_SDA){Byte|=(0x80>>i);}
		I2C_SCL=0;
	}
	return Byte;
}

//I2C发送应答
void I2C_SendAck(unsigned char AckBit){
	I2C_SDA=AckBit;
	I2C_SCL=1;
	I2C_SCL=0;
}

//I2C接收应答
unsigned char I2C_ReceiveAck(){
	unsigned char AckBit;
	I2C_SDA=1;
	I2C_SCL=1;
	AckBit=I2C_SDA;
	I2C_SCL=0;
	return AckBit;
}

I2C.h

cpp 复制代码
//I2C.h

#ifndef __I2C_H__
#define __I2C_H__

unsigned char I2C_ReceiveAck();
void I2C_SendAck(unsigned char AckBit);
unsigned char I2C_ReceiveByte();
void I2C_SendByte(unsigned char Byte);
void I2C_Shop();
void I2C_Start();

#endif

Delay.c

cpp 复制代码
//Delay.c

#include <STC89C5xRC.H>
#include <INTRINS.H>

//延时函数
void Delay(unsigned int xms)		//@11.0592MHz
{
	unsigned char i, j;
	while(xms){
		i = 2;
		j = 199;
		do
		{
			while (--j);
		} while (--i);
		xms--;
	}
}

Delay.h

cpp 复制代码
//Delay.h

#ifndef __Delay_H__
#define __Delay_H__

//延时函数头文件
void Delay(unsigned int xms);
#endif

代码解析与教程:

Dealy模块
  • 包含源代码与头文件,不需要知道怎么实现的会用即可,后续使用,直接将头文件和源代码拿过来用即可;

xms是定义的毫秒,1000毫秒就是1秒;模版生成的是1毫秒的,因此xms等于1000

LCD1602模块
  • 包含源代码与头文件,不需要知道怎么实现的会用即可,后续使用,直接将头文件和源代码拿过来用即可;使用格式:(参考江科大的视频素材)

  • LCD1602相关重要知识:
    • LCD1602有两上下两行显示屏,每行各有16个小显示屏,如上图中的LCD_ShowString(1,3,"Hello"),第一个参数是第一行还是第二行,第2个参数是对应第几行的第几个小显示屏,最后一个是输出的东西,同理,到LCD_ShowNum(1,9,123,3)里,前三个和前面一样,最后一个参数是显示的位数,不够就在前面补0,例如输入1,参数为4,显示就是0001,输入23,参数为3,显示就是023

  • 上图是LCD1602的开发原理模块图,由图可知,P10-P17是控制显示屏的重点;像矩阵那样,S1,由P17和P13控制,同理,其他按键一样,由于开发板限制,我们一般使用列遍历来控制按键,例如:S1,S5,S9,S13他们四个共用P13,所以将其为1列,将P13设定为1,P17设定为0,S1就会亮,其他按键同理。
Key模块
  • 包含源代码与头文件,不需要知道怎么实现的会用即可,后续使用,直接将头文件和源代码拿过来用即可;

    序号1是按键的防抖操作,不需要理解,有按键的地方直接用即可
    序号2是独立按键控制变量。
    KeyNumber就是返回值,按键K1就返回1,其他同理
I2C总线模块
  • 包含源代码与头文件,需要知道怎么实现的,会用,后续使用,直接将头文件和源代码拿过来用即可;因为这部分比较难,轻度认识理解就行,越深越难
  • 在此之前,我们要认识一下存储器:
  • 本篇博客,以及博主的板子型号(STC89c52rc),用的储存器就是E2PROM储存器,简单介绍一下,RAM就是可读写储存器,SRAM是静态的,容量较大,成本高,类似于我们手机内存,DRAM是动态的,容量较小,成本较低,类似于我们手机的运行内存;ROM按常理来说是不可写的,只能读,但是他比RAM不易丢失,有断电保护,断电后数据不易丢失,因此非常受大家的喜欢,所以在后续的更新中,好多ROM也可以读写了,例如E2PROM。
  • 了解上面之后,I2C总线可以理解成一个传输协议,或者传输方式,规则;作用是将一个机器(主机)的数据传输到另一个机器(从机);来看E2PROM原理图

  • 可以看到SCL,SDA是I2C接口,A0,A1,A2是I2C地址,通过这些东西,将主机(单片机)数据传递到从机(E2PROM);下面来看传输是怎么实现的
  • I2C总线传输时有两大部分,时序结构和数据帧,时序结构就是SCL,SDA这种东西的先后顺序或者说他俩的一些重要关系
  • 时序结构有6个小模块,看图:

++这是开始和结束两部分++ ,中间框起来的部分是数据确认阶段,高电平是1(高一点的部分),低电平是0(低一点的部分);图中可以看到在数据确认阶段SCL始终为1,SDA也会变化,因此有

cpp 复制代码
//定义SCL,SDA的引脚
sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;

//I2C开始
void I2C_Start(){
	I2C_SDA=1;
	I2C_SCL=1;
	I2C_SDA=0;
	I2C_SCL=0;
}

//I2C停止
void I2C_Shop(){
//因为开始后SCL=0了,所有这里不需要重复定义了
	I2C_SDA=0;
	I2C_SCL=1;
	I2C_SDA=1;
}

接下来是发送数据,发送一个字节(8个bit),在数据确认期间,SCL先0后1再0,SDA是数据,有可能是1,有可能是0,也会变化,即可发送一个bit,然后循环8次就是一个字节:

cpp 复制代码
//I2C发送一个字节
void I2C_SendByte(unsigned char Byte){
	unsigned char i;
	for(i=0;i<8;i++){
		I2C_SDA=Byte&(0x80>>i);
		I2C_SCL=1;
		I2C_SCL=0;
	}
}

发送字节是参数Byte,i是循环次数,也是右移几个单位,重点来了:注意看图中的先后顺序,SDA先变化,数据是高位在前,0x80是1000 0000,Byte&(有0即0)0x80就是保留Byte的第一位(最高位),其他全变0;然后变化SCL0,1,0;循环八次

接下来是接收数据,接收一个字节(8个bit),在数据确认期间,SCL先0后1再0,SDA是数据,有可能是1,有可能是0,也会变化,即可发送一个bit,然后循环8次就是一个字节:

cpp 复制代码
//I2C接收一个字节
unsigned char I2C_ReceiveByte(){
	unsigned char i,Byte=0x00;
	I2C_SDA=1;
	for(i=0;i<8;i++){
		if(I2C_SDA){Byte|=(0x80>>i);}
		I2C_SCL=1;
		I2C_SCL=0;
	}
	return Byte;
}

接收字节是无参数,返回值是Data ,i是循环次数,也是右移几个单位,重点来了:++注意,主机接收之前需要释放SDA(使SDA=1);++注意看图中的先后顺序,SDA先变化,数据是高位在前,0x80是1000 0000,Byte&(有0即0)0x80就是保留Byte的第一位(最高位),其他全变0;然后变化SCL0,1,0;循环八次

接下来是发送应答和就收应答,作用就是在发送和接收时进行一个反馈,告诉你发送或者接收成功。

cpp 复制代码
//I2C发送应答
void I2C_SendAck(unsigned char AckBit){
	I2C_SDA=AckBit;
	I2C_SCL=1;
	I2C_SCL=0;
}

//I2C接收应答
unsigned char I2C_ReceiveAck(){
	unsigned char AckBit;
	I2C_SDA=1;
	AckBit=I2C_SDA;
	I2C_SCL=1;
	I2C_SCL=0;
	return AckBit;
}

发送应答参数AckBit是应答数据,0就是表示应答,1是不应答; 注意看图中的先后顺序,SDA先变化,将应答数据赋值给SDA;然后变化SCL0,1,0;
接收应答无参数,返回值是AckBit是应答数据,0就是表示应答,1是不应答; ++注意,主机接收之前需要释放SDA(使SDA=1);++注意看图中的先后顺序,SDA先变化将SDA赋值给AckBit;然后变化SCL0,1,0;

  • 了解时序结构之后,来看数据帧,也就是数据是怎么在I2C中传输的:

发送一帧数据是有I2C时序结构的6个小模块组成的,图中都标注了;需要注意的是要告诉I2C总线向谁发送,也就是要先发送从机地址,从机地址最后一个是告诉你是读还是写;

接收一帧数据是有I2C时序结构的6个小模块组成的,图中都标注了;需要注意的是要告诉I2C总线向谁接收,也就是要先发送从机地址,从机地址最后一个是告诉你是读还是写;注意最后一个发送应答是1,表示非应答

复合格式 数据是有I2C时序结构的6个小模块组成的,图中都标注了;需要注意的是要告诉I2C总线向谁发送并接收,也就是要先发送从机地址,从机地址最后一个是告诉你是读还是写;注意最后一个发送应答是1,表示非应答

AT24C02模块 /E2PROM模块
  • 包含源代码与头文件,需要知道怎么实现的,会用,后续使用,直接将头文件和源代码拿过来用即可;因为这部分比较难,轻度认识理解就行,越深越难
  • AT24C02是 E2PROM模块中的一小块,可以理解上述中所提到的从机 ,**主机就是单片机,**因此从机地址就是AT24C02地址;

字节写,随机读 数据帧是有I2C时序结构的6个小模块组成的,图中不再标注了;需要注意的是要告诉I2C总线读还是写,也就是要发送从机地址SLAVE ADDRESS,从机地址最后一个是告诉你是读还是写;还有一个就是发送存储字节地址WORD ADDRESS;注意最后一个发送应答是1,表示非应答

cpp 复制代码
//AT24C02.c

#include <STC89C5xRC.H>
#include "I2C.h"

#define AT24C02_ADDRESS 0xA0

/**
  * @brief  AT24C02写入一个字节
  * @param  WordAddress 要写入字节的地址
  * @param  Data 要写入的数据
  * @retval 无
  */

void AT24C02_WriteByte(unsigned char WordAddress,Data){
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(WordAddress);
	I2C_ReceiveAck();
	I2C_SendByte(Data);
	I2C_ReceiveAck();
	I2C_Shop();
}

/**
  * @brief  AT24C02读取一个字节
  * @param  WordAddress 要读出字节的地址
  * @retval 读出的数据
  */

unsigned char AT24C02_ReadByte(unsigned char WordAddress){
	unsigned char Data;
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(WordAddress);
	I2C_ReceiveAck();
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS|0x01);
	I2C_ReceiveAck();
	Data=I2C_ReceiveByte();
	I2C_SendAck(1);
	I2C_Shop();
	return Data;
}

按照图中的I2C总线时序结构,依次调用函数,即可实现

注意写周期是5ms,意味着每次写完后要延时5ms;

main模块
  • 注释写的很清楚,这里不做解释了
cpp 复制代码
#include <STC89C5xRC.H>
#include "LCD1602.h"
#include "Key.h"
#include "Delay.h"
#include "AT24C02.h"

//获取按键值
unsigned char KeyNum;
//16位的int类型的数
unsigned int Num;

//主函数
void main()
{
	LCD_Init();//初始化LCD
	LCD_ShowNum(1,1,Num,5);//初始化显示
	while(1)
	{
		KeyNum=Key();//获取按键值
		if(KeyNum==1)	//K1按键,Num自增
		{
			Num++;
			LCD_ShowNum(1,1,Num,5);//LCD显示当前Num
		}
		if(KeyNum==2)	//K2按键,Num自减
		{
			Num--;
			LCD_ShowNum(1,1,Num,5);//LCD显示当前Num
		}
		if(KeyNum==3)	//K3按键,向AT24C02写入数据
		{
			AT24C02_WriteByte(0,Num%256);//获取高8位,存到0字节地址
			Delay(5);//注意写周期5ms
			AT24C02_WriteByte(1,Num/256);//获取低8位,存到1字节地址
			Delay(5);
			LCD_ShowString(2,1,"Write OK");//LCD显示
			Delay(1000);//显示1秒后消失
			LCD_ShowString(2,1,"        ");//显示1秒后消失
		}
		if(KeyNum==4)	//K4按键,从AT24C02读取数据
		{
			Num=AT24C02_ReadByte(0);//返回值Data赋值给Num,获取0字节地址的高8位
			Num|=AT24C02_ReadByte(1)<<8;//返回值Data赋值给Num,获取1字节地址的低8位,因为Num是16字节,先左移8将前8位变成0,再|(有1即1)将低8位获取出来
			LCD_ShowNum(1,1,Num,5);//LCD显示当前Num(Data)
			LCD_ShowString(2,1,"Read OK ");//LCD显示
			Delay(1000);//显示1秒后消失
			LCD_ShowString(2,1,"        ");//显示1秒后消失
		}
	}
}

注:该代码是本人自己所写,可能不够好,不够简便,欢迎大家指出我的不足之处。如果遇见看不懂的地方,可以在评论区打出来,进行讨论,或者联系我。上述内容全是我自己理解的,如果你有别的想法,或者认为我的理解不对,欢迎指出!!!如果可以,可以点一个免费的赞支持一下吗?谢谢各位彦祖亦菲!!!!!

相关推荐
FreakStudio6 分钟前
一文速通Python并行计算:09 Python多进程编程-进程之间的数据同步-基于互斥锁、递归锁、信号量、条件变量、事件和屏障
单片机·嵌入式·大学生·面向对象·多进程·技术栈·并行计算·电子diy
Rousson6 分钟前
硬件学习笔记--57 MCU相关资源介绍
笔记·单片机·mcu·学习
XINVRY-FPGA1 小时前
XCZU7EG‑L1FFVC1156I 赛灵思XilinxFPGA ZynqUltraScale+ MPSoC EG
c++·嵌入式硬件·阿里云·fpga开发·云计算·fpga·pcb工艺
汤姆_5112 小时前
【c语言】深度理解指针4——sizeof和strlen
c语言·开发语言
_GR2 小时前
2025年蓝桥杯第十六届C&C++大学B组真题及代码
c语言·数据结构·c++·算法·贪心算法·蓝桥杯·动态规划
Paraverse_徐志斌3 小时前
MySQL 线上大表 DDL 如何避免锁表(pt-online-schema-change)
数据库·mysql·ddl·mysql锁·锁表·pt-osc
哈哈幸运3 小时前
MySQL运维三部曲初级篇:从零开始打造稳定高效的数据库环境
linux·运维·数据库·mysql·性能优化
照海19Gin3 小时前
数据结构中的宝藏秘籍之广义表
c语言·数据结构·算法
愚公搬代码4 小时前
【愚公系列】《Python网络爬虫从入门到精通》055-Scrapy_Redis分布式爬虫(安装Redis数据库)
数据库·爬虫·python
pwzs4 小时前
深入浅出 MVCC:MySQL 并发背后的多版本世界
数据库·后端·mysql