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;
	}
}
相关推荐
振南的单片机世界1 小时前
PVD掉电中断——让单片机“咽气前”写完遗书
arm开发·stm32·单片机·嵌入式硬件
续写烂尾4 小时前
SD NAND存储实测:正点原子STM32精英板SDIO读写验证全流程
stm32·单片机·嵌入式硬件
zlinear数据采集卡6 小时前
USB HS 480M高速传输与SRAM记录仪:DABM-D223数据存储系统全解析
arm开发·嵌入式硬件·fpga开发·开源
wuyk5556 小时前
1.栈:后进先出的线性数据结构
c语言·数据结构·stm32·单片机
Crkylin7 小时前
Cortex-M SysTick系统滴答定时器详解
单片机·嵌入式硬件
Hello_Damon_Nikola7 小时前
AC7911从入门到精通
开发语言·嵌入式硬件·物联网·php
gscsded8 小时前
AUTOSAR CanTp 模块学习笔记
单片机·嵌入式硬件·汽车
Hello_Damon_Nikola8 小时前
扰流筋从原理到应用
人工智能·单片机·嵌入式硬件
某林2128 小时前
从“仿真能跑”到“真机能走”:一套轮腿机械狗强化学习系统的工程化实践
人工智能·stm32·嵌入式硬件·架构·机器人·机械狗
luiyarch9 小时前
IP8到底是什么?
嵌入式硬件·车载系统