AT24C02使用详解
---恢复内容开始---
这篇文章是写给一个学弟看的,关于IIC,关于24C02的单字节写入\读取..页写入和读取,,学弟总是害怕协议,,,我总是对人家说,本来就这样的,协议就是人家这样规定的,,,如果你早生几十年你也可能规定个IIC协议......
我的单片机和24C02通信,,,我的单片机就叫主机,,,24C02叫从机
先看IIC

IIC协议规定开始传输数据的时候要先发一个起始信号,,,目的应该是告诉从机要开始通信了,准备准备
终止信号就是拜拜啦,再见!
起始信号就是 在SCL在高电平期间SDA来一个下降沿,,终止信号就是在SCL在高电平期间SDA来一个上升沿(所以协议上才会说,在正常传输数据的时候,只有在SCL为低电平的时候,数据线SDA的高低电平状态才允许改变,要不然岂不是和起始信号或者终止信号冲突了)
/*******************************************************************
起动总线函数
函数原型: void Start_I2c();
功能: 启动I2C总线,即发送I2C起始条件.
********************************************************************/
void Start_I2c()
{
SDA=; /*发送起始条件的数据信号*/
_Nop();
SCL=;
_Nop(); /*起始条件建立时间大于4.7us,延时*/
_Nop();
_Nop();
_Nop();
_Nop();
SDA=; /*发送起始信号*/
_Nop(); /* 起始条件锁定时间大于4μs*/
_Nop();
_Nop();
_Nop();
_Nop();
SCL=; /*钳住I2C总线,准备发送或接收数据 */
_Nop();
_Nop();
}
void Stop_I2c()
{
SDA=; /*发送结束条件的数据信号*/
_Nop(); /*发送结束条件的时钟信号*/
SCL=; /*结束条件建立时间大于4μs*/
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SDA=; /*发送I2C总线结束信号*/
_Nop();
_Nop();
_Nop();
_Nop();
}
发送完起始信号就能传输数据了

下面是程序
void SendByte(unsigned char c)
{
unsigned char BitCnt;
//SCL=0; 起始信号最后是SCL=0;所以不用写了
for(BitCnt=;BitCnt<;BitCnt++) /*要传送的数据长度为8位*/
{
if((c<<BitCnt)&0x80)/*判断发送位*/
{
SDA=;
}
else
{
SDA=;
}
_Nop();
SCL=; /*置时钟线为高,通知被控器开始接收数据位*/
_Nop();
_Nop(); /*保证时钟高电平周期大于4μs*/
_Nop();
_Nop();
_Nop();
SCL=;
} _Nop();
_Nop();
SDA=; /*8位发送完后释放数据线,准备接收应答位*/
_Nop();
_Nop();
SCL=;
_Nop();
_Nop();
_Nop();
if(SDA==)/*判断是否接收到应答信号*/
ack=;//没有接收到应答信号
else
ack=;//接收到应答信号
SCL=;
_Nop();
_Nop();
}
现在说一下接收,,,假设上面发送完0xaa以后,从机就返回给我们数据(11001100, 0xcc),当然SCL为低电平的时候模块准备数据,,SCL为高电平的时候,从机就把数据放在了SDA上,这样循环8次,一个8位数据就过来了

整体上应该是
Start_I2c();起始信号程序
SendByte(0xaa);
判断下ack是不是等于1,应答了(是继续执行还是停止看自己了)
Data = RcvByte();//接收数据
Ack_I2c(1);//发送非应答,就是SDA=1;,这个程序在下面
Stop_I2c();发送停止信号
接收程序如下
unsigned char RcvByte()
{
unsigned char retc;
unsigned char BitCnt; retc=;
SDA=; /*置数据线为输入方式*/
for(BitCnt=;BitCnt<;BitCnt++)
{
_Nop();
SCL=; /*置时钟线为低,准备接收数据位*/
_Nop();
_Nop(); /*时钟低电平周期大于4.7μs*/
_Nop();
_Nop();
_Nop();
SCL=; /*置时钟线为高使数据线上数据有效*/
_Nop();
_Nop();
retc=retc<<;
if(SDA==)retc=retc+; /*读数据位,接收的数据位放入retc中 */
_Nop();
_Nop();
}
SCL=;
_Nop();
_Nop();
return(retc);
}
应答或者非应答程序如下
/********************************************************************
应答子函数
函数原型: void Ack_I2c(bit a);
功能: 主控器进行应答信号(可以是应答0或非应答1信号,由位参数a决定)
********************************************************************/
void Ack_I2c(bit a)
{
if(a==)SDA=; /*在此发出应答或非应答信号 */
else SDA=;
_Nop();
_Nop();
_Nop();
SCL=;
_Nop();
_Nop(); /*时钟低电平周期大于4μs*/
_Nop();
_Nop();
_Nop();
SCL=; /*清时钟线,钳住I2C总线以便继续接收*/
_Nop();
_Nop();
}
IIC其实就这样了,主要看支持IIC通信的芯片的资料了,写好这些就是IIC通用的了
资料链接
https://wenku.baidu.com/view/3fc8558002d276a200292ef9.html
现在看芯片资料如何写进去一个字节

关于器件的地址
写就是0xa0;;;;读就是0xa1
所以写函数就是
/**
* @brief 向24C02写数据
* @param Data--数据
* @param Address--地址
* @param None
* @retval None
* @example
**/
unsigned char WriteData(unsigned char Data,unsigned char Address)
{
Start_I2c();
SendByte(0xa0);//最后一位为0写入
if(ack==)return(); SendByte(Address); //发送地址
if(ack==)return(); SendByte(Data); //发送数据
if(ack==)return(); Stop_I2c(); //结束总线
return();
}
关于应答哈我的SendByte(unsigned char c)函数里面发送完8位数据后就写了应答,然后把应答标志给ack,,后面直接判断的ack
现在想想为什么叫应答...直接说判断从机正没正确接收到数据就完了呗,就是把SDA拉高,然后把SCL拉高,等一会然后判断SDA引脚有没有被从机拉低,拉低了就说明好了......没拉低从机可能接收的数据不正确
_Nop();
_Nop();
SDA=1; /*8位发送完后释放数据线,准备接收应答位*/
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop();
_Nop();
if(SDA==1)/*判断是否接收到应答信号*/
ack=0;//没有接收到应答信号
else
ack=1;//接收到应答信号
SCL=0;
_Nop();
_Nop();
}
再看从任意地址读一个数据


注意哈第一个发送的器件地址是0xa0,后面的是0xa1
所以程序如下
/**
* @brief 从24C02读出数据
* @param None
* @param Address--地址
* @param None
* @retval 读到的数据
* @example
**/
unsigned char ReadData(unsigned char Address)
{
unsigned char Data =; Start_I2c();
SendByte(0xa0);//最后一位为0
if(ack==)return(); SendByte(Address); //发送地址
if(ack==)return(); Start_I2c(); SendByte(0xa1);//最后一位为1
if(ack==)return(); Data = RcvByte();
Ack_I2c(); //发送非就答位
Stop_I2c(); //结束总线
return(Data);
}
现在看页写

把程序先放上,对了写的时候的开始地址最好是0,8,16,24,32,40,68,,,,8的倍数,要不然数据可能有错误,当然我用的芯片页写最多一次能写入8个字节.....感觉有点少哈......可以在现在的基础上再做一个函数实现哈,,或者用写单字节的for循环下....
/**
* @brief 向24C02写数据----页写,,,最多一次写入8个字节,多了会覆盖前面的
* @param Data--数据
* @param StartAddress--开始的地址--最大255
* @param None
* @retval None
* @example
**/
unsigned char PageWrite(unsigned char *Data,unsigned char Address,unsigned char cnt)
{
Start_I2c();
SendByte(0xa0);//最后一位为0写入
if(ack==)return(); SendByte(Address); //发送地址
if(ack==)return(); while(cnt--)
{
SendByte(*Data++); //发送数据
if(ack==)return();
DelayMs();
}
Stop_I2c(); //结束总线
return();
}
现在看页读

看程序
/**
* @brief 从24C02读出数据----页读
* @param Data--数据指针
* @param StartAddress--开始的地址--最大255
* @param None
* @retval None
* @example
**/
unsigned char PageRead(unsigned char *Data,unsigned char Address,unsigned char cnt)
{
Start_I2c();
SendByte(0xa0);//最后一位为0
if(ack==)return(); SendByte(Address); //发送要读的地址
if(ack==)return(); Start_I2c(); SendByte(0xa1);//最后一位为1
if(ack==)return(); while(cnt--)
{
*Data = RcvByte();
Data ++;
Ack_I2c(); //发送应答位
DelayMs();
} Ack_I2c(); //发送非应答位
Stop_I2c(); //结束总线
return();
}
说一下读的时候最好开始读取的地址是8的倍数,读取的数据个数也是8的倍数,,,我测试的如果不是这样有时候,第二次页读的时候就会读错........
这芯片和8干上了............
还有一个立即读,,,看明白就行,就是立即返回当前读地址加1后的那个数据

源码链接
链接:http://pan.baidu.com/s/1i4M7BId%20密码:r9ov
AT24C02使用详解的更多相关文章
- Linq之旅:Linq入门详解(Linq to Objects)
示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...
- 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)
一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...
- EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解
前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...
- Java 字符串格式化详解
Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...
- Android Notification 详解(一)——基本操作
Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...
- Android Notification 详解——基本操作
Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...
- Git初探--笔记整理和Git命令详解
几个重要的概念 首先先明确几个概念: WorkPlace : 工作区 Index: 暂存区 Repository: 本地仓库/版本库 Remote: 远程仓库 当在Remote(如Github)上面c ...
- Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)
Android XML shape 标签使用详解 一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...
- Node.js npm 详解
一.npm简介 安装npm请阅读我之前的文章Hello Node中npm安装那一部分,不过只介绍了linux平台,如果是其它平台,有前辈写了更加详细的介绍. npm的全称:Node Package M ...
随机推荐
- 解决win10系统以太网适配器的驱动程序可能出现问题
插上网线显示未连接-连接可用,连上无线显示未连接-连接不可用,右下角显示感叹号 ,以太网和无线属性显示ipv4未连接详细信息为空,在设备管理器里卸载网卡驱动重装上仍然没有,通过windoes自带的网络 ...
- 常见MD5加密解密值及免费解密网站
常用的MD5解密 MD5(admin,16) = 7a57a5a743 MD5(admin,16) = 7a57a5a743894a0e MD5(admin888,16) = 469e ...
- Apple使用Apache Mesos重建Siri后端服务
苹果公司宣布,将使用开源的集群管理软件Apache Mesos,作为该公司广受欢迎的.基于iOS的智能个人助理软件Siri的后端服务.Mesosphere的博客指出,苹果已经创建了一个命名为J.A.R ...
- 二维坐标点排序(JavaScript)
今天给大家分享下最近web项目中出现的一个技术难点问题--坐标排序: 如下图所示,要求在前端页面上按顺序将下面5个模块的坐标依次保存至数据库 现在已知信息如下: 1.每个模块分别为一个div 2.每个 ...
- InnoDB关键特性之change buffer
一.关于IOT:索引组织表 表在存储的时候按照主键排序进行存储,同时在主键上建立一棵树,这样就形成了一个索引组织表,一个表的存储方式以索引的方式来组织存储的. 所以,MySQL表一定要加上主键,通过主 ...
- (转) Eclipse Maven 编译错误 Dynamic Web Module 3.1 requires Java 1.7 or newer 解决方案
场景:在导入Maven项目时候遇到如下错误. 1 问题描述及解决 Eclipse Maven 开发一个 jee 项目时,编译时遇到以下错误:Description Resource Path Loca ...
- 将bbr功能合入到centos7.3
今天将bbr的算法合入到了centos7.3的内核,基线内核版本是3.10.0-514.el7.x86_64, 内核编译测试通过.感谢隆春和文洋的帮助,隆春是将bbr合入到了cgslv5版本. 这种反 ...
- 云游戏学习与实践(二)——安装GamingAnywhere
安装GamingAnywhere 一.GamingAnywhere项目 GamingAnywhere是一个开源的实现云游戏的引擎,并且高效.跨平台.易扩展.可调配. GitHub地址:https:// ...
- 初学Python(四)——set
初学Python(四)——set 初学Python,主要整理一些学习到的知识点,这次是set. # -*- coding:utf-8 -*- #先来看数组和set的差别 d=[1,1,2,3,4,5] ...
- yii2 队列 shmilyzxt/yii2-queue 简介
在yii2论坛中看到一个关于队列的帖子,感觉不错.http://www.yiichina.com/extension/1084 (注:SendMail 错写为 SendMial,粘贴时要注意了.) 在 ...