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;
	}
}
相关推荐
尼喃25 分钟前
PW5100-50和PW5150:1.5V转5V芯片有什么区别?
嵌入式硬件
iowin8881 小时前
在 MCU 上跑 AI:端侧语音识别的极限压缩
人工智能·单片机·边缘计算·语音识别
硅基手札10 小时前
【串口技术系列文档 10】低功耗与唤醒机制
驱动开发·stm32·单片机·嵌入式硬件·mcu·计算机外设
逐光者93311 小时前
STM32——SPI 屏 · Flash · 高速
java·前端·stm32
yuehuaxin0111 小时前
上海贝岭 BL6523GX(D78) 单相计量芯片开发笔记:引脚定义、寄存器配置与校表流程
嵌入式硬件·智能家居·适配器模式·智能硬件
Kuakewei88811 小时前
可调OVP/OCP USB限流保护芯片IC的50μs过流响应测试
嵌入式硬件
HRTOS12 小时前
HRTOS 官网内容调整记录:首页、系统架构与文档页面优化
单片机·系统架构·51单片机
雨田言炎12 小时前
STM32之SysTick--系统定时器(内容简单但重要,附件有程序源码)
stm32·单片机·嵌入式硬件
ccbw1613 小时前
CH32M007K8U7:集成48V三相预驱的RISC-V电机MCU
单片机·嵌入式硬件
编程圈子14 小时前
I.MX6U 裸机开发 24. 电容触摸屏与 I2C 驱动
单片机·嵌入式硬件