STM32 IIC双机通信—— HAL库硬件IIC版
Posted xingboy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32 IIC双机通信—— HAL库硬件IIC版相关的知识,希望对你有一定的参考价值。
关于IIC的原理这里我就不多说了,网上有很多很好的解析,如果要看我个人对IIC的理解的话,可以点击查看,这里主要讲一下怎样利用STM32CubeMx实现IIC的通讯,经过个人实践,感觉HAL库的硬件IIC要比标准库的稳定。好了,下面就从STM32CubeMx 配置开始一步步实现IIC通讯。
STM32CubeMx的配置,这里关于新建工程的步骤我就不细说了,如果还不会操作STM32CubeMx 的可以点击链接查看, 这里主要对IIC的配置进行说明。
了解IIC的都知道,IIC通信有主从机之分,用两片STM32进行IIC通信当然也不例外,不过使用STM32CubeMx 配置有一个好处,就是不用分别配置主从机,在STM32CubeMx 配置里面,主从机的配置是一样,唯一不同的就是IIC的地址如上图,这个地址很重要,只要配置好了,基本就成功了。
还有一个要注意的,就是IIC的SDA、SCK引脚要配置成NPP模式,不然容易出现信号线忙,检测不到从机的情况。
配置配好后我们生成代码,就可以进行通信了,主从机核心代码如下:
下面是主机的重要代码:
/* I2C2 init function IIC配置*/ static void MX_I2C2_Init(void) { hi2c2.Instance = I2C2; hi2c2.Init.Timing = 0x10805D88; hi2c2.Init.OwnAddress1 = 20; //用户自己配置的地址 hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c2.Init.OwnAddress2 = 0; hi2c2.Init.OwnAddress2Masks = I2C_OA2_NOMASK; hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c2) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure Analogue filter */ if (HAL_I2CEx_ConfigAnalogFilter(&hi2c2, I2C_ANALOGFILTER_ENABLE) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure Digital filter */ if (HAL_I2CEx_ConfigDigitalFilter(&hi2c2, 0) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } } while(HAL_I2C_Master_Transmit_IT(&hi2c2 ,0x0b,&BUFF[0], 1)!= HAL_OK){}
//IIC主机发送函数,主要IIC配置好了,这个可以添加到main函数里面测试
关于STM32CubeMx的HAL库IIC收发有几种函数,用户可以根据自己不同的需求进行选择,以下就是主要的几个HAL库IIC收发函数:
/* 第1个参数为I2C操作句柄 第2个参数为从机设备地址 第3个参数为从机寄存器地址 第4个参数为从机寄存器地址长度 第5个参数为发送的数据的起始地址 第6个参数为传输数据的大小 第7个参数为操作超时时间 */ HAL_I2C_Mem_Write(&hi2c2,salve_add,0,0,PA_BUFF,sizeof(PA_BUFF),0x10); HAL_I2C_Mem_Write_IT(); HAL_I2C_Mem_Read(); HAL_I2C_Mem_Read_IT(); HAL_I2C_Mem_Read_DMA(); HAL_I2C_Mem_Write_DMA(); /* 不需要用到寄存器地址的主机HAL库IIC收发函数 */ HAL_I2C_Master_Receive(); //STM32 主机接收,不需要用到寄存器地址 HAL_I2C_Master_Receive_IT(); //中断IIC接收 HAL_I2C_Master_Receive_DMA(); //DMA 方式的IIC接收 HAL_I2C_Master_Transmit_IT(); //中断IIC发送 HAL_I2C_Master_Transmit_DMA(); //DMA 方式的IIC发送 HAL_I2C_Master_Transmit(&hi2c2,0x0B,PA_BUFF,sizeof(PA_BUFF),0x10); //STM32 主机发送 /* 不需要用到寄存器地址的从机HAL库IIC收发函数 */ HAL_I2C_Slave_Receive(); //STM32 从机机接收,不需要用到寄存器地址 HAL_I2C_Slave_Transmit(); //STM32 从机机发送,不需要用到寄存器地址 HAL_I2C_Slave_Receive_IT(); HAL_I2C_Slave_Receive_DMA(); HAL_I2C_Slave_Transmit_IT(); HAL_I2C_Slave_Transmit_DMA();
我这里因为只是做两个STM32间的单向通行而已,不需要对寄存器进行写数据。
所以主机发送函数选择了 HAL_I2C_Master_Transmit( ); 函数,而我从机则选择HAL_I2C_Slave_Receive( );函数,从机代码如下:
/* I2C2 init function 从机IIC初始化配置 */ static void MX_I2C2_Init(void) { hi2c2.Instance = I2C2; hi2c2.Init.Timing = 0x10805D88; hi2c2.Init.OwnAddress1 = 0x0A; hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c2.Init.OwnAddress2 = 0; hi2c2.Init.OwnAddress2Masks = I2C_OA2_NOMASK; hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c2) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure Analogue filter */ if (HAL_I2CEx_ConfigAnalogFilter(&hi2c2, I2C_ANALOGFILTER_ENABLE) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure Digital filter */ if (HAL_I2CEx_ConfigDigitalFilter(&hi2c2, 0) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } } while(HAL_I2C_Slave_Receive(&hi2c2, RE_BUFF, 1, 100)!= HAL_OK) {}
// 在配置好IIC后,可直接把该函数放到main函数测试,第一个参数是IIC通道选择,第二个参数是接收缓存,第三个数据的是接收长度,第四个参数是超时时间
作为从机,要与主机完成通信,有一个特别要注意的事情,就是IIC配置的地址要与主机发送的地址一致,否则无法完成应答。我一开始就是直接发送自己在软件配置的IIC地址,可是没有通信成功,检查才发现,软件配置好IIC后,生成代码时,地址会最后一位补0,自动补够8位;而我从机发送出来的地址,也会把你发送的地址最后一位改为0再发送,这个我查了一下函数地层,好像是因为这是是发送函数,所以直接帮你把R/W位改为0了。所以导致我一开始怎么都调不通,使用逻辑分析仪后,分析采集到的数据才发现这个问题,于是我,直接手动改从机的IIC地址,改成逻辑分析仪发出来的地址一样,这样就通了。
通信结果如图所示:
以上是关于STM32 IIC双机通信—— HAL库硬件IIC版的主要内容,如果未能解决你的问题,请参考以下文章
STM32模拟IIC与IIC四种实现数字光强采集模块GY30(标准库与HAL库)
STM32模拟IIC与IIC四种实现数字光强采集模块GY30(标准库与HAL库)
STM32实现0.96寸OLED显示模拟IIC和IIC四种实现(标准库和HAL库)