Vol.932 12.Dec.2025

タイヤ・リフター OneDriveの同期を解除したい USBシリアル-CANコンバータ

L タイヤ・リフター

by fjk

 毎年、冬が近づくと冬用タイヤに交換しているが、タイヤの穴がなかなか合わず、重い物を持ち上げる続けるのに苦労することがある。こんな時に便利なのが、タイヤリフター(クルピタ丸)である。
 クルピタ丸(エマーソン、@4,980)は組み立て式で、組立後、タイヤを乗せて、ハンドルを回して高さ調整を行い、さらにタイヤを回して取付け穴の位置に合わせることができる。重いタイヤを持ち上げる重労働から解放され、高齢者と腰が痛い人のタイヤ交換には、必需品かな。。


クルピタ丸ーの概要

タイヤ交換作業中


O OneDriveの同期を解除したい

by fjk

 MicrosoftのOneDriveは便利な機能ですが、思わぬファイルが同期され、ストレージが足りなくなってしまうことがある。そこで、不要なフォルダーの同期を行わないように、「同期する/しない」フォルダの設定を行った。
<参考>

● フォルダーの同期を設定・解除するには、

  1. タスクバーのOneDriveアイコン(雲のマーク)をクリック
  2. 表示されたウィンドウの右上にある歯車アイコンをクリックし、「設定」を選択
  3. 「アカウント」タブを選択し、「フォルダーの選択」をクリック
  4. 同期しているフォルダの一覧で、同期を解除したいフォルダのチェックボックスを外す

● 自動バックアップを停止するには、上記の1,2と同じように「設定」を選択、後、

  1. 「同期とバックアップ」タブを選択し、「バックアップを管理」をクリック
  2. バックアップのオン/オフを切り替えるボタンを「オフ」にする


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

by fjk

 abc930でMCP25625を使ったCANトランシーバーを作製したが、SSOPパッケージのハンダ付けが苦手な方のために、abc931で紹介したMCP25625-BreakOutを使ったCANトランシーバー(1)、そして、データ書式変換機能を有するUSBシリアル−CANコンバーター(2)を紹介する。

1.MCP25625CANBO利用CANトランシーバー 【ノード6B】
 ADT7410による温度測定、データ表示、USBシリアル接続、CANデータ送受信と、その機能はabc930の「おまけ3」と同じ。なお、プログラムはabc930とほぼ同じだが、PICの利用端子がabc930と異なるので注意が必要。
   @MCCで各ポートを変更。さらに、CAN受信割込ハンドラーも 「 IOCCF2_****」 に変更すること。
   Amcp_can_dfs.hでMCP25625BOのCSポートを変更。
 さらに、メッサージの文字数を減らし、PIC18F325(ROM=8k、99.8%)も利用出来るようした。そして、RC3に動作確認用LEDを接続した(割込のINTを利用しないならRC2も汎用ポートとして利用可)。

【ハード】


PIC16F18325/326+AQM8020AとADT7410

BB(ブレッドボード)配線例

Pin Modules

CAN送受信テスト例(id=131受信時)

【ソフト】   ・abc932-18325.c [ノード6B]

  • CSのポート番号をRC1に変更: #define MCP25XX_SPI_CS LATAbits.LATC1  (mcp_can_dfs.h)
  • 上記のmcp_can_dfs.hのCS宣言以外、myProject.h、sKMCP25xx.c/h、はabc930と同じ。


 

2.USBシリアル−CANコンバータ (今回は送信のみ)【ノード6B2】
前記のトランシーバーはターミナルから入力した文字列を、そのままCAN送信しているが、シリアル受信文字列からバイナリーデータなどに変換して、CAN送信できるコンバータを作製した。
 
<送信>
・USB接続シリアルターミナルから送られた文字列データを、指定された条件で数値をバイナリーデータ等へ変換し、CANバスにそのデータを送信する。
・送信条件は、~(チルダー)に続く文字列で指定する。
・送信時は文字列の先頭文字が、 ~ または ^ 以外の場合、指定された条件で、CAN送信する。
 
<受信>
・受信機能はabc930と同じ(そのまま)で、id = 0x123の受信データを表示。

【ハード】
PICを16F18326に変更した以外は、前記の回路をそのまま利用。
 
【ソフト】  ・abc932-18326.c [ノード62B]
@ 8バイトの送信書式文字列データ Fsd[8] を利用し、各バイトに、下記の書式データを格納。
A 送信データ書式の指定
  ~(チルダー)に続けて書式文字を入力。複数を指定する場合は、コンマ区切りで続けて入力
  • n は書式指定文字数(オプション、型バイト数×nバイト、指定無しは n = 1)
  • n の無い S のみは最大8文字まで可変長文字列(以降の書式文字は無視)
  • ~(チルダー)のみは現在書式を表示
  • X/R/Tはコマンド。hhh は16進数(0xは付けない)
  • 指定文字は大小文字を問わない(大文字に自動変換)
    <書式指定例> ~C,U,H2
 
B ^(ハット)は "~T" と同じ(温度送信モード変更)
C 先頭文字が ~ or ^ 以外の場合、(データが複数ある場合はコンマ区切りで)入力されたデータを、指定された書式で変換し、CAN送信を実施。
D 送信データは16進数でシリアルターミナルにも表示


変換データ受信例
 

【テスト時】

  • ノード6B2のCAN送信データは、ノード5(CANモニター)のOLEDに表示されるので、ノード5の表示モードを「16進数表示」など、適当に変更して下さい。
  • 送信データの先頭文字を変えると、そのビット0に応じてノード7のLED点灯が変わります。


≪≪ ノード6B ≫≫   ▼abc930-18325.c(zip)

/***********************************(abc930-18325.c)*****
 *      CAN Transiever (MCP25625BO)     <ノード6B>    *
 ********************************************************/

#include "myProject.h"
#include "myFunction.h"
#include "mcp_can_dfs.h"
#include "skMCP25xx.h"
#include "i2c_LCD_lib.h"

#define  ADT_ADR  0x48                  // ADT I2Cアドレス

#define  MBF_SIZE    64                 // メッセージ用BFサイズ

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

//-----  EUSARTシリアル用
char     RBuf[EU_BFSIZE];               // 受信文字Buffer
uint8_t  SFlg;                          // 受信フラグ

//---- 汎用データ処理用
char     Msg[MBF_SIZE];                 // コメント等送信用文字列

//---- CAN用共通変数の宣言
char     flagRecv = 0 ;                 // CAN受信有無フラグ
uint8_t  R_len = 0 ;                    // CAN受信データサイズ
char     RcvBuf[9];                     // CAN受信データ
uint8_t  S_len = 0 ;                    // CAN送信データサイズ
char     SndBuf[9];                     // CAN送信データ
uint8_t  T_Snd = 1;                     // 温度送信フラグ
uint32_t S_id = 0x149;                  // 送信id
		
/************************************************
  *  タイマ0 Callback関数 (1秒周期割り込み)      *
 ************************************************/
void TMR0_Process(void){
    TFlg = 1;                           // タイマーフラグセット
}

void chg_TM0_INT(void){
    T_Snd ^= 1;                         // 温度送信モード変更
    if(T_Snd) PIE0bits.TMR0IE = 1;      // タイマー割込有効
     else     PIE0bits.TMR0IE = 0;      // タイマー割込無効
}

//----  MCP25625のINTピン割り込み
void IOCCF2_Process(void){
     flagRecv = 1 ;                     // CAN割込有りフラグセット
}

/************************************************/
//---- 温度データの計算
uint16_t calc_Temp(char *bf, uint16_t tDat){
    uint16_t tp;
    if(tDat & 0x8000){                          // 負数
        tp = ((8192 - (tDat >> 3)) * 10) / 16;
        sprintf(bf,"-%2d.%1dC", tp / 10, tp % 10);
    }else{                                      // 正数なら
        tp = ((tDat >> 3) * 10) / 16;
        sprintf(bf,"%3d.%1dC", tp / 10, tp % 10);
    }
    return tp;
}

//---- 温度データの表示 ----
uint16_t prt_Temp(uint16_t tDat){
    uint16_t  tp;
    sprintf(Msg,"Tmp:%04X",tDat);
    EU_Write(Msg);
    LCD_clr(); LCD_str(Msg);
    tp = calc_Temp(SndBuf, tDat);
    EU_Puts(SndBuf);
    LCD_cursor(1,1); LCD_str(SndBuf);
    return tp;
}

//--- 温度データの取得
uint16_t get_ADT7410(void){
    uint16_t temp;
    I2C2_ReadNBytes(ADT_ADR,(uint8_t *)&temp,2); // 温度データ読込
    temp = (temp<<8) | ((uint8_t)(temp>>8));    // 上下バイトデータ入替
    prt_Temp(temp);
    return temp;
}

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

    while (CAN_MSGAVAIL == mcp_checkReceive()) {
        // 受信したメッセージを読み込む,
        mcp_readMsgBuf(&R_len, (uint8_t *)RcvBuf);
        // データフレームなら処理する
        if (mcp_isRemoteRequest() == 0) {
            id = mcp_getCanId() ;
            switch (id) {
                case 0x123 :
                    data.c[0] = RcvBuf[0] ;
                    data.c[1] = RcvBuf[1] ;
                    sprintf(Msg,"%03X:%8d",(uint16_t)id,data.i);
               //   --- sprintfを使わない場合
               //     my_xtoa(Msg,id,3); Msg[3]=':'; Msg[4]=' ';
               //     my_utoa(Msg + 5, data.i);
                    EU_Puts(Msg);
                    break ;
            }
        }
    }
}

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

/*******************************************************
 *    Main application
 *******************************************************/
void main(void)
{
    uint8_t d[] = { 0x30, 0x40 };
    char cmd;
    uint8_t *p, n;
    // initialize the device
    SYSTEM_Initialize();
    SSP1CON1bits.SSPEN = 1;
    LCD_init();

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

    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();

    // MCP25625によるCAN通信の初期化
    // CANバス通信速度=100Kbps  MCP25625のクロック=16MHz
    while (CAN_OK != mcp_begin(CAN_100KBPS,MCP_16MHz)) {
        LCD_str("InitFail") ;
        while(1) ;                          // 終了
    } 
    LCD_str("Init OK!") ;
    LED_SetHigh();
    
    // MASK0->Filter0->RXB0(オーバフローでRXB1)のみ使用します。
    mcp_init_Mask(0, 0, 0x3ff) ;            // 全て受付る
    mcp_init_Filt(0, 0, 0x123) ;            // ID:0x123のみ受け取る

    EU_Puts("-- Ok\n");                     //  LCD_str("Ready");

    while (1){
        if(TFlg){
            TFlg = 0;
            get_ADT7410();
            S_len = (uint8_t)strlen(SndBuf);
            p = (uint8_t *)SndBuf;
            if(T_Snd)                       // 温度送信モードなら
                CAN_Send(0x123, p, S_len);
        }
        if(flagRecv) {
            flagRecv = 0 ;                  // 割り込みフラグをクリア
            CAN_Receive();                  // CAN受信データを取得・処理
        }
        if(IO_RA3_GetValue()==0){           // RA3_SWが押されていたら
            T_Snd ^= 1;                     // 温度送信モード変更
            if(T_Snd) PIE0bits.TMR0IE = 1;  // タイマー割込有効
             else     PIE0bits.TMR0IE = 0;  // タイマー割込無効
            while(IO_RA3_GetValue() == 0);  // キーが離れるまで待つ
            __delay_ms(100);
        }
        if(SW0_GetValue()==0){              // SW0が押されていたら
            d[0] ^= 1;                      // ビット0を反転
            CAN_Send(0x149,d,1);            // データ1文字CAN送信
            while(SW0_GetValue() == 0);     // キーが離れるまで待つ
            __delay_ms(100);
        }
        if(SFlg){
            EU_Puts(RBuf);
            cmd = RBuf[0];
            p = (uint8_t *)RBuf;
            n = (uint8_t)strlen(RBuf) - 1;
            if(n > 8) n = 8;
            switch(cmd){
                case 'T':
                    T_Snd ^= 1;             // 温度送信モード変更
                    break;
                case 'R':
                    CAN_Send(S_id,p,0);     // リモート送信
                    break;
                case 'S':
                    CAN_Send(S_id,p+1,n);   // 文字列CAN送信
                    break;
                case 'X':
                    S_id = my_xtol(RBuf+1); // 送信id設定
                    break;
            }
            SFlg = 0;
        }
    }
}
/*************** End of File **********************/


≪≪ ノード6B2 ≫≫   ▼abc932-18326.c(zip)

/***********************************(abc932-18326.c)********
 *      USB-CAN Converter  (MCP25625BO使用)  <ノード6B2> *
 ***********************************************************/

#include "myProject.h"
#include "myFunction.h"
#include "mcp_can_dfs.h"
#include "skMCP25xx.h"
#include "i2c_LCD_lib.h"

#define  ADT_ADR  0x48                  // ADT I2Cアドレス

#define  MBF_SIZE    64                 // メッセージBFサイズ

void CAN_Send(uint32_t id, uint8_t *buf, uint8_t len);


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

//---- EUSARTシリアル用
char     RBuf[EU_BFSIZE];               // 受信文字Buffer
uint8_t  SFlg;                          // 受信フラグ

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

//---- CAN用共通変数
uint32_t Crv_id = 0x123;                // 受信id
char     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送信書式データ

//---- 温度データ処理用
uint8_t  Tmp_Snd = 1;                   // 温度送信フラグ
char     Tmp_Buf[9];                    // 変換後温度データ

/************************************************************
 *  汎用関数 (my_function.cに移行予定)
 *==========================================================*/
//--- バイトデータの交換
void swap_b(uint8_t *a, uint8_t *b){
    uint8_t temp;
    temp  = *a;
    *a = *b;
    *b = temp;
}
//--- ワードデータの交換
void swap_w(uint16_t *a, uint16_t *b){
    uint16_t temp;
    temp  = *a;
    *a = *b;
    *b = temp;
}
//---- 2バイトデータの上下バイト変換
uint16_t exchg_word(uint16_t wd){
    wd = (wd<<8) | ((uint8_t)(wd>>8));  // 上下バイトデータ入替
    return wd;
}
//---- 4バイトデータの上下バイト変換
uint32_t exchg_long(uint32_t Ld){
    union {  uint8_t   b[4];
             uint32_t  L;    } dt ;
    dt.L = Ld;
    swap_b(&dt.b[0], &dt.b[3]);
    swap_b(&dt.b[1], &dt.b[2]);
    return dt.L;
}

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

//--- タイマー0 割込有効/無効切り替え
void chg_TM0_INT(void){
    Tmp_Snd ^= 1;                 // 温度送信モード変更
    if(Tmp_Snd){       
        PIE0bits.TMR0IE = 1;      // タイマー割込有効
        EU_Puts("Int_TM0 Enable");
    }else{      
        PIE0bits.TMR0IE = 0;      // タイマー割込無効
        EU_Puts("Int_TM0 Disenable");
    }
}
//----  MCP2562のINTピン割り込み
void IOCCF2_Process(void){
     Crv_Flg = 1 ;                // CAN割込有りフラグセット
}

/***********************************************************
 *  温度センサー関係
 *=========================================================*/
//---- 温度データの計算
uint16_t calc_Temp(char *bf, uint16_t tDat){
    uint16_t tp;
    if(tDat & 0x8000){                  // 負数なら
        tp = ((8192 - (tDat >> 3)) * 10) / 16;
        sprintf(bf,"-%2d.%1dC", tp / 10, tp % 10);
    }else{                              // 正数なら
        tp = ((tDat >> 3) * 10) / 16;
        sprintf(bf,"%3d.%1dC", tp / 10, tp % 10);
    }
    return tp;
}
//---- 温度データの表示 ----
uint16_t prt_Temp(uint16_t tDat){
    uint16_t  tp;
    sprintf(Msg,"Tmp:%04X",tDat);       // 変換前データ表示
   // --- sprintfを使わない場合
   // strcmp(Msg,"Tmp:"); my_xtoa(Msg+4,tDat,4);
    EU_Write(Msg);
    LCD_clr(); LCD_str(Msg);            // LCD1行目に表示
    tp = calc_Temp(Tmp_Buf, tDat);      // 温度データ計算
    EU_Puts(Tmp_Buf);
    LCD_cursor(1,1); LCD_str(Tmp_Buf);  // LCD2行目に表示
    return tp;
}
//--- 温度データの取得
uint16_t get_ADT7410(void){
    uint16_t temp;
    I2C2_ReadNBytes(ADT_ADR,(uint8_t *)&temp,2); // 温度データ読込
    temp = exchg_word(temp);            // 上下バイトデータ入替
    prt_Temp(temp);                     // 温度データの表示
    return temp;
}
//--- 温度チェック・処理
void chk_Tmp_Proc(void){
    uint8_t *p;
    if(TFlg){                           // TM0割込有れば?
        TFlg = 0;                       // TMO割込フラグをクリア
        if(Tmp_Snd){                    // 温度送信モードなら
            get_ADT7410();              // 温度データ取込
            Csd_len = (uint8_t)strlen(Tmp_Buf);
            p = (uint8_t *)Tmp_Buf;
            CAN_Send(0x123, p, Csd_len); // 温度データをCAN送信
        }
    }
}

/************************************************************
 *  送受信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){
        if(sr){
            Crv_id = id;
            sprintf(Msg,"Snd_ID = %3X",Crv_id);
        }else{
            Csd_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受信の処理
 *---------------------------------------------------------*/
//---- CAN受信確認&処理
void chk_CANrcv_Proc(void){
    union {  unsigned char c[2] ;
             unsigned int  i ;
          }   data ;
    uint32_t id;

    if(Crv_Flg) {                       // CAN受信があれば
        Crv_Flg = 0 ;                   // CAN割込みフラグをクリア
        while (CAN_MSGAVAIL == mcp_checkReceive()) {
            // 受信したメッセージを読み込む,
            mcp_readMsgBuf(&Crv_len, (uint8_t *)Crv_Buf);
            // データフレームなら処理する
            if (mcp_isRemoteRequest() == 0) {
                id = (uint32_t)mcp_getCanId() ;
                if(id == Crv_id) {
                        data.c[0] = Crv_Buf[0] ;    // バイトの入替
                        data.c[1] = Crv_Buf[1] ;
                        sprintf(Msg,"%03X:%8d",id,data.i);
                    //   --- sprintfを使わない場合
                    //     my_xtoa(Msg,id,3); Msg[3]=':'; Msg[4]=' ';
                    //     my_utoa(Msg + 5, data.i);
                        EU_Puts(Msg);
                }
            }
        }
    }
}

/************************************************************
 *  CAN送信の処理
 *==========================================================*/
//---- CAN送信実施(標準id、送信済み待ち)
/*      uint32_t   id:  11ビット識別子
 *      uint8_t  *buf:  送信するデータ列アドレス
 *      uint8_t   len:  送信するバイト数* 
 *----------------------------------------------------------*/
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);
}

/*==========================================================
 *  文字列データを指定書式で変換しバイナリー配列に追加
 *---------------------------------------------------------*/
//---- 数値文字列 -> 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;

    if(strlen(RBuf) == 1){              // '~'のみ
        EU_Puts(Csd_Fmt);               // 現在書式表示
        return;
    }
    ps = ++str;                         // *psは次文字に
    cmd = *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 'T':
            chg_TM0_INT();              // 温度送信モード変更
            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);
    }
    return sn;
}

/***********************************************************
 *  スイッチアクション
 *---------------------------------------------------------*/
//---- RA3スイッチ・チェック・処理
void chk_RA3_Proc(void){
    if(IO_RA3_GetValue()==0){           // RA3_SWが押されていたら
        __delay_ms(40);                 // チャッタリング対策
        if(IO_RA3_GetValue()==0){       // まだ押されていたら
            chg_TM0_INT();              // 温度送信モード変更
            while(IO_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)
{
    char cmd;
    uint8_t *p, n;
    // initialize the device
    SYSTEM_Initialize();                // システム初期化
    SSP1CON1bits.SSPEN = 1;             // SPIを有効に
    LCD_init();                         // LCDを初期化

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

    INTERRUPT_GlobalInterruptEnable();  // 汎用割込許可
    INTERRUPT_PeripheralInterruptEnable(); // 周辺割込許可

    // MCP25625によるCAN通信の初期化
    // CANバス通信速度=100Kbps  MCP25625のクロック=16MHz
    while (CAN_OK != mcp_begin(CAN_100KBPS,MCP_16MHz)) {
        LCD_str("InitFail") ;
        exit(1) ;                       // エラー終了
    } 
    LCD_str("Init OK!") ;
    LED_SetHigh();
    
    // MASK0->Filter0->RXB0(オーバフローでRXB1)のみ使用します。
    mcp_init_Mask(0, 0, 0x3ff);         // 全て受付る
    mcp_init_Filt(0, 0, Crv_id);        // ID:0x123のみ受け取る

    EU_Puts("- CAN use OK\n");

    while (1){
        chk_Tmp_Proc();                 // 温度データ処理
        chk_RA3_Proc();                 // RA3スイッチ処理
        chk_SW0_Proc();                 // SW0(RA0)スイッチ処理
        chk_CANrcv_Proc();              // CAN受信処理

        if(SFlg){                       // シリアル入力有れば?
            p = (uint8_t *)RBuf;
            n = (uint8_t)strlen(RBuf) - 1;
            if(n > 8) n = 8;
            cmd = RBuf[0];              // コマンドは先頭文字
            switch(cmd){
                case '~':               // コマンドが'~'なら
                    CAN_Snd_Cmd(RBuf);  // 送信条件設定
                    break;
                case '^':               // コマンドが'^'なら
                    chg_TM0_INT();      // 温度送信モード変更
                    break; 

                default:
                    CAN_SendData(RBuf); // データをCAN送信
                    break;
            }
            SFlg = 0;
       }
    }
}

/*********** end of file ***********************************/

【その他のプログラム】

mcp_can_dfs.h(zip)
skMCP25xx.c/h(zip)
myProject.h(zip)
myFunction.c/h(zip)
i2c_LCD_lib.c/h(zip)
※ EUSARTの設定についてはabc917等を参照


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


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


タイヤ・リフター OneDriveの同期を解除したい USBシリアル-CANコンバータ