本帖最后由 sujingliang 于 2025-7-19 11:12 编辑
I2C的实例位于:
STM32Cube_FW_U3_V1.2.0\Projects\NUCLEO-U385RG-Q\Examples\I2C
其中I2C_TwoBoards_MultiMasterIT_Master,I2C_TwoBoards_MultiMasterIT_Slave可以实现一对开发板进行I2C发送接收演示。
如果没有2个STM32U385RG开发板,可以用其他的STM32开发板代替,其他开发板也有这个2个示例,可以和STM32U385RG进行I2C通讯。
我将STM32U385RG做Slave,STM32H533RE做Master发现可以很容易实现两者的I2C通信实验。
于是想如果用CH347做Master,是否也可以和做为Slave的STM32U385RG进行I2C通信呢?
一、尝试HAL_I2C_Slave_Receive_IT失败了
然后发现竟然不行,也许是认知有限吧。
在I2C_TwoBoards_MultiMasterIT_Slave中采用的HAL_I2C_Slave_Receive_IT做为接收函数。
HAL_I2C_Slave_Receive_IT 设计用于简单的单次传输(主机发送数据后结束通信)。可能 CH347 的通信协议中包含了重复起始条件(Repeated Start)或连续传输(如先写后读),此函数无法自动处理,导致 Slave 无响应。
试了很多次,没有成功,还是放弃了。
二、使用HAL_I2C_Master_Seq_Receive_IT成功了
后来看了I2C_TwoBoards_RestartComIT这个示例,这个例子使用HAL_I2C_Master_Seq_Receive_IT做为接收函数,经过尝试发现可以实现和CH347通信。
1、CH347简介
CH347 是南京沁恒微电子(WCH)推出的一款高速USB总线转接芯片,支持 USB 转多协议串行接口,包括:
USB 转 I2C(主/从模式)、USB 转 SPI(主模式)、USB 转 异步串口(UART)、GPIO 控制
其中,
I2C 支持 - 主模式(Master)- 速率:标准模式(100kHz)、快速模式(400kHz)、高速模式(1MHz)
从已知的资料上看CH347支持I2C Master模式,所以STM32U385RG只能做为Slave
2、STM32U385RG软件部分
1)I2C初始化
速率:100khz
hi2c2.Instance = I2C2;
hi2c2.Init.Timing = 0x0070123C;
hi2c2.Init.OwnAddress1 = I2C_ADDRESS;
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();
}
2)启用监听模式
int main(void)
{
...
if(HAL_I2C_EnableListen_IT(&hi2c2) != HAL_OK)
{
Error_Handler();
}
while(1)
{
}
3)地址匹配回调
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
{
HAL_I2C_Slave_Seq_Receive_IT(&hi2c2, aRxBuffer, 10, I2C_FIRST_FRAME);
}
4)接收完成回调
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *I2cHandle)
{
printf("Received data: [%s]\r\n", aRxBuffer);
if (hi2c2.State != HAL_I2C_STATE_READY) {
HAL_I2C_DeInit(&hi2c2);
HAL_I2C_Init(&hi2c2);
}
HAL_I2C_EnableListen_IT(&hi2c2);
}
在 RxCpltCallback 中强制复位 I2C,并重启监听模式
3、ch347 I2C Master发送部分
#! /usr/bin/env python
#coding=utf-8
import os
import time
from ctypes import *
class USBI2C():
ch347 = windll.LoadLibrary("./CH347DLLA64.dll")
def __init__(self, usb_dev = 0, i2c_dev = 0x30):
self.usb_id = usb_dev
self.dev_addr = i2c_dev
USBI2C.ch347.CH347I2C_Set(self.usb_id,4)
if USBI2C.ch347.CH347OpenDevice(self.usb_id) != -1:
USBI2C.ch347.CH347CloseDevice(self.usb_id)
else:
print("USB CH347 Open Failed!")
def read(self):
if USBI2C.ch347.CH347OpenDevice(self.usb_id) != -1:
rec = (c_byte * 1)()
ibuf = (c_byte * 9)()
rec[0] = self.dev_addr
USBI2C.ch347.CH347StreamI2C(self.usb_id, 1, rec, 9, ibuf)
USBI2C.ch347.CH347CloseDevice(self.usb_id)
return ibuf
else:
print("USB CH347 Open Failed!")
return 0
def write(self,cmd,size):
if USBI2C.ch347.CH347OpenDevice(self.usb_id) != -1:
tcmd = (c_byte * (size + 1))()
ibuf = (c_byte * 1)()
tcmd[0] = self.dev_addr
for i in range (size):
tcmd[i+1] = cmd[i] & 0xff
print(tcmd[i+1])
USBI2C.ch347.CH347StreamI2C(self.usb_id,11,tcmd,1,ibuf)
USBI2C.ch347.CH347CloseDevice(self.usb_id)
else:
print("USB CH347 Open Failed!")
if __name__ == "__main__":
cmd = (c_byte * 10)(0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39)
size = sizeof(cmd)
q = USBI2C()
while True:
q.write(cmd,size)
time.sleep(1) #1s
也可以利用沁恒提供的上位机
三、运行效果
1、使用PYTHON脚本
2、使用CH347上位机
|