STM32实战篇:I2C发送与接收数据

I2C初始化

cpp 复制代码
#include "stm32f10x.h"                  // Device header

void MyI2C_Init()
{
	//初始化SCL、SDA引脚
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_OD;
	GPIO_Init(GPIOB, &GPIO_InitStruct);
	
	//开启I2C时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); //使能
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); //复位,首次使用时进行复位,硬件bug
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, DISABLE);
	
	//配置I2C参数
	I2C_InitTypeDef I2C_InitStruct;
	I2C_InitStruct.I2C_ClockSpeed=400000
	I2C_InitStruct.I2C_Mode=I2C_Mode_I2C;
	I2C_InitStruct.I2C_DutyCycle=I2C_DutyCycle_2;
	I2C_Init(I2C1, &I2C_InitStruct);
	
	//使能I2C  (闭合总开关)
	I2C_Cmd(I2C1, ENABLE);
}

I2C发送数据

参数:Add-地址、Size-要发送的数据个数、pData-要发送的数据

返回值:无

cpp 复制代码
void MyI2C_SendData(uint8_t Add,uint16_t Size,uint8_t *pData)
{
	//等待总线空闲
	while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)==SET);
	
	//发送起始位
	I2C_GenerateSTART(I2C1, ENABLE);
	while(I2C_GetFlagStatus(I2C1, I2C_FLAG_SB)==RESET);//查询SB标志位
	
	//发送地址
	I2C_ClearFlag(I2C1, I2C_FLAG_AF);
	I2C_SendData(I2C1,Add);
	
	while(I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR)==RESET)
	{
		if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF)==SET)
		{
			goto STOP;
		}
	}
	
	//发送数据
	I2C_ReadRegister(I2C1, I2C_Register_SR1);
	I2C_ReadRegister(I2C1, I2C_Register_SR2);//清除ADDR
	
	uint32_t i;
	for(i=0;i<Size;i++)  //连续发送数据(1个或多个)
	{
		while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE)==RESET)
		{
			if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF)==SET){
				goto STOP;
			}
		}
		I2C_SendData(I2C1,pData[i]);
	}
	
	while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF)==RESET){
		if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF)==SET){
			goto STOP;
		}
	}
	
	//发送停止位
	STOP:
	I2C_GenerateSTOP(I2C1, ENABLE);//发送停止位
	while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)==SET);//直到总线空闲为止
}

I2C接收数据

参数:Add-从机地址、Size-需要接收的数据数量、pData-接收的数据

返回值:0-接收失败、1-接收成功

cpp 复制代码
uint16_t MyI2C_Receive(uint8_t Add,uint16_t Size,uint8_t *pData)
{
	//#1.等待总线空闲
	while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)==SET);
	
	//#2.发送起始位
	I2C_GenerateSTART(I2C1,ENABLE);
	
	while(I2C_GetFlagStatus(I2C1, I2C_FLAG_SB)==RESET);
	
	//#3.发送从机地址
	I2C_ClearFlag(I2C1, I2C_FLAG_AF);
	I2C_SendData(I2C1, Add|0x01);
	while(I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR)==RESET){
		if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF)==SET){//如果从机接收数据失败
			I2C_GenerateSTOP(I2C1,ENABLE);//发送停止位
			while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)==SET);//等待总线空闲
			return 0;//表示数据接收失败
		}
	}
	
	//#4.接收数据
	if(Size==1){
		//清除ADDR标志位
		I2C_ReadRegister(I2C1, I2C_Register_SR1);
		I2C_ReadRegister(I2C1, I2C_Register_SR2);
		
		//ack=0,stop=1
		I2C_AcknowledgeConfig(I2C1, DISABLE);
		I2C_GenerateSTOP(I2C1,ENABLE);
		
		//等待RXNE,把数据读出来
		while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE)==RESET);
		pData[0]=I2C_ReceiveData(I2C1);
		while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)==SET);
		
		return 1;//成功
	}
	else if(Size==2){
		//清除ADDR标志位
		I2C_ReadRegister(I2C1, I2C_Register_SR1);
		I2C_ReadRegister(I2C1, I2C_Register_SR2);
		
		//等待RXNE=1
		while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE)==RESET);
		I2C_AcknowledgeConfig(I2C1, DISABLE);
		I2C_GenerateSTOP(I2C1,ENABLE);
		pData[0]=I2C_ReceiveData(I2C1);
		
		//接收第二个字节
		while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE)==RESET);
		pData[1]=I2C_ReceiveData(I2C1);
		
		//等待总线空闲
		while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)==SET);
		
		return 1;
	}
	else if(Size>2){
		//ack=1
		I2C_AcknowledgeConfig(I2C1, ENABLE);
		//清除ADDR标志位
		I2C_ReadRegister(I2C1, I2C_Register_SR1);
		I2C_ReadRegister(I2C1, I2C_Register_SR2);
		//
		uint32_t i;
		for(i=0;i<Size-3;i++){
			while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE)==RESET);
			pData[i]=I2C_ReceiveData(I2C1);
		}
		//等待BTF标志位为1
		while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF)==RESET);
		pData[Size-3]=I2C_ReceiveData(I2C1);
		pData[Size-2]=I2C_ReceiveData(I2C1);
		//ACK=0,stop=1
		I2C_AcknowledgeConfig(I2C1, DISABLE);
		I2C_AcknowledgeConfig(I2C1, ENABLE);
		//等待RXEN=1
		while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF)==RESET);
		pData[Size-1]=I2C_ReceiveData(I2C1);
		//等待总线空闲
		while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)==SET);
		
		return 1;
	}
	else{
		return 0;
	}
}
相关推荐
知识充实人生30 分钟前
时序收敛方法一:控制集优化
stm32·单片机·fpga开发
逆小舟3 小时前
【STM32】学习准备、初识
stm32·嵌入式硬件
点灯小铭7 小时前
基于单片机的多模式自动洗衣机设计与实现
数据库·单片机·嵌入式硬件·毕业设计·课程设计
La Pulga8 小时前
【STM32】RTC实时时钟
c语言·stm32·单片机·嵌入式硬件·mcu·实时音视频
m0_555762908 小时前
STM32产品程序测试完整指南
stm32·单片机·嵌入式硬件
普中科技8 小时前
【普中Hi3861开发攻略--基于鸿蒙OS】-- 第 26 章 WIFI实验-AP 建立网络
单片机·嵌入式硬件·wifi·liteos·hi3861·普中科技
普中科技9 小时前
【普中Hi3861开发攻略--基于鸿蒙OS】-- 第 24 章 OLED液晶显示实验
单片机·嵌入式硬件·oled·liteos·hi3861·普中科技
冻结的鱼9 小时前
STM32H5 的 PB14 引脚被意外拉低的问题解析
stm32·单片机·嵌入式硬件
小莞尔10 小时前
【51单片机】【protues仿真】基于51单片机彩灯控制器系统
单片机·嵌入式硬件
文火冰糖的硅基工坊10 小时前
[嵌入式系统-146]:五次工业革命对应的机器人形态的演进、主要功能的演进以及操作系统的演进
前端·网络·人工智能·嵌入式硬件·机器人