HOME
  Security
   Software
    Hardware
  
FPGA
  CPU
   Android
    Raspberry Pi
  
nLite
  Xcode
   etc.
    ALL
  
LINK
BACK
 

2022/02/04

WCH CH341Aの I2C機能を Windowsの Visual Cで使い SSD1306 OLED モジュールを制御する方法 WCH CH341Aの I2C機能を Windowsの Visual Cで使い SSD1306 OLED モジュールを制御する方法

(How to Control SSD1306 OLED module I2C device on Windows using WCH CH341A)

Tags: [Windows], [無人インストール]




● WCH CH341Aの I2C機能を Windowsの Visual Cで使い SSD1306 OLEDを制御する方法

 How to Control SSD1306 OLED I2C device on Windows using WCH CH341A

 WCHの CH341Aを使った USBシリアル変換アダプタをパソコンの USBに接続する事で直接 I2Cのデバイスを制御できます。

 目的としては TFTのミニ液晶を繋げてパソコンの情報表示用のデバイスが作れるかな?と思い、先ずは I2C接続のモノクロの OLED液晶を制御してみて、目的のアプリが作れるかを検証してみます。

 先に結論:アニメーションや頻繁に書き換える用途には速度的に無理
 描画内容が波打つものの秒間 5画面程度の書き換え頻度なら大丈夫。

 なので、情報量が RGB+諧調でもっと多いカラー液晶の場合は絶望的。

 どれくらい描画が遅いかはこちらの動画で確認できます。
How to Control I2C device on Windows using WCH CH341A . SSD1306 OLED


今回購入


LMUWF電源タップCH341AプログラマーUSBからUARTIIC SPII2Cコンバーターパラレルポートコンバーター
ASIN: B09M3JPF65

Ren He CH341A プログラミング器 ROMライター FLASH 24 25 コピー器 EEPROMルーティングUSBプログラマ メインボード ルート
ASIN: B07LGNTJ29

VKLSVAN CH341Aライター SPI Flashプログラミング器 24 25シリーズ EEPROM BIOS プログラマー + SOP8 ICテストクリップ 8ピン
ASIN: B08HCJW1F5

Rasbee CH341A プログラミング器 FLASH 24 25 コピー器 EEPROMルーティング USBプログラマ メインボード 焼きます 並行輸入品
ASIN: B01FVUI3I4
※ ROMライターのアダプタの場合、I2C用として使用する場合は信号線 SCLと SDAを ICの足から配線する必要が有ります。(コネクタ等に信号線の配線が無い)


● WCH CH341Aを I2C機能で使う場合のジャンパピンの設定

 ・動作電圧 +3.3V
 ・I2C/SPIモード
 で使用します。

・WCH CH341Aを I2C機能で使う場合のジャンパピンの設定
WCH CH341Aを I2C機能で使う場合のジャンパピンの設定



・購入した CH341A USBモジュールの回路図(LC Technology公式資料より)
購入した CH341A USBモジュールの回路図(LC Technology公式資料より)




2022/02/04
パソコンから I2Cや SPIのデバイスを制御できる WCH CH341Aの USBシリアル変換アダプタを買ってみた
パソコンから I2Cや SPIのデバイスを制御できる WCH CH341Aの USBシリアル変換アダプタを買ってみた

  ラズパイ等を使わなくてもパソコンから直接 I2Cや SPIのデバイスを制御できます


●中華なシリアル変換アダプタの WCH CH340 CH341 南京沁恒微电子股份有限公司の Windows用デバイスドライバのダウンロード方法


2022/02/01
中華なシリアル変換アダプタの WCH CH340 CH341 CH9102の Windows用デバイスドライバのダウンロード方法
中華なシリアル変換アダプタの WCH CH340 CH341 CH9102の Windows用デバイスドライバのダウンロード方法

  How to Download WCH Qinheng China cheap USB serial bridge Windows Device Driver


● WCH CH341Aの I2C機能を Windowsの Visual Cで使い SSD1306 OLEDを制御する方法

 上記の記事を参考に CH341PAR.ZIPをダウンロードして、解凍します。

 デバイスドライバは WIN 1Xの物を使います。

 Visual C用のライブラリは LIB/Cの中にあります。

 CH341DLL.Hファイルの文字コードが中国語エンコード(GB18030)になっているので Unicodeに変換が必要です。

 アプリを作成する時に必要なライブラリファイル。
CH341DLL.H
CH341DLL.LIB

 作成したアプリを動かす時に必要な DLLファイル。
CH341DLL.DLL

 SSD1306 OLDの初期化部分は Adafruitと Waveshareの OLDモジュールの資料を使いました。
 (ソースリスト中でどちらか片方を使用します)

Monochrome 1.3" 128x64 OLED graphic display - STEMMA QT / Qwiic
Monochrome 1.3


Monochrome 1.3



128x32 General 0.91inch OLED display Module
128x32 General 0.91inch OLED display Module



 SSD1306の I2Cの SCLの動作周波数は Tcycleが min 2.5usなので最大 400kHzで駆動できます。
SSD1306の I2Cの SCLの動作周波数は Tcycleが min 2.5usなので最大 400kHzで駆動できます



// WCH CH341A I2C control sample program
#include <iostream>
#include <iomanip>
#include <Windows.h>
#include <tchar.h>
#include "CH341DLL.H"

#pragma comment(lib,"./CH341DLL.LIB")

#define SSD1306_I2C_ADDR 0x3C
#define SSD1306_COMMAND 0x00
#define SSD1306_DATA 0x40

#define SSD1306_WIDTH 128
#define SSD1306_HEIGHT 64

BOOL sendCommand(ULONG iIndex, UCHAR iDevice, UCHAR command) {
    // I2C Write
    UCHAR iAddr = SSD1306_COMMAND; // SSD1306 OLED Register Address
    UCHAR iByte = command; // SSD1306 OLED Write Data Byte

    BOOL b = CH341WriteI2C(iIndex, iDevice, iAddr, iByte); // Display OFF
    return b;
}

BOOL sendCommandArray(ULONG iIndex, UCHAR iDevice, UCHAR commandArray[], ULONG arraySize) {
    // I2C Write
    UCHAR iAddr = SSD1306_COMMAND; // SSD1306 OLED Register Address
    UCHAR iByte; // Write Data Byte
    BOOL b; // Result

    for (int i = 0; i < arraySize; ++i) {
        iByte = commandArray[i]; // SSD1306 OLED Write Data Byte
        b = CH341WriteI2C(iIndex, iDevice, iAddr, iByte); // SSD1306 OLED Write Command、
        if (!b) break;
    }
    return b;
}

BOOL sendDataBuffer(ULONG iIndex, UCHAR iDevice, ULONG iWriteLength, PVOID iWriteBuffer) {
    // I2C Transfer
    ULONG iTmpWriteLength = iWriteLength + 2;
    PUCHAR iTmpWriteBuffer = new UCHAR[iTmpWriteLength];

    memcpy(&iTmpWriteBuffer[2], iWriteBuffer, iWriteLength);
    iTmpWriteBuffer[0] = iDevice << 1; // SSD1306 I2C Address (But Need Shifted)
    iTmpWriteBuffer[1] = SSD1306_DATA; // SSD1306 OLED Write Data
    BOOL b = CH341StreamI2C(iIndex, iTmpWriteLength, iTmpWriteBuffer, 0UL, NULL);

    delete[] iTmpWriteBuffer;
    return b;
}

int main()
{
    // Device Index Number
    ULONG iIndex = 0;

    // Open Device
    HANDLE h = CH341OpenDevice(iIndex);

    // DLL verison
    ULONG dllVersion = CH341GetVersion();
    std::cout << "DLL verison " << dllVersion << "\n";

    // Driver version
    ULONG driverVersion = CH341GetDrvVersion();
    std::cout << "Driver verison " << driverVersion << std::endl;

    // Device Name
    PVOID p = CH341GetDeviceName(iIndex);
    std::cout << "Device Name " << (PCHAR)p << std::endl;

    // IC verison 0x10=CH341,0x20=CH341A,0x30=CH341A3
    ULONG icVersion = CH341GetVerIC(iIndex);
    std::cout << "IC version " << std::hex << icVersion << std::endl;

    // Reset Device
    BOOL b = CH341ResetDevice(iIndex);
    std::cout << "Reset Device " << b << std::endl;

    // Set serial stream mode
    // B1-B0: I2C SCL freq. 00=20KHz,01=100KHz,10=400KHz,11=750KHz
    // B2:    SPI I/O mode, 0=D3 CLK/D5 OUT/D7 IMP, 1=D3 CLK/D5&D4 OUT/D7&D6 INP)
    // B7:    SPI MSB/LSB, 0=LSB, 1=MSB
    // ULONG iMode = 0; // SCL = 10KHz
    // ULONG iMode = 1; // SCL = 100KHz
    ULONG iMode = 2; // SCL = 400KHz
    // ULONG iMode = 3; // SCL = 750KHz
    b = CH341SetStream(iIndex, iMode);
    std::cout << "Set Stream " << b << std::endl;

    // I2C Transfer
    UCHAR iDevice = 0x3C; // SSD1306 OLED I2C Address
    UCHAR iAddr; // SSD1306 OLED Register Address
    UCHAR iByte; // SSD1306 OLED Write Data Byte
    UCHAR oByte; // SSD1306 OLED Read Data Byte

    // Initialise SSD1306 OLED
    iAddr = 0x00; // SSD1306 OLED Write Command

    // Adafruit
    // 4.4 Actual Application Example
    // https://cdn-shop.adafruit.com/datasheets/UG-2864HSWEG01.pdf
    UCHAR initialization_command_array_adafruit[] = {
        0xAE, // Set Display Off
        0xD5, 0x80, // Set Display Clock Divide Ratio/Oscillator Frequency
        0xA8, SSD1306_HEIGHT - 1, // Set Multiplex Ratio
        0xD3, 0x00, // Set Display Offset
        0x40, // Set Display Start Line
        0x8D, 0x14, // Set Charge Pump, VCC Generated by Internal DC/DC Circuit
        0xA1, // Set Segment Re-Map
        0xC8, // Set COM Output Scan Direction
#if (SSD1306_HEIGHT == 32)
        0xDA, 0x02, // Set COM Pins Hardware Configuration
#else
        0xDA, 0x12, // Set COM Pins Hardware Configuration
#endif
        0x81, 0xCF, // * Set Contrast Control, VCC Generated by Internal DC/DC Circuit
        0xD9, 0xF1, // * Set Pre-Charge Period, VCC Generated by Internal DC/DC Circuit
        0xDB, 0x40, // Set VCOMH Deselect Level
        0xA4, // Set Entire Display On/Off
        0xA6, // Set Normal/Inverse Display
        // omit // Clear Screen
        0xAF, // Set Display On
    };

    // Waveshare
    // 3 Software Configuration
    // https://www.waveshare.com/w/upload/a/af/SSD1306-Revision_1.1.pdf
    UCHAR initialization_command_array_waveshare[] = {
        0xAE, // Set Display Off
        0xA8, SSD1306_HEIGHT - 1, // Set Multiplex Ratio
        0xD3, 0x00, // Set Display Offset
        0x40, // Set Display Start Line
        0xA1, // Set Segment Re-Map
        0xC8, // Set COM Output Scan Direction
#if (SSD1306_HEIGHT == 32)
        0xDA, 0x02, // Set COM Pins Hardware Configuration
#else
        0xDA, 0x12, // Set COM Pins Hardware Configuration
#endif
        0x81, 0x7F, // * Set Contrast Control
        // 0xD9, 0xF1, // * Set Pre-Charge Period, VCC Generated by Internal DC/DC Circuit
        // 0xDB, 0x40, // Set VCOMH Deselect Level
        0xA4, // Set Entire Display On/Off
        0xA6, // Set Normal/Inverse Display
        0xD5, 0x80, // Set Display Clock Divide Ratio/Oscillator Frequency
        0x8D, 0x14, // Set Charge Pump, VCC Generated by Internal DC/DC Circuit
        0xAF, // Set Display On
    };

    b = sendCommandArray(iIndex, iDevice, initialization_command_array_adafruit, sizeof(initialization_command_array_adafruit));
    // b = sendCommandArray(iIndex, iDevice, initialization_command_array_waveshare, sizeof(initialization_command_array_waveshare));

    for (UCHAR k = 0; k < 100; ++k) {
        for (UCHAR i = 0; i < SSD1306_HEIGHT / 8; ++i) {
            b = sendCommand(iIndex, iDevice, 0xB0 | i); // Set the current RAM page address.
            b = sendCommand(iIndex, iDevice, 0x00); //
            b = sendCommand(iIndex, iDevice, 0x10); //

            // Write Stream
            ULONG iWriteLength = SSD1306_WIDTH;
            UCHAR iWriteBuffer[SSD1306_WIDTH];
            for (UCHAR j = 0; j < SSD1306_WIDTH; ++j) {
                iWriteBuffer[j] = j + i + k;
            }
            b = sendDataBuffer(iIndex, iDevice, iWriteLength, iWriteBuffer);

            Sleep(1); // 1ms Need Waiting

            // ???
            // ULONG iDelay = 100UL;
            // b = CH341SetDelaymS(iIndex, iDelay);
        }
    }

    // Close Device
    CH341CloseDevice(iIndex);
}

WCH CH341Aの I2C機能を Windowsの Visual Cで使い SSD1306 OLEDを制御する方法
 SSD1306 128x64

WCH CH341Aの I2C機能を Windowsの Visual Cで使い SSD1306 OLEDを制御する方法
 SSD1306 128x32


● WCH CH341Aの I2C機能を Windowsの Visual Cで使い MPU-6050の 6軸加速度センサーを使う方法

 SSD1306 OLED モジュールを制御する前に、CH341Aの I2C制御のライブラリの練習として値の読み出しだけで動作確認ができる MPU-6050の 6軸加速度センサーのプログラムを作りました。

INT16 word2int16(UCHAR h, UCHAR l) {
    INT16 t = h << 8 | l;
    if (h & 0x80 != 0) t = -((65535 - t) + 1);
    return t;
}
    // I2C Transfer
    UCHAR iDevice = 0x68; // MPU-6050 I2C Address
    UCHAR iAddr; // MPU-6050 Register Address
    UCHAR iByte; // MPU-6050 Write Data Byte
    UCHAR oByte; // MPU-6050 Read Data Byte

    // Read
    iAddr = 0x75; // MPU-6050 Register Address WHO_AM_I
    b = CH341ReadI2C(iIndex, iDevice, iAddr, &oByte);
    std::cout << "Read " << b << " " << std::hex << (INT)oByte << std::endl;
    std::cout << std::dec;
    // Read Value Equals MPU-6050 I2C Address (0x68)

    // Read
    iAddr = 0x6B; // MPU-6050 Register Address PWR_MGMT_1
    b = CH341ReadI2C(iIndex, iDevice, iAddr, &oByte);
    std::cout << "Read " << b << " " << std::hex << (INT)oByte << std::endl;
    std::cout << std::dec;

    // Write
    iAddr = 0x6B; // MPU-6050 Register Address PWR_MGMT_1
    iByte = 0x00; // MPU-6050 Write Data 0x00 = Release SLEEP mode ( = Device to Active)
    b = CH341WriteI2C(iIndex, iDevice, iAddr, iByte);
    std::cout << "Write " << b << std::endl;

    // Read Write Stream
    ULONG iWriteLength;
    UCHAR iWriteBuffer[256];
    ULONG iReadLength;
    UCHAR oReadBuffer[256];

    iWriteLength = 2UL;
    iWriteBuffer[0] = iDevice << 1; // MPU-6050 I2C Address (But Need Shifted)
    iWriteBuffer[1] = 0x3B; // MPU-6050 Register Address ACCEL_XOUT_H (Start address of sensor data)
    iReadLength = 14UL; // 0x3B ACCEL_XOUT_H - 0x48 GYRO_ZOUT_L

    for (int i = 0; i < 100; ++i) {
        b = CH341StreamI2C(iIndex, iWriteLength, iWriteBuffer, iReadLength, oReadBuffer);
        std::cout << "Stream " << b << ",";
        if (true) {

            std::cout << std::hex;
            for (ULONG index = 0; index < iReadLength; ++index) {
                std::cout << " " << std::setw(2) << std::setfill('0') << (INT)oReadBuffer[index];
            }
            std::cout << std::dec;
        }
        else {

            // Accelerometer
            FLOAT ACCEL_DIV = 16384.0;
            FLOAT ACCEL_XOUT = word2int16(oReadBuffer[0], oReadBuffer[1]) / ACCEL_DIV;
            FLOAT ACCEL_YOUT = word2int16(oReadBuffer[2], oReadBuffer[3]) / ACCEL_DIV;
            FLOAT ACCEL_ZOUT = word2int16(oReadBuffer[4], oReadBuffer[5]) / ACCEL_DIV;

            // Temperature
            // Temperature in degrees C = (TEMP_OUT Register Value as a signed quantity)/340 + 36.53
            FLOAT TEMP_OUT = word2int16(oReadBuffer[6], oReadBuffer[7]) / 340.0 + 36.53;

            // Gyroscope
            FLOAT GYRO_DIV = 131.0;
            FLOAT GYRO_XOUT = word2int16(oReadBuffer[8], oReadBuffer[9]) / GYRO_DIV;
            FLOAT GYRO_YOUT = word2int16(oReadBuffer[10], oReadBuffer[11]) / GYRO_DIV;
            FLOAT GYRO_ZOUT = word2int16(oReadBuffer[12], oReadBuffer[13]) / GYRO_DIV;

            std::cout << std::fixed;
            std::cout << std::setprecision(3) << std::setw(7) << ACCEL_XOUT << ",";
            std::cout << std::setprecision(3) << std::setw(7) << ACCEL_YOUT << ",";
            std::cout << std::setprecision(3) << std::setw(7) << ACCEL_ZOUT << ",";
            std::cout << std::setprecision(3) << std::setw(9) << TEMP_OUT << ",";
            std::cout << std::setprecision(3) << std::setw(7) << GYRO_XOUT << ",";
            std::cout << std::setprecision(3) << std::setw(7) << GYRO_YOUT << ",";
            std::cout << std::setprecision(3) << std::setw(7) << GYRO_ZOUT;
        }
        std::cout << std::endl;

        Sleep(100);
    }

WCH CH341Aの I2C機能を Windowsの Visual Cで使い MPU-6050の 6軸加速度センサーを使う方法


WCH CH341Aの I2C機能を Windowsの Visual Cで使い MPU-6050の 6軸加速度センサーを使う方法


WCH CH341Aの I2C機能を Windowsの Visual Cで使い MPU-6050の 6軸加速度センサーを使う方法


WCH CH341Aの I2C機能を Windowsの Visual Cで使い MPU-6050の 6軸加速度センサーを使う方法


WCH CH341Aの I2C機能を Windowsの Visual Cで使い MPU-6050の 6軸加速度センサーを使う方法





Tags: [Windows], [無人インストール]

●関連するコンテンツ(この記事を読んだ人は、次の記事も読んでいます)

パソコンから I2Cや SPIのデバイスを制御できる WCH CH341Aの USBシリアル変換アダプタを買ってみた
パソコンから I2Cや SPIのデバイスを制御できる WCH CH341Aの USBシリアル変換アダプタを買ってみた

  ラズパイ等を使わなくてもパソコンから直接 I2Cや SPIのデバイスを制御できます

パソコンの BIOS焼きに失敗したので WCH CH341Aを使って BIOSを復活させるが ROMチップが 1.8Vだった件
パソコンの BIOS焼きに失敗したので WCH CH341Aを使って BIOSを復活させるが ROMチップが 1.8Vだった件

  WCH CH341A ROM Writerで 1.8V系の EEPROM MX25を使う方法、NXP ALVC164245、YF08E TXS0108E等

中華なシリアル変換アダプタの WCH CH340 CH341 CH9102の Windows用デバイスドライバのダウンロード方法
中華なシリアル変換アダプタの WCH CH340 CH341 CH9102の Windows用デバイスドライバのダウンロード方法

  How to Download WCH Qinheng China cheap USB serial bridge Windows Device Driver

Windows用 USB シリアル変換アダプタのメーカー別デバイスドライバの一覧、USB UART
Windows用 USB シリアル変換アダプタのメーカー別デバイスドライバの一覧、USB UART

  Windows VCP Device Driverのリンク FTDI、CP210x、Prolific PL2303、STM32 VCP、WCH CH340等

Raspberry Piの I2C機能を有効化する方法、最新の Raspbian Stretch対応 2018年版
Raspberry Piの I2C機能を有効化する方法、最新の Raspbian Stretch対応 2018年版

  ラズパイの I2C機能を有効にして各種センサーを繋げる方法まとめ

Raspberry Pi 3で 標準とは別の GPIO端子の I2C機能を有効化する方法(I2C-3編)
Raspberry Pi 3で 標準とは別の GPIO端子の I2C機能を有効化する方法(I2C-3編)

  ラズパイ3の GPIO23と GPIO24で I2C機能を有効にする方法まとめ

Lenovo ThinkCentre M75s Small Gen2の BIOSアップデートに失敗したので CH341Aで BIOSを根性焼きして復活させる方法
Lenovo ThinkCentre M75s Small Gen2の BIOSアップデートに失敗したので CH341Aで BIOSを根性焼きして復活させる方法

  Lenovo ThinkCentre M75s Small Gen2 Recovery BIOS with CH341A SPI EEPROM BIOS Programmer

HDMIの仮想ディスプレイアダプタを改造して自分好みの解像度の EDIDエミュレータを作成する方法
HDMIの仮想ディスプレイアダプタを改造して自分好みの解像度の EDIDエミュレータを作成する方法

  HDMIダミーアダプタ内の I2Cメモリの EDID情報を書き換えて好きな解像度に改造する方法




[HOME] | [BACK]
リンクフリー(連絡不要、ただしトップページ以外は Web構成の変更で移動する場合があります)
Copyright (c) 2022 FREE WING,Y.Sakamoto
Powered by 猫屋敷工房 & HTML Generator

http://www.neko.ne.jp/~freewing/software/wch_ch341a_i2c_control_windows_visual_c/