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.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); // 指定地址读取一个字节
注:这里不使用 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.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.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 模块代码编写完毕!