2017/12/19

WR250R タコメーター 水温計 回路図

最近1巻が発売された速水螺旋人の「男爵にふさわしい銀河旅行」のランパチカに脳をやられてしまった。電球マークのフェースプレート、手首のごついフランジ、宇宙服みたいな質感のメイド服、パーフェクトだ。元々はiMacの擬人化キャラだったと思うがここまで魅力的だとは思わなかった。顔のプレートを外したらアースライト姫に瓜二つだったとか実は姫その人だったとかそういう展開になったら楽しいなあ。アゾンかどこかから立体化して出ないものかなあ。

ウイッチャー3がセールで安かったので今更プレイしてみたのだがこれもどはまりしてしまった。不満な点が多少あるものの、ストーリーが圧倒的に面白い。もうそろそろ終わりかな、と思ったところからさらに話がグイグイ進む。不満な点というのは些細な事で、町や村の中を歩いていると咳や唾を吐く音が不自然にリアルでヘッドホンでプレイするのが非常につらい。西成か山谷シミュレーターかっていうくらい汚い。あとはそのへんのこすっからい農奴を無闇に切り伏せたりできない。カジュアルに村を燃やしたりできないのが微妙にストレスだ。まあ、主人公のゲラルトさんはそういう事をしないんだろうけど、たまには悪いことをしたっていいんじゃないかな。
今思いついたんだがゲラルトさんってスケベだし、魔女のセックスフレンドが何人もいるし、国王とかに知り合いがいるし、大きな剣をかついでるし、 これはもう事実上のランスシリーズなんじゃないかな。馬のローチにピンクのもこもこヘアーをつけたらシイルではないか。違うところといったらむやみやたらに村娘を犯して回らないことくらいだ。今度ゲラルトさんを茶髪にして鎧を緑色に染めてみよう。


で、タイトルのタコメーターだ。キットにしてメルカリで売ろうと考えていたのだがどうにも売れそうもないし、売れてもよくわからん狂人相手にサポートするのも面倒なので放置していたものをブログの埋め草にすることにした。

ECUとメーターの間でシリアル通信を行っているのを傍受して表示させようというものです。回転数、水温、速度のデータが取れます。速度は解読できていないので表示できないです。ここが解読できたら完全自作のメーターとか作れそうだけど別に純正のメーターでも困ってないので特に手はつけてません。


 回路図です。LINからの信号を分圧してマイコンで取り込んで液晶に表示させるだけのシンプルな回路です。

割り込ませる場所はここです。

 ECUから出てスピードメーターに繋がっている黄/青の線がそうです。年式によって違うかもしれないのでテスターとかで確認してください。12vの振幅のある信号が流れているので注意してください。この線からECUの書き換えができたりします。書き換えのプロトコルもキャプチャーして保存してあるので簡単な書き換え装置まであと一歩なんですが、需要があるのかないのかさっぱりわからないので放置状態です。

一応XC16のソースも載せておくのでArduinoで作り直すなりしてください。
水温と回転数の補正式はどこかのフォーラムに載っていたものを使ったので何がどうだったのか忘れました。
昔作ったプログラムとか自分で見てもさっぱり何やってたかわからないですね。
通信は15625bpsのシリアル通信です。
フォーマットは0x01のヘッダーに続いて回転数、謎、速度、水温、チェックサムが続きます。 
なんか同年代のヤマハの他のバイクでも同じような規格らしいので色々試してください。

追記:R6のプロトコルを見ていると気温のパラメーターもある模様。車種によって違うのか5バイト目はチェックサムじゃなかったのか検証するのも手間だからわからん。2バイト目はエラーコードになっていたがこれも解読する価値はそんなになさそう。

 /*
 * File:   main.c
 * Author:
 *
 * Created on 2015/04/04, 18:01
 */
#define FCY 16000000UL

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>        /* Includes uint16_t definition                    */
#include <stdbool.h>       /* Includes true/false definition                  */
#include <string.h>
#include <p24FJ64GA002.h>
#include <math.h>
#include <spi.h>

#include <libpic30.h>


#define PI  3.14159


  #define LCD_ADDR  0b01111100
  #define LCD_CMD    0x80  //c0=1  d/c=0
  #define LCD_DATA    0b01000000  //c0=1  d/c=0

unsigned char BUF[6];
int DAT_POS=0;
int RCV_FLG=0;

 unsigned int RPM;
 int E_TEMP;


/*
 *
 */
 void IdleI2C1();
  int makeWord(unsigned char HB, unsigned char LB);
int validateData(void);


  /* TIMER5 interrupt DISPLAY AND EXUP */
void __attribute__((interrupt,auto_psv)) _T5Interrupt(void)
{


 IFS1bits.T5IF = 0;
}
  /* TIMER4 interrupt TEST */
void __attribute__((interrupt,auto_psv)) _T4Interrupt(void)
{
    IFS1bits.T4IF = 0;

}

 /* TIMER2 interrupt TACH */
void __attribute__((interrupt,auto_psv)) _IC1Interrupt(void)
{

    IFS0bits.IC1IF = 0;//clear interrupt

}

void __attribute__((interrupt,auto_psv)) _U1RXInterrupt(void)
{

    unsigned char rcv=0;

IFS0bits.U1RXIF=0;

if(U1STAbits.OERR ||U1STAbits.FERR){
U1STA &= 0xFFF0;
U1MODEbits.UARTEN = 0;
U1MODEbits.UARTEN = 1;
}else{
    IEC0bits.U1RXIE =0;
rcv = U1RXREG;
U2TXREG = rcv;
    }

__delay_ms(2);
   IEC0bits.U1RXIE =1;

}


 /* K-LINE interrupt*/
void __attribute__((interrupt,auto_psv)) _U2RXInterrupt(void)
{

    unsigned char rcv=0;

IFS1bits.U2RXIF=0;

if(U2STAbits.OERR ||U2STAbits.FERR){
U2STA &= 0xFFF0;
U2MODEbits.UARTEN = 0;
U2MODEbits.UARTEN = 1;
}else{

   
rcv = U2RXREG;
U1TXREG = rcv;
    }

if(rcv==0x01 && DAT_POS==0){
    RCV_FLG=1;
}

if( RCV_FLG==1){
BUF[DAT_POS]=rcv;
DAT_POS++;
}

if(DAT_POS==6){
    DAT_POS=0;
    RCV_FLG=0;
    if(validateData()){
   RPM=BUF[1]*40;
   E_TEMP=(BUF[4]*0.92515)-25.724;
//   printf("RPM:%d\n",RPM);
    }else{
  // printf("DAT ERR\n");
    }
}
}

 /* AD interrupt*/
void __attribute__((interrupt, auto_psv)) _ADC1Interrupt(void){

IFS0bits.AD1IF=0;

}//AD

/*
Gate Interrupt
*/
void __attribute__((interrupt, no_auto_psv)) _T1Interrupt(void){

IFS0bits.T1IF=0; //clear interrupt flag

}//capture interrupt

int validateData(void){
    /* validate k-line data checksum  */
    unsigned char  checksum;

    checksum=BUF[1]+BUF[2]+BUF[3]+BUF[4];

    if(checksum==BUF[5]){
        return 1;
    }else{
        return 0;
    }

}



void I2Cstart(){
   IdleI2C1();
   I2C1STATbits.I2COV = 0; //error flag clear
   I2C1CONbits.SEN=1;//output start
   while(I2C1CONbits.SEN);


}


void I2Cstop(){
    IdleI2C1();
    I2C1CONbits.PEN = 1; //stop output
    while(I2C1CONbits.PEN);
}



void I2Cdata(unsigned char data){

    I2C1TRN = data; // transmit 1byte
    while(I2C1STATbits.TBF);
   // while(I2C1STATbits.TRSTAT);
    while(I2C1STATbits.ACKSTAT);
    IdleI2C1();

}


 void LCDcommand(unsigned char data){
    I2Cstart();
    I2Cdata(LCD_ADDR); //send slave addr
    I2Cdata(LCD_CMD);
    I2Cdata(data);
    I2Cstop();
}

  void LCDdata(unsigned char data){
    I2Cstart();
    I2Cdata(LCD_ADDR); //send slave addr
    I2Cdata(LCD_DATA);
    I2Cdata(data);
    I2Cstop();
}
  void LCDchar(int x,int data){
    I2Cstart();
    I2Cdata(LCD_ADDR); //send slave addr
    I2Cdata(LCD_CMD);
    I2Cdata(x);
    I2Cdata(LCD_DATA);
     I2Cdata(data);
    I2Cstop();
    __delay_ms(5);
}

void LCDstr(int x,int y,char *s){
    if(y>0){
        x=x+0xC0;
    }else{
        x=x+0x80;
    }

   while(*s){
     LCDchar(x,*s++);
    x++;
}

}

  void LCDclear(){
    I2Cstart();
    I2Cdata(LCD_ADDR); //send slave addr
    I2Cdata(LCD_CMD);
    I2Cdata(0x01);
    I2Cstop();
}

 void LCDInit(){
     LCDcommand(0x38);//function set
     __delay_ms(1);
     LCDcommand(0x39);//function set
     __delay_ms(1);
     LCDcommand(0x14);//internal ofc
     __delay_ms(1);
     LCDcommand(0x70);//contrast
     __delay_ms(1);
     LCDcommand(0x56);//icon contrast
     __delay_ms(1);
     LCDcommand(0x6C);//Follower control
     __delay_ms(1);
     LCDcommand(0x38);//function set
     __delay_ms(1);
     LCDcommand(0x0C);//display on
     __delay_ms(1);
     LCDcommand(0x01);//clear display
     __delay_ms(2);
 }



/* wait idle */

void IdleI2C1(void){

 while(I2C1CONbits.SEN || I2C1CONbits.PEN || I2C1CONbits.RCEN ||
         I2C1CONbits.ACKEN || I2C1STATbits.TRSTAT);
}

  int makeWord(unsigned char HB, unsigned char LB)
{
    int dat = 0;

   dat = HB;
   dat <<= 8;
   dat |= LB;
   return dat;
}

void IoInit (void)
{
    CLKDIV=0;

    /* Initialize GPIO ports */
    AD1PCFG = 0b1111111111110000; //AN0 1 2 analog
    //LATB =  0x0000;
            TRISB=0b1000111100110011; // RB4 input

    //LATA =  0x0000;
    TRISA = 0b0000000000010111; // a0,a1 a2 a4 input
       //exup analog ra2


            //UART1
RPINR18bits.U1RXR = 1;//RX RP1
RPOR0bits.RP0R = 3;//TX  RP0

U1BRG = 25;//  38400
U1MODE = 0b1000100000000000;
U1STA  = 0b0000010000000000;

//UART2   TO K-LINE
RPINR19bits.U2RXR = 5;//RX B5
RPOR2bits.RP4R = 5;//TX  RP4

U2BRG=63; //15625bps k-LINE
U2MODE = 0b1000100000000000;
U2STA  = 0b0000010000000000;

IPC7bits.U2RXIP = 4;


/* I2C1 */
I2C1BRG=0x13;//400kHz at 16Mhz
I2C1CON=0x8000; //enable I2C1

        LATBbits.LATB7=1;

        __delay_ms(10);
                LATBbits.LATB7=0;
        __delay_ms(40);
        LATBbits.LATB7=1;

        LCDInit();

//IEC0bits.AD1IE = 1; //AD interrupt enable

}

/* int to ascii */
void ltostring(char digit,unsigned long data,char *buffer){
        int dig,num;
    char i;

    buffer+=digit;
    *buffer=0;
    for(i=digit;i>0;i--){
    buffer--;
    *buffer = (data % 10) + '0';
    data=data/10;
    }//for
}

int getDigit(unsigned long data){
   int a;
   a = (int)log10(data) + 1;

   return a;

}


int main(int argc, char** argv) {

    char buf_str[8];

__delay_ms(40);

    IoInit();


__delay_ms(1000);
LCDclear();

IEC1bits.U2RXIE =1; //enable UART2 interrupt

IEC0bits.U1RXIE =1; //enable UART1 interrupt

    while(1){
     
   ltostring(5,(unsigned long)(RPM),buf_str);
       LCDstr(0,0,buf_str);
        LCDstr(5,0,"rpm");

    ltostring(3,(unsigned long)(E_TEMP),buf_str);
       LCDstr(4,1,buf_str);
       LCDstr(7,1,"c");


        __delay_ms(250);

    }


    return (EXIT_SUCCESS);
}


最新の投稿

プクサを採りに行く

春なので道北のウコチャヌプコロ川(秘匿名称)にプクサを取りに行った。アイヌのグルメ漫画がヒットしてるので今年はプクサ争奪が激しくなるから一番乗りしようというさもしい魂胆からの行動である。  U川には当然ながら熊が出るので熊対策も完全だ。熊スプレーに100均のピストルだ。...