Files
Handcontrol_LYT_Version_Win…/class_ch341.py
2026-07-16 15:24:40 +08:00

263 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import time
import os
import sys
from ctypes import *
import ctypes
import glob
# ch341类iic读写int引脚读写速度设置
class ClassCh341:
# 接口固定宏
_mCH341A_CMD_I2C_STREAM = 0xAA # I2C接口的命令包,从次字节开始为I2C命令流
_mCH341A_CMD_I2C_STM_STA = 0x74 # I2C接口的命令流:产生起始位
_mCH341A_CMD_I2C_STM_STO = 0x75 # I2C接口的命令流:产生停止位
_mCH341A_CMD_I2C_STM_OUT = 0x80 # I2C接口的命令流:输出数据,位5-位0为长度,后续字节为数据,0长度则只发送一个字节并返回应答
_mCH341A_CMD_I2C_STM_IN = 0xC0 # I2C接口的命令流:输入数据,位5-位0为长度,0长度则只接收一个字节并发送无应答
_mCH341A_CMD_I2C_STM_MAX = 63 # I2C接口的命令流单个命令输入输出数据的最大长度
_mCH341A_CMD_I2C_STM_SET = 0x60 # I2C接口的命令流:设置参数,位2=SPI的I/O数(0=单入单出,1=双入双出),位1位0=I2C速度(00=低速,01=标准,10=快速,11=高速)
_mCH341A_CMD_I2C_STM_US = 0x40 # I2C接口的命令流:以微秒为单位延时,位3-位0为延时值
_mCH341A_CMD_I2C_STM_MS = 0x50 # I2C接口的命令流:以亳秒为单位延时,位3-位0为延时值
_mCH341A_CMD_I2C_STM_DLY = 0x0F # I2C接口的命令流单个命令延时的最大值
_mCH341A_CMD_I2C_STM_END = 0x00 # I2C接口的命令流:命令包提前结束
_mStateBitINT = 0x00000400
IIC_SPEED_20 = 0
IIC_SPEED_100 = 1
IIC_SPEED_400 = 2
IIC_SPEED_750 = 3
def __init__(self):
self.deviceID = ctypes.c_uint32()
pass
def init(self):
if os.name == 'nt': # Windows 环境
libPath = os.path.join(os.path.dirname(__file__), 'lib/ch341/CH341DLLA64.DLL')
elif os.name == 'posix':
libPath = os.path.join(os.path.dirname(__file__), 'lib/ch341/libch347.so')
dllExist = os.path.exists(libPath)
if not dllExist:
print('未找到库文件:', libPath)
return False
else:
try:
if os.name == 'nt': # Windows 环境
self.ic = windll.LoadLibrary(libPath) # ch341接口
self.ch341GetInput = self.ic.CH341GetInput
self.ch341CloseDevice = self.ic.CH341CloseDevice
self.ch341WriteData = self.ic.CH341WriteData
self.ch341WriteRead = self.ic.CH341WriteRead
self.ch341SetOutput = self.ic.CH341SetOutput
self.ch341SetStream = self.ic.CH341SetStream
elif os.name == 'posix':
self.ic = cdll.LoadLibrary(libPath) # ch341接口
self.ch341GetInput = self.ic.CH34xGetInput
self.ch341CloseDevice = self.ic.CH34xCloseDevice
self.ch341WriteData = self.ic.CH34xWriteData
self.ch341WriteRead = self.ic.CH34xWriteRead
self.ch341SetOutput = self.ic.CH34xSetOutput
self.ch341SetStream = self.ic.CH34xSetStream
print("ch341加载成功")
return True
except Exception as e:
print("ch341加载失败")
return False
# 判断ch341是否插入
# return0未插入1插入
def open(self):
if os.name == 'nt': # Windows 环境
try:
self.fd = self.ic.CH341OpenDevice(0)
if self.fd == -1:
print("CH341 device open failed on Windows.")
return False
else:
self.fd = 0 #todo 改成扫描端口
print("CH341 device opened successfully on Windows.")
return True
except Exception as e:
print(f"Error occurred while opening CH341 device on Windows: {e}")
return False
elif os.name == 'posix': # Linux 环境
try:
devices = glob.glob('/dev/ch34x_pis*') # 动态查找设备
if devices:
device_path = devices[0].encode()
self.fd = self.ic.CH34xOpenDevice(device_path)
if self.fd == -1:
print("CH341 device open failed on Linux.")
return False
else:
print("CH341 device opened successfully on Linux.")
return True
else:
print("No CH341 device found on Linux.")
return False
except Exception as e:
print(f"Error occurred while opening CH341 device on Linux: {e}")
return False
else:
print("Unsupported operating system.")
return False
def disconnect(self):
self.ch341CloseDevice(self.fd)
def connectCheck(self):
if True == self.ch341GetInput(self.fd, ctypes.byref(self.deviceID)):
return True
else:
return False
# iic写数据
# addr:iic从机地址
# data要写的数据列表
# return写入长度不一定正确
def write(self, addr, data):
sLen = len(data)
tmpData = [] # 临时列表
tmpLen = sLen # 发送数据
pack = [] # 发送列表
cnt = 20 # 每包数量
packNum = sLen // cnt # 拆包数量
sLen %= cnt # 不足字节数
tmpData.extend(data)
pack.append(self._mCH341A_CMD_I2C_STREAM)
pack.append(self._mCH341A_CMD_I2C_STM_STA)
pack.append(self._mCH341A_CMD_I2C_STM_OUT | 1)
pack.append(addr << 1)
for i in range(0, packNum):
pack.append(self._mCH341A_CMD_I2C_STM_OUT | cnt)
pack.extend(tmpData[0:20])
del tmpData[0:20]
pack.append(self._mCH341A_CMD_I2C_STM_END)
sendBuf = (c_byte * len(pack))()
for j in range(0, len(pack)):
sendBuf[j] = pack[j]
sendLen = (c_byte * 1)()
sendLen[0] = len(pack)
if not self.ch341WriteData(self.fd, sendBuf, sendLen):
return 0
if sendLen == 0:
return 0
pack.clear()
pack.append(self._mCH341A_CMD_I2C_STREAM)
if sLen >= 1:
pack.append(self._mCH341A_CMD_I2C_STM_OUT | sLen)
pack.extend(tmpData[0:sLen])
pack.append(self._mCH341A_CMD_I2C_STM_STO)
pack.append(self._mCH341A_CMD_I2C_STM_END)
sendBuf = (c_byte * len(pack))()
for j in range(0, len(pack)):
sendBuf[j] = pack[j]
sendLen = (c_byte * 1)()
sendLen[0] = len(pack)
if not self.ch341WriteData(self.fd, sendBuf, sendLen):
return 0
if sendLen == 0:
return 0
return tmpLen
# iic读数据
# addriic从机地址
# data读取数据列表。根据列表大小确定读取长度
# return读取长度不一定正确
def read(self, addr, data):
if id(data) == 0 or len(data) == 0:
return 0
rLen = len(data)
#print(f"rLen={rLen}")
pack = []
readBuf = []
readLen = 0
packNum = rLen // 30
rLen %= 30
if rLen == 0:
rLen = 30
packNum -= 1
#print(f"packNum={packNum}")
pack.append(self._mCH341A_CMD_I2C_STREAM)
pack.append(self._mCH341A_CMD_I2C_STM_STA)
pack.append(self._mCH341A_CMD_I2C_STM_OUT | 1)
pack.append((addr << 1) | 0x01)
pack.append(self._mCH341A_CMD_I2C_STM_MS | 1)
for i in range(0, packNum):
pack.append(self._mCH341A_CMD_I2C_STM_IN | 30)
pack.append(self._mCH341A_CMD_I2C_STM_END)
sendBuf = (c_byte * len(pack))()
for j in range(0, len(pack)):
sendBuf[j] = pack[j]
recLen = (c_byte * 1)()
recBuf = (c_byte * self._mCH341A_CMD_I2C_STM_MAX)()
if not self.ch341WriteRead(self.fd, len(pack), sendBuf, self._mCH341A_CMD_I2C_STM_MAX, 1, recLen, recBuf):
return 0
if recLen == 0:
return 0
for j in range(0, recLen[0]):
readBuf.append(recBuf[j])
readLen += 30
pack.clear()
pack.append(self._mCH341A_CMD_I2C_STREAM)
if rLen > 1:
pack.append(self._mCH341A_CMD_I2C_STM_IN | (rLen - 1))
pack.append(self._mCH341A_CMD_I2C_STM_IN | 0)
pack.append(self._mCH341A_CMD_I2C_STM_STO)
pack.append(self._mCH341A_CMD_I2C_STM_END)
sendBuf = (c_byte * len(pack))()
for j in range(0, len(pack)):
sendBuf[j] = pack[j]
recLen = (c_byte * 1)()
recBuf = (c_byte * self._mCH341A_CMD_I2C_STM_MAX)()
if not self.ch341WriteRead(self.fd, len(pack), sendBuf, self._mCH341A_CMD_I2C_STM_MAX, 1, recLen, recBuf):
return 0
if recLen[0] == 0:
return 0
for j in range(0, recLen[0]):
readBuf.append(recBuf[j])
data.clear()
data.extend(readBuf)
readLen = len(pack)
#print(f"readLen={len(readBuf)}")
return readLen
# 设置int引脚状态
# lvl高低电平。1高电平0低电平
def set_int(self, lvl):
status = (c_long * 1)()
self.ic.CH341GetInput(0, status)
time.sleep(0.01)
if lvl:
self.ch341SetOutput(self.fd, 0x03, 0xFF00, status[0] | self._mStateBitINT)
else:
self.ch341SetOutput(self.fd, 0x03, 0xFF00, status[0] & (~self._mStateBitINT))
# 读取int引脚状态
# 返回:高低电平
def get_int(self):
status = (c_long * 1)()
self.ic.CH341GetInput(0, status)
return (status[0] & self._mStateBitINT) >> 10
# 设置IIC速度
# return0错误1成功
def set_speed(self, speed):
if speed != self.IIC_SPEED_20 and speed != self.IIC_SPEED_100 and speed != self.IIC_SPEED_400 and speed != self.IIC_SPEED_750:
return False
if False == self.ch341SetStream(self.fd, speed | 0):
print("speed err")
return False
else:
return True