Vol.900 9.Aug.2024

Microsoft_Copilot EasyCommでシリアル通信 PICミニBB(10)_Myライブラリ

C Microsoft Copilot

by fjk

 最近Edgeを使っていて気づいたが、通常の検索結果と共にヒントを表示してくれる機能が追加されている。結構曖昧な検索キーワードでも、それなりの回答(プログラムも)が得られ、なかなか便利である。
 この機能は、「Microsoft Copilot(マイクロソフト コパイロット)」と呼ばれ、Microsoft社が提供している生成AIツールで、Copilotは「副操縦士」という意味である。
 CopilotはOpenAI社が開発した「GPT」という言語モデルがベースとなっており、 Microsoftアカウントがあれば、誰でも無料で文章・コード・画像などを生成することができる。
 さらに、有料版であれば Microsoft 365 と連携することも可能。

Copilotは、主に以下の三つの技術から成り立っている、
@ テキストを理解し生成する「GPT-4」
A コードを理解し生成する「Codex」
B 入力されたテキストから画像を生成する「DALL-E3」


E Excel_VBAのチップス  〜EasyCommでPICとシリアル通信

by fjk

 PICとの通信にテラタームを利用しているが、さらにExcel_VBAでPICとのデータ通信を試みた。Excelのシリアル通信には、widowsAPIを利用する例がよく紹介されているが、記述コードが多く、使い方も難しそうである。
 そこで、さらに探してみると、APIを含むVBモジュールとしてEasyCommが見つかった。
 EasyCommは木下隆さんが開発されたモジュールで、既にサポートは終了しているが、未だに多くの方がフォローされているようである(以下のHPを参考にさせていただいた)。
 ・ HatenaBlog[NOB]さん
 ・ jizilogさん

【準備】
1.EasyComm(zip)をダウンロードし、zipファイルを適当なところに解凍。
2.Excelで「開発」「VisualBasic」とし、さらに解凍した「ec.bas」と「ecDef.bas」をインポートする
3.標準モジュールを追加し、コードを記述する。
 
【VBA開発】 NOBさんの一部を変更([]内はデフォルト)、使い方の詳細はecManual.xls参照

Option Explicit

Sub EasyCommTest()
    Dim rcv as string
    '@初期設定
    ec.COMn = 6                     ' 使用するポート番号を記述(自分のポート番号を設定)
    ec.Setting = "115200,n,8,2"     ' 通信条件(ボーレート,パリティ,データbit,ストップbit)
    'ec.HandShaking = ec.HANDSHAKEs.RTSCTS  ' 通信ハンドシェークの設定 [ハンドシェーク無し]
    'ec.Delimiter = ec.DELIMs.CrLf  ' データの区切りを示す文字列を設定します [デリミタはCr]
    'Aデータの送信
    'ec.OutBuffer = 100& * 1024&    ' ポートの送信バッファを100kBに設定 [デフォルトは2048バイト]
    ec.AsciiLine = "*Test"          ' *Testという文字列をデリミタ付きで送信
    'Bデータの受信
    rcv = ec.AsciiLine              ' デリミタの手前までの受信文字列をrcvに代入
    ec.InBufferClear                ' 受信バッファをクリア
    'C受信データの表示
    MsgBox rcv
(デフォルトの条件のままで良いものはコメントにした)

ポート番号セル、入出力セル、ボタンを追加
testEasyComm.xlsm(zip)

VisualBasic開発中画面(前記VBAの一部を変更)
(B2にポート番号、B5データを送信、B7に受信データ) 

 使用したパソコン環境は、windows10、Excel2019で、以上のような簡単な記述(コメント行を除くと数行)のみで、(USB)シリアル通信が行えた。なお、USB接続PICターミナルは、次項のバックライトLCD付きのものを用いた(テストは次項の写真参照)。
 EasyCommは、windowsAPIを理解しなくても、VBAで簡単かつ手軽に使えるシリアル通信ツールで、改めて木下隆さんに感謝!


P PICミニBBシリーズ(10)  〜Myライブラリーとプリプロセッサ

by fjk

 abc899まで、プロジェクトに合わせていくつかのライブラリを作成し、個々に利用していたが、使用するPICによって、その一部を書き換える必要があるなど、使いづらかった。
 そこで、MPLABXProjectsフォルダーの下に「myXC8lib」フォルダーを作って、これまでのライブラリをまとめて格納することにした。
 しかし、I2CライブラリなどMCCがGenerateしたファイルをライブラリーで利用するには、ライブラリーに現在プロジェクトのパス・ファイル名を記述しなければならず、共有のライブラリとして使えなくなる。それゆえ、共有ライブラリーをmyXC8libから現在プロジェクトフォルダーにコピーすることは避けられなかった(今後の課題)。なお、MCCがGenerateしたファイルを使わないライブラリはコピー不要で使用可能。
 そして、現在プロジェクトフォルダーに「myProject.h」ファイルを作成し、このファイルに「#define文」などを記述することで、使用するPICやハードなどプロジェクト毎の違いを吸収することにした。

【ハードウェア】
 キャラクター表示LCDに16文字x2行のAQM1602Y-RN-GBWを使ってきたが、ミニBBでもバックライト付のAQM1602Y-NLW-FBWを使えるようにLCDボードの配線を変更した。
 LCDの接続には11ピンの丸ピンヘッダーを利用し、バックライト配線を両端のピンに接続した。また、ボードの上隅にLCDを支えるスペーサー用のピンヘッダーも配置した。


LCD表示ボードの配線図
(バックライト用抵抗は220Ω)
(抵抗は交換が容易な位置に配置)
 
 


LCDバックライトの配線

PIC-Base14と接続した状態
(RA4はLEDに接続)

テラターム画面例
 

【ソフトウェア】 (EUSARTの設定については後述の「おまけ」を参照)
 新ボードのテストとライブラリの動作確認を兼ねて、シリアル受信ターミナルソフトを作成した。
 (ターミナルの機能は、受信データーに"Received"を頭に付けて返送するだけ)
 
<ターミナルのエコー設定>
 シリアル通信のエコーの有無はON/OFFで設定でき、
     VBA用ターミナルでは ECHO = OFF
     テラタームでは    ECHO = ON/OFF のどちらでもOK

<I2Cライブラリの設定例>
 例えば、I2Cの場合、
   @I2Cが2つ以上あるPICの場合は、I2C番号をセット
      #define I2C 1
   AI2Cが1つしかないPICの場合は
      文字列I2Cは宣言しない


Excelとシリアル通信中画面例

Excel画面例(再掲)
【myProject.hファイル】 myProject.h(zip)

/**************************(myProject.h)***
 *   プロジェクト個別条件指定ファイル     *
 *   (main.cと同じフォルダーに作成)     *
 ******************************************/
#include "mcc_generated_files/mcc.h"
#include "i2cLCDST7032i.h"

#define  ON    1
#define  OFF   0

/***** 使用電源電圧 ***********************/
//--- VCC宣言無しは5V(VCC=50と同じ)
#define VCC   50		// 電源電圧は5V
//#define VCC   33		// 電源電圧は3.3V

/***** EUSARTモジュール *******************/
#define BFSIZE  80
//--- ECHO宣言はどちらかを必ず行うこと
//#define ECHO  ON		// エコー有り
#define ECHO  OFF		// エコー無し

/***** MSSPモジュール *********************/
#define MASTER 1
#define SRAVE  2
#define I2CMODE MASTER    	// マスターとして使用
//#define I2CMODE SRAVE    	// スレーブとして使用
//--- MSSPが一つしか無い場合は I2C宣言無し
#define I2C  1            	// I2C1を使用
//#define I2C  2            	// I2C2を使用

#if I2CMODE == MASTER
    #if I2C == 1
        #include "mcc_generated_files/examples/i2c1_master_example.h"
    #elif I2C == 2
        #include "mcc_generated_files/examples/i2c2_master_example.h"
    #else
        #include "mcc_generated_files/examples/i2c_master_example.h"
    #endif
  //  #define I2CLCD_Adr 0x3c // LCDのI2Cアドレス(i2cLCD_ST7032i.hで設定)
#endif
【i2cLCD_ST7032i.c/hファイル】 i2cLCD_St7032i.c/h(zip)

 /*****************************(i2cLCD_ST7032i.c)***
 *   LCD ライブラリ use for AQM0802A,AQM1602Y,..  *
 **************************************************/

#include "myProject.h"
#include "i2cLCD_ST7032i.h"

#if VCC == 33
    #define  CONTRAST   0x30   // for 3.3V
    #define  BOOST       0x04   // for 3.3V Bon=on
#else
    #define  CONTRAST   0x18   // for 5.0V
    #define  BOOST       0x00   // for 5.0V Bon=off
#endif

//-------- send command -------------------------
void LCD_cmd(char cmd){
#if I2C == 1
    I2C1_Write1ByteRegister(I2CLCD_Adr, 0x00, cmd);
#elif I2C == 2
    I2C2_Write1ByteRegister(I2CLCD_Adr, 0x00, cmd);
#else
    I2C_Write1ByteRegister(I2CLCD_Adr, 0x00, cmd);
#endif
//-- Clear かHomeか?
    if(cmd & 0xFC)              // bit6 = 1
        __delay_us(30);         // 30us
    else
        __delay_ms(2);          // 2ms Clear or Home
}

//-------- send data ----------------------
void LCD_dat(char chr){
#if I2C == 1
    I2C1_Write1ByteRegister(I2CLCD_Adr, 0x40, chr);
#elif I2C == 2
    I2C2_Write1ByteRegister(I2CLCD_Adr, 0x40, chr);
#else
    I2C_Write1ByteRegister(I2CLCD_Adr, 0x40, chr);
#endif
    __delay_us(30);             // 30us
}


//--------- Home -----------------------------
void LCD_home(void){
    LCD_cmd(0x02);
}

//--------- Cursor X,Y -----------------------
void LCD_cursor(int x, int y){
    if (y == 0)
        LCD_cmd((char)(0x80 + x));
    else if (y == 1)
        LCD_cmd((char)(0xc0 + x));
}

//-------- display strings -------------------------
void LCD_str(char *str){
    while(*str)
 	LCD_dat(*str++); //pointer increment
}

//------- Create CG Char ---------
uint8_t LCD_CGchar(uint8_t c, char* dt){
    uint8_t i;
	if(c > 7) return 1;
	LCD_cmd((char)(0x40 | (c << 3)));
	__delay_us(30);
	for(i = 0; i < 7; i++){
		LCD_dat(*dt++);
	    __delay_us(30);
	}
	return 0;
}

//-------- LCD sift position -----------------
void LCD_sift(uint8_t d){
	if(d) LCD_cmd(0x18);
	else  LCD_cmd(0x1C);    
}

//-------- LCD initialize ---------------------------
void LCD_init(void){
    __delay_ms(40);         // 40ms wait
    LCD_cmd(0x38);          // 8bit,2line
    LCD_cmd(0x39);          // IS=1 : extention mode set
    LCD_cmd(0x14);          // Internal OSC Frequency
    LCD_cmd(0x70 + (CONTRAST & 0x0F)); 	//Contrast set
    LCD_cmd(0x58 + BOOST + (CONTRAST >> 4));
                            //Power/ICON/Contrast Control
    LCD_cmd(0x6C);          // Follower control
    __delay_ms(200);        // 200ms wait
    LCD_cmd(0x38);          // IS=0 : extention mode cancel
    LCD_cmd(0x0C);          // Display ON
    LCD_cmd(0x01);          // Clear Display
    __delay_ms(2);          // wait more than 1.08ms
}

//-------- Redirect STDIO to LCD ----------------
//   LCDを標準出力にする場合はここを有効にする
/*
void putch(char ch){
    LCD_dat(ch);
}
*/

/********  End of File ******/

/******************************************
 *      LCD library  (i2cLCD_ST7032i.h)   *
 *      use for AQM0802A,AQM1602Y,....    *
 ******************************************/

#define I2CLCD_Adr 0x3c     // LCDのI2Cアドレス

//-------- send command -------------------
void LCD_cmd(char cmd);

//-------- send data ----------------------
void LCD_dat(char chr);

//-------- clear LCD-----------------------
void LCD_clr(void);

//--------- Home --------------------------
void LCD_home(void);

//--------- Cursor X,Y --------------------
void LCD_cursor(int x, int y);

//-------- display strings ----------------
void LCD_str(char *str);

//------- Create CG Char ------------------
uint8_t LCD_CGchar(uint8_t c, char* dt);

//-------- LCD sift position --------------
void LCD_sift(uint8_t d);

//-------- LCD initialize ------------------
void LCD_init(void);

/********  End of Header File ******/
【abc900-18325.cファイル】 abc900-18325.c(zip)

/*****************************(abc900-18325.c)***
 *      ライブラリーテスト
 *************************************************/

#include "mcc_generated_files/mcc.h"
#include "myProject.h"

#define VBA

char  RBuf[BFSIZE];
uint8_t SFlg;

/*===============================
 *    Main application
 *==============================*/
void main(void){
    SYSTEM_Initialize();
    LCD_init();

    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();

    puts("ready!\r");
    LCD_str("Ready!");

    while (1)
    {
        if(SFlg){
             #if ECHO==OFF
                #ifdef VBA
                    printf("Received %s\r",RBuf);
                #else
                    printf("Received %s\n\r",RBuf);
                #endif
            #else
                puts("\n--next\r");
            #endif
            LCD_clr(); 
            LCD_str(RBuf);    
            SFlg = 0;
        }
        IO_RA4_Toggle();
        __delay_ms(500);
    }
}
/***   End of File ***/

【おまけ】
 <EUSARTの設定>
 これまでは、mcc_generated_filesにあるeusart.cとeusart.hの両方を修正していたが、eusart.cのみを変更することにした。
 また、EUSART_Receive_ISRの中に追加部分の全てを記述していたが、myEusart()関数を作成し、ISRの中ではこの関数を呼ぶだけにした。
 なお、 myEusart()はプロトタイプ宣言していないので、EUSART_Receive_ISR(使用場所)より前に記述すること。
【eusart.cファイル】

/**
  Section: Included Files
*/
#include "eusart.h"
#include "../myProject.h"

/**
  Section: Macro Declarations
*/

#define EUSART_TX_BUFFER_SIZE 8
#define EUSART_RX_BUFFER_SIZE 8
/**
  Section: Global Variables
*/
extern char    	RBuf[];         // シリアル受信バッファー
extern uint8_t 	SFlg;           // 受信完了フラグ

static uint8_t 	sIdx;           // 受信文字列インデックス

volatile uint8_t eusartTxHead = 0;

	・・・<途中省略>・・・

void myEusart(){
    char ch;
    ch = getch();
    #if ECHO == ON
    		putch(ch);
    #endif

    if((ch == 0x0a)||(ch == 0x0d)){	  // 改行処理
        SFlg = 1;
        RBuf[sIdx] = 0;
        sIdx = 0;
    }else if((ch == 0x08)&&(sIdx > 0)){	   // BS処理
        sIdx--;
    }else{
        if(sIdx < BFSIZE) RBuf[sIdx++] = ch;
    }
}

void EUSART_Receive_ISR(void)
{
    eusartRxStatusBuffer[eusartRxHead].status = 0;

    if(RC1STAbits.FERR){
        eusartRxStatusBuffer[eusartRxHead].ferr = 1;
        EUSART_FramingErrorHandler();
    }

    if(RC1STAbits.OERR){
        eusartRxStatusBuffer[eusartRxHead].oerr = 1;
        EUSART_OverrunErrorHandler();
    }
    
    if(eusartRxStatusBuffer[eusartRxHead].status){
        EUSART_ErrorHandler();
    } else {
        EUSART_RxDataHandler();
    }
    
    // or set custom function using EUSART_SetRxInterruptHandler()
    myEusart();
}
 	・・・<以下省略>・・・


※プログラムのリストをハイライト無しのスタイルで見る場合はここをクリック


※ 本レポートの参考・利用は、あくまでも自己責任でお願いします。


Microsoft_Copilot EasyCommでシリアル通信 PICミニBB(10)_Myライブラリ