STM32:IIC详解

文章目录

  • 1.IIC历史
  • 2.IIC优势
  • 3.IIC时序
    • [3.1 初始化IIC](#3.1 初始化IIC)
    • [3.2 产生IIC起始信号](#3.2 产生IIC起始信号)
    • [3.3 产生IIC停止信号](#3.3 产生IIC停止信号)
    • [3.4 等待ACK](#3.4 等待ACK)
    • [3.5 产生ACK / 不产生ACK](#3.5 产生ACK / 不产生ACK)
    • [3.6 IIC发送一个字节](#3.6 IIC发送一个字节)
    • [3.7 IIC读取一个字节](#3.7 IIC读取一个字节)
    • [3.8 IIC发送多字节](#3.8 IIC发送多字节)
    • [3.9 IIC读取多字节](#3.9 IIC读取多字节)
  • [4 IIC问题](#4 IIC问题)
    • [4.1 STM32 HAL库的IIC设备地址没有左移](#4.1 STM32 HAL库的IIC设备地址没有左移)

1.IIC历史

2.IIC优势

3.IIC时序

3.1 初始化IIC

c 复制代码
//初始化IIC
void PCA9557_Init(void)
{					     
 	RCC->APB2ENR |= 1<<4;//先使能外设IO PORTC时钟 							 
	GPIOC->CRH &= 0XFFFF00FF;//PC10/11 推挽输出
	GPIOC->CRH |= 0X00003300;	   
	GPIOC->ODR |= 1<<10;     //PC10 输出高
	GPIOC->ODR |= 1<<11;     //PC11 输出高
}

3.2 产生IIC起始信号

c 复制代码
//产生IIC起始信号
void PCA9557_Start(void)
{
	PCA9557_SDA_OUT(); //sda线输出
	PCA9557_SDA=1;
	PCA9557_SCL=1;
	delay_us(4);
	PCA9557_SDA=0;//START:when CLK is high,DATA change form high to low
	delay_us(4);
	PCA9557_SCL=0;//钳住I2C总线,准备发送或接收数据
}

3.3 产生IIC停止信号

c 复制代码
//产生IIC停止信号
void PCA9557_Stop(void)
{
	PCA9557_SDA_OUT();//sda线输出
	PCA9557_SCL=0;
	PCA9557_SDA=0;//STOP:when CLK is high DATA change form low to high
	delay_us(4);
	PCA9557_SCL=1;
	PCA9557_SDA=1;//发送I2C总线结束信号
	delay_us(4);
}

3.4 等待ACK

c 复制代码
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
uint8_t PCA9557_Wait_Ack(void)
{
	uint8_t ucErrTime=0;
	PCA9557_SDA_IN(); //SDA设置为输入
	PCA9557_SDA=1;delay_us(1);
	PCA9557_SCL=1;delay_us(1);
	while(PCA9557_READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			PCA9557_Stop();
			return 1;
		}
	}
	PCA9557_SCL=0;//时钟输出0
	return 0;
}

3.5 产生ACK / 不产生ACK

c 复制代码
//产生ACK应答
void PCA9557_ACK(void)
{
	PCA9557_SCL=0;
	PCA9557_SDA_OUT();
	PCA9557_SDA=0;
	delay_us(2);
	PCA9557_SCL=1;
	delay_us(2);
	PCA9557_SCL=0;
}

//不产生ACK应答
void PCA9557_NAck(void)
{
	PCA9557_SCL=0;
	PCA9557_SDA_OUT();
	PCA9557_SDA=1;
	delay_us(2);
	PCA9557_SCL=1;
	delay_us(2);
	PCA9557_SCL=0;
}

3.6 IIC发送一个字节

c 复制代码
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
uint8_t PCA9557_Send_Byte(uint8_t txd)
{
	uint8_t t;
	PCA9557_SDA_OUT();
	PCA9557_SCL=0;//拉低时钟开始数据传输
	for(t=0;t<8;t++)
	{
		if (txd&0x80) PCA9557_SDA = 1;
		else PCA9557_SDA = 0;
		txd<<=1;
		delay_us(2); //对TEA5767这三个延时都是必须的
		PCA9557_SCL=1;
		delay_us(2);
		PCA9557_SCL=0;
		delay_us(2);
	}
	t=PCA9557_Wait_Ack();  //这里固定只要写字节就需要等待应答
	return (t);
}

3.7 IIC读取一个字节

c 复制代码
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
uint8_t PCA9557_Read_Byte(uint8_t ack)
{
	uint8_t i,receive=0;
	PCA9557_SDA_IN();//SDA设置为输入
	for(i=0;i<8;i++ )
	{
		PCA9557_SCL=0;
		delay_us(2);
		PCA9557_SCL=1;
		receive<<=1;
		if(PCA9557_READ_SDA)receive |= 1;
		delay_us(1);
	}
	if (!ack)
	PCA9557_NAck();//发送nACK
	else
	PCA9557_ACK(); //发送ACK
	return receive;
}

3.8 IIC发送多字节

c 复制代码
uint8_t PCA9557Write(uint8_t addr, uint8_t len, uint8_t *pData)
{
	uint8_t i;
	PCA9557_Start();
	if(PCA9557_Send_Byte(PCA9557_ADDR_WRITE)==1)
	{
		PCA9557_Stop();
		return 0;
	}
	if(PCA9557_Send_Byte(addr)==1)
	{
		PCA9557_Stop();
		return 0;
	}
	for(i = 0; i < len; i++)
	{
		if(PCA9557_Send_Byte(pData[i])==1)
		{
			PCA9557_Stop();
			return 0;
		}
	}
	PCA9557_Stop();
	
	return 1;
}

3.9 IIC读取多字节

c 复制代码
uint8_t PCA9557Read(uint8_t addr,uint8_t len,uint8_t *pData)
{
	uint8_t i;
	PCA9557_Start();
	if(PCA9557_Send_Byte(PCA9557_ADDR_WRITE)==1)
	{
		PCA9557_Stop();
		return 0;
	}
	if(PCA9557_Send_Byte(addr)==1)
	{
		PCA9557_Stop();
		return 0;
	}
	PCA9557_Start();
	if(PCA9557_Send_Byte(PCA9557_ADDR_READ)==1)
	{
		PCA9557_Stop();
		return 0;
	}
	for(i=0; i<len-1; i++)
	{
		pData[i] = PCA9557_Read_Byte(1);
	}
	pData[len-1] = PCA9557_Read_Byte(0);
	PCA9557_Stop();
	
	return 1;
}

4 IIC问题

4.1 STM32 HAL库的IIC设备地址没有左移

c 复制代码
#define I2C_7BIT_ADD_WRITE(__ADDRESS__)                    ((uint8_t)((__ADDRESS__) & (uint8_t)(~I2C_OAR1_ADD0)))
#define I2C_7BIT_ADD_READ(__ADDRESS__)                     ((uint8_t)((__ADDRESS__) | I2C_OAR1_ADD0))

底层中并没有把设备的地址左移,而是直接把最低位改为"0"或"1",需要自己把器件地址的左移了一位。

c 复制代码
	stat = HAL_I2C_Mem_Read(&hi2c1,(PCA9557_I2C_BUS_ADDR << 1),PCA9557_INPUT_REG,1,&io_statu,1,0xFF);
	
	if(stat != 0 )
	{
	  LOG_INFO("io %d Read Error STAT %d\r\n",io,stat);
	}
	
相关推荐
niuTaylor1 小时前
STM32平衡车开发实战教程:从零基础到项目精通
stm32·单片机·嵌入式硬件
可待电子单片机设计定制(论文)10 小时前
【STM32设计】基于STM32的智能门禁管理系统(指纹+密码+刷卡+蜂鸣器报警)(代码+资料+论文)
stm32·单片机·嵌入式硬件
不可思议迷宫11 小时前
Verilog编程实现一个分秒计数器
单片机·嵌入式硬件·fpga开发
life_yangzi13 小时前
关于单片机IAP升级的那点事儿|智能设置中断向量表
单片机·嵌入式硬件
了一li15 小时前
STM32实现一个简单电灯
stm32·单片机·嵌入式硬件
可待电子单片机设计定制(论文)17 小时前
【STM32设计】数控直流稳压电源的设计与实现(实物+资料+论文)
stm32·嵌入式硬件·mongodb
march_birds18 小时前
FreeRTOS 与 RT-Thread 事件组对比分析
c语言·单片机·算法·系统架构
小麦嵌入式18 小时前
Linux驱动开发实战(十一):GPIO子系统深度解析与RGB LED驱动实践
linux·c语言·驱动开发·stm32·嵌入式硬件·物联网·ubuntu
触角0101000120 小时前
STM32F103低功耗模式深度解析:从理论到应用实践(上) | 零基础入门STM32第九十二步
驱动开发·stm32·单片机·嵌入式硬件·物联网
昊虹AI笔记20 小时前
使用STM32CubeMX和Keil在STM32上创建并运行一个简单的FreeRTOS多任务程序
stm32·单片机·嵌入式硬件