【STC15单片机】模拟I2C操作AT24C02数据读取【更新中】

news2024/11/28 14:33:06

目录

I2C时序结构

I2C代码

AT24C02代码(继承I2C底层代码)

PCF8591


 PCB上线的长短可能影响数据传输的时间,写I2C时序可能就要加一点延时

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)

I2C代码

#include "I2C.h"

//15开发板中AT24C02的IIC通信引脚
sbit I2C_SDA = P2^1;
sbit I2C_SCL = P2^0;

/**
  * @brief	I2C起始信号
  * @param	无
  * @retval	无
  */
void I2C_Start(void)
{
	I2C_SDA = 1;	//拼接其他块,确保默认是1
	I2C_SCL = 1;
	I2C_SDA = 0;	//时序上先拉低
	I2C_SCL = 0;
}

/**
  * @brief	I2C停止信号
  * @param	无
  * @retval	无
  */
void I2C_Stop(void)
{
	I2C_SDA = 0;	//确保默认0,保证由低电平拉高至高电平
	I2C_SCL = 1;
	I2C_SDA = 1;
}

/**
  * @brief	I2C发送一个字节数据
  * @param	Byte 要发送的字节
  * @retval	无
  */
void I2C_SendByte(unsigned char Byte)
{
	unsigned char i;
//	I2C_SCL = 0;	//起始信号已经拉低了,无需重复
	for (i = 0; i < 8; i ++)
	{		
		I2C_SDA = Byte & (0x80>>i);	//把Byte最高位取出,赋值给I2C_SDA,依次从高到底
		I2C_SCL = 1;
//		_nop_();_nop_();_nop_();_nop_();_nop_();//需要0.4us
		I2C_SCL = 0;
	}
}

/**
  * @brief	I2C接收一个字节数据
  * @param	无
  * @retval	接受到的一个字节数据	
  */
unsigned char I2C_ReceiveByte(void)
{
	unsigned char i,Byte=0x00;
	
	I2C_SDA = 1;	//接收之前,先把I2C_SDA置1,释放总线
	for(i=0;i<8;i++)
	{
		I2C_SCL = 1;	//拉高SCL,SCL读取SDA
		if(I2C_SDA == 1){Byte |= (0x80>>i);}
			/*如果读取到的SDA为1,把Byte最高位置1,如果读取到的SDA为0,不处理,默认最高位为0,放在循环里从高位到低位依次读取*/
		I2C_SCL = 0;	//拉低SCL,结束当前循环
	}
	return Byte;
}

/**
  * @brief	I2C发送应答
  * @param	AckBit 应答位,0为应答,1为非应答
  * @retval	无
  */
void I2C_SendAck(unsigned char AckBit)
{				
	I2C_SDA = AckBit;//给应答就是0,不给应答就是1
	I2C_SCL = 1;
	I2C_SCL = 0;
}

/**
  * @brief	I2C接收应答
  * @param	无
  * @retval	接收到的应答位,0为应答,1为非应答
  */
unsigned char I2C_ReceiveAck(void)
{
	unsigned char AckBit;
	I2C_SDA = 1;	//先释放SDA
	I2C_SCL = 1;	//高电平期间读取SDA
	AckBit=I2C_SDA;	//读取到什么,就返回什么
	I2C_SCL = 0;
	return AckBit;	//返回0,代表有应答,返回1,代表无应答
}
#ifndef __I2C_H__
#define __I2C_H__

#include <STC15F2K60S2.H>
#include "intrins.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

 AT24C02设备地址: 

 A2A1A0这三个引脚是用来扩展的,如果不用就默认是000

所以默认设备地址是10100000(0xA0   写数据),10100001(0xA1   读数据)

AT24C02代码(继承I2C底层代码)

#include "AT24C02.h"

#define AT24C02_ADDRESS   0xA0   //从机地址+写  1010 0000

/**
  *@brief   名称:AT24C02写入一个字节
  *@param   参数:WordAddess 要写入字节的地址(0~255)
  *@param   参数: Data 要写入的数据
  *@retval返回值:无
  */
void AT24C02_WriteByte(unsigned char WordAddress, unsigned char Data)
{
//	unsigned char Ack;
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);//从机地址+写
//	Ack = I2C_ReceiveAck();
//	if(Ack == 0) 
//	{
//		P2 = 0x80;	// 1000 0000
//		P0 = 0x00;
//	}	//先测试是否有应答,定义的Ack被I2C_ReceiveAck();赋值,然后就可以测试了
	I2C_ReceiveAck();
	I2C_SendByte(WordAddress);	//要写入数据的地址
	I2C_ReceiveAck();
	I2C_SendByte(Data);	//写入数据
	I2C_ReceiveAck();
	I2C_Stop();
}

/**
  *@brief   名称:AT24C02读取一个字节
  *@param   参数:WordAddess 要读出字节的地址
  *@retval返回值:读出的数据
  */
unsigned char AT24C02_ReadByte(unsigned char WordAddess)
{
	unsigned char Data;
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);	//从机地址+写
	I2C_ReceiveAck();				//接受应答
	I2C_SendByte(WordAddess);		//数据的地址
	I2C_ReceiveAck();
	
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS | 0x01);//发送从机地址+读本函数第二个函数,或上0x01变成读地址(0xA1)
	I2C_ReceiveAck();
	Data = I2C_ReceiveByte();
	I2C_SendAck(1);	//不发送应答
	I2C_Stop();
	
	return Data;
}
#ifndef __AT24C02_H__
#define __AT24C02_H__

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

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

#endif

测试:先写入,不读取,然后下载只读取的函数,如果读出数值没有问题,那就正确了

#include <STC15F2K60S2.H>
#include "smg.h"
#include "I2C.h"
#include "AT24C02.h"

unsigned char Data;

void main()
{
	All_Init();

	AT24C02_WriteByte(0,88);
	Delay_ms(5);		//写数据的周期 5ms
	Data = AT24C02_ReadByte(0);	
	
	while(1)
	{
		Nixie(1,Data/10);
		Nixie(2,Data%10);
	}
}

PCF8591

PCF8591地址:1001 0000(0x90   写),1001 0001(0x91   读)

 

 支持四路AD转换(模拟信号转数字信号),支持一路DA转换(数字信号转模拟信号)

 程序有问题,不粘贴了,调成功了在粘贴过来


学习资料:

江科大自化协---51单片机入门教程-2020版 程序全程纯手打 从零开始入门【12-2】

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

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

相关文章

什么蓝牙耳机好用性价比高?性价比最高的蓝牙耳机品牌排行

无线耳机迅速成为了电子产品中的佼佼者&#xff0c;无论是日常通勤、办公或是休闲、娱乐&#xff0c;几乎都能看到戴耳机听音乐的人&#xff0c;细心的朋友应该能够发现&#xff0c;蓝牙耳机在这几年有了很大的进步&#xff0c;下面我就分享几款当前性价比最高的蓝牙耳机。 TO…

T38,数的递归

描述 输入一棵节点数为 n 二叉树&#xff0c;判断该二叉树是否是平衡二叉树。 在这里&#xff0c;我们只需要考虑其平衡性&#xff0c;不需要考虑其是不是排序二叉树 平衡二叉树&#xff08;Balanced Binary Tree&#xff09;&#xff0c;具有以下性质&#xff1a;它是一棵空…

分账系统逻辑

一、说明 主体与业务关系方进行相关利益和支出的分配过程 使用场景&#xff1a; 在分销业务中&#xff0c;主营商户收到用户购买分销商品所支付的款项后&#xff0c;可以通过分账逻辑&#xff0c;与分销商进行佣金结算。在零售、餐饮等行业中&#xff0c;当销售人员完零售等…

小樽 C++指针—— (壹) 指针变量

(壹) 指针变量 一、指针的概念与定义 二、给指针变量p赋值 三、指针变量的的、-运算 四、无类型指针 五、多重指针 C (壹) 指针变量 小明想把从李华家借来的书——《CCF中学生计算机程序设计》还给李华&#xff0c;但李华不在家&#xff0c;于是把书放到书架第3层的最右边…

入门介绍对ChatGPT的应用程序接口API的访问<openai模块>

首先本人建议使用国内环境安装openai模块(这是我切换环境使用国外IP之后安装有问题的建议)pip install openai -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com安装好了之后&#xff0c;我们切换成科学上网&#xff0c;然后我们来到https://platform.openai…

十大开源测试工具和框架,一定有你需要的

目录 前言 Katalon Studio Selenium Appium JMeter SOAP UI Robot Framework Watir JUnit Robotium Citrus 总结 前言 免费的开源框架和工具由于其开源特性&#xff0c;现在逐渐成为自动化测试的首选解决方案。区别在于&#xff0c;你是喜欢使用类库编写一个全新的…

Ubuntu20.04安装redis与远程连接

一、安装Redis5.7 1、安装Redis apt-get install redis-server2、安装完成后&#xff0c;Redis服务器会自动启动。查看redis是否启动成功 service redis-server status #查看状态如下显示Active:active(running)状态&#xff1a;表示redis已在运行&#xff0c;启动成功。 …

Linux常用命令1

目录1、远程登陆服务器2、文件相关&#xff08;1&#xff09;文件和目录属性&#xff08;2&#xff09;创建目录mkdir&#xff08;3&#xff09;删除目录rmdir&#xff08;4&#xff09;创建文件touch&#xff08;5&#xff09;删除文件或目录rm&#xff08;6&#xff09;ls命令…

使用Python调用ChatGPT

import openai# Set up the OpenAI API clientopenai.api_key "你的KEY"# Set up the model and promptmodel_engine "ada"prompt input(请输入字符串&#xff1a;)# Generate a responsecompletion openai.Completion.create(enginemodel_engine,prom…

情人节使用AI TOOL来创建一个甜言蜜语的女伴

一、首先使用chatgpt生成一段情侣间的对话&#xff0c;需要反复几次&#xff0c;达到满意的程度&#xff0c;然后将女方的话归在一起。 这是一个情侣私下谈话的场景&#xff0c;女方表示对男朋友精心准备的情人节安排和礼物表示很满意 二、 打开网站&#xff1a;https://lexic…

Global mapper下载并使用在线数据---以下载ASTER GDEM为例

Global mapper 有个非常厉害的功能&#xff0c;就是下载在线资源&#xff0c;且不需要插件 当我们需要使用dem的时候&#xff0c;手头没有&#xff0c;需要去官网或者其他地方下载&#xff0c;就很麻烦 下载在线数据步骤—以下载ASTER DEM为例 打开global mapper后&#xff…

Unity 工具 之 SoftMask软遮罩 实现 UI 边缘渐变过渡的简单使用介绍

Unity 工具 之 SoftMask软遮罩 实现 UI 边缘渐变过渡的简单使用介绍 目录 Unity 工具 之 SoftMask软遮罩 实现 UI 边缘渐变过渡的简单使用介绍 一、简单介绍 二、Mask 实现的遮罩效果 三、Soft Mask 实现遮罩效果 四、 Soft Mask 的一些设置 五、插件下载 一、简单介绍 U…

Google Chrome开发者工具

文章目录简介debuggerDOMContentLoaded与load的区别最后我们来回答这个问题&#xff1a;我们为什么一再强调将css放在头部&#xff0c;将js文件放在尾部简介 Chrome 开发者工具是一套内置于 Google Chrome 中的Web开发和调试工具&#xff0c;可用来对网站进行迭代、调试和分析…

[数据结构笔记]常见排序算法

分类与性能 排序方法平均情况最好情况最坏情况辅助空间稳定性冒泡排序O(N^2)O(N)O(N^2)O(1)稳定简单选择排序O(N^2)O(N^2)O(N^2)O(1)不稳定直接插入排序O(N^2)O(N)O(N^2)O(1)稳定希尔排序O(N*logN) ~ O(N^2)O(N^1.3)O(N^2)O(1)不稳定堆排序O(N*logN)O(N*logN)O(N*logN)O(1)不稳…

英文视频字幕生成和翻译工具、AI拟声工具

文章目录一、Autosub-ahk&#xff1a;英文视频字幕生成工具二、VideoSrt&#xff1a;英文视频字幕生成和翻译工具三、SubtitleEdit&#xff1a;字幕编辑工具四、PotPlayer&#xff1a;视频播放器&#xff08;可导入字幕&#xff09;五、MockingBird&#xff1a;AI拟声工具一、A…

软件架构知识3-系统复杂度-高可用性、可扩展性、低成本、安全、规模

高可用性 系统无中断地执行其功能的能力&#xff0c;代表系统的可用性程度&#xff0c;是进行系统设计时的准则之一。 高可用的“冗余”解决方案&#xff0c;单纯从形式上来看&#xff0c;和之前讲的高性能是一样的&#xff0c;都是通过增加更多机 器来达到目的&#xff0c;但…

MyBatis案例 | 使用映射配置文件实现CRUD操作——删除数据

本专栏主要是记录学习完JavaSE后学习JavaWeb部分的一些知识点总结以及遇到的一些问题等&#xff0c;如果刚开始学习Java的小伙伴可以点击下方连接查看专栏 本专栏地址&#xff1a;&#x1f525;JavaWeb Java入门篇&#xff1a; &#x1f525;Java基础学习篇 Java进阶学习篇&…

Linux--网络基础(1)--0211 12

1.网络传输基本流程 1.1 同一个网段内的两台主机进行文件传输 局域网中的两态主机是可以直接通信的。&#xff08;手机和电视链接同一个wifi就可以投屏&#xff09; 从逻辑上讲&#xff0c;应用层的数据可以直接给另一个人的应用层。 从物理上讲&#xff0c;应用的数据需要自…

分库分表索引设计:分布式环境下的 主键索引、二级索引、全局索引的最佳设计实践

文章目录主键选择索引设计全局表唯一索引总结结语主键选择 对主键来说&#xff0c;要保证在所有分片中都唯一&#xff0c;它本质上就是一个全局唯一的索引。如果用大部分同学喜欢的自增作为主键&#xff0c;就会发现存在很大的问题。 因为自增并不能在插入前就获得值&#xf…

TDengine 3.0.2.5 查询再优化!揭秘索引文件的工作原理

TDengine 3.0 虽然对底层做了大规模的优化重构&#xff0c;但是相对于数据文件的工作逻辑和 2.0 相比是整体保持不变的。本系列文章的主旨在于帮助用户深入理解产品&#xff0c;并且拥有基本的性能调试思路&#xff0c;从而获得更好的产品体验。本期文章会在讲解 TDengine 时序…