前言

talk is cheap, show me the code, 直接看下列的 初始化代码, 以及读写函数吧。

void Configure_I2Cx_Master(I2C_TypeDef *I2Cx)
{/* (1) Enables GPIO clock and configures the I2C3 pins **********************//*    (SCL on PC.0, SDA on PC.1)                     **********************//* Enable the peripheral clock of GPIOC */LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOC);/* Configure SCL Pin as : Alternate function, High Speed, Open drain, Pull up */LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_0, LL_GPIO_MODE_ALTERNATE);LL_GPIO_SetAFPin_0_7(GPIOC, LL_GPIO_PIN_0, LL_GPIO_AF_7);LL_GPIO_SetPinSpeed(GPIOC, LL_GPIO_PIN_0, LL_GPIO_SPEED_FREQ_HIGH);LL_GPIO_SetPinOutputType(GPIOC, LL_GPIO_PIN_0, LL_GPIO_OUTPUT_OPENDRAIN);LL_GPIO_SetPinPull(GPIOC, LL_GPIO_PIN_0, LL_GPIO_PULL_UP);/* Configure SDA Pin as : Alternate function, High Speed, Open drain, Pull up */LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_1, LL_GPIO_MODE_ALTERNATE);LL_GPIO_SetAFPin_0_7(GPIOC, LL_GPIO_PIN_1, LL_GPIO_AF_7);LL_GPIO_SetPinSpeed(GPIOC, LL_GPIO_PIN_1, LL_GPIO_SPEED_FREQ_HIGH);LL_GPIO_SetPinOutputType(GPIOC, LL_GPIO_PIN_1, LL_GPIO_OUTPUT_OPENDRAIN);LL_GPIO_SetPinPull(GPIOC, LL_GPIO_PIN_1, LL_GPIO_PULL_UP);/* (2) Enable the I2C3 peripheral clock and I2C3 clock source ***************//* Enable the peripheral clock for I2C3 */LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3);/* Set I2C3 clock source as SYSCLK */LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_SYSCLK);/* (3) Configure NVIC for I2C3 **********************************************//* Configure Event and Error IT:*  - Set priority for I2C3_IRQn*  - Enable I2C3_IRQn*/
//  NVIC_SetPriority(I2C3_IRQn, 0);
//  NVIC_EnableIRQ(I2C3_IRQn);/* (4) Configure I2C3 functional parameters *********************************//* Disable I2C3 prior modifying configuration registers */LL_I2C_Disable(I2C3);/* Configure the SDA setup, hold time and the SCL high, low period *//* (uint32_t)0x00601B28 = I2C_TIMING*/uint32_t timing = __LL_I2C_CONVERT_TIMINGS(0x0, 0x6, 0x0, 0x1B, 0x28);LL_I2C_SetTiming(I2C3, timing);/* Configure the Own Address1                   *//* Reset Values of :*     - OwnAddress1 is 0x00*     - OwnAddrSize is LL_I2C_OWNADDRESS1_7BIT*     - Own Address1 is disabled*///LL_I2C_SetOwnAddress1(I2C3, 0x00, LL_I2C_OWNADDRESS1_7BIT);//LL_I2C_DisableOwnAddress1(I2C3);/* Enable Clock stretching *//* Reset Value is Clock stretching enabled *///LL_I2C_EnableClockStretching(I2C3);/* Configure Digital Noise Filter *//* Reset Value is 0x00            *///LL_I2C_SetDigitalFilter(I2C3, 0x00);/* Enable Analog Noise Filter           *//* Reset Value is Analog Filter enabled *///LL_I2C_EnableAnalogFilter(I2C3);/* Enable General Call                  *//* Reset Value is General Call disabled *///LL_I2C_EnableGeneralCall(I2C3);/* Configure the 7bits Own Address2               *//* Reset Values of :*     - OwnAddress2 is 0x00*     - OwnAddrMask is LL_I2C_OWNADDRESS2_NOMASK*     - Own Address2 is disabled*///LL_I2C_SetOwnAddress2(I2C3, 0x00, LL_I2C_OWNADDRESS2_NOMASK);//LL_I2C_DisableOwnAddress2(I2C3);/* Configure the Master to operate in 7-bit or 10-bit addressing mode *//* Reset Value is LL_I2C_ADDRESSING_MODE_7BIT                         *///LL_I2C_SetMasterAddressingMode(I2C3, LL_I2C_ADDRESSING_MODE_7BIT);/* Enable Peripheral in I2C mode *//* Reset Value is I2C mode *///LL_I2C_SetMode(I2C3, LL_I2C_MODE_I2C);/* (5) Enable I2C3 **********************************************************/LL_I2C_Enable(I2C3);/* (6) Enable I2C3 transfer complete/error interrupts:*  - Enable Receive Interrupt*  - Enable Not acknowledge received interrupt*  - Enable Error interrupts*  - Enable Stop interrupt*/
//  LL_I2C_EnableIT_RX(I2C3);
//  LL_I2C_EnableIT_NACK(I2C3);
//  LL_I2C_EnableIT_ERR(I2C3);
//  LL_I2C_EnableIT_STOP(I2C3);
}/*** @brief  This Function handle Master events to perform a transmission process* @note  This function is composed in different steps :*        -1- Initiate a Start condition to the Slave device*        -2- Loop until end of transfer received (STOP flag raised)*             -2.1- Transmit data (TXIS flag raised)*        -3- Clear pending flags, Data consistency are checking into Slave process* @param  None* @retval None*/
void I2C_Write(I2C_TypeDef *I2Cx, unsigned char slave_addr, unsigned char reg_addr, unsigned char reg_data)
{unsigned char data_size = 2;/* Master Generate Start condition for a write request :              *//*    - to the Slave with a 7-Bit SLAVE_OWN_ADDRESS                   *//*    - with a auto stop condition generation when transmit all bytes */LL_I2C_HandleTransfer(I2Cx, slave_addr, LL_I2C_ADDRSLAVE_7BIT, data_size, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_WRITE);/* Loop until STOP flag is raised  */while(!LL_I2C_IsActiveFlag_STOP(I2Cx)){/* Check TXIS flag value in ISR register */if(LL_I2C_IsActiveFlag_TXE(I2Cx) && data_size == 2){/* Write data in Transmit Data register.TXIS flag is cleared by writing data in TXDR register */LL_I2C_TransmitData8(I2Cx, reg_addr);data_size--;}/* Check TXIS flag value in ISR register */if(LL_I2C_IsActiveFlag_TXE(I2Cx) && data_size == 1){/* Write data in Transmit Data register.TXIS flag is cleared by writing data in TXDR register */LL_I2C_TransmitData8(I2Cx, reg_data);data_size--;}if(Loop_Is_Timeout_Xms(5))break;}/* (3) Clear pending flags, Data consistency are checking into Slave process *//* End of I2C_SlaveReceiver_MasterTransmitter Process */LL_I2C_ClearFlag_STOP(I2Cx);
}/*** @brief  This Function handle Master events to perform a transmission process* @note  This function is composed in different steps :*        -1- Initiate a Start condition to the Slave device*        -2- Loop until end of transfer received (STOP flag raised)*             -2.1- Transmit data (TXIS flag raised)*        -3- Clear pending flags, Data consistency are checking into Slave process* @param  None* @retval None*/
unsigned char I2C_Read(I2C_TypeDef *I2Cx, unsigned char slave_addr, unsigned char reg_addr)
{unsigned char read_byte = 0;unsigned char data_size = 1;/* Master Generate Start condition for a write request :              *//*    - to the Slave with a 7-Bit SLAVE_OWN_ADDRESS                   *//*    - with a auto stop condition generation when transmit all bytes */LL_I2C_HandleTransfer(I2Cx, slave_addr, LL_I2C_ADDRSLAVE_7BIT, data_size, LL_I2C_MODE_SOFTEND, LL_I2C_GENERATE_START_WRITE);/* Loop until STOP flag is raised  *//* This loop is dangerous when power support is terrrible. */while(!LL_I2C_IsActiveFlag_TC(I2Cx)){/* Check TXIS flag value in ISR register */if(LL_I2C_IsActiveFlag_TXE(I2Cx) && data_size == 1){/* Write data in Transmit Data register.TXIS flag is cleared by writing data in TXDR register */LL_I2C_TransmitData8(I2Cx, reg_addr);data_size--;}if(Loop_Is_Timeout_Xms(3))break;}data_size = 1;LL_I2C_HandleTransfer(I2Cx, slave_addr, LL_I2C_ADDRSLAVE_7BIT, data_size, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_READ);/* Loop until STOP flag is raised  */while(!LL_I2C_IsActiveFlag_STOP(I2Cx)){if(Loop_Is_Timeout_Xms(4))break;}if(LL_I2C_IsActiveFlag_RXNE(I2Cx))read_byte = LL_I2C_ReceiveData8(I2Cx);/* (3) Clear pending flags, Data consistency are checking into Slave process */LL_I2C_ClearFlag_STOP(I2Cx);return read_byte;
}

问题

Q1: 该LL_I2C_HandleTransfer(I2Cx, slave_addr, LL_I2C_ADDRSLAVE_7BIT, data_size, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_READ) 函数,非常容易造成使用上的误解问题,如果不借助逻辑分析仪的话。

A1: 关于这个问题,有几点需要了解。

  1. 如果设置了stm32中硬件iic为 7bit地址模式,要注意slave_addr的值其实要配置为写地址的值(slave_addr<<2)。 因为在stm32的硬件iic中, 会将传入函数的地址值的最后一位改成读写状态的值, 而不是将传入函数的地址之后再附加一位读写状态值。 比如说, 传入为7位的slave_addr地址值得话, 那么会改变了7位slave_addr地址的最后一位bit的值。
    众所周知, 在IIC器件中, 一般有三个地址, 比如hmcl5883设备器件地址为 0x1E, 写地址为0x3c,读地址为0x3d, 那么我们在使用stm32的硬件iic的时候, 要将slave_addr的地址值填写为( 0x1e<<1), 也就是要设置为写地址0x3c(不是设备地址0x1e),因为在配置了LL_I2C_GENERATE_START_READ之后,芯片会在最后一位自动改变读写位的电平状态, 在读的时候,自动产生高位电平, 也就是产生读地址0x3d的电平出去,而如果配置了LL_I2C_GENERATE_START_WRITE之后, 在传输完( 0x1e<<1)的地址之后, 最后的地址位为低电平, 也就是写地址为0x3c。
  2. 设置了data_size以及LL_I2C_MODE_AUTOEND之后, I2C会在发送完所有数据或者读取完所有数据之后,自动发送终止信号。写的过程中, 硬件iic自动会读取从机的ack信号; 而读的过程后,如果需要后续继续操作, 需要产生ack信号给从机, 而如果已经读完,那么会自动产生nack信号给从机,有些从机一定要接收到主机的nack信号, 然后才能正常接收主机的stop信号, 否则会导致后续一连串读取异常
  3. 接收器在收到数据之后, 应该拉低引脚来产生应答信号(正常来说, 引脚都是开漏上拉,所以,下拉为有效电平),以此通知对方已完整收到相关的数据。 而在主机作为接收器的时候,当接收完从设备的最后一个字节数据之后, 需要不应答, 以此告诉从设备传输即将结束, 准备接收结束信号。

Q2: 硬件IIC在信号出现抖动(频率过快的话或者供电不足的情况下), 主机发出的时序会完全错乱, 比如说, 当频率过高或者数据线接触不良,此时我们通过重新初始化从机,且重置硬件iic的错误标志,iic硬件接收到的数据虽然会有变化, 但是,读到的值完全不对, 这时候只能通过重新初始化IIC硬件才能解决, 但是,在L0系列上,利用外部中断不断地打断硬件iic时, 未发现iic数据读取出现任何较大的异常。

A2:当信号抖动之后, 根据逻辑分析仪,会发现主机在发送从机设备地址的时候,会多发一个字节的数据时序,但是,这个字节数据的值不知从何而来,这便会导致后面读到的值各种异常, 怀疑是不是移位寄存器在发送的时候,也发送了之前发生总线错误的时候,移位寄存器缓存部分字节信息。 因为调试时,相关的接收, 发送寄存器的值都是正常。

通过LL库初始化STM32的硬件IIC相关推荐

  1. 【STM32-I2C学习总结】STM32:硬件-IIC详解 , 固件库编程 , 手把手教你实现IIC

    STM32:硬件-IIC详解 , 固件库编程 , 手把手教你实现IIC 一 .I2C物理层 二.协议层 1.I2C基本读写过程 (1)主机写数据到从机 (2)主机由从机中读数据 (3)I2C 通讯复合 ...

  2. 【STM32】 硬件IIC 驱动SSD1302(0.96 OLED模块) -- 3/4 OLED的命令表 学习

    书接上回 文章1:[STM32] 硬件IIC 驱动SSD1306(0.96 OLED模块) – 1/4 库函数 学习 文章2:[STM32] 硬件IIC 驱动SSD1302(0.96 OLED模块) ...

  3. STM32 HAL 硬件IIC+DMA+简单图形库控制OLED

    目录 前言 一.建立工程 二.编写和移植 前期准备 驱动部分修改 三.使用和验证 结论 (2022年1月22日重制)本文主要是移植带简单图形库的程序,如果只是实现DMA控制,建议看[0.96寸 OLE ...

  4. stm32hal库应用笔记之硬件IIC读写SHTC31000温湿度传感器

    话不多说上图: 完成的数据手册百度吧 嘻嘻 这是SHTC31000芯片的时序图: 这个怎么看我就不多解释了哈 SHTC3.h #ifndef SHTC3_SHTC3_H_ #define SHTC3_ ...

  5. 【STM32】CubeMX+HAL库之 硬件IIC+DMA控制OLED(兼容SSD1306SH1106驱动)

    [STM32]CubeMX+HAL库之 硬件IIC+DMA控制1.3寸OLED 前言 目前网上大多数驱动OLED屏都采用软件IIC,因为HAL库的升级使得硬件IIC的稳定性得到了保障,所以想采用硬件I ...

  6. 【STM32】HAL库 STM32CubeMX教程十二---IIC(读取AT24C02 )

    前言: 本系列教程将HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 在之前的标准库中,STM32的硬件IIC非常复杂,更重要的是它并不稳定,所以都不推荐使用. 但是 ...

  7. stm32 硬件IIC使用方法说明与示例---LIS3DH的IIC通信

    有时我们可能需要MCU进行速率较高的IIC总线通信,一般stm32的IIC默认传输速率是100kpbs,最大为400kpbs.现在大部分项目会使用程序IO模拟的IIC,使用方便,具体网上例子很多. 这 ...

  8. STM32单片机硬件I2C读取AHT10温湿度传感器数据

    STM32使用硬件IIC读取AHT10温湿度传感器的数据并显示在0.96寸OLED屏上. 我用的单片机是STM32F103C8T6,程序用的是ST标准库写的. STM32使用硬件I2C读取SHTC3温 ...

  9. 【国货之光】GD32E230F4使用硬件IIC+DMA读写24C04

    在很久很久以前,我就写过GD32E230替换STM32F031的帖子,主要介绍了USART和SPI的外设移植开发,当时IIC使用的是软件i2c,没有介绍的价值.在使用IIC时,大多数我们都是采用软件的 ...

  10. 基于cubemx的硬件iic SHT30的iic调试

    一直对stm32的硬件iic敬而远之,好像说是有问题的,就一直用的模拟iic实现,今天用sht30试了一下,发现基于cubemx来配置iic还挺方便的.现做如下记录 首先是硬件平台:stm32f103 ...

最新文章

  1. 为什么都说 Go 是大厂通行证!
  2. 简单的按键控制LED
  3. centos7.2下安装mysql5.7数据库
  4. 学Python做人工智能的前景怎么样?如何入行?
  5. 年末裁员事件背后的启示录(2)
  6. 前端学习(1869)vue之电商管理系统电商系统之配置axios发出登录请求
  7. 行内元素中的非替换行内元素和替换行内元素
  8. 英伟达美女工程师:AI从业者要不要读博?要不要自己创业?
  9. 蓝桥杯 ALGO-119 算法训练 寂寞的数
  10. apache http server 停止工作_Tomcat9配置HTTP/2
  11. Nginx-1.6.2更改端口
  12. JavaScript 自定义对象 及 new()原理与实现 如何完整地手写实现new
  13. quick-cocos2d-x GameCenter 排行榜
  14. 【射频识别技术】期末重点整理
  15. JDK正式免费、Log4j2爆核弹级漏洞、LayUI下线,2021的10 件大事
  16. C Library User 手册(25)
  17. 概率论总结——泊松分布与指数分布
  18. 关于错误local variable ‘str‘ referenced before assignment
  19. D. Bouncing Boomerangs
  20. Python 分析电影《南方车站的聚会》

热门文章

  1. ffmpeg的使用笔记
  2. 制作js原生瀑布流插件
  3. 邮件群发平台_群发开发信不进垃圾箱的技巧
  4. 厦门大学LaTeX毕业论文模板:中英文双目录
  5. Docker 配置国内源加速镜像下载
  6. 解决OSS传输的文本文件网页打开乱码
  7. 薅羊毛算副业吗?薅羊毛到底是怎么赚钱的?
  8. python-类(class)是什么?怎么用?
  9. 杰理之无线MIC【篇】
  10. 图像工作回顾之三:极线匹配