嵌入式入门教学——C51(下)

news2024/9/21 0:37:58
  •  嵌入式入门教学汇总:
    • 嵌入式入门教学——C51(上)
    • 嵌入式入门教学——C51(中)
    • 嵌入式入门教学——C51(下)

十三、AT24C02(I2C总线)

1、存储器

  • RAM、ROM各有优势,所以需要结合使用。
1.1、AT24C02简介
  • AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息。
  • 存储介质:E2PROM
  • 通讯接口:I2C总线
  • 容量:256字节

2、AT24C02原理图

  • VDD、VSS:电源(1.8V~5.5V)
  • WE:写使能(低电平有效)
  • SCL、SDA:I2C接口
  • E0、E1、E2:I2C地址

3、I2C总线

3.1、I2C简介
  • 12C总线 (InterIC BUS) 是由Philips公司开发的一种通用数据总线。
  • 两根通信线:SCL (Serial Clock)、SDA(Serial Data )
  • 特点:同步,半双工,带数据应答
  • 通用的I2C总线,可以使各种设备的通信标准统一,对于厂家来说使用成熟的方案可以缩短芯片设计周期、提高稳定性,对于应用着来说,使用通用的通信协议可以避免学习各种各样的自定义协议降低了学习和应用的难度。
3.2、I2C电路规范
  • 所有I2C设备的SCL连在一起,SDA连在一起。
  • 设备的SCL和SDA均要配置成开漏输出模式
    • 【注】开漏输出模式:输出电平只能被拉低,而不能被拉高。开关断开时,处于一种浮空的状态;开关连接时,输出低电平。
  • SCL和SDA各添加一个上拉电阻(把一个信号通过一个电阻接到电源),阻值一般为4.7KQ左右。
    • 【注】为什么开漏输出又要加上拉电阻?
      • 接上拉电阻是因为I2C通信需要输出高电平的能力。一般开漏输出无法输出高电平,如果在漏极接上拉电阻,则可以进行电平转换。
  • 开漏输出和上拉电阻的共同作用实现了“线与”的功能,此设计主要是为了解决多机通信互相干扰的问题。
3.3、I2C时序结构
  • 起始条件:SCL高电平期间,SDA从高电平切换到低电平。
  • 终止条件:SCL高电平期间,SDA从低电平切换到高电平。
  • 发送一个字节(主机->从机):SCL低电平期间,主机将数据位依次放到SDA线上(高位在前),然后拉高SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节。
  • 接收一个字节(从机->主机):SCL低电平期间,从机将数据位依次放到SDA线上(高位在前),然后拉高SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA,让从机使用)。
  • 发送应答:在接收完一个字节之后,主机在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答。
  • 接收应答:在发送完一个字节之后,主机在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)。
3.4、I2C数据帧
  • 发送一帧数据:在起始条件开始后,第一个字节一定是发送从机地址+写标志0。从机地址前四位是固定的,后三位是可配置的,即E0,E1,E2。每发送一个字节的数据,主机需要接收从机的应答。
  • 接受一帧数据:第一个字节一定是发送从机地址+读标志1。第一次发送从机地址后,主机需要接收从机的应答。之后每接收一个字节的数据,主机需要向从机发送应答。
  • 先发送再接收数据帧:

4、AT24C02数据帧

  • 字节写:在WORD ADDRESS(字地址)处写入数据DATA。
  • 随机读:读出在WORD ADDRESS处的数据DATA。
  • AT24C02的固定地址为1010,可配置地址本开发板上为000,所以SLAVE ADDRESS+W为0xA0,SLAVE ADDRESS(从机地址)+R为0xA1。
  • 【注】每次写入需要延时5ms,因为AT24C02的写周期为5ms。连续读不用。

5、AT24C02数据存储(LCD1602显示)

  • 内容:按下按键1,Num加1;按下按键2,Num减1;按下按键3,将十六位的Num拆开写入AT24C02存储器中;按下按键4,AT24C02存储器中读出Num。(数据是写入芯片中的,掉电后仍会保留)
  • 新建工程,在工程目录下新建Functions、Objects、Listings文件夹,将延时函数、独立按键和LCD1602模块放入Functions文件夹中。设置生成.hex文件并将其存放到Objects中,将.lst文件存放到Listings中。新建main.c文件,添加Delay.c、Key.c和LCD1602.c到工程中,并设置其引入路径。
  • 代码结构:
5.1、I2C模块
  • I2C.c
  • #include <REGX52.H>
    sbit I2C_SCL=P2^1;
    sbit I2C_SDA=P2^0;
    /**
    	*	@brief	I2C开始
    	* 	@param	无
    	*	@retval	无
    	*/
    void I2C_Start(void){
    	I2C_SDA=1;
    	I2C_SCL=1;
    	I2C_SDA=0;
    	I2C_SCL=0;
    }
    /**
    	*	@brief	I2C停止
    	* 	@param	无
    	*	@retval	无
    	*/
    void I2C_Stop(void){
    	I2C_SDA=0;
    	I2C_SCL=1;
    	I2C_SDA=1;
    }
    /**
    	*	@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;
    	}
    }
    /**
    	*	@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;
    }
    /**
    	*	@brief	I2C发送应答
    	* 	@param	AckBit 应答位,0为应答,1为非应答
    	*	@retval	无
    	*/
    void I2C_SendAck(unsigned char AckBit){
    	I2C_SDA=AckBit;
    	I2C_SCL=1;
    	I2C_SCL=0;
    }
    /**
    	*	@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.h
  • #ifndef __I2C_H__
    #define __I2C_H__
    void I2C_Start(void);
    void I2C_Stop(void);
    void I2C_SendByte(unsigned char Byte);
    unsigned char I2C_ReceiveByte(void);
    void I2C_SendAck(unsigned char AckBit);
    unsigned char I2C_ReceiveAck(void);
    #endif
5.2、AT24C02模块
  • AT24C02.c
  • #include <REGX52.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_Stop();
    }
    /**
    	*	@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(0); // 发送应答
    	return Data;
    	I2C_Stop();
    }
  • AT24C02.h 
  • #ifndef __AT24C02_H__
    #define __AT24C02_H__
    void AT24C02_WriteByte(unsigned char WordAddress,Data);
    unsigned char AT24C02_ReadByte(unsigned char WordAddress);
    #endif
5.3、编写main.c文件
  • #include <REGX52.H>
    #include "Delay.h"
    #include "Key.h"
    #include "LCD1602.h"
    #include "AT24C02.h"
    unsigned char KeyNum;
    unsigned int Num; // Num为十六位数据,所以需要拆开存放
    void main(){
    	LCD_Init();
    	LCD_ShowNum(1,1,Num,5);
    	while(1){
    		KeyNum=Key();
    		if(KeyNum==1){
    			Num++;
    			LCD_ShowNum(1,1,Num,5);
    		}
    		if(KeyNum==2){
    			Num--;
    			LCD_ShowNum(1,1,Num,5);
    		}
    		if(KeyNum==3){
    			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){
    			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,"        ");
    		}
    	}
    }

待续。。。

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

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

相关文章

pandas(pd)数据的一些操作( np数据转成pd数据、pd数据保存csv文件)

一. np数据转成pd数据 import pandas as pd import numpy as np# 第一种 data {Category: [A, B, C],Value: [10, 20, 15]}df pd.DataFrame(data) print(df)# 第二种 data np.array([[0, 1, 2, 5],[0, 3, 4, 5],[0, 5, 6, 5]]) df pd.DataFrame(data,columns[num1, num2, …

手撕vector容器

一、vector容器的介绍 vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素&#xff0c;但是又不像数组&#xff0c;它的大小是可以动态改变的&#xff0c;而且它的大小会被容器自动处理。 总结&#xff1a;vector是一个动态…

OpenAI Function calling

开篇 原文出处 最近 OpenAI 在 6 月 13 号发布了新 feature&#xff0c;主要针对模型进行了优化&#xff0c;提供了 function calling 的功能&#xff0c;该 feature 对于很多集成 OpenAI 的应用来说绝对是一个“神器”。 Prompt 的演进 如果初看 OpenAI 官网对function ca…

计算机网络-物理层(三)编码与调制

计算机网络-物理层&#xff08;三&#xff09;编码与调制 在计算机网络中&#xff0c;计算机需要处理和传输用户的文字、图片、音频和视频&#xff0c;它们可以统称为消息 数据是运输信息的实体&#xff0c;计算机只能处理二进制数据&#xff0c;也就是比特0和比特1。计算机中…

不含数字的webshell绕过

异或操作原理 1.首先我们得了解一下异或操作的原理 在php中&#xff0c;异或操作是两个二进制数相同时&#xff0c;异或(相同)为0&#xff0c;不同为1 举个例子 A的ASCII值是65&#xff0c;对应的二进制值是0100 0001 的ASCII值是96&#xff0c;对应的二进制值是 0110 000…

CSS加载失败的6个原因

有很多刚刚接触 CSS 的新手有时会遇到 CSS 加载失败这个问题&#xff0c;但测试时&#xff0c;网页上没有显示该样式的问题&#xff0c;这就说明 CSS 加载失败了。出现这种状况一般是因为的 CSS 路径书写错&#xff0c;或者是在浏览器中禁止掉了 CSS 的加载&#xff0c;可以重新…

Linux/Ubuntu 的日常更新,如何操作?

我安装的是Ubuntu 20.04.6 LTS的Windows上Linux子系统版本&#xff0c;启动完成后显示&#xff1a; Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.15.90.4-microsoft-standard-WSL2 x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.c…

使用mysql:5.6和owncloud镜像构建个人网盘

一、拉取镜像 使用docker拉取mysql:5.6和owncloud的镜像 [rootexam ~]# docker pull mysql:5.6 [rootexam ~]# docker pull owncloud 运行镜像生成容器实例 [rootexam ~]# docker run -d --name mydb1 --env MYSQL_ROOT_PASSWORD123456 mysql:5.6 a184c65b73ff993cc5cf86f…

保姆级教程:从0到1搭建Stable Diffusion XL完整工作流进行AI绘画 | 【人人都是算法专家】

Rocky Ding 公众号&#xff1a;WeThinkIn 写在前面 【人人都是算法专家】栏目专注于分享Rocky在AI行业中对业务/竞赛/研究/产品维度的思考与感悟。欢迎大家一起交流学习&#x1f4aa; 大家好&#xff0c;我是Rocky。 之前Rocky详细介绍了Stable Diffusion&#xff08;SD&#…

Scratch 之 RPG 引擎制作教程(1) / 地图行走

大家好&#xff0c;又和大家见面了&#xff0c;那么我们这期讲的就是RPG游戏的地图以及人物的行走。 我发现大家并不是很懂RPG游戏引擎&#xff0c;也就是说这种引擎对于技术的要求还是比较高的。为了让更多人直接上手制作RPG游戏&#xff0c;我打算开启这一系列教程。 这个教程…

又一个 Python 图形界面库,简单好用

迷途小书童的Note 读完需要 10分钟 速读仅需 4 分钟 1 环境 python 3.9.16nicegui 1.3.9 2 前言 在现代计算机应用程序开发中&#xff0c;图形用户界面&#xff08;GUI&#xff09;是用户与程序交互的重要组成部分。然而&#xff0c;GUI 开发往往需要大量的代码和复杂的布局&am…

损失函数——感知损失

感知损失&#xff08;Perceptual Loss&#xff09;是一种基于深度学习的图像风格迁移方法中常用的损失函数。与传统的均方误差损失函数&#xff08;Mean Square Error&#xff0c;MSE&#xff09;相比&#xff0c;感知损失更注重图像的感知质量&#xff0c;更符合人眼对图像质量…

webshell实践复现

目录 一.Nginx负载均衡&#xff08;反向代理及负载均衡配置以省略&#xff09; 1.环境搭建 2.复现 二.webshell实践 1&#xff1a;异或操作绕过 2&#xff1a;取反绕过 3&#xff1a;php语法绕过 一.Nginx负载均衡&#xff08;反向代理及负载均衡配置以省略&#xff09; 注…

EndNote(四)【文献引文格式、同步、智能分组、引文报告、文献笔记导出】

参考文献格式&#xff1a;&#xff08;官网引文格式下载文章引文格式更新-word&#xff09; 官网引文格式下载 网址&#xff1a;Downloads | EndNote 点击output styles&#xff1a; 下下来之后&#xff0c;放在这个路径下&#xff1a; 双击看一下&#xff1a; ok. 比如我们要…

Java面试题(1) 为什么重写 equals() 就一定要重写 hashCode() 方法?

目录 一、问题分析1.equals() 的实现2.equals() 和 hashCode() 的关系3.存在的问题 二、完整回答 一、问题分析 1.equals() 的实现 关于这个问题&#xff0c;首先需要深入了解一下 equals() 这个方法。 String 类 equals() 源码如下&#xff1a; public boolean equals(Obj…

Linux —— 进程间通信(System V)

目录 一&#xff0c;共享内存 申请共享内存 shmget 控制共享内存 shmctl 关联共享内存 shmat / 去联共享内存 shmdt 二&#xff0c;消息队列 创建或打开消息队列 msgget 发送消息 msgsnd / 接收消息 msgrcv 控制消息 msgctl 三&#xff0c;信号量 创建或打开信号量 s…

java八股文面试[java基础]——面相对象特点

三大特点&#xff1a; 封装 继承 多态 面试题&#xff1a;java如何实现多继承&#xff08;除了使用接口之外&#xff09; 实现多继承有三个方法&#xff1a; 多层继承内部类接口 知识来源&#xff1a; 【基础】面向对象_哔哩哔哩_bilibili 【2023年面试】Java面向对象有哪些…

Vue--BM记事本

效果如下&#xff1a; 用到了如下的技术&#xff1a; 1.列表渲染&#xff1a;v-for key的设置 2.删除功能&#xff1a;v-on调用参数 fliter过滤 覆盖修改原数组 3.添加功能&#xff1a;v-model绑定&#xff0c;unshift修改原数组添加 html文件如下&#xff1a; <!DOCTYPE …

1.进程控制

1.进程概念 进程是管理事务的基本单元 2.并发并行 并行(parallel)&#xff1a;指在同一时刻&#xff0c;有多条指令在多个处理器上同时执行。并发(concurrency)&#xff1a;指在同一时刻只能有一条指令执行&#xff0c;但多个进程指令被快速的轮换执行&#xff0c;使得在宏观上…

7-5 特殊a串数列求和

分数 20 全屏浏览题目 切换布局 作者 颜晖 单位 浙大城市学院 给定两个均不超过9的正整数a和n&#xff0c;要求编写程序求aaaaaa⋯aa⋯a&#xff08;n个a&#xff09;之和。 输入格式&#xff1a; 输入在一行中给出不超过9的正整数a和n。 输出格式&#xff1a; 在一行中…