STM32L1XX系列IIC

1 使用STM32CubeMx建立IIC工程

通用部分配置见软件使用

  • 开启IIC,参数可默认


    image.png
  • 将GPIO设置成无需上下拉,依靠外部电路即可


    image.png
  • 关于生成代码,主要在i2c.c中,该工程已经将IIC初始化相关操作完成,我们要做的仅仅是进行设备的读写了而已。这里简单说明一下自动生成的代码。

他首先在工程中添加了stm32l1xx_hal_i2c.c,这便是我们调用的驱动库,然后在stm32l1xx_hal_conf.h中打开了宏#define HAL_I2C_MODULE_ENABLED,至此在算将IIC库引入了进来。
接下来便是通过驱动库来初始化IIC,i2c.c中的HAL_I2C_MspInit和HAL_I2C_MspDeInit是对引脚的初始化和反初始化,但是不需要我们来调用,他在库中被弱实现,在使用库函数HAL_I2C_Init来初始化的时候,内部将会调用此函数来进行引脚初始化,所以这里仅仅是来实现这个函数而已。实际在主函数调用的IIC初始化函数是MX_I2C1_Init,他是根据在cube中的配置信息来初始化IIC的。

2 测试程序-HTU21D温湿度

我们使用一个温湿度传感器来测试一下。
以下列举库中我们可能用到的库函数,取至库函数抬头的注释

    (#) Blocking mode functions are :
        (++) HAL_I2C_Master_Transmit()
        (++) HAL_I2C_Master_Receive()
        (++) HAL_I2C_Slave_Transmit()
        (++) HAL_I2C_Slave_Receive()
        (++) HAL_I2C_Mem_Write()
        (++) HAL_I2C_Mem_Read()
        (++) HAL_I2C_IsDeviceReady()
        
    (#) No-Blocking mode functions with Interrupt are :
        (++) HAL_I2C_Master_Transmit_IT()
        (++) HAL_I2C_Master_Receive_IT()
        (++) HAL_I2C_Slave_Transmit_IT()
        (++) HAL_I2C_Slave_Receive_IT()
        (++) HAL_I2C_Master_Sequential_Transmit_IT()
        (++) HAL_I2C_Master_Sequential_Receive_IT()
        (++) HAL_I2C_Slave_Sequential_Transmit_IT()
        (++) HAL_I2C_Slave_Sequential_Receive_IT()
        (++) HAL_I2C_Mem_Write_IT()
        (++) HAL_I2C_Mem_Read_IT()

    (#) No-Blocking mode functions with DMA are :
        (++) HAL_I2C_Master_Transmit_DMA()
        (++) HAL_I2C_Master_Receive_DMA()
        (++) HAL_I2C_Slave_Transmit_DMA()
        (++) HAL_I2C_Slave_Receive_DMA()
        (++) HAL_I2C_Mem_Write_DMA()
        (++) HAL_I2C_Mem_Read_DMA()

    (#) A set of Transfer Complete Callbacks are provided in non Blocking mode:
        (++) HAL_I2C_MemTxCpltCallback()
        (++) HAL_I2C_MemRxCpltCallback()
        (++) HAL_I2C_MasterTxCpltCallback()
        (++) HAL_I2C_MasterRxCpltCallback()
        (++) HAL_I2C_SlaveTxCpltCallback()
        (++) HAL_I2C_SlaveRxCpltCallback()
        (++) HAL_I2C_ErrorCallback()
        (++) HAL_I2C_AbortCpltCallback()

编写两个函数,一个发送命令使其复位传感器,一个读温度数据
前者的命令格式是地址+命令,所以使用了HAL_I2C_Master_Transmit,通信成功了就返回0

int htu21d_soft_reset()
{
      uint8_t val = 0xFE;
      if(HAL_I2C_Master_Transmit(&hi2c1,0X80,&val,1,100) == HAL_OK)
        {
            return 0;
        }           
        else
        {
           return 1;
        }
}

这里补充一下,IIC设备非常多,很多传感器说明文档的地址表述方式不一样,使其有的需要自己移位来得到实际填入地址,有的着不需要。当然你可以自己仔细看文档,然后再追踪代码看库函数的具体实现,得到自己应该填写的地址,这里库函数仅仅是补上了读写位。 还有一种比较暴力的方法,但是挺好用的,那就是轮询地址。反正一般地址就0到FF间,一个循环,几秒钟的找出来了。
例如上列修改成

uint8_t i;
uint8_t val =0xfe;
for(i=0;i<0xff;i++)
{
    if(HAL_I2C_Master_Transmit(&hi2c1,i,&val,1,100) == HAL_OK)
   {
        printf("%02X\n",i);
   }
}

然后就会看到在0X80和0X81的被打印出来,一个读一个写。

然后时读温度函数,这里需要用的具体寄存器地址所以需要使用HAL_I2C_Mem_Read函数

uint16_t htu21d_get_temp()
{
    uint16_t temp=0;
      float temp_f=0;
      uint8_t buff[2];
      
      if(HAL_I2C_Mem_Read(&hi2c1,0X81,0XE3,I2C_MEMADD_SIZE_8BIT,buff,2,100) == HAL_OK)
        {
            uint16_t ret = (buff[0] << 8) | (buff[1] & 0xfc);   
              temp_f = ret*175.72/65536-46.85;      
            temp = (uint16_t)(temp_f*10.0);
        }
        else
        {
           temp=0;
        }
      return temp;
}

结果如图,用手按一按就会变化的


image.png

你可能感兴趣的:(STM32L1XX系列IIC)