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;
	}
}
相关推荐
朝发如雪8 小时前
快速掌握单片机基础(3)(PWM)(通信协议基础)(串口通信时序与参数)(电气特性与电平标准)(51单片机UART寄存器配置)(串口应用层协议)
单片机
天空'之城10 小时前
单片机基础核心知识点汇总(四十)
单片机·嵌入式硬件
smartpi_ai10 小时前
离线语音模块误识别问题全面解决方案:命令词设计、防误触与灵敏度调优指南
人工智能·单片机·语音识别
LCG元11 小时前
STM32F103 驱动 HX711 称重实战:DOUT 就绪时序、增益切换陷阱与两点标定精度实测
stm32·单片机·嵌入式硬件
染予11 小时前
代码中相关C语言知识点总结
stm32
优信电子11 小时前
STM32 驱动 DHT30 测量环境温湿度(兼容SHT30):从时序解析到完整代码实战
stm32·嵌入式·传感器·sht30·温湿度·环境测量·dht30
小李不想当小白13 小时前
DMA直接存储器存取(STM32标准库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·分享
朝发如雪13 小时前
快速掌握单片机基础(6)(数据处理与传送指令)(跳转与分支指令)(栈操作与混合编程)(程序状态寄存器操作指令)(内存映射)
单片机·arm
blue_ice .13 小时前
Verilog DDS 数字信号发生器:DAC 输出模拟波形与 ADC 回采观测
开发语言·单片机·嵌入式硬件·fpga开发
深圳市恒锐丰科技杨生13 小时前
EG4318 / EG4319 / EG4320 铅酸电池三段式充电副边管理芯片|屹晶 EGmicro
嵌入式硬件·硬件工程