江协科技51单片机学习- p27 I2C AT24C02存储器

news2024/12/27 9:41:31

  🚀write in front🚀  
🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​ 

💬本系列哔哩哔哩江科大51单片机的视频为主以及自己的总结梳理📚 

前言:

本文是根据哔哩哔哩网站上“江协科技51单片机”视频的学习笔记,在这里会记录下江协科技51单片机开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了江协科技51单片机教学视频和链接中的内容。

引用:

51单片机入门教程-2020版 程序全程纯手打 从零开始入门_哔哩哔哩_bilibili

​​​​​c51语言变量语句意思,C51中循环语句-CSDN博客

51单片机和AT24C02链接:

51之AT24C02数据存储(I2C总线)_at24c02的地址线-CSDN博客

江协科技 51单片机 AT24C02(I2C总线) 学习笔记——略带拓展_iic总线江协科技-CSDN博客

51单片机系列--AT24C02(总线)_at24c02电路-CSDN博客

单片机学习笔记---AT24C02(I2C总线)_i2c发送应答和接收应答区别-CSDN博客

ROM简介:

ROM学习笔记1-ROM、PROM、EPROM、EEPROM_掩膜rom-CSDN博客

正文:

0. 🌿概述

在淘宝上购买了江协科技51单片机开发板套件(普中科技STC51单片机A2型号),就上在上一篇博文里说的自己计划学习下江协科技51单片机开发教程,通过STC51单片机这种MCU这种贴近于裸机的开发来增加对于系统硬件层面知识的了解和掌握。

术语和缩略语:

缩写全称说明
I2CInter-Integrated Circuit一种串行通信总线
SDA(Serial Data)串行数据线,用于数据传输
SCL(Serial Clock)串行时钟线

1. 🚀 存储器介绍

    正如图所示,存储器主要分为2大类,RAM(Random Access Memory,随机存取存储器)和ROM(Read-Only Memory,只读存储器)。RAM由于是随机存储,所以存储速度快,但是它存在掉电数据丢失的缺点;ROM就正好相反,它存储速度较慢,但是掉电不丢失。

1.1 RAM

  RAM主要分成两种:SRAM和DRAM。

        🌳SRAM(Static RAM,静态RAM),速度比DRAM还更快,内部结构主要是使用触发器来完成数据存储,现在广泛使用于我们的电脑CPU等需要快速缓存的地方,缺点就是相对较贵。

        🌳DRAM(Dynamic RAM,动态RAM),速度稍慢于SRAM,内部主要基于电容来存储数据,所以价格稍微更低。但是电容在存入电信号之后会放电导致电流失,所以DRAM就要每隔一段时间再把数据重新读入,从而完成数据的持续存储。

1.2 ROM

  ROM分为很多种,有:Mask ROM(掩膜ROM),PROM(可编程ROM),EPROM(可擦除编程ROM),E2PROM(电可擦除可编程ROM),Flash(闪存),以及硬盘,软盘,光盘等。

  • 🌳Mask ROM(掩膜ROM)
  • 🌳PROM(可编程ROM)
  • 🌳EPROM(可擦除编程ROM,有一个开窗可以用紫外线照射进行ROM数据擦除)
  • 🌳E2PROM(电可擦除可编程ROM)
  • 🌳Flash(闪存)
  • 🌳硬盘,软盘,光盘等

1.2.1Mask ROM(掩膜ROM)

作为最早出现的一种ROM,它的缺陷自然是很多的,首先它的主要结构是下面的这种二极管:

 并且,由于使用的是这种二极管为基础的电路,它存储的数据就无法被更改,所以得名只读存储器。Mask ROM的数据写入是不可逆的,即一旦数据被写入,就无法更改。这种类型的存储器通常用于存储固定内容,因为它的成本相对较低,且由于其不可擦写的特性,适合于大批量生产。Mask ROM的优点包括成本较低和稳定性较高,因为它们不像其他可擦写存储器那样需要额外的擦写机制。然而,它们的缺点是缺乏灵活性,一旦制造完成,就不能更改存储在其中的数据。

🌳掩膜ROM的读取原理,是按照行列的方式扫描,横线为地址线,竖线为数据输出线,地址横线选中加上高电平,因为二极管的单向导电性,掩膜有二极管的交叉线(相当于一个bit位)就读取到高电平,没有掩膜二极管的就读取到低电平,通过这种方式就可以存储0或者1,这也就是掩膜ROM的工作模型。

1.2.2PROM(可编程ROM)

 PROM,即Program ROM,也称为可编程ROM,它的主要基本原理也是基于二极管:

🌲这里的蓝色二极管是根据我们写入的程序更改的,不同于Mask ROM,Mask ROM的数据是在厂家生产时就定下来了,PROM的数据则是在写入程序的时候生成,所有的电路都具备一对反向的二极管,这样的组成,当我们写入数据为高电平的时候,会触发击穿电压,从而达到写入数据的目的,因为是把这个蓝色的二极管击穿,所以我们写入程序也叫“烧入程序”,名字就是由此而来。但是PROM依旧是不能够擦除数据,只能写入程序,所以它的局限性依旧很大。

1.2.3EPROM(可擦除编程ROM)

由于时代的变迁和技术的革新,ROM的材料也开始变革,所以产生了EPROM,即可擦除编程ROM,它无非就是在PROM的二极管基础上更新材料,变成了可以恢复的一种材料,导致半导体击穿之后还可以通过一定的技术手段恢复,所以称为可擦除编程ROM。

通过紫外线照射擦写ROM的数据,ROM芯片封装上有一个开口,用紫外线灯照射就可以擦除数据。

擦除:EPROM的die会漏在外面,如下图所示。擦除时,只需要用如紫外灯照射20min即可。

1.2.4E2PROM(电可擦除可编程ROM)

由于技术的革新,产生了电可擦除编程ROM,E2PROM和前面的EPROM的区别就是:E2PROM可以通过电直接擦除数据,但是EPROM是不能用电直接擦除的,所以使用电擦除数据,也是一种使用电控制电的手段,也是现在大部分ROM存储的前身。

🌲EEPROM全称Electricially Erasable Programmable Read Only Memory, 通过分析EPROM的原理可知,SIMOS的二氧化硅层比较厚,势垒比较高,所以不管是往浮栅中充入电子还是擦除电子,都需要给电子充较大的能量,使用上的体现就是较高的电压和长时间的光照擦除。后来科学家门对其结构进行改进,在浮栅和漏区设置了一个极薄的氧化层区域,如下图所示。这样的mos管学名叫浮栅隧道氧化层MOS管(Floating-gate Tunnel Oxide MOS),又称Flotox管。

🌲Flotox管的工作原理与SIMOS类似,只是给浮栅充电方式是隧穿(Fowler-Nordheim隧穿),而不是热电子注入。当隧道区的电场足够大时,电子就能在电场的作用下通过隧道形成隧道电流,这种现象叫隧道效应。

  • 🌲编程前,浮栅上没有电荷,就是一个普通NMOS。
  • 🌲编程时,漏源均接地,控制栅上施加一个20V的脉冲。此时,隧道区产生强电场,吸引漏极的电子穿过隧道到达浮栅。撤除电压后,浮栅上的电子可以永久保留(通常可达十年以上)。
  • 🌲擦除时,源极与控制栅接地,在漏极上施加一个20V的脉冲。类似编程,隧道区产生一个反向的强电场,浮栅上的电子又被吸引回漏极,从而擦除信息。

EEPROM的存储单元由两个MOS管组成,T1为Flotox管,T2为普通mos管。
读过程:当要读这个存储单元时,首先给字线施加一个高电平,选通T2。如果T1管未经过编程,浮栅上不带电,在控制栅上施加正电压可以导通T1,位线上读到0;若浮栅中带电荷,控制栅上给高电平无法使T1管导通,位线上读到1(位线上有未画出的上拉到高电平的部分,常态读取时将电压拉高)。
擦除(相当于写1):擦除时,在字线和控制栅线上施加一个高电平脉冲,同时将位线拉低。在脉冲时间内,T2导通,T1的Ugd之间为20V高压,T1管被编程,浮栅上带了电荷。
写过程:对于要写0的存储单元,在字线和位线上施加一个高电平脉冲,同时将控制栅线拉低。在脉冲时间内,T2导通,T1的Ugd之间为-20V高压,T1管浮栅上的电荷被释放(如果有电荷的话)。

1.2.5Flash(闪存)

现在最为广泛使用的ROM存储手段,非常适合用作便携式设备的存储介质,如USB闪存驱动器、智能手机、平板电脑和其他嵌入式系统,广泛适用于各个地方,包括我们的51单片机,堪称ROM唯一真神。

 当然,除了上面这些,还有硬盘,软盘,光盘等ROM式的存储,我们这里就不多赘述了。

2.地址总线

 地址总线较为复杂,我们可以简化成上面的原理图进行说明:首先,地址总线上对应的是不同的设备,一般前面还会加一个译码器,通过对应的地址找到需要选中的设备,并且只能选中一行,这样就可以实现每次只有一个设备写入读取数据,就不会搞混了。选中设备后,设别就把数据写入到数据总线中去了。

3.AT24C02芯片简介

AT24C02芯片
存储介质: E2PROM
通讯接口: I2C 总线
容量: 256 字节

引脚

功能

VCC、GND

电源(1.8V~5.5V )

WP

写保护(高电平有效)

SCL、SDA

I2C接口

A0、A1、A2

I2C地址

AT24C02芯片是一个典型的掉电不丢失的ROM芯片,在单片机中,它的原理图是这样的:

  这里写的是EEPROM,其实就是我们前面所说的E2PROM,电可擦除编程ROM,这里的这个引脚好像和前面标注的不太一样,其实是一样的,只是不同的工程师对它有不同的命名罢了。

🌳还有这里有一个WE,上面有一个横线,在这里就表示Write Eable,即写入使能且低电平有效,意思就是接低电平这个芯片才可以写入数据,在原来的引脚定义图里面其实是WP即Write Protect,写保护,高电平有效,意思就是高电平开启写保护,此时无法写入数据,相反的,想要写入数据就要低电平,在普中单片机的原理图里面,这个引脚接GND,即默认这个引脚就是低电平,无论什么时候都是可以直接写入数据的。

所以,普中科技51单片机开发板在使用单片机的时候其实只要配置SCL,SDA还有三根数据线就行了。它们都是使用的I2C接口,所以我们这里就先了解一下I2C总线。

4.I2C总线

I2C总线(Inter IC BUS)是由Philips公司开发的一种通用数据总线,它使用两根通信线:SCL(Serial Clock)、SDA(Serial Data)。

  • 🌳工作特点是:同步、半双工,带数据应答
  • 🌳前面在讲串口通信的时候稍微提了一下I2C还有这个半双工和同步
  • 🌳同步且半双工就是下面这样:两个设备通过一根时钟线约定时钟周期(同步),在使用通信的两个设备可以通过同一个时钟线互相传递数据。

  • 1.🌿所有I2C设备的SCL连在一起,SDA连在一起。总线结构,在线上外接各种设备。如图中所示。
  • 2🌿.设备的SCL和SDA均要配置成开漏输出模式

这张图就是我们单片机IO口的输出线路,可以将控制器理解为一个电源连上一个无限大的电阻,Q1是一个控制开关的MOS口,当Q1打开时相当于此处不分压,所以输出低电平;当Q1关闭时,Q1处的电阻无限大,外部的VCC和控制器内部形成一个串联电路电阻相比于Q1很小,所以输出高电平。(我们可能在视频中常听到的强/弱上拉就是改变上拉电阻的阻值来达到控制输出电流电压大小的情况。)

  • 🌿开漏输出模式就是将此图中的VCC和上拉电阻去掉,那么在Q1关闭时电路相当于断开,输出的电平是不稳定,非常容易被影响的。

  • 3.🌿SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右
  • 4.🌿开漏输出和上拉电阻的共同作用实现了“线与”的功能,此设计主要是为了解决多机通信互相干扰的问题 


这是一个设备的内部电路图:

  • 🌿I2C总线协议使用两条通信线,一条是SCL串行时钟线,一条是SDA串行数据线。
  • 🌿I2C总线上的所有设备的SCL总线连接在一起,SDA总线连接在一起。
  • 🌿I2C总线是同步,半双工,带应答的协议。
  • 🌿I2C总线的IO口需要配置为开漏输出模式,并且SCL,SDA总线上接上拉电阻,一般接上拉电阻为 4.7K~10K。
  • 🌿I2C总线当SCL为高电平,SDA为高电平时为空闲状态。
  • 🌿I2C总线的通信速率一般是 100Kb/s,高速I2C总线速率为 400Kb/s。

I2C总线是半双工通信协议,也就是同一时间数据只能由主机发送从机接受,或者从机发送主机接收,I2C总线的通信时钟总是由主机控制的,从机按照主机的时钟信号做出反应。

🔍️I2C总线是真正的多主机多从机通信协议,I2C主机和从机通信之间需要先进行从机地址呼叫,I2C从机的地址一般是7位,最多支持2 ^7=128个从机地址。

🔍️I2C从机地址的高4位是向飞利浦公司申请的,第3位地址是设备厂商自行设置的。

4.1 I2C通信协议

起始条件SCL为高电平,SDA从高电平变为低电平表示起始信号
结束条件SCL为高电平,SDA从低电平变为高电平表示接受信号
应答

I2C固定每发送或接受8个数据位,需要回复应答ACK或者非应答

应答ACK=0

非应答NACK=1

非应答

I2C固定每发送或接受8个数据位,需要回复应答ACK或者非应答

应答ACK=0

非应答NACK=1

发送bit在SCL为高电平时SDA必须保持不变,在SCL为低电平时SDA总线上数据才允许变化
接收bit

在SCL为高电平时SDA必须保持不变,在SCL为低电平时SDA总线上数据才允许变化。

主机释放SDA,在主机发送SCL低电平时,从机将0或者1发送到SDA总线,在SCL为高电平时,主机读取SDA总线获取从发送的数据。

4.2 数据帧(针对AT24C02芯片)

  1. Start起始信号
  2. 从机地址7位+1位写位
  3. 等待从机应答ACK
  4. 发送8位地址
  5. 等待从机应答ACK
  6. 发送8位数据
  7. 等待从机应答ACK
  8. 发送Stop信号

  1. Start起始信号
  2. 从机地址7位+1位写位
  3. 等待从机应答ACK
  4. 发送8位地址
  5. 等待从机应答ACK
  6. 重新Start起始信号 (Restart)
  7. 从机地址7位+1位读位
  8. 等待从机应答ACK
  9. 接收从机发送8位数据
  10. 回复NACK给从机,通知从机读取结束
  11. 发送Stop信号

4.3 I2C从机地址 

📒这里我们发现,在S(即开始)之后,有一个SLAVE ADRESS+R/W的一个字节,这个字节就是我们前面说过的匹配对象的过程同时也确定了主机为接收端还是发送端。

📒SLAVE ADRESS+R/W分为前面七个位表示地址和最后一位表示读/写模式

 在不同的设备中,这里都有不同的含义,这里就主要用我们这次使用的AT24C02芯片为例:

首先,对于AT24C02芯片而言,前面四位为它的固定位,这四个位是在I2C原厂商为AT24C02制定的固定地址位,为1 0 1 0,不能更改,后面的三位可以仔细看看:

4.4 I2C时序

根据上述原理图,写程序时我们要建立六个子函数模块,开始传输数据时SCL和SDA都应该处于高电平,先拉低SDA电平再拉低SCL电平,在传输或者接收数据时要拉高并保持SCL高电平然后读取放到SDA上的数据,结束传输数据就和开始时相反,还要设置应答模块在主机和从机间建立应答通讯。

📚️发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位在前),然后拉高SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节 。注:真正传输时只有一条SDA

📚️接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位在前),然后拉高SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA,SDA置1)  

4.5 AT24C02写周期

AT24C02写之后,内部需要5ms的写周期,数据才能写入到内部存储位置。

我们可以发现,这里最短时间限制少于1us,然而我们的单片机最短反应时间足足有1us,所以我们根本不需要担心时间不够的问题,直接使用,不需要延时,单片机完全有时间反应过来。

✏️注意:

写进去立马读出来能读到吗?

✏️不能!

为什么不能?

我们看一下手册上的写周期是5ms

5. 程序源码

I2C.c中模拟I2C总线的时序,起始信号,结束信号,发送字节,接收字节,发送ACK,接收ACK。

I2C.c

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


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

/**
  * @brief  I2C延时通过 
  * @param  
  * @retval 
  */
void I2C_Nop(void)
{
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}

/**
  * @brief  I2C发送起始信号Start
  * @param  无
  * @retval 无
  */
void I2C_Start(void)
{
	I2C_SDA = 1;
	I2C_SCL = 1;	//SCL时钟拉高电平
	I2C_SDA = 0;	//当SCL为高电平时,SDA从高变低表示Start
	I2C_Nop();
	I2C_SCL = 0;
}

/**
  * @brief  I2C发送停止信号Stop
  * @param  无
  * @retval 无
  */
void I2C_Stop(void)
{
	I2C_SDA = 0;	//SDA拉低
	I2C_SCL = 1;	//SCL拉高
	I2C_SDA = 1;	//当SCL为高电平时SDA从低变为高电平表示Stop
}

/**
  * @brief  I2C发送8位数据
  * @param  无
  * @retval 无
  */

void I2C_SendByte(unsigned char byte)
{
	unsigned char i = 0;
	
	for(i=0; i < 8; i++){
		I2C_SDA = byte & (0x80 >> i);
		I2C_Nop();
		I2C_SCL = 1;
		I2C_Nop();
		I2C_SCL = 0;
	}
}

/**
  * @brief  I2C接收8位数据
  * @param  无
  * @retval 接收到的8位数据
  */
unsigned char I2C_RecvByte(void)
{
	unsigned char i = 0;
	unsigned char byte = 0;
		
	byte = 0;
	
	for(i=0; i < 8; i++){
		I2C_SDA = 1;				//释放SDA总线
		I2C_SCL = 1;				//SCL拉高
		if(I2C_SDA){
			byte |= (0x80 >> i);	//读取SDA
		}
		I2C_Nop();
		I2C_SCL = 0;				//SCL拉低
	}
	
	return byte;
}

/**
  * @brief  I2C发送ACK应答信号
  * @param  无
  * @retval 无
  */
void I2C_SendAck(void)
{
	I2C_SDA = 0;
	I2C_SCL = 1;
	I2C_Nop();
	I2C_SCL = 0;
}

/**
  * @brief  I2C发送NACK应答信号
  * @param  无
  * @retval 无
  */
void I2C_SendNack(void)
{
	I2C_SDA = 1;
	I2C_SCL = 1;
	I2C_Nop();
	I2C_SCL = 0;
}

/**
  * @brief  获取I2C ACK应答
  * @param  无
  * @retval 返回值为0或1,0表示ACK,1表示NACK
  */
unsigned char I2C_RecvAck(void)
{
	unsigned char ack = 0;
	
	I2C_SDA = 1;		//释放SDA总线
	I2C_SCL = 1;		//拉高SCL总线
	if(I2C_SDA == 1)	//读取SDA总线
		ack = 1;
	else
		ack = 0;
	
	I2C_Nop();
	I2C_SCL = 0;
	
	return ack;
}


I2C.h

#ifndef __I2C_H__
#define __I2C_H__

void I2C_Start(void);
void I2C_Stop(void);
void I2C_SendByte(unsigned char byte);
unsigned char I2C_RecvByte(void);
void I2C_SendAck(void);
void I2C_SendNack(void);
unsigned char I2C_RecvAck(void);

#endif

AT24C02.C

#include <REGX52.H>
#include <INTRINS.H>
#include "I2C.h"
#include "AT24c02.h"

#define AT24C02_ADDR		0xA0

/**
  * @brief  AT24C02 EPROM存储器指定地址写一个字节数据
  * @param  addr 写存储器地址
  * @param  data 写存储器数据
  * @retval 0 写成功,1 写失败
  */
unsigned char AT24c02_WriteByte(unsigned char addr, unsigned char byte)
{
	I2C_Start();
	
	I2C_SendByte(AT24C02_ADDR);
	I2C_RecvAck();
	
	I2C_SendByte(addr);
	I2C_RecvAck();
	
	I2C_SendByte(byte);
	I2C_RecvAck();
	
	//结束条件
	I2C_Stop();
}

/**
  * @brief  AT24C02 EPROM存储器指定地址读一个字节数据
  * @param  addr 读存储器地址 
  * @retval 
  */
unsigned char AT24c02_ReadByte(unsigned char addr)
{
	unsigned char byte = 0;
	
	//起始条件
	I2C_Start();
	
	//从机地址 写
	I2C_SendByte(AT24C02_ADDR);
	I2C_RecvAck();
	
	//写存储器地址
	I2C_SendByte(addr);
	I2C_RecvAck();
	
	//Restart起始条件
	I2C_Start();
	
	//从机地址 读
	I2C_SendByte(AT24C02_ADDR | 0x01);
	I2C_RecvAck();
	
	byte = I2C_RecvByte();
	I2C_SendNack();
	
	
	//结束条件
	I2C_Stop();
	
	return byte;
}

AT24C02.H

#ifndef __AT24C02_H__
#define __AT24C02_H__

unsigned char AT24c02_ReadByte(unsigned char addr);
unsigned char AT24c02_WriteByte(unsigned char addr, unsigned char byte);

#endif

main.c

#include <REGX52.H>
#include <INTRINS.H>
#include "Delay.h"
#include "Key.h"
#include "timer0.h"
#include "LCD1602.h"
#include "Nixie.h"
#include "AT24c02.h"

unsigned char Minute;
unsigned char Second;
unsigned char HunSecond;
unsigned char Second_Enable = 1;

void main()
{
	unsigned char Key_Num = 0;
	unsigned char Byte = 0;
	unsigned int i = 0;
	
	
	Timer0_Init();
	P2 = 0xff;
	//LCD_Init();
	
	//LCD_ShowString(1,1,"Hello!");
	

	
	Nixie_Setbuffer(1, 0);
	Nixie_Setbuffer(2, 0);
	Nixie_Setbuffer(3, 10);
	Nixie_Setbuffer(4, 0);
	Nixie_Setbuffer(5, 0);
	Nixie_Setbuffer(6, 10);
	Nixie_Setbuffer(7, 0);
	Nixie_Setbuffer(8, 0);
	
	Minute = AT24c02_ReadByte(0x00);
	Second = AT24c02_ReadByte(0x01);
	HunSecond = AT24c02_ReadByte(0x02);
	
	
	while(1)
	{
		Key_Num = Key();
		if(Key_Num == 1){
			Second_Enable = !Second_Enable;
		}
		if(Key_Num == 2){
			AT24c02_WriteByte(0x00, Minute);
			Delay(5);
			AT24c02_WriteByte(0x01, Second);
			AT24c02_WriteByte(0x02, HunSecond);
			
			//LCD_Init();
			//LCD_ShowString(1,1,"Saving Data");
			//Delay(1000);
			//LCD_Init();
			
		}
		if(Key_Num == 2){
			Minute = AT24c02_ReadByte(0x00);
			Second = AT24c02_ReadByte(0x01);
			HunSecond = AT24c02_ReadByte(0x02);
			
			//LCD_Init();
			//LCD_ShowString(1,1,"Read Data");
			//Delay(1000);
			//LCD_Init();
			
		}
		
		//Delay(1000);
	}
}


/**
  * @brief  定时器0中断处理函数模版
  * @param  无
  * @retval 无
  */
void Timer_Routine(void) interrupt 1
{
	static unsigned int key_count = 0;
	static unsigned int nixie_count = 0;
	static unsigned int sec_count = 0;
	
	TR0 = 0;
	
	key_count++;
	if(key_count >= 20)
	{
		Key_Loop();
		key_count = 0;		
	}
	
	
	nixie_count++;
	if(nixie_count >= 2)
	{
		Nixie_Loop();
		nixie_count = 0;		
	}
	
	
		
	sec_count++;
	if(sec_count >= 10)		//10ms
	{
		sec_count = 0; 		//10ms counter
		
		
		if(Second_Enable)
		{
			HunSecond++;
			if(HunSecond >= 100)
			{
				HunSecond = 0;
				Second++;
			}
			if(Second >= 60)
			{
				Second = 0;
				Minute++;
			}
			if(Minute >= 60)
			{
				Minute = 0;
			}
			
			
			
			Nixie_Setbuffer(1, HunSecond%10);
			Nixie_Setbuffer(2, HunSecond/10);
			Nixie_Setbuffer(3, 10);
			Nixie_Setbuffer(4, Second%10);
			Nixie_Setbuffer(5, Second/10);
			Nixie_Setbuffer(6, 10);
			Nixie_Setbuffer(7, Minute%10);
			Nixie_Setbuffer(8, Minute/10);
		}

	}
		
	//定时器溢出之后需要重新装载
	TH0 = (65535 - 1000) / 256;					//12MHz晶振,12分频
	TL0 = (65535 - 1000) % 256 + 1; 			//
	
	TR0 = 1;
}

6. 实验结果

使用Keil5编译代码,并使用STC-ISP烧录到普中科技51单片机开发板上上效果如下:

使用淘宝购买的24MHz逻辑分析仪抓取的51单片机IO口和AT24C02之间的I2C通信时序:

🌳该时序是51单片机IO口通过I2C总线线AT24C02的字地址 0x00 写入数据 0x00时的SCL,SDA总线上的电平时许。

🌳使用逻辑分析仪来分析I2C通信程序故障和抓程序Bug,简直是一把利器,通过逻辑分析仪抓取到的51单片机IO口输出的时序波形对照程序源码可以很容易的发现程序工作异常的问题。

7. 实验遇到问题总结

⚠️ 实验遇到了问题,当把更新数码管显示缓冲区数组的如下10行代码放大定时器中断里的话,发现定时器独立按键扫描不灵敏,有时间会漏扫描按键,按键按下 Key1并松开了但是在定时器中断里的独立按键扫描循环却没有扫描到按键按下和松开。

⚠️有时间检测不到按键被按下

✅️如果将定时器Timer0中断里的更新数码管缓存区的这8行代码从中断处理函数中移出到主函数main(),定时器中断按键扫描就不会漏掉按键按下了。

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

动手学深度学习——5.卷积神经网络

1.卷积神经网络特征 现在&#xff0c;我们将上述想法总结一下&#xff0c;从而帮助我们设计适合于计算机视觉的神经网络架构。 平移不变性&#xff08;translation invariance&#xff09;&#xff1a;不管检测对象出现在图像中的哪个位置&#xff0c;神经网络的前面几层应该对…

C++从入门到起飞之——类的定义/实例化 全方位剖析!

个人主页&#xff1a;秋风起&#xff0c;再归来~ C从入门到起飞 个人格言&#xff1a;悟已往之不谏&#xff0c;知来者犹可追 克心守己&#xff0c;律己则安&#xff01; 目录 1.类的定义 1.1、类定义格式 1.2、访问限定符 1.3、类域 2.实例化 2.…

基于Vue CLI 3构建Vue3项目(Vue2也可参考)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

基于嵌入式Linux的高性能车载娱乐系统设计与实现 —— 融合Qt、FFmpeg和CAN总线技术

随着汽车智能化的发展&#xff0c;车载娱乐系统已成为现代汽车的标配。本文介绍了一个基于Linux的车载娱乐系统的设计与实现过程。该系统集成了音视频娱乐、导航、车辆信息显示等功能&#xff0c;旨在提供安全、便捷、丰富的驾驶体验。 1. 项目概述 随着汽车智能化的发展&…

基于Java的在线考试系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;Java MySQL B/S架构 SpringBoot框架 工具&#xff1a;Eclipse、MySQL环境配置工具 系统展示 首…

备忘录删除了怎么恢复 备忘录误删恢复办法

备忘录作为我们日常生活中的得力助手&#xff0c;帮助我们记录重要事项和灵感&#xff0c;然而&#xff0c;使用中偶尔会出现误删的情况。若不能及时找回误删的内容&#xff0c;可能会造成重要信息的丢失&#xff0c;给我们的工作和生活带来不必要的麻烦。 如果你也担心备忘录…

【权威发布】2024年金融科技与信息技术国际会议(ICFTIT 2024)

2024年金融科技与信息技术国际会议 2024 International Conference on Financial Technology and Information Technology 【1】会议简介 2024年金融科技与信息技术国际会议将在中国成都隆重举行。本次会议围绕“金融创新”、“金融科技”与“信息技术”等核心议题&#xff0c;…

【STC89C51单片机】定时器中断系统

中断概念 中断是一种重要的硬件机制&#xff0c;用于在处理器正在执行程序时&#xff0c;能够及时响应某些外部或内部事件。中断可以临时中止当前正在执行的指令序列&#xff0c;转而去执行专门的中断服务程序&#xff08;ISR&#xff0c;Interrupt Service Routine&#xff0…

navicat15已连接忘记密码

1.导出链接 2.使用文本打开 connections.ncx UserName"root" PasswordXXXX 3.复制加密密码&#xff0c;在线解密 代码在线运行 - 在线工具 php解密代码 <?php class NavicatPassword {protected $version 0;protected $aesKey libcckeylibcckey;protected…

沙尘传输模拟教程(基于wrf-chem)

沙尘传输模拟教程(基于wrf-chem) 文章目录 沙尘传输模拟教程(基于wrf-chem)简介实验目的wrf-chem简介 软件准备wps、wrf-chem安装conda安装ncl安装ncap安装 数据准备气象数据准备下垫面数据准备 WPS数据预处理namelist.wps的设置geogrid.exe下垫面处理ungrib.exe气象数据预处理…

ppt文本框复制到word自动缩进的问题

ppt里的字是无缩进的&#xff1a; 复制粘贴到word中&#xff0c;突然出现2字符缩进&#xff1a; 微软官方嘴硬说没问题我也是无语&#xff01;&#xff01;word保留原格式复制后&#xff0c;出现莫名其妙的缩进 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直…

C++ | Leetcode C++题解之第239题滑动窗口最大值

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {int n nums.size();vector<int> prefixMax(n), suffixMax(n);for (int i 0; i < n; i) {if (i % k 0) {prefixMax[i] num…

阿里云短信PHP集成api类

无需安装sdk扩展包&#xff0c;直接引入类即可使用 V3版本请求体&签名机制:自研请求体和签名机制 - 阿里云SDK - 阿里云 模版内容&#xff1a; <?phpnamespace common\components;use common\constant\UserConst; use common\models\bee\SmsReferer; use common\mode…

git镜像链接

镜像链接https://registry.npmmirror.com/binary.html?pathgit-for-windows/ CNPM Binaries Mirror 1.git init 2.克隆 IDEA集成git git分支

WSL-Ubuntu20.04部署环境配置

1.更换Ubuntu软件仓库镜像源 为了在WSL上使用TensorRT进行推理加速&#xff0c;需要安装以下环境&#xff0c;下面将按以下顺序分别介绍安装、验证以及删除环境&#xff1a; #1.C环境配置 gcc、gdb、g #2.gpu环境 cuda、cudnn #3.Cmake环境 CMake #4.OpenCV环境 OpenCV #5.Ten…

13.8和13.11哪个大?网友吵翻!多个大模型翻车

13.8和13.11哪个更大&#xff1f; 没想到 这样一道简单的数学题 竟引发网友激烈讨论 还难倒了不少大模型 13.8%和13.11%哪个大&#xff1f; 《歌手》排名引网友热议 上周 最新一期的《歌手》公布排名 孙楠得票13.8% 外国歌手香缇莫得票13.11% 引发了网友对排名的质疑…

3.动态规划.题目3

3.动态规划.题目3 题目23.买卖股票的最佳时机3-困难24.买卖股票的最佳时机425.买卖股票的最佳时机含冷冻期26.买卖股票的最佳时机含手续费27.最长递增子序列28.最长连续递增序列29.最长重复子数组30.最长公共子序列31.不相交的线 编辑距离总结 题目 23.买卖股票的最佳时机3-困…

探索LangFlow 1.0:多代理RAG应用程序的未来

在当今快速发展的科技时代&#xff0c;自动化和人工智能&#xff08;AI&#xff09;已经成为了许多企业和个人提高效率的关键工具。对于那些对科技有兴趣的用户来说&#xff0c;寻找一种既创新又易于使用的解决方案是非常重要的。今天&#xff0c;我们将介绍一款名为LangFlow的…

排序算法(4)之快速排序(1)

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 排序算法(4)之快速排序(1) 收录于专栏【数据结构初阶】 本专栏旨在分享学习数据结构学习的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目…

【HarmonyOS】HarmonyOS NEXT学习日记:三、初识ArkUI

【HarmonyOS】HarmonyOS NEXT学习日记&#xff1a;三、初识ArkUI 忘掉HTML和CSS&#xff0c;ArkUI里构建页面的最小单位就是 “组件”&#xff0c;所以今天的目标就是认识一些常用的基础组件&#xff0c;以及他们的用法&#xff0c;对ArkUI形成一个基本认识。 基本组成 了解…