/***********************************(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 ***********************************/
|