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;
	}
}
相关推荐
LN花开富贵1 小时前
stm32g431rbt6芯片中VREF+是什么?在电路中怎么设计?
笔记·stm32·单片机·嵌入式硬件·学习
qq21084629531 小时前
【stm32笔记】使用rtt-studio与stm32CubeMx联合创建项目
笔记·stm32·嵌入式硬件
CV金科1 小时前
蓝桥杯—STM32G431RBT6按键的多方式使用(包含软件消抖方法精讲)从原理层面到实际应用(一)
stm32·单片机·嵌入式硬件·蓝桥杯
2021.091 小时前
五、CAN总线
嵌入式硬件
luckyluckypolar1 小时前
STM32——输入捕获
stm32·单片机·嵌入式硬件·物联网
hong1616881 小时前
嵌入式硬件基础知识
嵌入式硬件
hai405871 小时前
单片机(Microcontroller)原理及应用
单片机·嵌入式硬件
jun7788952 小时前
嵌入式硬件基础知识
嵌入式硬件
Projectsauron3 小时前
STM32 芯片启动过程
stm32·单片机·芯片启动过程
CDialog3 小时前
arduino ide开发esp32-wroom-32E
单片机·嵌入式硬件