Vol.933 26.Dec.2025

EdgeでIEモードが使えない 半導体パッケージ USBシリアル-CANコンバータ(2)

E EdgeでIEモードが使えない

by fjk

 現在、E-Taxなどの行政サービスや銀行等のファイル送信等には、EdgeではなくIE(InternetExplore)を使わなければなりませんが、IEの脆弱性対策のため、Microsoftでは2025年10月より「IEモードでの再読込」アイコン等がなくなっています。(参考記事
 そこで、E-Tax等を管理する国の機関では、「IEモードが有効にならず、公文書が表示できない事象について」を2025年11月4日に発表し、とりあえずの対策方法を、お知らせしています。

IEモードが有効にならず、公文書が表示できない事象について(e-GOV)
IEモードで公文書を読み込む暫定対処手順
@「Edge/設定/既定のブラウザ/ページの追加」にIEで開きたいページのアドレスをコピー
A「Edgeで開いたページ」に戻り、「F5キー」を押してページを更新すると、IEでページが表示される
 私がよく使っているEdyViewerもIEで無いと動作しないので、同様の手順で「ページの追加」を行うことで、Edyによるネット支払ができました。
 
 また、追加したページは30日間はIEで開け、その後、削除されるようです(IEは2029年までサポート、IEでしか使えないシステムをEdgeで動かす方法)。


I 半導体パッケージ

by fjk

 半導体の主なパッケージ形状は、以下の「挿入用」と「表面実装用」に分類される。

 ● 挿入実装用パッケージの種類

・SIP(Single In-line Package):
リードがパッケージの1側面から出ており、リードが1列。
・ZIP(Zigzag In-line Package):
リードがパッケージの1側面から出ており、リードがジグザグ状。
・DIP(Dual In-line Package):
リードがパッケージの2側面から出ており、リードが下方向。

 ●表面実装用パッケージの種類

・SOP、SOJ、SON等:
パッケージの2側面からリードが出ているパッケージ
・QFP、QFJ、QFN等:
パッケージの4側面からリードが出ているパッケージ
・BGA、LGA、PGA等:
パッケージの底面から格子状に端子が配置されているパッケージ

 <参考> 「半導体のパッケージの種類」

 PICの自作電子回路ではDIPとSOP形状がよく利用され、DIPは2.54mmピッチのリードが下方に出ている。SOP(Small Outline Package)はリードがパッケージの2側面から、ピンピッチが1.27mmで、ガルウィング形(L字形)の出ている。SOP等の後に付く数字はピン数で、SOP8は8ピンのSOPとなる。
 SOPの前に英文字が付くことで、「パッケージ取り付け高さ」や「ピンピッチ」等が変わる。例えば、「L」はパッケージ取り付け高さLが『1.20mm<高さL≦1.70mm』となる。SOPの前に「S」、「M」、「Q」が付くと、ピンピッチが変わる。例えば、SSOPはSOPの前にShrink(縮小)の「S」が付いたもので、ピンピッチは1.0、0.8、0.65、0.5mmがある。すなわち、ピンピッチが複数あり、「SSOP」だけではどのピンピッチか分からないため、必ずデータシートでサイズ確認をする必要がある。
 
<参考>


P PICでCAN通信(7) 〜USBシリアル-CANコンバータ(2)

by fjk

 abc932でUSBシリアルデータを任意の形式でCANデータとして送信することができるようになったが、受信機能は以前のままだった。そこで、abc932の送信機能をそのままで、abc929のCANバスモニターと同様の受信機能を有し、受信データも任意の形式に変換できる機能を追加した。

<送信>
・abc932の機能をそのまま使用可能(Mコマンドは強化)。
・「^」(ハット)に続く文字があれば、そのまま文字列としてCAN送信
・温度センサー関係は削除
<受信>
・受信機能にはabc929と同様の簡易CANバスモニター機能も追加した。
  (受信データの表示はabc929に「書式指定表示モード」を追加))
・受信書式条件などは、|(パイプ)に続く文字列で指定する。
  (書式文字はabc932と同じ)
・受信idが一致した場合、指定された条件でデータを文字列に変換し、OLEDなどに表示。
  (受信idが不一致の場合、SWまたはMコマンドで指定した書式で表示)
【ハード】 (ノード5B)
abc929のMCP2515モジュールをMCP25625BOに変更した(PIC利用端子がabc929と異なる!)。
PIC16F18326、OLED-128x60、24FC1025(フォントROMは無くても動作可能)を使用

PIC16F18326 + OLED-12864 + MCP25625BO

ブレッドボード配線例

【ソフト】   ・abc933-18326.c [ノード5B]

  1. abc929の「簡易CANバスモニター」をベースとしたが、PICの利用端子がabc929と異なるので注意!(MCCでピン設定の変更が必要。割込ハンドラーも IOCCF2_**** に変更すること)。
  2. 受信書式文字列データFrv[8]を利用し、書式はabc932とほぼ同じで|に続けて指定。
    (|or〜のみは、現在書式を表示)
  3. 受信idが一致した場合、書式指定表示モードで受信データを表示。(|Xhhhで受信idを変更)
  4. ^ に続く文字があれば、以降の文字列を(書式指定を無視し)CAN送信(最大8文字)。
  5. その他の送信機能はabc932と同じ



CANテスト(Node5B+6B2+7)

ターミナル例


≪≪ ノード5B ≫≫   ▼abc933-18326.c(zip)

/*****************************(abc933-18326.c)*******
 *      簡易CANコンバーター                         *
 ****************************************************/
#include "myProject.h"
#include "myFunction.h"
#include "mcp_can_dfs.h"
#include "skMCP25xx.h"
#include "i2c_SSD1306.h"

#define USE_ASC_FONT
#ifdef USE_ASC_FONT
	#include "Font_8x16ASC.h"
#else
	#include "Font_8x16NA.h"
#endif

#define USE_RA3_PORT
#ifdef USE_RA3_PORT 
	#define GET_SW()    RA3_GetValue() 
#else
	#define GET_SW()    SW0_GetValue()  
#endif

#define  MBF_SIZE    64                 // メッセージBFサイズ
#define  OLED_SZ     21                 // OLED行表示最大文字数

char *Md_Msg[] = { "** Integer Mode",
                   "** Ascii Mode",
                   "** HexNum Mode",
                   "** Format Mode"
                  };

/************************************************************
 *  グローバル変数
 *==========================================================*/
//--- タイマー用変数
uint8_t  TFlg;                          // タイマーフラグ

//---- EUSARTシリアル用
char RBuf[EU_BFSIZE];                   // BFSIZEはmyProject.hで宣言
uint8_t  SFlg;                          // シリアル受信フラグ

//---- 汎用データ処理用
char     Msg[MBF_SIZE];                 // コメント等用文字列
char     Dlm[] = ",";                   // 文字列区切りデリミタ

//---- OLED表示用
uint8_t  CrtLn = 0;                     // OLED表示現在行
uint8_t  DspMd = 0;                     // データ表示モード
uint8_t  Mx_Ln = 4;                     // 最終行は5行目

//---- CAN用共通変数
uint32_t Crv_id = 0x123;                // 受信id
uint8_t  Crv_Flg = 0 ;                  // CAN受信有無フラグ
uint8_t  Crv_len = 0 ;                  // CAN受信データサイズ
uint8_t  Crv_Buf[8];                    // CAN受信データ
char     Crv_Fmt[9] = "SSSSSSSS";       // CAN受信書式データ

uint32_t Csd_id = 0x149;                // 送信id
uint8_t  Csd_len = 0 ;                  // CAN送信データサイズ
uint8_t  Csd_Buf[8];                    // CAN送信データ
char     Csd_Fmt[9] = "SSSSSSSS";       // CAN送信書式データ

/*==================================================*
 *  割り込みの処理                                  *
 *--------------------------------------------------*/
//--- タイマ0 Callback関数 (1秒周期割り込み) 
void TMR0_Process(void){
    TFlg = 1;                           // タイマーフラグセット
}

//----  MCP2515のINTピン割り込み
void IOCCF2_Process(void) {
    Crv_Flg = 1;                        // CAN受信(有り)セット
}

/*==================================================*
 *  OLED表示用関数 & 表示テスト関数                *
 *--------------------------------------------------*/
//---- スクロール付き表示(5x7ドット文字)
//      (スクロール範囲は[0 - Mx_Ln])
void i2cOLED_Prt(char *str) {
    i2cOLED_posPX(CrtLn, 0);
    i2cOLED_str(str);
    if (CrtLn < Mx_Ln)  CrtLn++;
     else CrtLn = 0;
    i2cOLED_Clr(CrtLn, CrtLn, 0);
}

//---- 半角文字表示
uint8_t i2cPrint_Hchr(uint8_t py, uint8_t x,char ch){
#ifdef USE_ASC_FONT
    if((0x20 <= ch)&(ch <= 0x7F)){
        x = i2cOLED_Ptn(py,x,2,8,(char *)F_asc[ch-0x20]);
#else
    if((0x30 <= ch)&(ch <= 0x3A)){
        x = i2cOLED_Ptn(py,x,2,8,(char *)F_hn[ch-0x30]);
    }else if((0x41 <= ch)&(ch <= 0x5A)){
        x = i2cOLED_Ptn(py,x,2,8,(char *)F_af[ch-0x41]);
    }else if(ch == 0x20){
        x = i2cOLED_Ptn(py,x,2,8,(char *)F_sp);
    }else if((0x2A <= ch)&(ch <= 0x2F)){
        x = i2cOLED_Ptn(py,x,2,8,(char *)F_op[ch-0x2A]);
    }else if((0x61 <= ch)&(ch <= 0x7A)){
        x = i2cOLED_Ptn(py,x,2,8,(char *)F_af[ch-0x61]);
#endif
    }else{
        x = i2cOLED_Ptn(py,x,2,8,(char *)F_dt);
    }
    return x;
}

//---- 半角文字列の表示
uint8_t i2cPrint_Hstr(uint8_t py, uint8_t x, char *str) {
    uint8_t n;
    while(*str){
        x = i2cPrint_Hchr(py,x,*str++);
    }
    return x;
}

//----  配列データを16進数文字列に
void set_hex_data(char *bf, uint8_t *ary, uint8_t n){
    uint8_t i;
    for(i = 0; i < n; i++){
        my_xtoa(bf, ary[i], 2);
        bf += 2;
    }
    *bf = 0;
}

//--- 印刷可能な文字に変換して文字列を連結
void cv_prtcat(char *bf, char *str, uint8_t n){
    uint8_t i;
    for(i = 0; i < n; i++){
        if(isprint(*str))   *bf++ = *str;
         else               *bf++ = 0x7F;
        str++;
    }
    *bf = 0;
}

//---- OLEDとEUに文字列を出力
void OLED_EU_Prt(char *str){
     i2cOLED_Prt(str);
     EU_Puts(str);
}

//---- OLEDの最下行に半角文字表示
void OLED_Low_Hprt(char *str){
    i2cOLED_Clr(6, 7, 0);
    i2cPrint_Hstr(6, 0, str);           // 半角文字表示
}

//----  表示モードの変更
void chg_dspMd(uint8_t md) {
    if(md > 3) md = 0;
    i2cOLED_Clr(0, 7, 0); CrtLn = 0;
    if(md < 2)      Mx_Ln = 4;
     else           Mx_Ln = 7;
    OLED_EU_Prt(Md_Msg[md]);
    DspMd = md;
}

/************************************************************
 *  送受信IDを設定
 *      char    *str: 設定用文字列データ
 *      uint8_t   sr: IDの種類(0:送信、1:受信)
 *----------------------------------------------------------*/
void set_NewID(char *str, uint8_t sr){
    uint32_t id;
    id = my_xtol(str);                  // id取得
    if(id){
        id &= 0x3FF;                    // 11ビットに
        if(sr){
            Crv_id = id;                // 受信idに設定
            sprintf(Msg,"Snd_ID = %3X",Crv_id);
        }else{
            Csd_id = id;                // 送信idに設定
            sprintf(Msg,"Rsv_ID = %3X",Csd_id);
        }
        EU_Puts(Msg);
    }
}

/************************************************************
 *  CAN書式データを格納
 *      char *fmt:  格納する書式文字列(Crv_Fmt[]/Csd_Fmt[])
 *      char *str:  書式指定文字列(コンマ区切り)
 *----------------------------------------------------------*/
void set_CAN_Fmt(char *fmt, char *str){
    char *ps;                           // 切出し文字列ポインタ
    uint8_t p = 0;                      // 書式参照位置
    char fch;                           // 書式指定文字
    uint8_t i,j,k,n;
    
    ps = strtok(str,Dlm);               // 文字列の切り出し
    do{
        if(ps==NULL) break;             // 文字列がなくなれば
        
        fch = (char)toupper(*ps);       // 大文字に
        if(strlen(ps) > 1){             // パラメータがあれば
            j = (uint8_t)atoi(ps+1);    // 繰り返し数
        }else{                          // パラメータ無し
            if(fch == 'S') j = 0;       // Sでパラ無しは可変長
             else          j = 1;
        }

        switch(fch){
            case 'S':           k = j; break;
            case 'U': case 'W': k = 2; break;
            case 'L':           k = 4; break;
            default:            k = 1; break;
        }
 
        if(j)   n = j * k;              // パラなし文字列以外の場合
         else   n = 8 - p;              // パラなし文字列の場合
        
        if((p + n) > 8) break;          // 指定文字数オーバー
        
        for(i = 0; i < n; i++){
            fmt[p++] = fch;             // 書式文字を指定数セット
        }
        ps = strtok(NULL,Dlm);
    }while(p < 8);                      // 書式文字数が8文字以内なら
    fmt[p] = 0;                         // 文字列終了
    EU_Puts(fmt);                       // 変換結果表示
}

/*************************************************
 *  CAN受信処理
 *================================================
 *  バイナリー配列を指定書式で文字列に追加
 *---------------------------------------------*/
//--- 1バイトバイナリー => 数値文字列(最大3文字)
uint8_t set_B_S(char *str, uint8_t *d){
    char s[10];
    sprintf(s,"%d", d);
    strcat(str,s);
    return (uint8_t)strlen(s);
}

//--- 2バイトバイナリー => 数値文字列(最大5文字)
uint8_t set_U_S(char *str, uint8_t *bf){
    union {
        uint8_t b[2];
        uint16_t u;     } data;
    char s[10];
    
    data.b[0] = *bf++;
    data.b[1] = *bf;
    sprintf(s,"%d",data.u);    
    strcat(str,s);
    return (uint8_t)strlen(s); 
}

//--- 1バイトバイナリー => 16進数文字列(2文字)
uint8_t set_H_S(char *str, uint8_t *h){
    union {
        uint8_t b[2];
        uint16_t w;     } data;
    data.b[0] = *h;
    my_xtoa((char *)str,data.w,2);
    return 2;
}

//--- 2バイトバイナリー => 16進数文字列(4文字)
uint8_t set_W_S(char *str, uint8_t *bf, uint8_t en){
    union {
        uint8_t b[2];
        uint16_t w;     } data;
    uint8_t i;
    for(i = 0; i < 2; i++)
        data.b[i]= *bf++;  
    if(en) data.w = exchg_word(data.w);
    my_xtoa((char *)str,data.w,4);
    return 4;
}

//--- 4バイトバイナリー => 16進数文字列(6文字)
uint8_t set_L_S(char *str,uint8_t *bf, uint8_t en){
    union {
        uint8_t b[4];
        uint32_t L;     } data;
    uint16_t h;
    uint8_t i;
    for(i = 0; i < 4; i++)
        data.b[i]= *bf++;
    if(en) data.L = exchg_long(data.L);
    my_xLtoa2((char *)str,data.L,8);
    return 8;
}

/*===========================================================
 *  書式指定に従い、文字列データを変換し、バッファーに追加
 *      char     *str:  変換データを格納する文字列
 *      uint8_t   *bf:  変換する元データ配列
 *      uint8_t    of:  書式、データ参照オフセット位置
 *  return -> 正常に変換(格納)できた文字数
 *----------------------------------------------------------*/
uint8_t set_RecvData(char *str, uint8_t *rbf, uint8_t of){
    char    fch;                        // 書式指定文字
    uint8_t n = 0;                      // 格納した変換文字数
    uint8_t rm;                         // 参照残りバイト
    uint8_t i;
    
    fch = Crv_Fmt[of];
    rm = 8 - of;
    switch(fch){                        // 書式文字が・・
        case 'S':                       // 文字列の場合
            for(i = 0; i < rm; i++){
                if(Crv_Fmt[of+i] == 'S'){ // 書式指定が'S'なら
                    *str++ = (char)*rbf++; // 文字をコピー
                }else{
                    break;              // 'S'でなければ変換終了
                }
            }
            n = i;                      // 書き込んだ文字数
            break;
            
        case 'C':                       // 文字を1バイトに
            if(isprint(*rbf)) *str = *rbf;
             else             *str = '*'; //0x7F;
            n = 1;
            break;
            
        case 'B':                       // 数値文字列(1-3)に
            n = set_B_S(str, *rbf);
            break;
            
        case 'H':                       // 16進文字列(2)に
            n = set_H_S(str, rbf);
            break;
            
        case 'U':                       // 数値文字列(1-5)に
            n = set_U_S(str, rbf);
            break;
            
        case 'W':                       // 16進文字列(-4)に
            n = set_W_S(str, rbf, 1);
            break;
            
        case 'L':                       // 16進文字列(-6)に
            n = set_L_S(str, rbf, 1);
            break;
    }
    return n;
}

/*==========================================================
 *  データを指定書式でデータを文字列に格納
 *      [ 参照する書式データは、Crv_Fmt() ]
 *      char     *str:  変換後に格納する文字列
 *      uint8_t  *rbf:  変換する配列データ
 *      uint8_t    sz:  受信したデータ数
 *  return -> 正常に変換(格納)できた文字数(失敗時は0)
 *---------------------------------------------------------*/
uint8_t set_RdatF(char *str, uint8_t *rbf, uint8_t sz){
    uint8_t n = 0;                      // 追加文字数カウンタ
    uint8_t of = 0;                     // 書式参照オフセット
    char fch;                           // 書式指定文字
    char ss[20];

    do{
        fch = Crv_Fmt[of];              // 対応データ位置の書式
        if(fch){
            if(of>0){
                *str = ',';             // 文字区切り追加
                str++;
            }            
            n = set_RecvData(str,rbf,of);
            if(n){                      // 変換データが有効
                switch(fch){            // 参照、変換位置移動
                    case 'S':
                        of += n; rbf += n;
                        break;
                    case 'C': case 'B': case 'H':
                        of += 1; rbf += 1;
                        break;
                    case 'U': case 'W':
                        of += 2; rbf += 2;
                        break;
                    case 'L':
                        of += 4; rbf += 4;
                        break;
                }
                str += n;               // 次格納位置へ移動
            }else{                      // 変換データが無効
                break;                  // ループ脱出
            }
        }else{                          // 書式データ無し
            break;                      // ループ脱出
        }
        if(of >= sz) break;
    }while(of < 8);                     // 有効データが7文字以内
    *str = 0;
    return of;                          // 有効データ数を返す
}

/*===================================================*
 *  CAN受信の処理                                    *
 *---------------------------------------------------*/
void CheckReceiveProcess(void) {
    union {
        unsigned char c[2];
        unsigned int i;
        } data;
    unsigned long id;

    // INTピン割り込みが有れば処理する
    if (Crv_Flg) {
        Crv_Flg = 0;                    // 割り込みフラグをクリア
        while (CAN_MSGAVAIL == mcp_checkReceive()) {
            // 受信したメッセージを読み込む,
            mcp_readMsgBuf(&Crv_len, Crv_Buf);
            id = mcp_getCanId();
            my_xtoa(Msg, (uint16_t)id, 3);      // id表示設定 
            Msg[3] = ':';  Msg[4] = ' ';

            // データフレームなら
            if (mcp_isRemoteRequest() == 0) {
                // idが一致するか表示変換モードが3なら
                if((id == Crv_id)|(DspMd == 3)){ // 書式指定表示
                    set_RdatF(Msg+5,Crv_Buf,Crv_len);
                    EU_Puts(Msg);
                    if(strlen(Msg)>OLED_SZ){
                        Msg[OLED_SZ-1] = 0;
                    }
                    i2cOLED_Prt(Msg);
                    
                }else{
                     switch(DspMd){
                        case 0:                 // 整数表示
                            data.c[0] = Crv_Buf[0];
                            data.c[1] = Crv_Buf[1];
                            my_utoa(Msg + 5, data.i);
                            OLED_EU_Prt(Msg);
                            OLED_Low_Hprt(Msg); // 半角文字表示
                            break;
                        case 1:                 // 文字列表示 
                            cv_prtcat(Msg+5, (char *)Crv_Buf, Crv_len);
                            OLED_EU_Prt(Msg);
                            OLED_Low_Hprt(Msg); // 半角文字表示
                            break;
                        case 2:                 // 16進数表示
                            set_hex_data(Msg+5,Crv_Buf,Crv_len);
                            OLED_EU_Prt(Msg);
                            break;
                    }
                }
            }else{                              // リモートフレーム
                Msg[5] = 0;
                strcat(Msg," -- Remote");				
                OLED_EU_Prt(Msg);
                if(DspMd < 2){
                    OLED_Low_Hprt(Msg);         // 半角文字表示
                }
            }
        }
    }
}

/*==========================================================
 *  受信データ処理( '|'コマンド処理 ) 
 *      char *str:  受信指示文字列
 *  Return -> 受信データ数(n=0なら送信データ無し)
 *---------------------------------------------------------*/
void CAN_Rcv_Cmd(char *str){
    char *ps;
    char cmd;
    uint32_t id;
    uint8_t n, m;

    if(strlen(RBuf) == 1){              // '|'のみ
        EU_Puts(Crv_Fmt);               // 現在書式表示
        return;
    }
    ps = ++str;                         // *psは次文字に
    cmd = (char)toupper(*ps);
    switch(cmd){
        case 'X':
            ps = strtok(ps+1,Dlm);      // 文字列の切り出し
            if(ps!=NULL){               // id指定があれば
                set_NewID(ps,1);        // 受信idをセット
            }
            break;
        case 'M':                       // 表示モード変更
            if(strlen(ps) < 2){         // "|M"の2文字なら
                DspMd++;
                chg_dspMd(DspMd);
            }else{
                m = (uint8_t)atoi(ps+1);
                chg_dspMd(m);
            }
            break;
        default:
            set_CAN_Fmt(Crv_Fmt, ps);   // 書式データを格納
            break;
    }
}

/************************************************************
 *  CAN送信の処理
 *==========================================================*/
//---- CAN送信実施(標準id、送信済み待ち)
/*      uint32_t   id:  11ビット識別子
 *      uint8_t  *buf:  送信するデータ列アドレス
 *      uint8_t   len:  送信するバイト数(len=0ならリモート)
 *---------------------------------------------------------*/
void CAN_Send(uint32_t id, uint8_t *buf, uint8_t len){
    uint8_t res;
    if(len == 0)
        res = mcp_sendMsgBuf(id,CAN_STDID,CAN_RMTFRM,0,buf,1);
    else
        res = mcp_sendMsgBuf(id,CAN_STDID,CAN_DTFRM,len,buf,1);
}

//--- 最大8文字の文字列を(Csd_idで)CAN送信
void CAN_Snd_str(char *buf){
    uint8_t n;
    n = (uint8_t)strlen(buf);
    if(n > 8) n = 8;
    CAN_Send(Csd_id,(uint8_t *)buf,n);    
}

/*==========================================================
 *  文字列データを指定書式で変換しバイナリー配列に追加
 *---------------------------------------------------------*/
//---- 数値文字列 -> 1バイトバイナリー
uint8_t set_S_B(uint8_t *bf, char *str){
    *bf = (uint8_t)atoi(str);
    return 1;
}
//---- 数値文字列 -> 2バイトバイナリー
uint8_t set_S_U(uint8_t *bf, char *str, uint8_t en){
    union {  char       c[2] ;
             uint16_t   u ;     } dt ;
    dt.u = (uint16_t)atoi(str);
    if(en) dt.u = exchg_word(dt.u);     // 上下バイト入替
    bf[0] = dt.c[0], bf[1] = dt.c[1];
    return 2;
}
//---- 16進数文字列 -> 1バイトバイナリー
uint8_t set_S_H(uint8_t *bf, char *str){
    *bf = (uint8_t)my_xtol(str);
    return 1;
}
//---- 16進数文字列 -> 2バイトバイナリー
uint8_t set_S_W(uint8_t *bf, char *str, uint8_t en){
    union {  char       c[2] ;
             uint16_t   w ;     } dt ;
    dt.w = (uint16_t)my_xtol(str);
    if(en) dt.w = exchg_word(dt.w);     // 上下バイト入替
    bf[0] = dt.c[0], bf[1] = dt.c[1];
    return 2;
}
//---- 16進数文字列 -> 4バイトバイナリー
uint8_t set_S_L(uint8_t *bf, char *str, uint8_t en){
    union {  char       c[4] ;
             uint32_t   L ;
          }   dt ;
    dt.L = my_xtol(str);
    if(en) exchg_long(dt.L);           // 上下バイト入替
    bf[0] = dt.c[0], bf[1] = dt.c[1];
    bf[2] = dt.c[2], bf[3] = dt.c[3];
    return 4;
}

/*===========================================================
 *  書式指定に従い、文字列データを変換し、バッファーに追加
 *      char      fch:  書式指定文字
 *      uint8_t   *bf:  格納データ配列(最大8byte)
 *      char     *str:  変換する文字列
 *      uint8_t    sz:  格納出来るデータサイズ
 *  return -> 正常に変換(格納)できた文字数
 *----------------------------------------------------------*/
uint8_t set_SendData(char fch, uint8_t *bf, char *str, uint8_t sz){
    uint8_t n,i,p;
    p = 8 - sz;
    switch(fch){
        case 'S':                       // 文字列
            n = (uint8_t)strlen(str);
            if(n > sz) n = sz;
            for(i = 0; i < n; i++){     // 最大n文字
                if(Csd_Fmt[p+i]=='S'){  // 書式指定が'S'なら
                    *bf++ = (uint8_t)*str++; // 文字をコピー
                }else{
                    break;              // 'S'でなければ中断
                }
            }
            n = i;                      // 書き込んだ文字数
            break;
        case 'C':                       // 文字を1バイトに
            *bf = (uint8_t)*str; n = 1;
            break;
        case 'B':                       // 数値文字列を1バイトに
            set_S_B(bf, str); n = 1;
            break;
        case 'H':                       // 16進文字列を1バイトに
            set_S_H(bf, str); n = 1;
            break;
        case 'U':                       // 数値文字列を2バイトに
            set_S_U(bf, str, 0); n = 2;
            break;
        case 'W':                       // 16進文字列を2バイトに
            set_S_W(bf, str, 0); n = 2;
            break;
        case 'L':                       // 16進文字列を4バイトに
            set_S_L(bf, str, 0); n = 4;
            break;
    }
    return n;
}

/*==========================================================
 *  文字列を切り出し、指定書式でデータを変換し配列に格納
 *      [ 参照する書式データは、Csd_Fmt() ]
 *      uint8_t   *bf:  格納する配列データ
 *      char     *str:  変換される文字列
 *  return -> 正常に変換(格納)できた文字数(失敗時は0)
 *---------------------------------------------------------*/
uint8_t set_SdatF(char *bf, char *str){
    char *ps;                           // 切出し文字列ポインタ
    uint8_t n;                          // 変換・設定済バイト数
    uint8_t p = 0;                      // 書式参照位置
    char fch;                           // 書式指定文字

    ps = strtok(str,Dlm);               // 文字列の切り出し
    do{
        if(ps==NULL) break;             // 文字列がなければ
        fch = Csd_Fmt[p];               // 対応データ位置の書式
        if(fch){
            n = set_SendData(fch,Csd_Buf+p,ps,8-p);
            if(n)   p += n;             // 変換データが有効
             else   break;              // 変換データが無効
        }
        else{                           // 書式データ無し
            break;
        }
        ps = strtok(NULL,Dlm);          // 次の文字列取得
    }while(p < 8);                      // 有効データが7文字以内
    return p;                           // 有効データ数を返す
}

/*==========================================================
 *  送信データ処理( '~'コマンド処理 ) 
 *      char *str:  送信指示文字列
 *  Return -> 有効送信データ数(n=0なら送信データ無し)
 *---------------------------------------------------------*/
void CAN_Snd_Cmd(char *str){
    char *ps;
    char cmd;
    uint32_t id;
    uint8_t n, m;

    if(strlen(RBuf) == 1){              // '~'のみ
        EU_Puts(Csd_Fmt);               // 現在書式表示
        return;
    }
    ps = ++str;                         // *psは次文字に
    cmd = (char)toupper(*ps);
    switch(cmd){
        case 'X':  case 'R':
            ps = strtok(ps+1,Dlm);      // 文字列の切り出し
            if(ps!=NULL){               // id指定があれば
                set_NewID(ps,0);
            }
            if( cmd == 'R')             // リモート指示なら
                CAN_Send(Csd_id,Csd_Buf,0); // リモートCAN送信
            break;
        case 'M':                       // 表示モード変更
            if(strlen(ps) < 2){         // "|M"の2文字なら
                DspMd++;
                chg_dspMd(DspMd);
            }else{
                m = (uint8_t)atoi(ps+1);
                chg_dspMd(m);
            }
            break;
        default:
            set_CAN_Fmt(Csd_Fmt, ps);   // 書式データを格納
            break;
    }
}

/*==========================================================
 *  有効なデータをCAN送信
 *      char *str:  送信したいデータ
 *      (データは指定書式に従い、変換されて送信される)
 *---------------------------------------------------------*/
uint8_t CAN_SendData(char *str){
    uint8_t sn = 0;
    uint8_t i;
    char *p;
    
    sn = set_SdatF(Csd_Fmt, str);       // 書式付きデータセット
    if(sn){                             // データが有効なら
        CAN_Send(Csd_id,Csd_Buf,sn);    // CAN送信実施
        sprintf(Msg,"%3X : ",Csd_id);
        p = Msg + 6;
        for( i= 0; i < sn; i++){
            my_xtoa(p,Csd_Buf[i],2);
            p+=2;
        }
        *p = 0;
        EU_Puts(Msg);                   // データは16進数文字列で
    }
    return sn;
}

/***********************************************************
 *  スイッチアクション
 *---------------------------------------------------------*/
//---- RA3スイッチ・チェック・処理
void chk_RA3_Proc(void){
    if(RA3_GetValue()==0){              // RA3_SWが押されていたら
        __delay_ms(40);                 // チャッタリング対策
        if(RA3_GetValue()==0){          // まだ押されていたら
            chg_dspMd(++DspMd);
            while(RA3_GetValue() == 0); // キーが離れるまで待つ
        }
        __delay_ms(100);                // チャッタリング対策
    }
}

//---- SW0(RA0)スイッチ・チェック・処理
void chk_SW0_Proc(void){
    static uint8_t d[] = { '0',0 };
    if(SW0_GetValue() == 0){            // SW0が押されていたら
        __delay_ms(40);                 // チャッタリング対策
        if(SW0_GetValue() == 0){        // まだ押されていたら
            d[0] ^= 1;                  // ビット0を反転
            CAN_Send(0x149,d,1);        // データ1文字CAN送信
            while(SW0_GetValue() == 0); // キーが離れるまで待つ
        }
        __delay_ms(100);                // チャッタリング対策
    }
}

/********************************************************
 *       Main application                               *
 ********************************************************/
void main(void) {
    uint8_t cmd;                        // コマンド
    uint8_t buf[8];                     // CANデータ用
    uint8_t sw;                         // スイッチ情報
    char    s[12];
  
    SYSTEM_Initialize();
    SSP1CON1bits.SSPEN = 1;             //SPI1を有効に

    TMR0_SetInterruptHandler(TMR0_Process);     // Timer0 Callback関数
    IOCCF2_SetInterruptHandler(IOCCF2_Process); // Pin割込CallBack

    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();


    i2cOLED_init();
    i2cOLED_Clr(0, 7, 0);

    LED_SetHigh();
//    __delay_ms(1000);                 // CANモジュール準備待ち

    EU_Puts("start");

    // MCP25625によるCAN通信の初期化
    // CANバス通信速度=100Kbps  MCP25625のクロック=16MHz
    while (CAN_OK != mcp_begin(CAN_100KBPS, MCP_16MHz)) {
        OLED_EU_Prt("InitFail");
        exit(1);                        // エラー終了
    }
    OLED_EU_Prt("Init OK!");

    // MASK0->Filter0->RXB0(オーバフローでRXB1)のみ使用
    mcp_init_Mask(0, 0, 0x3ff);         // 全て受付る
    mcp_init_Filt(0, 0, Crv_id);        // 受信Allですが
    // MCP_PXB_RX_ANYに設定するとフィルター基準は無視
  
    OLED_EU_Prt("ready!");   
    
    while (1) {
        if(TFlg){                       // タイマー割込有り?
            TFlg = 0;
            LED_Toggle();               // LED点灯トグル
        }  
       
        chk_RA3_Proc();                 // RA3スイッチ処理
//        chk_SW0_Proc();               // SW0(RA0)スイッチ処理
        
        CheckReceiveProcess();          // CAN受信データ確認・処理
        
        if (SFlg) {                     // シリアル入力があれば
            cmd = RBuf[0];
            switch (cmd) {
                case '~':               // 送信書式設定など
                    CAN_Snd_Cmd(RBuf);
                    break;

                case '|':               // 受信書式設定など
                    CAN_Rcv_Cmd(RBuf);
                    break;

                case '^':               // コマンドが'^'なら
                    if(strlen(RBuf)>0)
                        CAN_Snd_str(RBuf+1);  // 文字列送信
                    break; 

                default:
                    CAN_SendData(RBuf); // 書式変換データをCAN送信
                    break;
            }
            SFlg = 0;
        }
    }
}
/*************** End of File **********************/

※すべてのテストが終わっていないのでバグがあるかも知れません。m(__)m

【その他のプログラム】

mcp_can_dfs.h(zip)
skMCP25xx.c/h(zip)
myProject.h(zip)
myFunction.c/h(zip)
i2c_SSD1306.c/h(zip)
Font_5x7.h+Font_8x16ASC.h+Font_8x16NA.h(zip)
Font_5x7.h:
5x7ドットアスキー文字
Font_8x16ASC.h:
8x16ドットアスキー文字
Font_8x16NA.h:
8x16ドット英(大文字のみ)数文字+α
※ EUSARTの設定についてはabc917等を参照


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


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


EdgeでIEモードが使えない 半導体パッケージ USBシリアル-CANコンバータ(2)