(学习日记)2023.04.23

写在前面:
由于时间的不足与学习的碎片化,写博客变得有些奢侈。
但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。
既然如此
不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质,以便于日后搜索起来更加容易。


标题的结构如下:“类型”:“知识点”——“简短的解释”
部分内容由于保密协议无法上传。


点击此处进入学习日记的总目录

2023.04.23

  • 一、元件:AT24C02——E2PROM存储器
  • 二、51:I2C总线
  • 三、51:AT24C02数据存储(I2C总线)
    • 1. 编写`I2C总线`函数
    • 2. 编写`AT24C02数据存储`函数
    • 3. 编写`main`函数

一、元件:AT24C02——E2PROM存储器

  1. 存储器介绍
    在这里插入图片描述
    在这里插入图片描述

详细可看计算机三级嵌入式系统开发 知识点笔记

  1. AT24C02介绍
    在这里插入图片描述
  2. 引脚及应用电路(SCL、SDA需要上拉电阻)
    在这里插入图片描述

(此处写保护为高电平有效,但我用的是低电平有效的存储器)

  1. 内部结构框图
    在这里插入图片描述

二、51:I2C总线

  1. I2C总线介绍
    在这里插入图片描述

详细可看计算机三级嵌入式系统开发 知识点笔记
在这里插入图片描述

  1. I2C电路规范
    在这里插入图片描述

上拉电阻
将一个不确定的信号(高或低电平),通过一个电阻与电源VCC相连,固定在高电平。
一般说法是上拉增大电流,下拉电阻是用来吸收电流。
在这里插入图片描述
上拉电阻阻值的选择原则:
1、从节约功耗及芯片的灌电流能力考虑应当足够大;电阻大,电流小。
2、从确保足够的驱动电流考虑应当足够小;电阻小,电流大。
3、对于高速电路,过大的上拉电阻可能边沿变平缓。
综合考虑以上三点,通常在 1K 到 10K 之间选取。对下拉电阻也是类似道理。

开漏输出(Open Drain Output)
常说的与推挽输出相对的就是开漏输出,对于开漏输出和推挽输出的区别最普遍的说法就是开漏输出无法真正输出高电平,即高电平时没有驱动能力,需要借助外部上拉电阻完成对外驱动。
在这里插入图片描述

  1. I2C时序结构
    在这里插入图片描述
    起始条件触发后,SCL开始产生时钟信号
    在这里插入图片描述
    SDA发送一个二进制,SCL拉高一次
    如果在SCL低电平切换SDA,不会有任何影响
    在这里插入图片描述
    和发送相同,不过拉高SCL和放置SDA的变成了从机
    在这里插入图片描述
    主机发送字节后,从机在下一时钟发送应答
    主机接收字节后,主机在下一时钟发送应答

  2. I2C数据帧
    在这里插入图片描述
    第一个字节中前7位为地址,第8位为读取或写入(1是read,0是write),如果器件只有A0~A2三个引脚,那么A3~A6为固定位(查手册)
    在这里插入图片描述
    如果在SCL低电平时切换SDA,认为触发了起始条件或终止条件
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

三、51:AT24C02数据存储(I2C总线)

1. 编写I2C总线函数

  1. 寻找I2C对应引脚,很明显是P20P21
    在这里插入图片描述
sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;
  1. 编写I2C发送开始信号函数
/**
  * @brief  I2C开始
  * @param  无
  * @retval 无
  */
void I2C_Start(void)
{
	I2C_SDA=1;
	I2C_SCL=1;
	I2C_SDA=0;
	I2C_SCL=0;
}
  • 将I2C总线的数据线(SDA)置为高电平(1)。
  • 将I2C总线的时钟线(SCL)置为高电平(1)。
  • 将I2C总线的数据线(SDA)置为低电平(0),表示发送开始信号。
  • 将I2C总线的时钟线(SCL)置为低电平(0),完成发送开始信号。

通过执行这段代码,可以在I2C总线上产生一个开始信号,该信号用于启动I2C通信过程。开始信号的形式是先将数据线(SDA)保持高电平,然后将时钟线(SCL)从高电平变为低电平,表示I2C通信的起始。

  1. 编写I2C发送停止信号函数
/**
  * @brief  I2C停止
  * @param  无
  * @retval 无
  */
void I2C_Stop(void)
{
	I2C_SDA=0;
	I2C_SCL=1;
	I2C_SDA=1;
}
  • 将I2C总线的数据线(SDA)置为低电平(0)。
  • 将I2C总线的时钟线(SCL)置为高电平(1)。
  • 将I2C总线的数据线(SDA)置为高电平(1),表示发送停止信号。

通过执行这段代码,可以在I2C总线上产生一个停止信号,该信号用于结束I2C通信过程。停止信号的形式是先将数据线(SDA)变为低电平,然后将时钟线(SCL)从高电平变为低电平,最后将数据线(SDA)变为高电平,表示I2C通信的结束。停止信号通常用于表示一次完整的数据传输完成。

  1. 编写I2C发送一个字节数据函数
/**
  * @brief  I2C发送一个字节
  * @param  Byte 要发送的字节
  * @retval 无
  */
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,表示要发送的字节数据。
  • 进入一个循环,循环执行8次,每次发送一个bit的数据。
  • 在每次循环中,通过按位与操作(Byte & (0x80 >> i))来获取要发送的bit的值。
  • 将得到的bit值设置到I2C总线的数据线(SDA)上,通过将I2C_SDA变量赋值为该bit值。
  • 将I2C总线的时钟线(SCL)置为高电平(1),表示准备发送数据。
  • 然后将I2C总线的时钟线(SCL)置为低电平(0),完成一个bit的发送。
  • 循环结束后,函数完成了一个字节数据的发送。

该函数用于通过I2C总线发送数据时,通过连续发送8个bit来传输一个字节数据。具体的工作流程是根据要发送的字节数据,按位设置I2C总线的数据线(SDA)的状态,并通过控制I2C总线的时钟线(SCL)来实现数据的发送。

  1. 编写I2C接收一个字节数据函数
/**
  * @brief  I2C接收一个字节
  * @param  无
  * @retval 接收到的一个字节数据
  */
unsigned char I2C_ReceiveByte(void)
{
	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;
}
  • 首先声明了一个无符号字符类型的变量iByte,并将Byte初始化为0x00,用于存储接收到的字节数据。
  • 将I2C总线的数据线(SDA)置为高电平(1),表示准备接收数据。
  • 进入一个循环,循环执行8次,每次接收一个bit的数据。
  • 在每次循环中,首先将I2C总线的时钟线(SCL)置为高电平(1),表示准备接收数据。
  • 然后通过判断I2C总线的数据线(SDA)的状态,来确定接收到的bit是0还是1。如果SDA为高电平,则将对应的bit位置为1(Byte的对应bit位根据循环次数递减),如果SDA为低电平,则对应的bit位置为0。
  • 最后,将I2C总线的时钟线(SCL)置为低电平(0),完成一个bit的接收。
  • 循环结束后,函数返回接收到的一个字节数据(Byte)。

该函数用于从I2C总线接收数据时,通过连续接收8个bit来组成一个字节数据。具体的工作流程是根据I2C总线的时钟和数据线状态来逐位接收数据,并将其组装成一个完整的字节数据。

  1. 编写I2C发送应答信号函数
/**
  * @brief  I2C发送应答
  * @param  AckBit 应答位,0为应答,1为非应答
  * @retval 无
  */
void I2C_SendAck(unsigned char AckBit)
{
	I2C_SDA=AckBit;
	I2C_SCL=1;
	I2C_SCL=0;
}
  • 将I2C总线的数据线(SDA)设置为应答位(AckBit),其中0表示应答,1表示非应答。
  • 将I2C总线的时钟线(SCL)置为高电平(1)。
  • 将I2C总线的时钟线(SCL)置为低电平(0),完成应答信号的发送。

通过执行这段代码,可以在I2C总线上发送应答信号,用于确认接收到的数据或指示拒绝接收数据。应答信号通常在主设备向从设备发送数据后,从设备进行响应,以指示是否成功接收数据。

  1. 编写I2C接收应答信号函数
/**
  * @brief  I2C接收应答位
  * @param  无
  * @retval 接收到的应答位,0为应答,1为非应答
  */
unsigned char I2C_ReceiveAck(void)
{
	unsigned char AckBit;
	I2C_SDA=1;
	I2C_SCL=1;
	AckBit=I2C_SDA;
	I2C_SCL=0;
	return AckBit;
}
  • 将I2C总线的数据线(SDA)置为高电平(1)。
  • 将I2C总线的时钟线(SCL)置为高电平(1)。
  • 将接收到的应答位(AckBit)设置为I2C总线的数据线(SDA)的状态。
  • 将I2C总线的时钟线(SCL)置为低电平(0),完成应答信号的接收。

通过执行这段代码,可以在I2C总线上接收从设备发送的应答信号,并将其作为函数的返回值返回。应答信号通常由从设备发送给主设备,用于确认接收到的数据或指示拒绝接收数据。函数返回的应答位为0表示应答,为1表示非应答。

2. 编写AT24C02数据存储函数

  1. 确定固定地址
    因为器件只有E0~E2三个引脚,那么E3~E6为固定位(1010)
    在这里插入图片描述

在这里插入图片描述

#define AT24C02_ADDRESS		0xA0
  1. 编写 向AT24C02芯片写入一个字节数据 的函数
/**
  * @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_Stop();
}
  • 参数WordAddress表示要写入字节的地址。
  • 参数Data表示要写入的数据。
  • 函数首先发送开始信号(I2C_Start()),然后发送AT24C02芯片的地址(AT24C02_ADDRESS)并接收应答信号(I2C_ReceiveAck())。
  • 接下来,发送要写入的字节的地址(WordAddress)并接收应答信号。
  • 最后,发送要写入的数据(Data)并接收应答信号。
  • 最后发送停止信号(I2C_Stop())结束通信。
  1. 编写 从AT24C02芯片读取一个字节数据 的函数
/**
  * @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_Stop();
	return Data;
}
  • 参数WordAddress表示要读取字节的地址。
  • 函数首先发送开始信号(I2C_Start()),然后发送AT24C02芯片的地址(AT24C02_ADDRESS)并接收应答信号。
  • 接下来,发送要读取的字节的地址(WordAddress)并接收应答信号。
  • 然后再次发送开始信号,发送AT24C02芯片地址的读取位(AT24C02_ADDRESS | 0x01)并接收应答信号。
  • 接下来,从AT24C02芯片读取一个字节数据(Data = I2C_ReceiveByte())。
  • 最后发送非应答信号(I2C_SendAck(1))表示读取结束,并发送停止信号(I2C_Stop())结束通信。
  • 函数返回读取到的数据。

3. 编写main函数

unsigned char KeyNum;
unsigned int Num;

void main()
{
	LCD_Init();
	LCD_ShowNum(1,1,Num,5);
	while(1)
	{
		KeyNum=Key();
		if(KeyNum==1)	//K1按键,Num自增
		{
			Num++;
			LCD_ShowNum(1,1,Num,5);
		}
		if(KeyNum==2)	//K2按键,Num自减
		{
			Num--;
			LCD_ShowNum(1,1,Num,5);
		}
		if(KeyNum==3)	//K3按键,向AT24C02写入数据
		{
			AT24C02_WriteByte(0,Num%256);
			Delay(5);
			AT24C02_WriteByte(1,Num/256);
			Delay(5);
			LCD_ShowString(2,1,"Write OK");
			Delay(1000);
			LCD_ShowString(2,1,"        ");
		}
		if(KeyNum==4)	//K4按键,从AT24C02读取数据
		{
			Num=AT24C02_ReadByte(0);
			Num|=AT24C02_ReadByte(1)<<8;
			LCD_ShowNum(1,1,Num,5);
			LCD_ShowString(2,1,"Read OK ");
			Delay(1000);
			LCD_ShowString(2,1,"        ");
		}
	}
}

main函数通过按键控制一个数字变量Num的增减以及与AT24C02 EEPROM芯片的读写操作。

下面是代码的执行流程:

  1. 首先,调用LCD_Init()函数初始化LCD显示器。
  2. 调用LCD_ShowNum()函数在LCD上显示Num的当前值。
  3. 进入一个无限循环,程序将不断检测按键状态。
  4. 使用Key()函数获取当前按下的按键编号,并将其存储在KeyNum变量中。
  5. 如果按下的是K1按键(KeyNum等于1),则将Num自增,并使用LCD_ShowNum()函数在LCD上显示更新后的Num的值。
  6. 如果按下的是K2按键(KeyNum等于2),则将Num自减,并使用LCD_ShowNum()函数在LCD上显示更新后的Num的值。
  7. 如果按下的是K3按键(KeyNum等于3),则将Num的低8位写入AT24C02的地址0,并将Num的高8位写入AT24C02的地址1。然后,在LCD上显示"Write OK"消息,并进行延迟等待一段时间后清除显示。
  8. 如果按下的是K4按键(KeyNum等于4),则从AT24C02的地址0读取一个字节,并将其存储在Num的低8位中,然后从地址1读取一个字节,并将其存储在Num的高8位中。最后,使用LCD_ShowNum()函数在LCD上显示读取到的Num的值,并显示"Read OK"消息,并进行延迟等待一段时间后清除显示。
  9. 回到步骤3,继续等待按键操作。

这段代码演示了如何使用按键控制一个变量的增减,并将该变量的值写入和从EEPROM芯片读取。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/24659.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

关于安卓以及微软用户chatgpt上一篇文章如今第五点无法正常进入更新解决方法以及附加本地部署

目录 一、问题出现&#xff1a; 1、问题&#xff1a; 原因&#xff1a; 二、解决办法&#xff08;本地部署chatgpt&#xff09; 1、解决&#xff08;国内网络使用真的chatgpt并非镜像&#xff09;一次部署终生使用 第一步&#xff1a; ​编辑第二步&#xff1a; 三、实现结…

让你不再好奇怎么给小说配音

你是否曾经想象过&#xff0c;当你在读小说时&#xff0c;你可以听到人物的声音&#xff0c;感受到情感和气氛的变化&#xff1f;有声书的出现已经让这一切成为可能。然而&#xff0c;如何为小说创造生动的配音效果却是一个需要仔细考虑的问题。如果你还不知道怎么给小说配音的…

智能计价器-第14届蓝桥杯省赛Scratch中级组真题第5题

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第140讲。 智能计价器&#xff0c;本题是2023年5月7日举行的第14届蓝桥杯省赛Scratch图形化编程中级组真题第5题&#…

信号处理与分析-卷积的性质与推导

目录 一、引言 二、信号分析中的卷积 1. 什么是卷积 2. 卷积的性质 3. 卷积的应用 三、离散卷积 1. 离散卷积的定义 2. 离散卷积的计算 3. 离散卷积的性质 四、连续卷积 五、卷积的实际应用 六、总结 一、引言 在信号处理中&#xff0c;卷积是一种非常重要的数学运…

2023年05月小结

5月一晃即将过去&#xff0c;先看看5月份都写了哪些文章&#xff1a; 往期推荐 国内手机号如何注册Google账号 Python中的布尔类型以及布尔值介绍 Python中深拷贝与浅拷贝介绍 Python中的集合介绍 Python中的字典学习笔记 Python学习历程-元组的基本操作回顾 记录我的Python学习…

STM32F103C8T6+2.4寸SPI TFT触摸屏代码+标准库 项目开发

目录 模块清单&#xff1a; 模块介绍&#xff1a; 1&#xff1a;STM32F103C8T6 2&#xff1a;2.4寸SPI TFT触摸屏 项目结果展示 2.4寸 TFT SPI显示触摸屏 2.4寸 SPI TFT 显示触摸屏代码下载链接&#xff1a; (1条消息) 2.4寸SPITFT显示触摸屏资源-CSDN文库 模块清单&#x…

低资源方面级情感分析研究综述

文章目录 前言1. 引言2. 问题定义、数据集和评价指标2.1 问题定义2.2 任务定义2.3 常用数据集 3. 方面级情感分析的方法3.1 **方面词抽取**3.1.1 基于无监督学习的方法3.1.1.1 基于规则的方面词抽取3.1.1.2 基于统计的方面词抽取 3.1.2 基于有监督浅层模型的方法3.1.3 基于有监…

Golang每日一练(leetDay0075) 打家劫舍II、最短回文串

目录 213. 打家劫舍 II House Robber ii &#x1f31f;&#x1f31f; 214. 最短回文串 Shortest Palindrome &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Golang每日一练 专栏 Python每日一练 专栏 C/C…

mysql加强小结 203446

数据库三范式: 什么是范式 规则:想要设计一个好的关系,必须要满足一定的约束条件,有几个等级,一级比一级高 ​ 解决什么问题:让数据库设计更加简洁,结构更加清晰,否则容易造成数据冗余 数据库有哪些范式? ​ 数据库有七大范式,常用的只有三个范式 **第一范式:**业务上属…

【1++的C++初阶】之模板

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的C初阶】 文章目录 一&#xff0c;浅谈模板二&#xff0c;函数模板三&#xff0c;类模板 一&#xff0c;浅谈模板 在前面的文章【【1的C初阶】之C入门篇1】中我们对函数重载有了一定的认识&a…

Linux网络服务:SSH远程访问及控制2

目录 一、理论 1.构建密钥对验证的SSH体系 2.TCP Wrappers访问控制 二、实验 1.ecdsa免密连接 2.rsa免密连接 一、理论 1.构建密钥对验证的SSH体系 &#xff08;1&#xff09;免密连接原理 ① 手动添加客户端的公钥到服务端 ② 服务端收到客户端的公钥后使用客户端公钥…

手机充电宝电子充气泵方案

该充气泵产品方案的运行原理是通过电动机将电能转化为机械能&#xff0c;带动电机做往复运动&#xff0c;从而产生大量压缩空气&#xff0c;达到快速充气的效果。该充气泵可用于气垫床、汽车轮胎、自行车轮胎、足球、游泳圈等各类充气物品。产品设计以人性化为主&#xff0c;简…

jQuery其他方法及插件使用

1. 拷贝对象 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width,…

学习c语言中的几道习题(小有难度)!

有兴趣的朋友可以看着题目自己做做&#xff0c;最后在和答案对比&#xff01;相信能力会有所提升的。我现在只是刚刚开始学习c语言&#xff0c;如果有什么说的不对的地方&#xff0c;网路过的大佬&#xff0c;及时予以指正。多谢&#xff01; 1、函数判断闰年 实现函数判断yea…

flowable的流程任务统计sql(续)

继续之前的文章&#xff0c;我们这里还需要进行按月统计&#xff0c;同时为了适应jeecg的图形显示&#xff0c;所以做了一些调整如下&#xff1a; 1、按月统计任务数量 select DATE_FORMAT(c.days, %Y%m) months, count(num) num from (SELECT DATE_FORMAT(START_TIME_, %Y-%m…

Niagara—— Events and Event Handlers

目录 一&#xff0c;Events 二&#xff0c;Event Handlers 多数情况下&#xff0c;系统中的发射器需相互交互&#xff0c;才能创建所需效果&#xff1b;意味着&#xff0c;一发射器生成数据&#xff0c;另一发射器监听该数据&#xff0c;以执行相应行为&#xff1b;在Niagar…

CentOS 系统上安装 Jenkins

#######################注意我这里安装jenkins版本要求实际是要安装jdk11版本的~~~我一开始弄错了 您可以按照以下步骤在 CentOS 上安装 JDK&#xff1a; 1. 首先&#xff0c;打开终端并使用 yum 命令更新系统软件包列表。输入以下命令来执行此操作&#xff1a; sudo yu…

TimSort——最快的排序算法

TimSort——最快的排序算法 排序算法是每个程序员绕不开的课题&#xff0c;无论是大学课程还是日常工作&#xff0c;都离不开排序算法。常见的排序算法有&#xff1a;冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、基数排序等。下面是这些算法性能的概…

【源码解析】EasyExcel导入导出源码解析

EasyExcel介绍 Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存&#xff0c;poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题&#xff0c;但POI还是有一些缺陷&#xff0c;比如07版Excel解压缩以及解压后存储都…

动态规划-分割回文串 II

动态规划-分割回文串 II 1 题目描述2 示例2.1 示例 1&#xff1a;2.2 示例 2&#xff1a;2.3 示例 3&#xff1a;2.4 提示&#xff1a; 3 解题思路和方法3.1 解题思路3.1.1 确定状态3.1.2 转移方程3.1.3 初始条件和边界情况3.1.4 计算顺序3.1.5 回文串的判断方法 3.2 算法代码实…