湖北建设厅官方网站,制作网站能赚钱吗,外贸做哪些网站平台好,如何仿做网站通讯协议之路主要分为两部分#xff0c;第一部分从理论上面讲解各类协议的通讯原理以及通讯格式#xff0c;第二部分从具体运用上讲解各类通讯协议的具体应用方法。 后续文章会同时发表在个人博客(jason1016.club)、CSDN#xff1b;视频会发布在bilibili(UID:399951374) 本文… 通讯协议之路主要分为两部分第一部分从理论上面讲解各类协议的通讯原理以及通讯格式第二部分从具体运用上讲解各类通讯协议的具体应用方法。 后续文章会同时发表在个人博客(jason1016.club)、CSDN视频会发布在bilibili(UID:399951374) 本文前缀 通讯协议专栏通讯协议_JASON丶LI的博客-CSDN博客 UART理论部分通讯协议学习之路IIC协议理论-CSDN博客 硬件IIC
硬件IICInter-Integrated Circuit是一种串行通信协议由飞利浦公司现在的恩智浦半导体开发。它使用两根线SDA和SCL来进行数据传输其中SDA线用于数据传输SCL线用于时钟同步。硬件IIC通常由硬件电路实现例如在微控制器或集成电路中集成的硬件模块。
硬件I2C的效率要远高于软件的而软件I2C由于不受管脚限制接口比较灵活。
软件IIC
软件IIC是一种通过软件实现的IIC通信协议。它不依赖于硬件电路而是通过软件控制GPIO通用输入输出引脚来模拟IIC通信。软件IIC通常用于一些资源受限的系统例如单片机或嵌入式系统这些系统可能没有硬件IIC模块。 软件IIC和硬件IIC之间的关系是软件IIC是对硬件IIC的一种软件实现。软件IIC可以在没有硬件IIC模块的情况下实现IIC通信但由于软件实现的限制软件IIC的速度和可靠性可能不如硬件IIC。在一些资源受限的系统中软件IIC是一种常用的替代方案。 硬件IIC用法比较复杂模拟IIC的流程更清楚一些。 硬件IIC速度比模拟快并且可以用DMA 模拟IIC可以在任何管脚上而硬件只能在固定管脚上。
软件i2c是程序员使用程序控制SCL,SDA线输出高低电平模拟i2c协议的时序。一般较硬件i2c稳定但是程序较为繁琐但不难。
硬件i2c程序员只要调用i2c的控制函数即可不用直接的去控制SCL,SDA高低电平的输出。但是有些单片机的硬件i2c不太稳定调试问题较多。
参考文章硬件IIC和软件IIC区别-CSDN博客
开发实践
标准库
软件IIC
软件IIC的实现核心在于把握IIC的通讯格式所谓协议通讯我的理解就是将10的高低电平状态整合成一段段有规律的预警就像我们规定逗号是停顿句号是句子结束一样其实协议通讯同样如此具体的IIC通讯格式可以移步到另外一篇文章通讯协议学习之路IIC协议理论-CSDN博客
接下来是具体配置代码
IIC_Control.c
#include IIC_Control.h
#include IIC_Software.h#define IIC_ADDRESS 0xA0void IIC_Write(uint8_t RegAddress,uint8_t Data)
{IIC_Software_Start();IIC_Software_SendByte(IIC_ADDRESS);IIC_Software_ReadBck();IIC_Software_SendByte(RegAddress);IIC_Software_ReadBck();IIC_Software_SendByte(Data);IIC_Software_ReadBck();IIC_Software_Stop();
}uint8_t IIC_Read(uint8_t RegAddress)
{uint8_t Data;IIC_Software_Start();IIC_Software_SendByte(IIC_ADDRESS);IIC_Software_ReadBck();IIC_Software_SendByte(RegAddress);IIC_Software_ReadBck();IIC_Software_Start();IIC_Software_SendByte(IIC_ADDRESS | 0x01);IIC_Software_ReadBck();Data IIC_Software_ReadByte();IIC_Software_SendBck();IIC_Software_Stop();return Data;
}
IIC_Control.h
#ifndef __IICCONTROL_H
#define __IICCONTROL_H#include stm32f10x.h // Device headervoid IIC_Write(uint8_t RegAddress,uint8_t Data);uint8_t IIC_Read(uint8_t RegAddress);#endif
IIC_Software.c
#include stm32f10x.h // Device header
#include IIC_Software.h
#include Delay.h//PB10-SCL PB11-SDA
//- 常态SCL1SDA1
//- 工作态SCL电频周期翻转SDA电频由数据而定
//- 起始位SCL1时SDA1--0
//- 停止位SCL1时SDA0--1
//- 逻辑1SCL1时SDA1
//- 逻辑0SCL1时SDA0void IIC_Delay(void)
{Delay_us(4);
} void IIC_Software_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_Initstructure;GPIO_Initstructure.GPIO_Mode GPIO_Mode_Out_OD;GPIO_Initstructure.GPIO_Pin GPIO_Pin_10 | GPIO_Pin_11;GPIO_Initstructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOB, GPIO_Initstructure);SDA_H;SCL_H; //设置空闲态
}void IIC_Software_Start(void) //起始位
{SDA_H;SCL_H;IIC_Delay();SDA_L;IIC_Delay();SCL_L;
}void IIC_Software_Stop(void) //停止位
{SDA_L;SCL_H;IIC_Delay();SDA_H;
// IIC_Delay();
// SCL_H;
}void IIC_Software_SendByte(unsigned char byte) //发送
{int i;for(i0; i8; i){SCL_L;if(byte1(7-i)){SDA_H;}else{SDA_L;}SCL_H;IIC_Delay();}SCL_L;}unsigned char IIC_Software_ReadBck(void) //接收应答
{u8 ack;SDA_L; //拉低SDA 这里是用来处理半高电平直接拉低sda总线再接收应答这样一来应答信号为0时可以直接读取当应答信号为1时也可以直接报错
// SDA_H; //拉高SDA SCL_H; //拉高SCLIIC_Delay(); //等待ack Read_SDA; //读取 SCL_L; //这里拉低回来是为了对齐时序SDA_L; return ack;
}void IIC_Software_SendBck(void) //发送应答
{SCL_L;SDA_L;SCL_H;IIC_Delay();SCL_L;
}unsigned char IIC_Software_ReadByte(void) //从总线上读一个字节
{int i;unsigned char byte0;SDA_H; //释放SDAfor(i0; i8; i){SCL_H; //拉高然后读IIC_Delay();if(Read_SDA){byte | (1(7-i));}SCL_L;IIC_Delay();}return byte;
}IIC_Software.h
#ifndef __IICSOFTWARE_H
#define __IICSOFTWARE_H//PB10-SCL PB11-SDA#define SCL_H GPIO_SetBits(GPIOB, GPIO_Pin_10)
#define SCL_L GPIO_ResetBits(GPIOB, GPIO_Pin_10)
#define SDA_H GPIO_SetBits(GPIOB, GPIO_Pin_11)
#define SDA_L GPIO_ResetBits(GPIOB, GPIO_Pin_11)
#define Read_SDA GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)void IIC_Delay(void);void IIC_Software_Init(void);void IIC_Software_Start(void); //起始位void IIC_Software_Stop(void); //停止位void IIC_Software_SendByte(unsigned char byte); //发送unsigned char IIC_Software_ReadBck(void); //接收应答void IIC_Software_SendBck(void); //发送应答unsigned char IIC_Software_ReadByte(void); //从总线上读一个字节#endif硬件IIC
硬件IIC就不需要像软件配置一样一步步来只需要使能配置I2Cx外设即可并且标准库对硬件IIC的各项指令都有对应的函数封装配置完成后只需要调用封装好的函数即可实现通讯。
标准库IIC函数
//配置自身设备地址2
void I2C_OwnAddress2Config(I2C_TypeDef* I2Cx, uint8_t Address);//发送设备地址
void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);//接收数据
uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);//停止接收
void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState);//IIC外设开始正常工作
void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState);MYIIC.c
#include MYIIC.h
#include delay.h#define EERADDRESS 0xA0void MYIIC_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);GPIO_InitTypeDef GPIO_Initstructure;GPIO_Initstructure.GPIO_Mode GPIO_Mode_AF_OD;GPIO_Initstructure.GPIO_Pin GPIO_Pin_10 | GPIO_Pin_11;GPIO_Initstructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOB, GPIO_Initstructure);I2C_DeInit(I2C2);I2C_InitTypeDef I2C_Initstructure;I2C_Initstructure.I2C_Mode I2C_Mode_I2C;I2C_Initstructure.I2C_DutyCycle I2C_DutyCycle_2; //该参数只有在 I2C 工作在快速模式时钟工作频率高于 100KHz下才有意义I2C_Initstructure.I2C_OwnAddress1 0xFF;I2C_Initstructure.I2C_Ack I2C_Ack_Enable;I2C_Initstructure.I2C_AcknowledgedAddress I2C_AcknowledgedAddress_7bit;I2C_Initstructure.I2C_ClockSpeed 100000;I2C_Init(I2C2, I2C_Initstructure); I2C_Cmd(I2C2, ENABLE);
}//指定超时退出机制防止下述死循环卡死
void I2C_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{uint32_t Timeout;Timeout 10000;while(I2C_CheckEvent(I2Cx, I2C_EVENT) ! SUCCESS){Timeout --;if(Timeout 0){break;}}
}void I2C_ByteWrite(uint8_t *pBuffer, uint8_t WriteAddr)
{//读一个字节while(I2C_GetFlagStatus(DEBUG_I2Cx_Port, I2C_FLAG_BUSY));//发送Start信号I2C_GenerateSTART(DEBUG_I2Cx_Port,ENABLE);//等待EV5事件IIC开始信号已经发出 I2C_SR1内SB位置1while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_MODE_SELECT)ERROR);//发送7位“EEPROM地址”I2C_Send7bitAddress(DEBUG_I2Cx_Port,EERADDRESS,I2C_Direction_Transmitter);//等待EV6事件表示地址已经发送while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)ERROR);//写入EEPROM内将要写入的地址数据I2C_SendData(DEBUG_I2Cx_Port,WriteAddr);//等待EV8事件返回SET则数据寄存器DR为空 while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_BYTE_TRANSMITTED)ERROR);//写入数据I2C_SendData(DEBUG_I2Cx_Port,*pBuffer);//等待EV8事件返回SET则数据寄存器DR为空while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_BYTE_TRANSMITTED)ERROR);//一个字节发送完成发送Stop信号I2C_GenerateSTOP(DEBUG_I2Cx_Port, ENABLE);
}/*** brief 从EEPROM里面读取一块数据 * param * arg pBuffer:存放从EEPROM读取的数据的缓冲区指针* arg WriteAddr:接收数据的EEPROM的地址* retval 无*/
void I2C_ByteRead(uint8_t *pBuffer, uint8_t ReadAddr)
{//发送Start信号I2C_GenerateSTART(DEBUG_I2Cx_Port,ENABLE);//等待EV5事件IIC开始信号已经发出 I2C_SR1内SB位置1while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_MODE_SELECT)ERROR);//发送7位“EEPROM地址”I2C_Send7bitAddress(DEBUG_I2Cx_Port,EERADDRESS,I2C_Direction_Transmitter);//等待EV6事件表示地址已经发送while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)ERROR);//写入EEPROM内存“单元地址”I2C_SendData(DEBUG_I2Cx_Port,ReadAddr);//等待EV8事件数据寄存器DR为空 ,地址数据已经发送while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_BYTE_TRANSMITTED)ERROR);//重新发送Start信号I2C_GenerateSTART(DEBUG_I2Cx_Port,ENABLE);//等待EV5事件while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_MODE_SELECT)ERROR);//发送7位“EEPROM地址”I2C_Send7bitAddress(DEBUG_I2Cx_Port,EERADDRESS,I2C_Direction_Receiver);//注意方向//等待EV6事件接收表示地址已经发送while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)ERROR);//注意方向//产生非应答I2C_AcknowledgeConfig(DEBUG_I2Cx_Port, DISABLE);//发送Stop信号I2C_GenerateSTOP(DEBUG_I2Cx_Port, ENABLE);//等待EV7事件 BUSY, MSL and RXNE flagswhile(I2C_CheckEvent(DEBUG_I2Cx_Port, I2C_EVENT_MASTER_BYTE_RECEIVED)ERROR); *pBuffer I2C_ReceiveData(DEBUG_I2Cx_Port);//重新初始化 为下次做准备I2C_AcknowledgeConfig(DEBUG_I2Cx_Port, ENABLE);
}MYIIC.h
#ifndef __MYIIC_H
#define __MYIIC_H#include stm32f10x.h // Device header#define DEBUG_I2Cx_Port I2C2
void MYIIC_Init(void);void I2C_ByteWrite(uint8_t *pBuffer, uint8_t WriteAddr);void I2C_ByteRead(uint8_t *pBuffer, uint8_t ReadAddr);#endifDMA IIC
还未调试
HAL库
HAL库IIC接收和发送的轮询、中断、DMA三种模式的函数
/* IO operation functions ****************************************************/
/******* Blocking mode: Polling */
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Slave_Transmit(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Slave_Receive(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout);/******* Non-Blocking mode: Interrupt */
HAL_StatusTypeDef HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Master_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Slave_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Slave_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Mem_Write_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Mem_Read_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size);HAL_StatusTypeDef HAL_I2C_Master_Seq_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_Master_Seq_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_Slave_Seq_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_Slave_Seq_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_EnableListen_IT(I2C_HandleTypeDef *hi2c);
HAL_StatusTypeDef HAL_I2C_DisableListen_IT(I2C_HandleTypeDef *hi2c);
HAL_StatusTypeDef HAL_I2C_Master_Abort_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress);/******* Non-Blocking mode: DMA */
HAL_StatusTypeDef HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Master_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Slave_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Slave_Receive_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Mem_Write_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Mem_Read_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size);HAL_StatusTypeDef HAL_I2C_Master_Seq_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_Master_Seq_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_Slave_Seq_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_Slave_Seq_Receive_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
IIC写函数 HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
功能IIC写数据
参数
*hi2c 设置使用的是那个IIC 例hi2c2DevAddress 写入的地址 设置写入数据的地址 例 0xA0*pData 需要写入的数据Size 要发送的字节数Timeout 最大传输时间超过传输时间将自动退出传输函数
IIC读函数 HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
功能IIC读一个字节
参数
*hi2c 设置使用的是那个IIC 例hi2c2DevAddress 写入的地址 设置写入数据的地址 例 0xA0*pData 存储读取到的数据Size 发送的字节数Timeout 最大读取时间超过时间将自动退出读取函数
举例 HAL_I2C_Master_Transmit(hi2c1,0xA1,(uint8_t*)TxData,2,1000) ;//发送两个字节数据
IIC写数据函数
HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t pData, uint16_t Size, uint32_t Timeout);
/* 第1个参数为I2C操作句柄第2个参数为从机设备地址第3个参数为从机寄存器地址第4个参数为从机寄存器地址长度第5个参数为发送的数据的起始地址第6个参数为传输数据的大小第7个参数为操作超时时间 */
功能 IIC写多个数据 该函数适用于IIC外设里面还有子地址寄存器的设备比方说E2PROM,除了设备地址每个存储字节都有其对应的地址
参数
*hi2c I2C设备号指针设置使用的是那个IIC 例hi2c2DevAddress 从设备地址 从设备的IIC地址 例E2PROM的设备地址 0xA0MemAddress 从机寄存器地址 每写入一个字节数据地址就会自动1MemAddSize 从机寄存器地址字节长度 8位或16位 写入数据的字节类型 8位还是16位I2C_MEMADD_SIZE_8BITI2C_MEMADD_SIZE_16BIT在stm32f1xx_hal_i2c.h中有定义 *pData 需要写入的的数据的起始地址Size 传输数据的大小 多少个字节Timeout 最大读取时间超过时间将自动退出函数
使用HAL_I2C_Mem_Write等于先使用HAL_I2C_Master_Transmit传输第一个寄存器地址再用HAL_I2C_Master_Transmit传输写入第一个寄存器的数据。可以传输多个数据
void Single_WriteI2C(uint8_t REG_Address,uint8_t REG_data)
{uint8_t TxData[2] {REG_Address,REG_data};while(HAL_I2C_Master_Transmit(hi2c1,I2C1_WRITE_ADDRESS,(uint8_t*)TxData,2,1000) ! HAL_OK){if (HAL_I2C_GetError(hi2c1) ! HAL_I2C_ERROR_AF){Error_Handler();}}
}在传输过程寄存器地址和源数据地址是会自加的。
至于读函数也是如此因此用HAL_I2C_Mem_Write和HAL_I2C_Mem_Read来写读指定设备的指定寄存器数据是十分方便的让设计过程省了好多步骤。
举例
8位
HAL_I2C_Mem_Write(hi2c2, ADDR, i, I2C_MEMADD_SIZE_8BIT,(I2C_Buffer_Write[i]),8, 1000);
HAL_I2C_Mem_Read(hi2c2, ADDR, i, I2C_MEMADD_SIZE_8BIT,(I2C_Buffer_Write[i]),8, 1000);
16位
HAL_I2C_Mem_Write(hi2c2, ADDR, i, I2C_MEMADD_SIZE_16BIT,(I2C_Buffer_Write[i]),8, 1000);
HAL_I2C_Mem_Read(hi2c2, ADDR, i, I2C_MEMADD_SIZE_16BIT,(I2C_Buffer_Write[i]),8, 1000);
如果只往某个外设中写数据则用Master_Transmit。 如果是外设里面还有子地址例如我们的E2PROM有设备地址还有每个数据的寄存器存储地址。则用Mem_Write。Mem_Write是2个地址Master_Transmit只有从机地址
IIC接收函数proteus未实现
在mian.c文件前面声明AT24C02 写地址和读地址 定义写数据数组和读数据数组
/* USER CODE BEGIN PV */
#include string.h#define ADDR_24LCxx_Write 0xA0
#define ADDR_24LCxx_Read 0xA1
#define BufferSize 256
uint8_t WriteBuffer[BufferSize],ReadBuffer[BufferSize];
uint16_t i;
/* USER CODE END PV */在main.c中添加 /* USER CODE BEGIN 2 */for(i0; i256; i)WriteBuffer[i]i; /* WriteBuffer init */printf(\r\n***************I2C Example Z小旋测试*******************************\r\n);for (int j0; j32; j){if(HAL_I2C_Mem_Write(hi2c1, ADDR_24LCxx_Write, 8*j, I2C_MEMADD_SIZE_8BIT,WriteBuffer8*j,8, 1000) HAL_OK){printf(\r\n EEPROM 24C02 Write Test OK \r\n);HAL_Delay(20);}else{HAL_Delay(20);printf(\r\n EEPROM 24C02 Write Test False \r\n);}}/*// wrinte date to EEPROM 如果要一次写一个字节写256次用这里的代码for(i0;iBufferSize;i){HAL_I2C_Mem_Write(hi2c1, ADDR_24LCxx_Write, i, I2C_MEMADD_SIZE_8BIT,WriteBuffer[i],10xff);//使用I2C块读出错。因此采用此种方式逐个单字节写入HAL_Delay(5);//此处延时必加与AT24C02写时序有关}printf(\r\n EEPROM 24C02 Write Test OK \r\n);*/HAL_I2C_Mem_Read(hi2c1, ADDR_24LCxx_Read, 0, I2C_MEMADD_SIZE_8BIT,ReadBuffer,BufferSize, 0xff);for(i0; i256; i)printf(0x%02X ,ReadBuffer[i]);/* USER CODE END 2 */注意事项
AT24C02的IIC每次写之后要延时一段时间才能继续写 每次写之后要delay 5ms左右 不管硬件IIC采用何种形式DMAIT都要确保两次写入的间隔大于5ms;
读写函数最后一个超时调整为1000以上 因为我们一次写8个字节延时要久一点
AT24C02页写入只支持8个byte所以需要分32次写入。这不是HAL库的bug而是AT24C02的限制其他的EEPROM可以支持更多byte的写入。
当然你也可以每次写一个字节分成256次写入也是可以的 那就用注释了的代码即可 /*// wrinte date to EEPROM 如果要一次写一个字节写256次用这里的代码for(i0;iBufferSize;i){HAL_I2C_Mem_Write(hi2c1, ADDR_24LCxx_Write, i, I2C_MEMADD_SIZE_8BIT,WriteBuffer[i],10xff);//使用I2C块读出错。因此采用此种方式逐个单字节写入HAL_Delay(5);//此处延时必加与AT24C02写时序有关}printf(\r\n EEPROM 24C02 Write Test OK \r\n);*/参考文章【精选】【STM32】HAL库 STM32CubeMX教程十二---IIC(读取AT24C02 )_hal iic-CSDN博客