Re: Программатор CH341T как I2C адаптер
Добавлено: Сб фев 08, 2025 22:42:47
Serjone, поддерживает.
Еще есть 10-битная адресация.
Еще есть 10-битная адресация.
Здесь можно немножко помяукать :)
https://radiokot.ru/forum/

Код: Выделить всё
#define MCPR_IODIR_A 0x00 // Для блока A | Настраивает работу портов на (1 вход, 0 выход) (соотношение бита к порту 0b00000000 - pa7 pa6 pa5 pa4 pa3 pa2 pa1 pa0)
#define MCPR_IODIR_B 0x01 // Для блока B |
#define MCPR_IPOL_A 0x02 // Для блока A | Задает для инпутных портов инверсию получаемого значения
#define MCPR_IPOL_B 0x03 // Для блока B |
#define MCPR_GPINTEN_A 0x04 // Для блока A | Опредетяет разрешена ли работа портов в качестве источника прерывания
#define MCPR_GPINTEN_B 0x05 // Для блока B |
#define MCPR_DEFVAL_A 0x06 // Для блока A | Хранит бит для каждого порта и если значение на порту не равно этому биту, то генерит прерывание (если разрешено регистром GPINTEN)
#define MCPR_DEFVAL_B 0x07 // Для блока B |
#define MCPR_INTCON_A 0x08 // Для блока A | Если 1чка для порта - то прерывания будут при любой смене состояния порта
#define MCPR_INTCON_B 0x09 // Для блока B |
#define MCPR_IOCON 0x0A // Управление всем устройством, каждый бит настройка (слева направо идут 0b00100000):
// BANK = 0 : если 0, то регистры идут как тут поочередно. Если 1, то сначала все регистры для порта A, после все для B
// MIRROR = 0 : если 0, то порт А и В генерит прерывания на свои ножки, если 1, то сразу на ножки прерываний обеих портов
// SEQOP = 1 : если 1, то адрес инкрементируется (можно слать последовательно данные и следующая порция попадет в следующий регистр)
// DISSLW = 0 : можно включать(0) и отключать (1) ножку SDA в i2c выходе
// HAEN = 0 : пины адреса всегда включены в микросхеме MCP23017 (этот бит не влияет)
// ODR = 0 : делает выходы открытый коллектор (1) или обычные цифровые (0)
// INTPOL = 0 : значение выхода на пинах прерывания: 1 - при активном hight, 0 - при активном будет low
// последний бит зарезервирован
#define MCPR_GPPU_A 0x0C // Для блока A | Определяет будет ли подтяжка input портов (если 1, то подтяжка 100кОм на +)
#define MCPR_GPPU_B 0x0D // Для блока B |
#define MCPR_INTF_A 0x0E // Для блока A | Только для чтения. Определяет на какой из ножек было прерывание (там будет 1)
#define MCPR_INTF_B 0x0F // Для блока B |
#define MCPR_INTCAP_A 0x10 // Для блока A | Напряжение на всех портах в момент события прерывания
#define MCPR_INTCAP_B 0x11 // Для блока B |
#define MCPR_GPIO_A 0x12 // Для блока A | Текущие значения портов input (чтение считывает порт, запись модифицирует OLAT регистр)
#define MCPR_GPIO_B 0x13 // Для блока B |
#define MCPR_OLAT_A 0x14 // Для блока A | Доопределяет output ножки (чтение его читает буфер, а не порт, запись модифицирует выходной буфер, который изменит выходные порты)
#define MCPR_OLAT_B 0x15 // Для блока B |Код: Выделить всё
#include <windows.h>
#include <iostream>
// Загрузка функций из CH341DLL.dll
typedef BOOL(__stdcall* CH341OpenDevice_t)(ULONG iIndex);
typedef BOOL(__stdcall* CH341CloseDevice_t)(ULONG iIndex);
typedef BOOL(__stdcall* CH341StreamI2C_t)(ULONG iIndex, ULONG iWriteLength, PUCHAR iWriteBuffer, ULONG iReadLength, PUCHAR oReadBuffer);
int main() {
// Загрузка DLL
HMODULE hDLL = LoadLibrary("CH341DLL.dll");
if (!hDLL) {
std::cerr << "Failed to load CH341DLL.dll. Install the driver for CH341T" << std::endl;
std::cin.get();
return -1;
}
// Получение указателей на функции
CH341OpenDevice_t CH341OpenDevice = (CH341OpenDevice_t)GetProcAddress(hDLL, "CH341OpenDevice");
CH341CloseDevice_t CH341CloseDevice = (CH341CloseDevice_t)GetProcAddress(hDLL, "CH341CloseDevice");
CH341StreamI2C_t CH341StreamI2C = (CH341StreamI2C_t)GetProcAddress(hDLL, "CH341StreamI2C");
if (!CH341OpenDevice || !CH341CloseDevice || !CH341StreamI2C) {
std::cerr << "Failed to get function pointers from CH341DLL.dll" << std::endl;
FreeLibrary(hDLL);
std::cin.get();
return -1;
}
// Открытие устройства CH341A (индекс 0)
ULONG deviceIndex = 0;
if (!CH341OpenDevice(deviceIndex)) {
std::cerr << "Failed to open CH341A device" << std::endl;
FreeLibrary(hDLL);
std::cin.get();
return -1;
}
// Адрес I2C устройства
const UCHAR i2cAddress = 0x20;
// Последовательность команд
UCHAR commands[4][2] = {
{ 0x0A, 0x20 },
{ 0x00, 0x00 },
{ 0x12, 0x00 },
{ 0x12, 0xFF }
};
// Буфер для данных
UCHAR writeBuffer[3]; // 1 байт для адреса + 2 байта данных
UCHAR readBuffer[1]; // Не используется в данном случае
for (int i = 0; i < 2; ++i) {
// Подготовка буфера для записи
writeBuffer[0] = i2cAddress << 1; // Адрес устройства (сдвинутый влево для I2C)
writeBuffer[1] = commands[i][0];
writeBuffer[2] = commands[i][1];
// Отправка команды через I2C
if (!CH341StreamI2C(deviceIndex, 3, writeBuffer, 0, readBuffer)) {
std::cerr << "Failed to send I2C command " << i + 1 << std::endl;
CH341CloseDevice(deviceIndex);
FreeLibrary(hDLL);
std::cin.get();
return -1;
}
}
// Мигалка
int i = 2;
while (true) {
writeBuffer[0] = i2cAddress << 1;
writeBuffer[1] = commands[i][0];
writeBuffer[2] = commands[i][1];
if (!CH341StreamI2C(deviceIndex, 3, writeBuffer, 0, readBuffer)) {
std::cerr << "Failed to send I2C command " << i + 1 << std::endl;
CH341CloseDevice(deviceIndex);
FreeLibrary(hDLL);
std::cin.get();
return -1;
}
Sleep(500);
i++;
if (i > 3) i = 2;
}
std::cout << "Commands sent successfully!" << std::endl;
// Закрытие устройства
CH341CloseDevice(deviceIndex);
// Освобождение DLL
FreeLibrary(hDLL);
std::cin.get();
return 0;
}