2021年10月15日金曜日

VC++ デバイス情報の取得

 現在、Yolo(darknet)による画像(物体)認識にトライしています。

ようやく、USBカメラ映像に対する処理プログラムの切り出しに目途が立ったところです。

そこで、プログラム内部で、PCに接続したカメラを特定し、そのカメラ映像を処理するようにしたいと思ったのですが、私にとって結構な難題であったので、以下にその手法について述べます。


デバイスリスト表示プログラムの作成

◎プロジェクトプロパティの設定

              C/C++/プリプロセッサ        INITGUID
              C/C++/詳細設定/「指定の警告を無効にする。」 4996
              〇リンカー/入力              setupapi.lib        

 ◎コーディング

           〇インクルードファイル指定 setupapi.h、devguid.h 、devpkey.h

           〇使用関数  SetupDiGetClassDevs、SetupDiEnumDeviceInfo、SetupDiGetDeviceProperty

◎デバイス情報の取得 

    〇クラスGUID は devguid.h で定義されています。

    〇要求する情報の種別は devpkey.h で定義で定義されています。


    〇プログラムソース

   以下はデバイス情報取得用のテストコードです。

/******************************************/

#include <iostream>

#include <windows.h>

#include <setupapi.h>

#include <devguid.h>

#include <devpkey.h>


void TransBuff(BYTE* buff);


int main()

{

    std::cout << "Hello World!\n";

    HDEVINFO hDevInfo;


    if (false) {

        //全デバイス

        hDevInfo = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);

    }

    else {

        //カメラ限定

        hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_CAMERA, NULL, NULL, DIGCF_PRESENT);

    }

    DWORD index = 0;

    SP_DEVINFO_DATA DeviceInfoData = { 0 };

    DeviceInfoData.cbSize = sizeof(DeviceInfoData);


    BYTE Buffer[4096];

    // Get device info data

    while (SetupDiEnumDeviceInfo(hDevInfo, index, &DeviceInfoData)) {

        DEVPROPTYPE PropType;

        if (true) {

            SetupDiGetDeviceProperty(

                hDevInfo,

                &DeviceInfoData,

                &DEVPKEY_Device_FriendlyName,       // プリプロセッサ INITGUID が必要

                &PropType,

                Buffer,

                sizeof(Buffer),

                NULL,

                0);

        }

        else {

            // DEVPKEY_Device_HardwareIds


            SetupDiGetDeviceProperty(

                hDevInfo,

                &DeviceInfoData,

                &DEVPKEY_Device_HardwareIds,       // プリプロセッサ INITGUID が必要

                &PropType,

                Buffer,

                sizeof(Buffer),

                NULL,

                0);

        }

         if (DeviceInfoData.ClassGuid.Data1 == (GUID_DEVCLASS_CAMERA).Data1) {

            std::cout << "Found Cammera ";


            if (PropType == DEVPROP_TYPE_STRING || PropType ==(MAX_DEVPROP_TYPEMOD| DEVPROP_TYPE_STRING)) {

                TransBuff(Buffer);

                std::cout << Buffer;

            }

            std::cout << "\n";

        }

        else if (DeviceInfoData.ClassGuid.Data1 == (GUID_DEVCLASS_DISPLAY).Data1) {

            std::cout << "Found Display ";


            if (PropType == DEVPROP_TYPE_STRING || PropType == (MAX_DEVPROP_TYPEMOD | DEVPROP_TYPE_STRING)) {

                TransBuff(Buffer);

                std::cout << Buffer;

            }

            std::cout << "\n";

        }

        else if (DeviceInfoData.ClassGuid.Data1 == (GUID_DEVCLASS_MOUSE).Data1) {

            std::cout << "Found Mouse ";


            if (PropType == DEVPROP_TYPE_STRING || PropType == (MAX_DEVPROP_TYPEMOD | DEVPROP_TYPE_STRING)) {

                TransBuff(Buffer);

                std::cout << Buffer;

                std::cout << "\n";

            }

        }

        index++;

   }

    SetupDiDestroyDeviceInfoList(hDevInfo);

}


void TransBuff(BYTE* buff) {

    int ip = 0;

    int ip2 = 0;

    for (int i = 0;; i++) {

        ip = i;

        ip2 = i * 2;

        buff[ip] = buff[ip2];

        if (buff[ip2] == 0x00) {

            break;

        }

    }

    return;

}

/*****************end code**********************/

◎実行結果

        〇カメラのデバイス情報 

ノートPC内臓カメラ
















USBカメラ










        〇テストプログラム実行結果
デバイス名表示











デバイスID表示














2021年10月1日金曜日

Yolo(darknet)画像検出をUSBカメラに特化したプログラムに改造

darknet本体プログラムは、画像(物体)検出、機械学習、、多機能な巨大プログラムで プログラムソースは難解そのものです。(私にとっては) そこで、USBカメラによる画像入力/画像検出のみに機能を限定したプログラムに改造することで、このプログラムの部分的な解析を行いました。
  
USBカメラでTV画面を撮影
取込み画像から物体検出


















1.プログラムの改造
  1)VisualStudio darknetソリューションのdarknetプロジェクトでの作業
    ・OpenCvのクラス、関数を直接 使用する
メインのプログラムソース darknet.c のファイル名を  AiDetect_Main.cpp (適宜)に変更 (darknet.hもdarknet.hppに変更  各ソースのヘッダー指定(#include)も変更)

            ・動画の画像検出を 画像(静止画)の画像検出のループ処理 に置き換える。
 関数 test_detector() [detector.c] の内容を AiDetect_Main.cpp に展開

プログラムソース AiDetect_Main.cpp
************************************************
#include <iostream>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>

#include <opencv2/opencv.hpp>
#include <opencv2/core/types.hpp>
#include <opencv2/videoio/videoio.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/highgui.hpp>

#include "darknet.h"

#include "list.h"
#include "parser.h"
#include "option_list.h"

#define CAM_FRAME_WIDTH 1920
#define CAM_FRAME_HEIGHT 1080

cv::VideoCapture* cap = NULL;
image mat_to_image(cv::Mat mat);
int main(int argc, char **argv)
{
#ifdef _DEBUG
    printf(" _DEBUG is used \n");
#endif

#ifdef DEBUG
    printf(" DEBUG=1 \n");
#endif

int i;
for (i = 0; i < argc; ++i) {
if (!argv[i]) continue;
strip_args(argv[i]);
}

    if(argc < 2){
        fprintf(stderr, "usage: %s <function>\n", argv[0]);
        return 0;
    }
    gpu_index = find_int_arg(argc, argv, "-i", 0);
    if(find_arg(argc, argv, "-nogpu")) {
        gpu_index = -1;
        printf("\n Currently Darknet doesn't support -nogpu flag. If you want to use CPU - please compile Darknet with GPU=0 in the Makefile, or compile darknet_no_gpu.sln on Windows.\n");
        exit(-1);
    }
    if (gpu_index >= 0) {
        cuda_set_device(gpu_index);
    }

    show_cuda_cudnn_info();

    show_opencv_info();


    int letter_box = 0;
    float thresh =0.25;    // 0.24
    float hier_thresh = 0.5;
  
    int* gpus = 0;
    int gpu = 0;
    int ngpus = 0;

    gpu = gpu_index;
    gpus = &gpu;
    ngpus = 1;


    char* datacfg = "cfg/coco.data";
    char* cfg = "cfg/yolov3.cfg";
    char* weights = "yolov3.weights";
  
    char* filename = 0;

    list* options = read_data_cfg(datacfg);
    char* name_list = option_find_str(options, "names", "data/names.list");
    int names_size = 0;
    char** names = get_labels_custom(name_list, &names_size); //get_labels(name_list);

    image** alphabet = load_alphabet();
    network net = parse_network_cfg_custom(cfg, 1, 1); // set batch=1
    if (weights) {
        load_weights(&net, weights);
    }
    if (net.letter_box) letter_box = 1;
    net.benchmark_layers = 0;
    fuse_conv_batchnorm(net);
    calculate_binary_weights(net);
    if (net.layers[net.n - 1].classes != names_size) {
        printf("\n Error: in the file %s number of names %d that isn't equal to classes=%d in the file %s \n",
            name_list, names_size, net.layers[net.n - 1].classes, cfg);
        if (net.layers[net.n - 1].classes > names_size) getchar();
    }
    srand(2222222);
    char buff[256];
    char* json_buf = NULL;
    int json_image_id = 0;
    FILE* json_file = NULL;

    int j;
    float nms = .45;    // 0.4F

    int index = 1;

    try {
        cap = new cv::VideoCapture(index);
        cap->set(cv::CAP_PROP_FRAME_WIDTH, CAM_FRAME_WIDTH);
        cap->set(cv::CAP_PROP_FRAME_HEIGHT, CAM_FRAME_HEIGHT);

        
    }
    catch (...) {
        std::cerr << " OpenCV exception: Web-camera " << index << " can't be opened! \n";
    }

    cv::Mat frame;


    const std::string windowNamePrediction = "predictions";

    cv::namedWindow(windowNamePrediction, cv::WINDOW_GUI_NORMAL | cv::WINDOW_GUI_NORMAL);
    cv::resizeWindow(windowNamePrediction, 960, 540);
    cv::moveWindow(windowNamePrediction,20,20);

    while (1) {

        //画像取得

        cap->read(frame);

        image im = mat_to_image_cv((mat_cv*)&frame);


        image sized;

        sized = resize_image(im, net.w, net.h);

        layer l = net.layers[net.n - 1];
        int k;


        for (k = 0; k < net.n; ++k) {
            layer lk = net.layers[k];
            if (lk.type == YOLO || lk.type == GAUSSIAN_YOLO || lk.type == REGION) {
                l = lk;
                printf(" Detection layer: %d - type = %d \n", k, l.type);
            }
        }


        float* X = sized.data;

        double time = get_time_point();
        // 画像認識
        network_predict(net, X);

        printf("Predicted in %lf milli-seconds.\n",  ((double)get_time_point() - time) / 1000);

        int nboxes = 0;
        detection* dets = get_network_boxes(&net, im.w, im.h, thresh, hier_thresh, 0, 1, &nboxes, letter_box);
        if (nms) {
            if (l.nms_kind == DEFAULT_NMS) do_nms_sort(dets, nboxes, l.classes, nms);
            else diounms_sort(dets, nboxes, l.classes, nms, l.nms_kind, l.beta_nms);
        }


        //draw_detections_v3(im, dets, nboxes, thresh, names, alphabet, l.classes, ext_output);

        //show_image(im, "predictions2");

        //draw_detection_v3 および show_imageを以下に展開

        int ditectNo = 0;

        std::list<detection> lstDetct =  std::list<detection>();


        lstDetct.clear();


        // 最も物体認識の確度が高いものを選択
        // 確度が閾値未満のものを除外
        for (i = 0; i < nboxes; ++i) {
            int best_class = -1;
            float best_class_prob = thresh;
            int j;
            for (j = 0; j < dets[i].classes; ++j) {
                int show = strncmp(names[j], "dont_show", 9);
                if (dets[i].prob[j] > best_class_prob ) {
                    best_class = j;
                    best_class_prob = dets[i].prob[j];
                }
            }


            if (best_class >= 0) {
                dets[i].best_class_idx = best_class;
                lstDetct.push_back(dets[i]);
               ++ditectNo;
            }
        }


        auto itrBox = lstDetct.begin();


        ///*  */
        for(int ib = 0 ; ib < ditectNo; ib++)
        {
            int idxBox = (&itrBox._Ptr->_Myval)->best_class_idx;
            int clsBox = (&itrBox._Ptr->_Myval)->classes;

            // 描画 BOX
            box b;
            b.x = (&itrBox._Ptr->_Myval)->bbox.x;
            b.y = (&itrBox._Ptr->_Myval)->bbox.y;
            b.h = (&itrBox._Ptr->_Myval)->bbox.h;
            b.w = (&itrBox._Ptr->_Myval)->bbox.w;
            std::string strlbl = names[idxBox];

            // 物体認識 確度
            float prob = (&itrBox._Ptr->_Myval)->prob[idxBox];


            // 描画 色 設定
            int offset = idxBox * 123457 % clsBox;
            float red = get_color(2, offset, clsBox);
            float green = get_color(1, offset, clsBox);
            float blue = get_color(0, offset, clsBox);
            

            cv::Scalar boxColor = cv::Scalar((int)(red*255),(int)(green*255),(int)(blue*255));

            if(ib < ditectNo -1)itrBox = itrBox.operator++();


            int left = (b.x - b.w / 2.) * im.w;
            int right = (b.x + b.w / 2.) * im.w;
            int top = (b.y - b.h / 2.) * im.h;
            int bot = (b.y + b.h / 2.) * im.h;

            if (left < 0) left = 0;
            if (right > im.w - 1) right = im.w - 1;
            if (top < 0) top = 0;
            if (bot > im.h - 1) bot = im.h - 1;




            cv::rectangle(frame, cv::Rect(left, top, right - left, bot - top), boxColor);

            cv::putText(frame, strlbl, cv::Point(left, top), 1, 1.5, boxColor,2);

            printf("%s left:%d right:%d top:%d bot:%d prob:%g \n",strlbl.c_str(),left,right,top,bot,prob);




        }

       

        

        cv::imshow(windowNamePrediction, frame);


        free_detections(dets, nboxes);
        free_image(im);
        free_image(sized);

        int key = cv::waitKey(1);
        if (key == 27/*ESC*/) break;
    }

    if (json_file) {
        char* tmp = "\n]";
        fwrite(tmp, sizeof(char), strlen(tmp), json_file);
        fclose(json_file);
    }

    cap->release();

    // free memory
    free_ptrs((void**)names, net.layers[net.n - 1].classes);
    free_list_contents_kvp(options);
    free_list(options);


    const int nsize = 8;
    for (j = 0; j < nsize; ++j) {
        for (i = 32; i < 127; ++i) {
            free_image(alphabet[j][i]);
        }
        free(alphabet[j]);
    }
    free(alphabet);

    free_network(net);





    if (gpus && ngpus > 1) free(gpus);


    return 0;
}

************************************************
コマンド引数 detect teset cfg/coco.data cfg/yolov3.cfg yolov3.weights
このプログラムでは detect,testは無意味

cfg/yolov3.cfg yolov3.weightsはYolo4でも使えそう。
************************************************

2.プログラムdarknetの解析
    1)画像認識(物体認識)の結果について。
   認識結果は、get_network_boxes()で物体の囲むBOXと cfg/coco.data data/coco.names で指定された認識可能な種別(class)ごとの認識確度が出力される。
従って、認識確度が最も高い種別が認識された画像(物体)の種別と判定される。

             
  

2021年9月26日日曜日

迷いに迷って DELL G15 5511を購入(Yolo darknetで)

  AIによる画像認識用にDELL G15を購入しました。

Windows10のセットアップからYoLo/darknetのインストール、画像認識の実行までを記します。

0.電源ON

DELL G15キーボード
  ・一瞬 「電源スイッチが 無い!」 と 思いきや、 キーボードの右奥端のキーに電源マーク 、1度そのキーを押してみる。 起動せず、 もう1度押してみる まだ起動せず。 しばらく置いて 数度 押す。するとようやく 画面にDELLのマークの表示。 ようやくセットアップ開始。

==> ノートPCを開くことがSW ON せっかちに電源キーを押したため 電源ON/OFF が意図せずに繰り返しため電源ONにてこずったようです。


1.Window10のセットアップ

  ・ローカルアカウントでセットアップできない! 昨年末 職場でLENOVOの3台のPCをローカルアカウントでセットアップしたのですが、今それが出来ない。一旦マイクロソフトアカウントでセットアップしてからローカルアカウントを作成。 最近のWindows10のアップデートでそうなったのか? DELL固有の話なのか分からない。


2.YoLo/darknetのインストール

    1)ツールのインストール

        ・VisualStudio Communication 2019 のインストール。

        ・CMake 3.21.2 のインストール

            VisualStudioのソリューション/プロジェクトの生成を行います。

            (数多くのパス設定、プリプロセッサ、etc.を行ってくれます。)

        ・Nvidia CUDA11.4.2ToolKit及びCUDNN

     ToolKitのインストール後 CUDNNのダウンロードファイル(cudnn-11.4-windows-x64**.zip)を解凍しbin等のフォルダをCUDA ToolKitのフォルダと統合する。

 2)OpenCVのインストール

   これが一番面倒 

        ・OpenCVをダウロード後 opencv-4.5.3-vc14-vc15.exe を実行(解凍)                 ・CMakeで CUDAを組み込むためのオプションを設定し、Generateを行う。

        ・CMakeで生成されたOpenCVのプロジェクトのビルドを行う。

    3darknetのインストール

   ・GitHubからdarknet をダウンロードする。取得したdarknet-master.zipを解凍する。

        ・CMakeでOpenCVを組み込むためのオプションを設定しGenerateを行う。

        ・CMakeで生成されたdarknetのプロジェクトビルドを行う。

3.YoLo/darknetの実行

darknetをDynabook及びDell G15で稼働
・次のコマンドラインで実行
darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights data/Car.mp4

 Car.mp4はフリー動画をダウンロード






        ・実行結果

        GPU非搭載のDynabookに比べ G15は 画像認識において70~80倍のパフォーマンスを示しました。

Dynabook AVG_FPS は 0.4fps
DELL G15 AGV_FPS は 31.6fps

(上の動画のAVG_FPSは OBS Studio を動画作成に使用したため3割程度低めの値を表示しています。)




2021年7月4日日曜日

妄想鉄道の夜 第1夜 Nゲージ+Arduino

 Arduino(ATMEGA328P)をNゲージに載せてみました。


 電子工作を始めたころから、鉄道模型にマイコン制御を組み込みたいと思っていました。
とりあえず、20年前に購入したNゲージを引っ張り出してSLの走行をためしました。
 最初、レールからの給電がうまくいかず。レールみがきから始めました。

それから3か月ようやくマイコン搭載の車両の走行が実現出来ました。
 

 概要

 Nゲージ車両にはマイコンATMEGA328Pを搭載、コントローラからIRによる指令を受信し、モータードライバを介して、モータを制御し、前進、停止、後退、速度調整を行います。











車両搭載/コントローラ マイコンの選定

 搭載マイコンは Texas InstrumentsのMSP430、Microchip Technology ATMEGA 考えています。 搭載スペースでは MSP430 開発の手軽さでは ATMEGA。とりあえず ATMEAG328Pを選択しました。

 コントローラ用のマイコンも開発の手軽さでArduino Nanoを選択。

Nゲージ車両






※モータドライバ、ATMEAG328P、2200uFコンデンサーの配置がポイント、配置を間違えると、発車、停止、前進後進切替え時にマイコンが暴走、制御不能に、









Nゲージコントローラ

 ※意外と、電動ポイントの駆動に電流が必要なことが判明、1000uF~4700uFのコンデンサに電荷をため込み、一気に放電させることでなんとか 電動ポイントの駆動に成功。
 極性(+/―)の反転用にモータドライバを使用。
 (コンデンサー/モータードライバ間に抵抗を配置して、過電流の防止を試みたが失敗、いろいろやって 2200uF のコンデンサを採用しました。)











マイコンのプログラミング 開発環境

 開発環境はArduinoIDEを使用します。




Arduino IDE は setup()関数で初期処理、Loop()関数で処理の本体を C言語で記述します。








ボードマネージャで 車両搭載マイコン ATMEAG328Pの場合Arduino Unoを選択、コントローラ用のマイコンの場合 Arduino Nano を選択して プログラミングを行います。 
(ターゲット毎に切替えるのは結構面倒)

ATMEAG328Pのプログラミングについて




ATMEAG328Pのプログラミングは、Aruduino UNO R3 自体に 取り外し可能な ATMEAG328P が搭載されているので Arduino Unoとしてプログラミングして、プログラムの書き込み後、UNOから取り外し、Nゲージ車両に搭載します。



 
※ Arduino IDEでのプログラミングで ピン「D9」 を使った場合 ATMEAG328Pでは  PB1 15ピンを使うことになる。





マイコンのプログラミング 実装

 今回のプログラミングの中心は 赤外線通信です。参考のプログラムコードはArduino IDEのスケッチ例から取得しました。

 IR通信 送信側(Nゲージコントローラ側)



Nゲージコントローラ側のプログラミングはスケッチ例/IRemote/IRsendRawDemoを参考にしました。

(※IrSender.sendRaw_P()を使用)

 IR通信 受信側(Nゲージ車両側)

【きむ茶工房ガレージハウス】 ◆ 赤外線リモコンを送信器にして何か動かす記事さんのコードを拝借
  赤外線リモコン受信モジュールの信号の Hi/Low の 間隔を測り 受信データをビットパターンで取得する。


 







2019年11月1日金曜日

LED8x8x8 デモ展示



1. 500個のLED
 今年の4月大阪 日本橋の電子パーツ屋のレジ横に、LEDキューブ(5✖5✖5)の展示が目につきました。ロジックIC等の会計をしている間、青く光る125個のLEDが綺麗に点滅しているのに目を奪われました。過去にCEATEC等の電子デバイスの展示会等で何回も目にしていたとは思うのですが、その時はあまり興味がわきませんでした。なぜかレジ横のLEDキューブが目に付いたのでした。会計を済ませ、店を出る間際、特売ワゴンの中に500個千円の赤LEDを発見、咄嗟にLED8X8X8が作れるかもと思い、それを手にとりレジに逆戻り。

2. 256個のロジックICの妄想
 帰りの電車の中、さてLEDキューブどうやって組み上げるかいろいろ考え、、ほぼ妄想レベル。。。 マイコンとのインターフェイスは XYZの3次元指定とし、8ピン×3 + GND で 25ピン。 LEDのON/OFFはANDのロジックICを2段で、、、と思いつきのままあれやこれやと考え、最終的には、ロジックIC幾つ使うのか、ANDのロジックICは4回路入りなので256個必要になると思い至り、こりゃ無理、絶対無理。帰宅早々 500個のLEDは、ストックBOXに。

3.トラ技5月号 PSoc付録基板 その2
74HC595によるシリアル/パラレルの信号変換の検証に、お題は8✖8のLEDの表示をマイコンの4ピン(SI✖2、RCK、SCK)で実現させること。マイコンは、直近で扱っていたトラ技のPSoc基板を使い。LED8x8は自作(市販で300円程度で買えるのですが、あいにく手元に無かったので)
 まず表示を 行(ROW)/列(COL) 指定で1つのLEDを点灯、これを64回繰り返して1面の表示を考えたが、輝度は1/64で暗く、かなりちらつくと予想されるのでNG、次に列(COL)ごとに8つのLEDを点灯、8列分繰り返しての表示を行うことにしました。
PSocで1列毎の表示データ(8ビット)を1面分8列、これを8面分持たせ8X8の8コマの動画の表示を行いました。






4.LED8x8x8
 さて、LED8x8の表示を実現すると、このLED8x8を8枚重ねれば、諦めていたLEDキューブ(8x8x8)ができると思い。ストックBOXから、半年ぶりに500個のLEDを取り出し、(不足分12は別の赤LED)8枚のLED8x8をはんだ付けで作成これを積み重ねてLEDキューブらしきものが出来上がりました。
 原理は、LED8x8の アノード(+)側 8ビットを64ビットにし LED64✖8 マイコン側のプログラムを 8ビットデータを64ビットに拡張しただけ、原理的には LED8x8とほぼ同じ思考で組み上げました。
 ただ、512個のLED、9個の74HC595、2個の74HC126(カソード側(-)反転用)
と配線のはんだ付けが大変でした。

2019年6月14日金曜日

トラ技PSoc基板をためしました。

トランジスタ技術5月号付録のPSoc基板を入手、この2か月あれやこれやといじっています。今回74HC595によるシリアル/パラレル変換をテストしました。

1.LCDディスプレイ表示
キャラクタLCDディスプレイ(SC1602)表示

キャラクタLCDディスプレイの表示にはPSoc Creatorで提供されるサンプルコードを利用します。










サンプルコード選択

〇プロジェクト新規作成
・プロジェクトテンプレート選択で「Code example」を選択。

・サンプルコード(code example)選択で「Char_LCD_Horizontal_Bar_Graph」を選択。


Bootladableコンポーネント追加

・Bootladableコンポーネントを追加(トラ技 Lチカプロジェクト(LEDBLINK) 参考)





〇このサンプルプロジェクトをビルド後PSoc基板に書き込む。
       ※書き込み後 サンプルプログラムが動き出す。
〇このプロジェクトのデモ表示部を削除して、LDC表示のみを残しベースプロジェクトとします。

2.GPIO割り込みの実装
操作SW用 Digital Input Pin コンポーネント追加
テスト基板の3つの操作スイッチの割り込みを実装します。
〇Digital Input Pinコンポーネントの追加
・Number Of Pinsを3に
・Interruptの設定



〇main.cの編集
・CY_ISR_PROTOマクロを使用してGPIO割り込み関数を宣言
  CY_ISR_PROTO(GPIO_ISR);
・CY_ISRマクロを使用してGPIO割り込み関数を定義
  CY_ISR(GPIO_ISR)
   {
       uint8 InterruptState = SW_ClearInterrupt();
      ・・・・・・・・
             ※InterruptStateにPinのIDが格納
・main()に初期処理を追加
     isr_1_StartEx(GPIO_ISR);  ・・・・GPIO割り込み関数を登録
     CyGlobalIntEnable;     ・・・・・割り込みを許可

3.74HC595のテスト
今回は、74HC595(シリアル/パラレル変換)のテストを行った。
74HC595テスト構成


・操作スイッチSW1~3でLEDの点灯パターンを切り替え。
・PSoc4100S ==> 74HC595 はシリアル。
・74HC126は今回のテストでは不要
(ほぼ無意味)
・PSoc4100S<==>LCDキャラクタLCDディスプレイの接続はP0をP2に変更
   






74HC595テスト




















※※※※※main.c※※※※※※

#include
#include

/* The LCD format in characters */
#define LCD_ROWS                (2u)
#define LCD_COLUMNS             (16u)

/* The delay between displaying bar graphs */
#define BARGRAPH_DELAY_MS       (15u)

CY_ISR_PROTO(GPIO_ISR);

int iPtn = 0;

void fnc_595(int ic){
    int i;
    int j;
    int k;
    k = 128;
    j = ic;
    RCK_Write(0);
    for(i=0;i<8 i="" p="">        if( k & j){
            SI_Write(1);
        } else {
            SI_Write(0);
        }
        SCK_Write(1);   
        CyDelay(10u);
        SCK_Write(0);
        k = k >> 1;
    }
    RCK_Write(1);
return;
}

int main()
{
    int idat = 1;
   
    /* Start the LCD */
    LCD_Start();

    /* Show the demo start message */
    LCD_Position(0u, 0u);
    LCD_PrintString("Test 74HC595");
    LCD_Position(1u, 0u);
    LCD_PrintString("#####05######");
    SI_Write(0);
    RCK_Write(0);
    SCK_Write(0);
    CyDelay(1000u);

    isr_1_StartEx(GPIO_ISR);
    CyGlobalIntEnable;
   
    for(;;)
    {
        if(iPtn == 0){
            idat++;
        }else if(iPtn ==1){
            if(idat == 0) idat = 1;
            else idat = idat << 1;
        }else if(iPtn ==2){
            if(idat == 0) idat = 128;
            else idat = idat >> 1;
            }
        idat = idat & 0xFF;
        fnc_595(idat);
        CyDelay(100u);
    }
}

CY_ISR(GPIO_ISR)
{
    uint8 InterruptState = SW_ClearInterrupt();
    char cbuff[8];
   
    itoa(InterruptState,cbuff,10);
   
    LCD_Position(1u, 0u);
   
    if (InterruptState == 1){
      LCD_PrintString("##Key1##");
       iPtn =0;

    }else if (InterruptState == 2){
     LCD_PrintString("##Key2##");
       iPtn =1;
 
    }else if (InterruptState == 4){
      LCD_PrintString("##Key3##"); 
       iPtn =2;
 
    }else {
      LCD_PrintString("##KeyX##");
   }
     LCD_Position(1u, 9u);
     LCD_PrintString(cbuff);
}
※※※※※※※※※※※※※※※※※※

GPIO割り込み時の押されたスイッチの識別は
 uint8 InterruptState = SW_ClearInterrupt();
の InterruptState  に格納される値で行いました。
Digital Input PinコンポーネントのSWのピンIDで
SW[0]の場合 1
SW[1]の場合 2
SW[2]の場合 4  となるようです。





2018年7月6日金曜日

Dynabook分解修理


 ◎昨年暮れ、電車の網棚からDynabook AZ85/UG が落下。
電車の網棚に置いたバックを下ろそうとしたところ、ちょっと何か引っかかる感覚があり、強引にバックの持ち手を引っ張ったところ、バックの勢いに、持ち手を放してしまい、バックは勢いよく床に落下、バックのDynabookを確認したところ、右のヒンジの付近が大破、電源のスイッチも浮き上がり押しても無反応、ああああああああ!
 帰宅後、「とりあえず、ハードディスクだけでも無事であってくれ!」 と思いながら、クラッシュDynabookを分解、筐体の損傷は激しいものの、マザーボードは奇跡的無事、そこで、分解途中で、電源スイッチ(内部 基板上)を押すと、いつもの通り起動、不幸中の幸い、しかし依然として、普段の使用には耐えない状態、何とかして、筐体を入手出来ないかと。。。
 

 ◎ヤフオク
  筐体入手に、Dynabookのジャンク品が無いかとヤフオクを検索、筐体だけ必要なので(メモリ、ハードディスク、LCDディスプレイなどは不要) 予算5000円前後でDynabook AZ」でジャンク品を探すのですが、AZシリーズ自体出品数が少なく、なかなか予算内で落札できず、3か月経過、そんな時、秋葉原でノートPC のジャンク品を漁っていた時(Dynabookのジャンク品はほとんど1世代より古い型ばかりで)、中古ノートPC売り場で、同じ筐体のものがあるのを見つける、はじめ AZシリーズの下位モデルと思いきや、「Dynabook T55」 あれれ!
そこで、ヤフオクの検索条件に Tシリーズを追加、一気に対象が増えました、しかし依然として、落札に至らず。
苦節6か月ようやく、Dynabook T45 ジャンク品を落札、届いたT45を確かめると、美品、筐体損傷なし、メモリなし、ハードディスクなし、送料込みで7300円、


 
T45AG85を移植
 一抹の不安を持ちながら、移植開始、
・両方の筐体を開く、まずマザーボードを確認、基板は同じ(乗っかっているパーツは結構異なっていました。)。
AZ85のメモリ、ハードディスクを外す。
ここからはAZ85T45平行して作業を行う。
・光学ドライブを外す。
・マザーボードに繋がっているフラットケーブルを外す(同じフラットケーブルでもコネクタのロックが異なっているものがある、要注意)。
・マザーボードのCPUクーラーを外す。固定のねじを外し、マザーボードを外す。
 ・LCDディスプレイ部を外す。
 ・その他のパーツを筐体から外す。
 ・取り外したAZ85のパーツをT45の筐体に取り付ける。


◎復活 Dynabook
 ・T45に電源アダプタをつなげスイッチON 無事起動(まずは念のため、最初はバッテリーパックを外した状態)


◎バッテリーパックの装着
バッテリーパックがT45AZ85で共通かどうか不明、いろいろ調べると、ヤフーショッピング等で購入できるDynabookのバッテリーパックの対応機種のリストにT45の記載があるもののAZ85は無い、注意書きに「型式が異なる場合、極性等が異なる場合があるので、他の型式のPCへの流用は行わない」との記載 覚悟を決めて、T45のバッテリーパックを装着、スイッチON、バッテリーパックの異常発熱等が無いか確かめながら、復活Dynabookの機能の確認をおこないました、最初バッテリーの状態を画面で確認すると、バッテリーが認識されていない表示、やはりだめかと思いながら十数分放置、すると充電が10%の表示、最終的に100%の充電が確認できました。


◎まとめ
 今までデスクトップPC、オフコン、EWS等の分解修理の経験(十数年まえ)はあったのですが、初のノートPCの分解で当初不安で、ヤフオクであまり高額のジャンク品には手が出ませんでした。実際にDynabookの分解を始めると、筐体の開きやフラットケーブルの扱いに若干手間取るものの、デスクトップPCの分解修理と大差無いことが実感されました。今思えば、ヤフオクでもう少し頑張れば、、、、6か月かけての復活は少々時間を無駄にした感が否めません。