蓝桥杯单片机设计与开发⑦ ---IIC、E2PROM

本文详细介绍了I2C通信的寻址模式、如何通过IIC总线进行E2PROM AT24C02的写入和读取操作,包括地址设置、数据传输时序,以及注意事项。重点讨论了E2PROM的写保护和数据搬运过程中的等待策略。
摘要由CSDN通过智能技术生成

有关IIC通信时序

请参考:https://blog.csdn.net/Xiaomo_haa/article/details/87902379

I2C寻址模式

I2C通信的起始信号之后,首先要发送一个从机地址,这个地址一共有7位,紧跟着第8位是数据方向位(#R/W),“0”表示接下来要发送数据(写),“1”表示接下来是请求数据(读)。

I2C官方程序

iic.c

/*
  程序说明: IIC总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台(12MHz)
  日    期: 2011-8-9
*/
#include <STC15F2K60S2.H>
#include "iic.h"

//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

//总线启动条件
void IIC_Start(void)
{
	SDA = 1;
	SCL = 1;
	somenop;
	SDA = 0;
	somenop;
	SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
	SDA = 0;
	SCL = 1;
	somenop;
	SDA = 1;
}

//应答位控制
void IIC_Ack(unsigned char ackbit)
{
	if(ackbit) 
	{	
		SDA = 0;
	}
	else 
	{
		SDA = 1;
	}
	somenop;
	SCL = 1;
	somenop;
	SCL = 0;
	SDA = 1; 
	somenop;
}

//等待应答
bit IIC_WaitAck(void)
{
	SDA = 1;
	somenop;
	SCL = 1;
	somenop;
	if(SDA)    
	{   
		SCL = 0;
		IIC_Stop();
		return 0;
	}
	else  
	{ 
		SCL = 0;
		return 1;
	}
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{   
		if(byt&0x80) 
		{	
			SDA = 1;
		}
		else 
		{
			SDA = 0;
		}
		somenop;
		SCL = 1;
		byt <<= 1;
		somenop;
		SCL = 0;
	}
}

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
	unsigned char da;
	unsigned char i;
	
	for(i=0;i<8;i++)
	{   
		SCL = 1;
		somenop;
		da <<= 1;
		if(SDA) 
		da |= 0x01;
		SCL = 0;
		somenop;
	}
	return da;
}

iic.h

#ifndef _IIC_H
#define _IIC_H
#include <intrins.h>
//器件地址 读写
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1

#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}
//函数声明
void IIC_Start(void); 
void IIC_Stop(void);  
void IIC_Ack(unsigned char ackbit); 
void IIC_SendByte(unsigned char byt); 
bit IIC_WaitAck(void);  
unsigned char IIC_RecByte(void); 

#endif

E2PROM

使用E2PROM可以保存数据,特点就是掉电不丢失。

在我们CT107D开发板上所使用的的器件是AT24C02,一个容量大小是2Kb/s,也就是256字节的E2PROM。
24C02是一个基于I2C通信协议的器件。

24C01/02/04/08/16 是低工作电压的1K/2K/4K/8K/16K 位串行电可擦除只读存储器,内部组织为128/256/512/1024/2048 个字节,每个字节8 位,该芯片被广泛应用于低电压及低功耗的工商业领域。

  • 串行时钟信号引脚(SCL):在SCL 输入时钟信号的上升沿将数据送入EEPROM器件,并在时钟的下降沿将数据读出。

  • 串行数据输入/输出引脚(SDA):SDA 引脚可实现双向串行数据传输。该引脚为开漏输出,可与其它多个开漏输出器件或开集电极器件线或连接。

  • 器件/页地址脚(A2,A1,A0):A2、A1 和A0 引脚为24C01与24C02 的硬件连接的器件地址输入引脚。24C01在一个总线上最多可寻址八个1K 器件,24C02 在一个总线上最多可寻址八个2K 器件,A2、A1 和A0 内部必须连接。

  • 24C04 仅使用A2、A1 作为硬件连接的器件地址输入引脚,在一个总线上最多可寻址四个4K 器件。A0 引脚内部未连接。

  • 24C08 仅使用A2 作为硬件连接的器件地址输入引脚,在一个总线上最多可寻址两个8K 器件。A0和A1 引脚内部未连接。

  • 24C16 未使用作为硬件连接的器件地址输入引脚,在一个总线上最多可连接一个16K器件。A0、A1 和A2 引脚内部未连接。

  • 写保护(WP)引脚:24C01/02/04/08/16
    具有用于硬件数据写保护功能的引脚。当该引脚接GND时,允许正常的读/写操作。当该引脚接VCC 时,芯片启动写保护功能。

E2PROM 时序图详解

在这里插入图片描述

我们蓝桥杯单片机开发与设计的开发板所使用的E2PROM器件型号是AT24C02,我们查询datasheet可得

24C02的七位地址中,高四位是固定的 1010,低三位的地址取决于具体的电路设计,由芯片上的A2、A1、A0决定。
在这里插入图片描述
在这里,24C02的7位地址实际上就是0b1010000,也就是0x50。

在比赛的时候提供的有I2C的代码,我现在直接给粘贴过来。

1.E2PROM写数据
在这里插入图片描述

  1. 首先是I2C的起始信号,接着跟上首字节,也就是I2C的器件地址,并且在读写方向上选择“写”操作。
  2. 发送数据的存储地址。24C02一共有256个字节的存储空间,地址从0x00~0xFF,想把数据存储在哪个位置,此刻写的就是哪个地址。
  3. 发送要存储的数据第一字节、第二字节、…注意在写数据的过程中,E2PROM每个字节都会回应一个“应答位0”,告诉我们写E2PROM数据成功,如果没有回应答位,说明写入不成功。

在写数据的过程中,每成功写入一个字节,E2PROM存储空间的地址就会自动加1,当加到0xFF后,再写一个字节,地址就会溢出又变成0x00。
写数据的时候需要注意,E2PROM是先写到缓冲区,然后再“搬运到”到掉电非易失区。所以这个过程需要一定的时间,AT24C02这个过程是不超过5ms!如果在这个时候去让它应答是没有响应的!
所以,当我们在写多个字节时,写入一个字节之后,再写入下一个字节之前,必须等待E2PROM再次相应才可以。

2.E2PROM读数据

  • 读当前地址
    在这里插入图片描述
  • 读连续地址
    在这里插入图片描述
  • 读随机地址
    在这里插入图片描述
  1. 首先是I2C的起始信号,接着跟上首字节,也就是I2C的器件地址,并在在读写方向上选择“写”操作。注意:这里写操作是为了要把所要读的数据的存储地址先写进去,告诉E2PROM要读取哪个地址的数据。
  2. 发送要读取的数据的地址,注意是地址而非存在E2PROM中的数据,通知E2PROM要哪个分机的信息。
  3. 重新发送I2C的起始信号和器件地址,并且在方向位选择“读”操作。在这三步中,每一个字节实际上都是在“写”,所以每一个字节E2PROM都会回应一个“应答位0”。
  4. 读取从器件发回的数据,读一个字节,如果还想继续读写一个字节,就发送一个“应答位ACK(0)”,如果不想读了,告诉E2PROM不想要数据了,就发送一个“非应答位NAK(1)”。

和写操作一样,每读一个字节,地址就会自动加1,如果想继续往下读,给E2PROM一个ACK(0)低电平,那再继续给SCL完整的时序,E2PROM会继续往外送数据。如果不想读了,直接给一个NAK(1)高电平即可。

E2PROM程序

在这里插入图片描述
I2C 通信分为低速模式 100kbit/s、快速模式 400kbit/s 和高速模式3.4Mbit/s。因为所有的 I 2 C 器件都支持低速,但却未必支持另外两种速度,所以作为通用的I 2 C 程序这里选择了 100k 这个速率来实现,也就是说实际程序产生的时序必须小于等于 100k的时序参数。由datasheet,很明显也就是要求 SCL 的高低电平持续时间都不短于 5us。

但是我们使用的是1T模式,nop()只占用一个机器周期,所以我们要写很多的_nop_(),没错就是这么多,一共33个。

#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); _nop_(); _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}    

单字节写入

/*******************************************************************************
* 函数名	:Write_E2PROM
* 输入值	:unsigned char addr, unsigned char dat
* 返回值	:none
* 作者		:guyao
* 时间		:2021/2/22
* 功能描述:在E2PROM某个地址写入数据
* 备注		:add为E2PROM数据地址,dat为需要写入数据
*******************************************************************************/
void Write_E2PROM(unsigned char addr, unsigned char dat)
{
		IIC_Start();
		IIC_SendByte(SlaveAddrW);//发送器件地址
		IIC_WaitAck();
		IIC_SendByte(addr);//发送操作地址
		IIC_WaitAck();
		IIC_SendByte(dat); //写一字节
		IIC_WaitAck();
		IIC_Stop();
		somenop;
}

读单字节

/*******************************************************************************
* 函数名	:Read_E2PROM
* 输入值	:unsigned char addr
* 返回值	:unsigend char d
* 作者		:guyao
* 时间		:2021/2/22
* 功能描述:读取E2PROM某个地址的数据
* 备注		:addr为E2PROM数据地址,d为往外传送的数据
*******************************************************************************/

unsigned char Read_E2PROM(unsigned char addr)
{
		unsigned char d;
		IIC_Start();
		IIC_SendByte(SlaveAddrW);//发送器件地址
		IIC_WaitAck();
		IIC_SendByte(addr);//发送操作地址
		IIC_WaitAck();
		IIC_Stop();
	
		IIC_Start();
		IIC_SendByte(SlaveAddrR);	//发送读操作
		IIC_WaitAck();
		d = IIC_RecByte();	//读一字节
		IIC_Ack(0);
		IIC_Stop();
		return d;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值