STM32学习-18-[I2C]读数据

主要实现一个函数
image

数据读取的流程

image
从机向主机发送,有效数据后面要加ACK表示应答,最后一帧后面加NAK表示数据发送完成

发送起始位和地址

image

先向START寄存器写1
然后确定状态寄存器的SB

image

先清空AF标志位
写入要发送的数据
确定寄存器的值
最后清空ADDR,使用固定的步骤,读取SR1和SR2

如何发送ACK和NAK

image
图中被影响的字节分别是字节2和字节3,是正在被接收的字节别作用

如何发送停止位

image
直接写STOP寄存器就好
图中字节一发送完成后就会发送停止位

Size = 1

image

Size = 2

image

Size > 2

image

完整代码实现

//
// I2Cx:目标I2C外设
// Addr:从机地址
// pBuffer:接收缓存区
// Size:接收的字节大小
//
int My_I2C_ReceiveBytes(I2CType *I2Cx, uint8_t Addr, uint8_t *pBuffer, uint16_t Size){
	// 发送起始位
	I2C_GenerateSTART(I2Cx, ENABLE);
	while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_SB) == RESET);

	// 寻址
	I2C_ClearFlag(I2Cx, I2C_FLAG_AF);	// 清楚AF寄存器
	// 发送地址与RW#
	I2C_SendData(I2Cx, Addr | 0xfe);

	// 等待ACK回应
	while(1){
		if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_ADDR) == SET) break;	// 收到ACK
		if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF) == SET){
			I2C_GenerateSTOP(I2Cx, ENABLE);	// 发送停止位
			return -1;	// 寻址失败
		}
	}

	// 接收数据
	if(Size == 1){
		// 清除ADDR
		I2C_ReadRegister(I2Cx, I2C_Register_SR1);
		I2C_ReadRegister(I2Cx, I2C_Register_SR2);
		// 向ACK写0
		I2C_AcknowledgeConfig(I2Cx, DISABLE);
		// 发送停止位
		I2C_GenerateSTOP(I2Cx, ENABLE);
		// 等待RxNE置位
		while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_RXNE) == RESET);
		// 读取数据
		pBuffer[0] = I2C_ReceiveData(I2Cx);
	}
	else if(Size == 2){
		// 清除ADDR
		I2C_ReadRegister(I2Cx, I2C_Register_SR1);
		I2C_ReadRegister(I2Cx, I2C_Register_SR2);
		// 向ACK写1
		I2C_AcknowledgeConfig(I2Cx, ENABLE);
		// 等待RxNE置位
		while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_RXNE) == RESET);
		// 读取第一个数据
		pBuffer[0] = I2C_ReceiveData(I2Cx);
		// 向ACK写0
		I2C_AcknowledgeConfig(I2Cx, DISABLE);
		// 发送停止位
		I2C_GenerateSTOP(I2Cx, ENABLE);
		// 等待RxNE置位
		while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_RXNE) == RESET);
		// 读取第二个数据
		pBuffer[1] = I2C_ReceiveData(I2Cx);
	}
	else{
		// 清除ADDR
		I2C_ReadRegister(I2Cx, I2C_Register_SR1);
		I2C_ReadRegister(I2Cx, I2C_Register_SR2);
		// 向ACK写1
		I2C_AcknowledgeConfig(I2Cx, ENABLE);
		for(int i = 0; i < Size - 1; ++i){
			// 等待RxNE置位
			while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_RXNE) == RESET);
			// 读取数据
			pBuffer[i] = I2C_ReceiveData(I2Cx);
		}
		// 向ACK写0
		I2C_AcknowledgeConfig(I2Cx, DISABLE);
		// 发送停止位
		I2C_GenerateSTOP(I2Cx, ENABLE);
		// 等待RxNE置位
		while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_RXNE) == RESET);
		// 读取最后一个数据
		pBuffer[Size - 1] = I2C_ReceiveData(I2Cx);
	}
}
posted @ 2026-09-01 09:33  灵垚克府  阅读(8)  评论(0)    收藏  举报