使用LL库配置STM32的IIC

本文驱动0.96寸IIC接口的OLED为例,向大家说明如何使用LL库配置STM32的IIC。
注意,本文并非教程,只作为使用STM32 IIC 外设的一些补充说明,关于IIC接口和OLED的一些相关知识在此不作说明。
LL库相对于HAL的优点别的不说,就一个字:快!!!,我使用公司的烂电脑编译一个HAL库的工程怎么说也得要两三分钟,使用LL库时可以缩减到30S左右(虽然还是很慢,公司给配的电脑辣鸡没法子)。
使用LL库的前提是需要我们拥有一个LL库的工程(这不是废话吗),最简单的方法是通过STM32CubeMX新建一个。使用STM32CubeMX新建时也没啥要求,配置好时钟就行,至于IIC的相应配置,我们直接通过代码配置就好。就是记得在最后在生成工程的时候把HAL切换为LL。
不懂的可以参考这篇帖子
基于STM32CubeMX的LL库学习记录(二)建立一个工程
下面开始贴代码

IIC引脚初始化

void I2C_GPIO_Init(void)
{
	LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
	
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOB);					//GPIO Ports Clock Enable

	LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_8|LL_GPIO_PIN_9);			//设置PB8 PB9 输出1
	\
	/*引脚功能设置*/
  GPIO_InitStruct.Pin = LL_GPIO_PIN_8|LL_GPIO_PIN_9;													//引脚
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;								//复用模式
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;					//输出速度:最高
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;				//开漏输出
  GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;												//上拉使能
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);												//写入配置

	LL_GPIO_SetAFPin_8_15(GPIOB,LL_GPIO_PIN_8,LL_GPIO_AF_4);				//引脚复用设置
	LL_GPIO_SetAFPin_8_15(GPIOB,LL_GPIO_PIN_9,LL_GPIO_AF_4);
}

使用的引脚为PB8 和PB9,所以这里是对引脚的初始化设置。LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_8|LL_GPIO_PIN_9);配置前把引脚置1,可以避免配置好后IIC总线被拉低(至于为什么会被拉低,我也不知道),另外我的IIC设备是直接通过杜邦线与stm32连接,没有上拉电阻,因此设置了引脚内部的上拉电阻,如果有外部上拉的话可以取消引脚内部上拉电阻。

IIC初始化

#define OLED_ADDRESS	0x78 

void IIC_Init(void)
{
	LL_I2C_InitTypeDef I2C_InitStructure = {0};
	
	LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);						//IIC时钟使能

	I2C_InitStructure.PeripheralMode = LL_I2C_MODE_I2C;
	I2C_InitStructure.OwnAddress1 = OLED_ADDRESS;
	I2C_InitStructure.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
	I2C_InitStructure.TypeAcknowledge = LL_I2C_ACK;
	I2C_InitStructure.DutyCycle = LL_I2C_DUTYCYCLE_2;
	I2C_InitStructure.ClockSpeed = LL_I2C_MAX_SPEED_FAST;
	LL_I2C_Init(I2C1,&I2C_InitStructure);
}

这一段配置IIC的主从模式(主机模式),地址(OLED不会对主机有读操作,所以地址就随便设了,这里设置为和OLED的地址一致),寻址模式(7位寻址),应答模式(应答使能),通信速度(400K)等。可以的话最好对着数据手册过一遍。

IIC 写数据

void I2C_WriteByte(unsigned char addr,unsigned char data)
{	
	while(LL_I2C_IsActiveFlag_BUSY(I2C1));	//判断总线是否忙碌
	LL_I2C_GenerateStartCondition(I2C1);																				//START 1
	while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));									//读SR1->SB位,判断起始位是否发送
	I2C_Send7bitAddress(I2C1,OLED_ADDRESS,I2C_Direction_Transmitter);						//发送从设备地址	
	while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));		//等待EV6完成;读SR1、SR2
	LL_I2C_TransmitData8(I2C1,addr);																						//从设备的寄存器地址
	while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
	LL_I2C_TransmitData8(I2C1,data);																						//发送数据
	while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
	LL_I2C_GenerateStopCondition(I2C1);																					//停止位
	
//	uint16_t temp = 0;
//	while(I2C1->SR2 & 0x0002);																									//判断总线是否忙碌
//	LL_I2C_GenerateStartCondition(I2C1);																				//START 1
//	while(!(I2C1->SR1 & 0x0001));																								//读SR1->SB位,判断起始位是否发送
//	I2C_Send7bitAddress(I2C1,OLED_ADDRESS,I2C_Direction_Transmitter);						//发送从设备地址	
//	while(!(I2C1->SR1 & 0x0002));																								//地址发送结束
//	temp = I2C1->SR2;																														//读SR2
//	LL_I2C_TransmitData8(I2C1,addr);																						//从设备的寄存器地址
//	while(!(I2C1->SR1 & 0x0080));
//	LL_I2C_TransmitData8(I2C1,data);																						//发送数据
//	while(!(I2C1->SR1 & 0x0080));
//	I2C1->CR1 |= 0x0200;																												//停止位
//	LL_I2C_GenerateStopCondition(I2C1);																					//停止位
	
}

没注释的是野火开发板的代码,注释掉的是我写的,都能用。使用野火那段的话需要把野火的一些代码拷贝到自己的工程上。代码如下

#define  I2C_Direction_Transmitter      ((uint8_t)0x00)		//发送模式
#define  I2C_Direction_Receiver         ((uint8_t)0x01)		//接收模式

/*IIC 事件*/
/* --EV5 : 起始位已发送...*/
#define  I2C_EVENT_MASTER_MODE_SELECT                      ((uint32_t)0x00030001)  /* BUSY, MSL and SB flag */
/* --EV6 : 发送/接收完成...*/
#define  I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED        ((uint32_t)0x00070082)  /* 发送 BUSY, MSL, ADDR, TXE and TRA flags */
#define  I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED           ((uint32_t)0x00030002)  /* 接收 BUSY, MSL and ADDR flags */
/* Master RECEIVER mode -----------------------------*/ 
/* --EV7 */
#define  I2C_EVENT_MASTER_BYTE_RECEIVED                    ((uint32_t)0x00030040)  /* BUSY, MSL and RXNE flags */
/* Master TRANSMITTER mode --------------------------*/
/* --EV8 */
#define I2C_EVENT_MASTER_BYTE_TRANSMITTING                 ((uint32_t)0x00070080) /* TRA, BUSY, MSL, TXE flags */
/* --EV8_2 */
#define  I2C_EVENT_MASTER_BYTE_TRANSMITTED                 ((uint32_t)0x00070084)  /* TRA, BUSY, MSL, TXE and BTF flags */
/*=========================================================================================*/
void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction)
{
  /* Test on the direction to set/reset the read/write bit */
  if (I2C_Direction != I2C_Direction_Transmitter)
  {
    /* Set the address bit0 for read */
    Address |= I2C_OAR1_ADD0;
  }
  else
  {
    /* Reset the address bit0 for write */
    Address &= (uint8_t)~((uint8_t)I2C_OAR1_ADD0);
  }
  /* Send the address */
  I2Cx->DR = Address;
}

uint8_t I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
  uint32_t lastevent = 0;
  uint32_t flag1 = 0, flag2 = 0;
  uint8_t status = 0;

  /* Read the I2Cx status register */
  flag1 = I2Cx->SR1;
  flag2 = I2Cx->SR2;
  flag2 = flag2 << 16;

  /* Get the last event value from I2C status register */
  lastevent = (flag1 | flag2) & ((uint32_t)0x00FFFFFF);

  /* Check whether the last event contains the I2C_EVENT */
  if ((lastevent & I2C_EVENT) == I2C_EVENT)
  {
    /* SUCCESS: last event is equal to I2C_EVENT */
    status = 1;
  }
  else
  {
    /* ERROR: last event is different from I2C_EVENT */
    status = 0;
  }
  /* Return status */
  return status;
}

至此本文结束,点击此处可下载相应工程代码,文件中包含野火开发板的工程代码和本文的工程代码

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值