IIC_STM32F1_AT24C02实验:AT24C02 模块(3)

IIC(集成电路总线)-STM32F1系列-AT24C02-简易实验开发详细流程(个人总结)

基于正点原子代码的个人改编,本篇(IIC实验)共3个章节。
注:本博客无盈利行为,真诚希望能帮助到大家!如有错误,还请指正!

IIC_STM32F1_AT24C02实验:AT24C02 模块(3)

第一步:编写基础的实现逻辑

(1)模块通信配置和写字节逻辑(本文中的代码均通过测试)
at24c02.h 文件

/*
* AT24C02 模块,总容量 2KB,总页数 32,8 字节/页,字地址长度 8 位。
* 基本的读写功能
* 程序员:贬道
*/

#ifndef AT24C02_H
#define AT24C02_H

#include "stm32f10x.h"

// 基础配置与实现逻辑
// 读写操作位:1 读;0 写
/************************************************************************************/
#define AT24C02	255		// AT24C02 共 256 个字节

void AT24C02_Init(void);

void AT24C02_WriteOneByte(u8 WriteAddr, u8 DataToWrite);	// 指定地址写入一个字节
/************************************************************************************/

#endif

AT24C02 写字节时序
at24c02.c 文件

#include "at24c02.h"
#include "iic.h"
#include "delay.h"

/************************************************************************************/
void AT24C02_Init(void){
	IIC_Idle();
}

// 写字节
/*
WriteAddr   : 写入数据的目的地址
DataToWrite : 要写入的数据
*/
void AT24C02_WriteOneByte(u8 WriteAddr, u8 DataToWrite){
	IIC_Start();
	
	IIC_Send_Byte(0XA0);			// 发送 AT24C02 器件地址 0XA0 和写操作
	IIC_WaitAck();					// 低电平为应答
	
    IIC_Send_Byte(WriteAddr%256);	// 发送要写的数据的低地址,地址由低到高
	IIC_WaitAck();
	
	IIC_Send_Byte(DataToWrite);		// 发送字节,传输数据
	IIC_WaitAck();
	
    IIC_Stop();						// 产生一个停止条件
	Delay_ms(10);					// 确保有足够的时间防止传输意外,最好不小于 5ms
}
/************************************************************************************/

(2)读字节逻辑(从这里开始为使过程清晰且节省文章篇幅,只列出关键代码,文章的最后会附上完整的模块代码)
at24c02.h 文件

u8 AT24C02_ReadOneByte(u8 ReadAddr);	// 指定地址读取一个字节

AT24C02 随机读时序
注:这里不使用 Current Address Read(读当前地址中的数据) 是因为随机读在实际使用中更为便利。

at24c02.c 文件

// 随机读
u8 AT24C02_ReadOneByte(u8 ReadAddr){
	u8 data = 0;
    IIC_Start();
	
	IIC_Send_Byte(0XA0);			// 发送器件地址 0XA0,假(伪)写操作,写一个目标字地址
	IIC_WaitAck();
	
    IIC_Send_Byte(ReadAddr%256);
	IIC_WaitAck();
	
	IIC_Start();
	
	IIC_Send_Byte(0XA1);			// 发送器件地址 0XA0 和读操作
	IIC_WaitAck();
	
    data = IIC_Read_Byte(0);		// 等待应答后记录数据
	
    IIC_Stop();						// 产生一个停止条件
	return data;					// 返回读取到的数据
}

第二步:编写实际使用的功能函数

(1)页写
at24c02.h 文件

// 从指定地址开始写入指定大小的数据
void AT24C02_Write(u8 WriteAddr, u8 *pBuffer, u16 SizeToWrite);

AT24C02 页写
at24c02.c 文件

/*
pBuffer		: 数据数组首地址
SizeToWrite	: 要写入数据的大小
*/
// 页写
void AT24C02_Write(u8 WriteAddr, u8 *pBuffer, u16 SizeToWrite){
	while(SizeToWrite--){
		AT24C02_WriteOneByte(WriteAddr, *pBuffer);
		WriteAddr++;	// 地址自增操作,每 ++ 8次相当于翻页操作一次
		pBuffer++;		// 这条语句可以理解为 pBuffer[索引++]
	}
}

(2)顺序读
at24c02.h 文件

// 从指定地址开始读出指定长度的数据
void AT24C02_Read(u8 ReadAddr, u8 *pBuffer, u16 SizeToRead);

AT24C02 顺序读
at24c02.c 文件

// 顺序读
void AT24C02_Read(u8 ReadAddr, u8 *pBuffer, u16 SizeToRead){
	while(SizeToRead--){
		// 这里 *pBuffer++ 先执行 pBuffer++,再执行 *pBuffer 的赋值操作
		*pBuffer++ = AT24C02_ReadOneByte(ReadAddr++);
	}
}

(3)单片机检测 AT24C02 模块是否存在
at24c02.h 文件

// 检查器件是否正常运行
u8 AT24C02_Check(void);

at24c02.c 文件

// 返回值:1 未检测到 AT24C02;0 检测到 AT24C02。
u8 AT24C02_Check(void){
	u8 temp;
	temp = AT24C02_ReadOneByte(AT24C02);	// 预读操作,检测器件有无回应
	
/*
许多串行通讯中测试或握手信号使用 0xAA 或 0x55 这两个特殊的十六进制数。
0xAA 展开为 10101010,0x55展开为 01010101,
变成串行电平的话就是一个占空比为 50% 的方波,
这种方波在电路中最容易被分辨是否受干扰或者畸变,
在实际波形的观察中也最容易看出毛病所在。
*/
	if(temp == 0X55) return 0;
	else									// 排除第一次初始化的情况
	{
		// 这里用了 AT24C02 的最后一个地址(255)来存储标志字
		AT24C02_WriteOneByte(255, 0X55);
	    temp = AT24C02_ReadOneByte(255);	  
		if(temp == 0X55) return 0;
	}
	return 1;
}

附录

at24c02.h

/*
* AT24C02 模块,总容量 2KB,总页数 32,8 字节/页,字地址长度 8 位。
* 基本的读写功能
* 程序员:贬道
*/

#ifndef AT24C02_H
#define AT24C02_H

#include "stm32f10x.h"

// 基础配置与实现逻辑
// 读写操作位:1 读;0 写
/************************************************************************************/
#define AT24C02	255		// 256 个字节

void AT24C02_Init(void);

void AT24C02_WriteOneByte(u8 WriteAddr, u8 DataToWrite);	// 指定地址写入一个字节
u8 AT24C02_ReadOneByte(u8 ReadAddr);						// 指定地址读取一个字节
/************************************************************************************/


// 实际使用的功能
/******************************************************************/
// 从指定地址开始写入指定大小的数据
void AT24C02_Write(u8 WriteAddr, u8 *pBuffer, u16 SizeToWrite);

// 从指定地址开始读出指定长度的数据
void AT24C02_Read(u8 ReadAddr, u8 *pBuffer, u16 SizeToRead);

// 检查器件是否正常运行
u8 AT24C02_Check(void);
/******************************************************************/


#endif

at24c02.c

#include "at24c02.h"
#include "iic.h"
#include "delay.h"

/************************************************************************************/
void AT24C02_Init(void){
	IIC_Idle();
}

// 写字节
/*
WriteAddr   : 写入数据的目的地址
DataToWrite : 要写入的数据
*/
void AT24C02_WriteOneByte(u8 WriteAddr, u8 DataToWrite){
	IIC_Start();
	
	IIC_Send_Byte(0XA0);			// 发送 AT24C02 器件地址 0XA0 和写操作
	IIC_WaitAck();					// 低电平为应答
	
    IIC_Send_Byte(WriteAddr%256);	// 发送要写的数据的低地址,地址由低到高
	IIC_WaitAck();
	
	IIC_Send_Byte(DataToWrite);		// 发送字节,传输数据
	IIC_WaitAck();
	
    IIC_Stop();						// 产生一个停止条件
	Delay_ms(10);					// 确保有足够的时间防止传输意外,最好不小于 5ms
}

// 随机读
u8 AT24C02_ReadOneByte(u8 ReadAddr){
	u8 data = 0;
    IIC_Start();
	
	IIC_Send_Byte(0XA0);			// 发送器件地址 0XA0,假写操作,写一个目标字地址
	IIC_WaitAck();
	
    IIC_Send_Byte(ReadAddr%256);
	IIC_WaitAck();
	
	IIC_Start();
	
	IIC_Send_Byte(0XA1);			// 发送器件地址 0XA0 和读操作
	IIC_WaitAck();
	
    data = IIC_Read_Byte(0);		// 等待应答后记录数据
	
    IIC_Stop();						// 产生一个停止条件
	return data;					// 返回读取到的数据
}
/************************************************************************************/


/***********************************************************************/
/*
pBuffer		: 数据数组首地址
SizeToWrite	: 要写入数据的大小
*/
// 页写
void AT24C02_Write(u8 WriteAddr, u8 *pBuffer, u16 SizeToWrite){
	while(SizeToWrite--){
		AT24C02_WriteOneByte(WriteAddr, *pBuffer);
		WriteAddr++;	// 地址自增操作,每 ++ 8次相当于翻页操作一次
		pBuffer++;		// 这条语句可以理解为 pBuffer[索引++]
	}
}

// 顺序读
void AT24C02_Read(u8 ReadAddr, u8 *pBuffer, u16 SizeToRead){
	while(SizeToRead--){
		// 这里 *pBuffer++ 先执行 pBuffer++,再执行 *pBuffer 的赋值操作
		*pBuffer++ = AT24C02_ReadOneByte(ReadAddr++);
	}
}

// 返回值:1 未检测到 AT24C02;0 检测到 AT24C02。
u8 AT24C02_Check(void){
	u8 temp;
	temp = AT24C02_ReadOneByte(AT24C02);	// 预读操作,检测器件有无回应
	
/*
许多串行通讯中测试或握手信号使用 0xAA 或 0x55 这两个特殊的十六进制数。
0xAA 展开为 10101010,0x55展开为 01010101,
变成串行电平的话就是一个占空比为 50% 的方波,
这种方波在电路中最容易被分辨是否受干扰或者畸变,
在实际波形的观察中也最容易看出毛病所在。
*/
	if(temp == 0X55) return 0;
	else									// 排除第一次初始化的情况
	{
		// 这里用了 AT24C02 的最后一个地址(255)来存储标志字
		AT24C02_WriteOneByte(255, 0X55);
	    temp = AT24C02_ReadOneByte(255);	  
		if(temp == 0X55) return 0;
	}
	return 1;
}
/***********************************************************************/

至此,AT24C02 模块代码编写完毕!

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用STM32软件IIC读取AT24C02的示例代码: ```c #include "stm32f10x.h" #define SDA_GPIO GPIOB #define SDA_PIN GPIO_Pin_7 #define SCL_GPIO GPIOB #define SCL_PIN GPIO_Pin_6 #define I2C_READ_ADDR 0xA1 #define I2C_WRITE_ADDR 0xA0 void i2c_start(void); void i2c_stop(void); void i2c_send_byte(uint8_t data); uint8_t i2c_read_byte(void); void i2c_ack(void); void i2c_nack(void); void i2c_wait(void); int main(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = SDA_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_Init(SDA_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = SCL_PIN; GPIO_Init(SCL_GPIO, &GPIO_InitStructure); while(1) { uint8_t data = 0; uint8_t addr = 0; // 打开I2C总线 i2c_start(); // 发送器件地址和读命令 i2c_send_byte(I2C_WRITE_ADDR); // 发送要读取的地址 i2c_send_byte(addr); // 重新启动I2C总线 i2c_start(); // 发送器件地址和读命令 i2c_send_byte(I2C_READ_ADDR); // 读取数据并发送NACK data = i2c_read_byte(); i2c_nack(); // 关闭I2C总线 i2c_stop(); // 显示读取到的数据 printf("Read data: %d\n", data); // 延时 for(int i = 0; i < 1000000; i++); } } void i2c_start(void) { GPIO_SetBits(SDA_GPIO, SDA_PIN); GPIO_SetBits(SCL_GPIO, SCL_PIN); GPIO_ResetBits(SDA_GPIO, SDA_PIN); GPIO_ResetBits(SCL_GPIO, SCL_PIN); } void i2c_stop(void) { GPIO_ResetBits(SDA_GPIO, SDA_PIN); GPIO_SetBits(SCL_GPIO, SCL_PIN); GPIO_SetBits(SDA_GPIO, SDA_PIN); } void i2c_send_byte(uint8_t data) { for(int i = 0; i < 8; i++) { if(data & 0x80) GPIO_SetBits(SDA_GPIO, SDA_PIN); else GPIO_ResetBits(SDA_GPIO, SDA_PIN); GPIO_SetBits(SCL_GPIO, SCL_PIN); GPIO_ResetBits(SCL_GPIO, SCL_PIN); data <<= 1; } } uint8_t i2c_read_byte(void) { uint8_t data = 0; for(int i = 0; i < 8; i++) { data <<= 1; GPIO_SetBits(SCL_GPIO, SCL_PIN); if(GPIO_ReadInputDataBit(SDA_GPIO, SDA_PIN)) data |= 0x01; GPIO_ResetBits(SCL_GPIO, SCL_PIN); } return data; } void i2c_ack(void) { GPIO_ResetBits(SDA_GPIO, SDA_PIN); GPIO_SetBits(SCL_GPIO, SCL_PIN); GPIO_ResetBits(SCL_GPIO, SCL_PIN); } void i2c_nack(void) { GPIO_SetBits(SDA_GPIO, SDA_PIN); GPIO_SetBits(SCL_GPIO, SCL_PIN); GPIO_ResetBits(SCL_GPIO, SCL_PIN); } void i2c_wait(void) { for(int i = 0; i < 100; i++); } ``` 注意:本示例代码仅作为参考使用,实际应用中需根据具体情况进行修改和适配。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值