1. Hello Guest. You have limited privileges and you can't "SEARCH" the forums. Please "Log In" or "Sign Up" for additional functionality. Click HERE to proceed.

XJ750E EFI project

Discussion in 'XJ Modifications' started by Yu Tanaka, Sep 21, 2016.

  1. Yu Tanaka

    Yu Tanaka Active Member

    Messages:
    65
    Likes Received:
    102
    Trophy Points:
    33
    Location:
    Shizuoka, Japan
    [​IMG]

    [​IMG]

    I'm trying to make EFI system with home made ECU (named TESLA). I designed this ECU to work without A/F sensor, so it works like a electronic controlled carburetor. I can't know correct A/F ratio, but I can change the fuel injection period by using remote controller while driving.


    Here is a sample of controller interface (mode of monitoring the engine RPM, vacuum sensor level, injection period, and ignition timing).

    [​IMG]
    I'll use ZRX1200DAEG throttle body. Inner diameter is 34mm, and the pitch is 71-94-71.


    [​IMG]
    Fuel pump and filter is mounted in L side cover. The fuel pump is a intank pump for Mitsubishi ek wagon(Japanese 660cc car), because I could not find small inline fuel pump. Anyone have good idea?


    [​IMG]
    Throttle body is mounted like this, but little bit short as you can see. And the pitch is different too, I need a adapter to insert between cylinder head and the insulator.

    [​IMG]
    This is a concept drawing of the adapter. You can get correct drawing as attached files if you need.

    If this adapter is finished, the hardware is almost complete, and I can turn on the engine with EFI system.
    Then I will work to debug ECU (I think that a lot of bugs). I checked this computer to work correctly for ignition, so I have to check about function of fuel injection.
     

    Attached Files:

    Mshawnm109r and Simmy like this.
  2. Polock

    Polock Well-Known Member

    Messages:
    9,751
    Likes Received:
    2,093
    Trophy Points:
    113
    Location:
    Beaver Falls, PA
    this sounds a lot like my bmw k100 system (open loop) but the bmw uses a mass air flow sensor rather than vacuum.
    is there a way to control the fuel pressure ?
     
  3. k-moe

    k-moe Pie, Bacon, Bourbon. Moderator Premium Member

    Messages:
    19,613
    Likes Received:
    6,706
    Trophy Points:
    113
    Location:
    The City of Seven Hills
    I'm curious. Being as how you are in Japan, why not get the throttle bodies from the factory XJ750D? I see them listed on Yahoo auctions occasionally. I realise that they can be costly, but making adapters is also going to be a fair expense.
     
  4. Yu Tanaka

    Yu Tanaka Active Member

    Messages:
    65
    Likes Received:
    102
    Trophy Points:
    33
    Location:
    Shizuoka, Japan
    Usual EFI system use a averaged vacuum value, but this system use a momentary vacuum value.

    [​IMG]
    This graph shows No.1 cylinder's vacuum sensor value and engine RPM at every TDC & BDC. Pink dots are vacuum, blue dots are RPM. The points of lowest vacuum value are intake BDC, and low points in the second are compression TDC, next combustion BDC. I carried out experiment with a variety of conditions, the value of vacuum sensor at intake BDC was always lowest. So I can implement sequential injection (timed injection) without cam angle sensor.

    [​IMG]
    This is a graph at running. When engine load is getting higher, the vacuum value at intake BDC is getting higher too. So I think that injection control can be realized only a vacuum sensor by using momentary vacuum value.

    I'll use pressure regulator.
    [​IMG]
    I was fitted with a regulator to modify the fuel pipe.


    Certainly throttle bodies of XJ750D will be able to get in Japan easily. But I want to use latest multi hole injector, and other parts also want to use as much as possible new.
     
  5. k-moe

    k-moe Pie, Bacon, Bourbon. Moderator Premium Member

    Messages:
    19,613
    Likes Received:
    6,706
    Trophy Points:
    113
    Location:
    The City of Seven Hills
    Sensable choice. My thought is that it might be less expensive to machine the Yamaha throttle bodies to accept a new injector than to make adapters for the ZRX throttle bodies.
     
  6. Yu Tanaka

    Yu Tanaka Active Member

    Messages:
    65
    Likes Received:
    102
    Trophy Points:
    33
    Location:
    Shizuoka, Japan
    I agree. But I have a friend who working in wire-cut processing factory, I can make adapters cheaply.
     
  7. Yu Tanaka

    Yu Tanaka Active Member

    Messages:
    65
    Likes Received:
    102
    Trophy Points:
    33
    Location:
    Shizuoka, Japan
    [​IMG]
    I completed the production of the adapter to connect cylinder head and throttle body.



    [​IMG]
    I can carry out injection test. But I'm busy now, so I'll be able to try this around Feb. I am looking forward to it!
     
    k-moe likes this.
  8. k-moe

    k-moe Pie, Bacon, Bourbon. Moderator Premium Member

    Messages:
    19,613
    Likes Received:
    6,706
    Trophy Points:
    113
    Location:
    The City of Seven Hills
    It's good to see how things are progressing. The adaptors turned out nicely.
     
    Yu Tanaka likes this.
  9. hogfiddles

    hogfiddles XJ-Wizard, Host-Central NY Carb Clinic Moderator Premium Member

    Messages:
    14,632
    Likes Received:
    5,012
    Trophy Points:
    113
    Location:
    near utica, new york
    Well here we go with yet another attempt at an EFI system.......maybe all the EFI guys should get together and come up with one that actually works
     
  10. Yu Tanaka

    Yu Tanaka Active Member

    Messages:
    65
    Likes Received:
    102
    Trophy Points:
    33
    Location:
    Shizuoka, Japan
    The current code of ECU is here. I'm sorry comments are Japanese only.

    I will explain the simple operation principle. First, if there is input from the pickup coil by cranking, start the timer. If there is input of the next pickup coil, stop the timer. Looking at the timer count value at this time, you will know the time it took for the crank half turn. Based on this, it converts to the rpm. Then read the preset ignition timing from table. From this ignition timing, calculate how long you can wait from the present time to calculate with that ignition timing.

    This is because we have a half rotation time now, so if you wait for that time from the present state it comes from the idea that the next signal will be input again. Of course, if the number of revolutions changes, that idea will collapse, but the countermeasure in that case is actually doing. But now I will not think about it.

    In other words, if you wait for the half rotation time measured now and then ignite, you will be able to ignite at top dead center. That means that if you advance this time a little more, you can ignite it to some extent.For example, you want to ignite at BTDC 20 °.

    Time required for 180 ° cranking - Time required for 20 ° cranking = Wait time to ignition

    In other words, if you know the time required to rotate 20 °, you can calculate the wait time before ignition. Therefore, we calculate the 20 ° time from the known 180 ° time.

    Now, we'be got the waiting time until ignition. However, it is necessary to energize the coil before ignition. This energizing time is called dwell time, it is fixed by the coil, and it is about 5 ms. From this waiting time until ignition, we also subtract this dwell time.

    We have now found the waiting time until energization. After that, we count down the waiting time until energization, when it gets to 0 it is energizated, then it gets ignited when it counts down for the dwell time.

    The above is about ignition control, but also for fuel injection. The target injection time is read out from the table from the current rpm and the intake pipe pressure and injected.

    I use a stock pick-up rotor now (using 2 pulse coils), but I've made a new pick-up rotor which have 7 peaks (peak to peak angle is 60 degree) already for future more precision control.


    Code:
    /****************************************************
    TITLE: TESLA_16bit メインプログラム
     PIC: 24FJ64GA002
     CLOCK: 32MHz
     1CYCLE: 62.5ns
    DATE: 2016.2.20
    CODED BY: ASHITAKA GIKEN
    OTHER:8MHz内蔵オシレータを用いてCPUはPLLで2倍.
    TMR2クロックは1:8プリスケーラで1usとして使う
    16/6/19 机上確認
    魔の4800rpm問題解決!
    同日 インジェクタ噴射 LEDで確認する限りは良さそう
    16/06/21 無効噴射時間 始動時補正 極低回転などLED確認
    16/06/30 FLASH書き込み作業開始
    同日 一応できた
    16/07/01 UART受信作成 未テスト
    16/07/10 バキューム進角車載テスト OK
    16/07/28 PWM出力のためにGB002へ変更
    16/08/02 GB002はピンアサインが違うため、一旦GA002使用に戻す
    16/08/07 GB002適合作業開始
    16/08/30 キャプチャをシステムクロックを利用して,32bitモードで行うようにした
    TMR2が開放されたのでインジェクタ用タイマは専用に出来た(空きタイマを探す必要がなくなった)
    TMR1点火用TMR2?5インジェクタ用
    ポンプPWM駆動成功 一応回転数によってPWM変わるようにしてある
    
    ****************************************************/
    #define FCY 16000000  // クロック周波数FOSC(32MHz)÷2
    #include    "tesla_16bit_config.h"
    
    //------------------------------------------------------------------
    //ピン設定
    //------------------------------------------------------------------
    #define    GATE14    LATBbits.LATB5            //14点火用信号出力
    #define    GATE23    PORTAbits.RA4            //23点火用信号出力
    #define    inj1    LATBbits.LATB3            //1番インジェクタ出力
    #define    inj2    LATAbits.LATA2            //2番インジェクタ出力
    #define    inj3    LATAbits.LATA3            //3番インジェクタ出力
    #define    inj4    LATBbits.LATB4            //4番インジェクタ出力
    #define    PU14    PORTBbits.RB10            //14ピックアップ入力
    #define    PU23    PORTBbits.RB11            //23ピックアップ入力
    
    //------------------------------------------------------------------
    //固定値
    //------------------------------------------------------------------
    #define    RPM_IDLE    0x4E20        //進角開始回転数1500RPMに設定
    #define    CALC_TIMEL    19            //進角開始回転数以下の時の計算時間
    #define    CALC_TIMEH    80          //進角開始後のときの計算時間
    
    //------------------------------------------------------------------
    //プロトタイプ宣言
    //------------------------------------------------------------------
    void main(void);
    void initialize_system(void);
    void _ISR _IC1Interrupt(void);
    void _ISR _IC2Interrupt(void);
    void _ISR _T1Interrupt(void);
    void _ISR _T2Interrupt(void);
    void _ISR _T3Interrupt(void);
    void _ISR _T4Interrupt(void);
    void _ISR _T5Interrupt(void);
    void _ISR _U1RXInterrupt(void);
    void under500(void);
    void wait_start(void);
    void calc(void);
    void calc_inj(void);
    void calc_time_fire(UINT T0s, UINT* ptime_fire, UINT* ptime_inj, UINT* deg_cr, UINT8* vac_level);
    void get_vaccum(void);
    void read_flash_all(void);
    void write_flash_all(void);
    void tx_uart_monitor(void);
    void tx_uart_debug(UINT data_kind);
    void tx_all_debug_data(void);
    void clr_icbuf(void);
    void clr_ictmr(void);
    
    //------------------------------------------------------------------
    //FLASH書き込み設定
    //------------------------------------------------------------------
    #define RAM_BUF_LEN (_FLASH_ROW*2) // length of buffer in bytes
    #define PAGE_ALIGN (_FLASH_PAGE*2) // alignment of page in PC units
    #define TABLE_LEN 60 // table len
    #define DATA_LEN  10// table len
    char ramBuf[RAM_BUF_LEN];
    
    // FLASH の1ページ分の領域確保をする為の共用体
    typedef union {
            UINT data[TABLE_LEN];
            char padding[PAGE_ALIGN];
    } FLASH_DATA_TABLE;
    
    typedef union {
            UINT data[DATA_LEN];
            char padding[PAGE_ALIGN];
    } FLASH_DATA;
    // 実際のプログラム領域にあるデータ
    
    FLASH_DATA_TABLE __attribute__ ((section(".myconfig"), space(prog), aligned(PAGE_ALIGN))) flash_deg1
            = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0%
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //8%
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};//16%
    
    FLASH_DATA_TABLE __attribute__ ((section(".myconfig"), space(prog), aligned(PAGE_ALIGN))) flash_deg2
            = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //32%
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //48%
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};//64%
    
    FLASH_DATA_TABLE __attribute__ ((section(".myconfig"), space(prog), aligned(PAGE_ALIGN))) flash_deg3
            = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //96%
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};//ダミー
    
    FLASH_DATA_TABLE __attribute__ ((section(".myconfig"), space(prog), aligned(PAGE_ALIGN))) flash_inj1
            = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0%
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //8%
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};//16%
    
    FLASH_DATA_TABLE __attribute__ ((section(".myconfig"), space(prog), aligned(PAGE_ALIGN))) flash_inj2
            = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //32%
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //48%
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};//64%
    
    FLASH_DATA_TABLE __attribute__ ((section(".myconfig"), space(prog), aligned(PAGE_ALIGN))) flash_inj3
            = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //96%
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};//ダミー
    
    FLASH_DATA __attribute__ ((section(".myconfig"), space(prog), aligned(PAGE_ALIGN))) flash_config
            = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};    //最高回転数等の各種データ
    
    FLASH_DATA_TABLE ram_data;    //点火時期、噴射時間テーブル用共用ram
    FLASH_DATA ram_config;        //最高回転数等データ用共用ram
    _prog_addressT p;
    
    //------------------------------------------------------------------
    //グローバル変数
    //------------------------------------------------------------------
    //                                  15   20   25   30   35   40   45   50   55   60   65   70   75   80   85   90   95  100 105 110 rpm
    volatile UINT8 deg_fire[8][20] = {
                                    {7, 15, 22, 30, 37, 38, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}, //0%
                                    {7, 15, 25, 32, 38, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}, //8%
                                    {7, 15, 25, 32, 38, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}, //16%
                                    {7, 15, 25, 32, 38, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}, //32%
                                    {7, 15, 25, 32, 38, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}, //48%
                                    {7, 15, 20, 28, 29, 30, 31, 33, 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35}, //64%
                                    {7, 12, 16, 22, 27, 29, 31, 33, 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35}, //96%                              
                                    {7, 12, 16, 22, 27, 29, 31, 33, 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35}}; //ダミー行(100%と同一にする)
    
    //                                  15   20   25   30   35   40   45   50   55   60   65   70   75   80   85   90   95  100 105 110 rpm
    volatile uint8_t table_inj[8][20] = {
                                    {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20}, //0%
                                    {15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 32}, //8%
                                    {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 32, 32, 32, 32, 32, 32, 32, 32, 32}, //16%
                                    {25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 40, 40, 40, 40}, //32%
                                    {30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49}, //48%
                                    {35, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 40, 40, 40, 40}, //64%
                                    {36, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49}, //96%              
                                    {36, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49}}; //ダミー行(100%と同一にする)
    
    
    volatile UINT T0 = 0;           //加減速補正付き半回転時間
    volatile UINT T0_real;   //半回転時間
    volatile UINT T0_old = 0;       //前回T0
    volatile UINT T1 = 0;           //回転数
    volatile UINT vac = 0;          //バキューム値
    volatile UINT time_fire = 0;    //点火までの待ち時間
    volatile UINT time_inj = 0;     //噴射時間
    volatile UINT deg_cr = 0;       //現在の点火時期
    volatile UINT8 vac_level = 0;   //現在のバキューム値(%)
    volatile UINT8 tx_req_flag = 0; //コントローラからのデータ送信要求フラグ
    
    //------------------------------------------------------------------
    //グローバル変数 各種ユーザ設定
    //------------------------------------------------------------------
    
    #define DUTY_LOW    25          //デューティ最低値設定
    
    volatile UINT RPM_MAX = 0xBB8;              //最高回転数
    volatile UINT TIME_DWELL = 0x1388;          //ドエルタイム
    volatile UINT DEG_IDLE = 700;               //アイドル点火時期
    volatile UINT START_REVISION_TIME = 5000;   //始動時燃料噴射量
    volatile UINT invalid_inj1 = 1200;          //無効噴射時間
    volatile UINT invalid_inj2 = 1200;
    volatile UINT invalid_inj3 = 1200;
    volatile UINT invalid_inj4 = 1200;
    volatile UINT idle_inj_time = 2000;         //1500回転以下固定噴射量
    volatile UINT ulow_inj_time = 2000;         //500rpm以下の極低回転噴射量
    volatile UINT period_pump = 64000;           //ポンプPWM周期 64000で250Hz
    volatile UINT duty_pump = DUTY_LOW;                //デューティ
    volatile UINT fix_inj_time = 1000;           //固定噴射モード噴射時間
    
    //------------------------------------------------------------------
    // エンジン状態マーク
    //------------------------------------------------------------------
    
    typedef enum{           //今回噴射するインジェクタマーク
        INJ4,
        INJ3,
        INJ1,
        INJ2,
    } INJ_STATE;
    INJ_STATE MARK_INJ;
    
    typedef enum{          //今どのピックアップが入ったか
        NO_PU,
        ON_14,
        ON_23,
    } PICKUP_STATE;
    PICKUP_STATE MARK_PU;
    
    typedef enum{           //進角前、通電までの待ちあり、待ちなし
        LOW_RPM,
        MID_RPM,
        HI_RPM,
    } ENGINE_STATE;
    ENGINE_STATE MARK_ENGINE;
    
    typedef enum{           //14,23気筒どちらを点火するか
        INTR_NO,
        INTR_14,
        INTR_23,
    } INTR_STATE;
    INTR_STATE MARK_INTR;
      
    typedef enum{           //高回転時先回り通電するか
        OFF,
        ON,
    } DADV_STATE;
    DADV_STATE DWELL_ADVANCE;
    
    typedef enum{       //通電or点火マーク
        DWELL,
        FIRE14,
        FIRE23,
    } FIRE_STATE;
    FIRE_STATE MARK_FIRE;
    
    typedef enum{ //バキューム進角オンオフ(デフォルトでオン)
        VAC_ON,
        VAC_OFF,
    } VAC_STATE;
    VAC_STATE VAC_ADV;
    
    typedef enum{ //固定噴射オンオフ(デフォルトでオフ)
        FIX_OFF,
        FIX_ON,
    } FIX_INJ_STATE;
    FIX_INJ_STATE FIX_INJ;
    
    
    //------------------------------------------------------------------
    // 回転数と負荷テーブル 不変
    //------------------------------------------------------------------
    const UINT table_rpm[19] = {1500, 2000, 2500, 3000, 3500, 4000, 4500,
                                5000, 5500, 6000, 6500, 7000, 7500, 8000,
                                8500, 9000, 9500, 10000, 10500, 11000};
    //                                           0%    8%    16%   32%  48%  64%  96%   max
    const UINT table_vac[8] = {369, 407, 438, 500, 562, 624, 752, 1024};
    
    //------------------------------------------------------------------
    //main
    //------------------------------------------------------------------
    
    void main(void){
        initialize_system();
    
        _init_prog_address(p, flash_deg1);          //ram_dataにFLASHからデータを読みだす
        _memcpy_p2d16(&ram_data, p, PAGE_ALIGN);
        if (ram_data.data[0]!=0) read_flash_all(); //フラッシュが空でないときだけ点火時期・噴射時間を読みだす
      
        __delay_ms(10);
        wait_start();
      
        while (1) {
            if (MARK_INTR==INTR_14 || MARK_INTR==INTR_23) calc();
        }
    }
    
    // -----------------------------------------------------------------
    // UART受信割り込み処理
    //------------------------------------------------------------------ */
    
    void _ISR _U1RXInterrupt(void){
        IFS0bits.U1RXIF = 0;
        static UINT counter = 0;
        static UINT buff[10] = {0};
        UINT8 recvcomp=0;
      
        UINT c = ReadUART1();      //1バイト受信
    
        if(counter==0) {
            if(c==0xB0) {
            buff[0] = c;        // counter=0で初回受信
            counter++;          //送信開始記号B0を受信できたら受信開始
            }
            else{
                asm("nop");     //カウンタ0で送信開始記号を受信できなかった
            }                   //エラー処理を後で考えておく
        }
        else {
            buff[counter] = c;  // 受信した1文字格納
            counter++;
            if(counter>=sizeof(buff)) {
                counter = 0;    // 受信バッファが満杯になってしまったらエラー
            }
            else if(c==0xA1) {
                recvcomp = 1;   // A1を受信したら終了
            }
        }
    
        if (recvcomp==1) {
            if (counter==3) {   //3byte受信した時は本体からの要求
                if (buff[1]==0xDF) {
                    tx_all_debug_data(); //設定値送信要求
                    tx_uart_debug(0x10); //バグ?rpm_maxだけ送れないのでもう一度
                }
                else if (buff[1]==0xEB) { //フラッシュ書き込み要求
                    write_flash_all();
                }
                else if (buff[1]==0xC5) { //バキューム進角オフ要求
                    VAC_ADV = OFF;
                }
                else if (buff[1]==0xC4) { //バキューム進角オン要求
                    VAC_ADV = ON;
                }
                else if (buff[1]==0xF0) { //固定噴射モードオン
                    FIX_INJ = ON;
                }
                else if (buff[1]==0xF1) { //固定噴射モードオフ
                    FIX_INJ = OFF;
                }
            }
            if (counter==4) {   //4byte受信したときは固定噴射モードでの噴射時間変更
                fix_inj_time = buff[1];          
            }
            if (counter==5) {   //5byte受信した時はその他データ
                UINT k = 0x10;
                while (1) {      //受信データ種類判別
                    if (buff[1]==k) break;
                    k++;
                }
    
                UINT ndata = (buff[2]<<8)|buff[3]; //データを連結する      
    
                switch (k) {
                    case 0x10:
                        RPM_MAX = ndata;
                        break;
                    case 0x11:
                        TIME_DWELL = ndata;
                        break;
                    case 0x12:
                        DEG_IDLE = ndata;
                        break;
                    case 0x13:
                        START_REVISION_TIME = ndata;
                        break;
                    case 0x14:
                        invalid_inj1 = ndata;
                        break;
                    case 0x15:
                        invalid_inj2 = ndata;
                        break;
                    case 0x16:
                        invalid_inj3 = ndata;
                        break;
                    case 0x17:
                        invalid_inj4 = ndata;
                        break;
                    case 0x18:
                        idle_inj_time = ndata;
                        break;
                    case 0x19:
                        ulow_inj_time = ndata;
                        write_flash_all();
                        break;                    
               }
           }
    
            if (counter==6) {       //6byte受信した時はテーブルデータ
                if (buff[1]==0x10){     //点火時期変更
                    deg_fire[buff[2]][buff[3]] = buff[4];
                }
                else if (buff[1]==0x11){    //噴射時間変更
                    table_inj[buff[2]][buff[3]] = buff[4];
                }
            }
    
            if (counter==10) { //10byte受信した時は簡単セッティングモード
                UINT8 area_row = buff[1];
                UINT8 area_colum = buff[2];
                UINT8 i;
                UINT8 j;
                UINT8 k = 3;
              
                for (i = 1+(area_row*2); i<3+(area_row*2); i++) {
                    for (j = 2+(area_colum*3); j<4+(area_colum*3); j++) {
                        table_inj[i][j] = buff[k];
                        k++;
                    }
                }              
            }
      
            counter = 0;      
            recvcomp = 0;           //受信完了フラグクリア
            UINT k = 0;
            for(k=0;k<=5;k++){
                buff[k] = 0;        //バッファクリア
            }
        }
        if (U1STAbits.OERR==1){         //FIFOバッファ・オーバーフローしていたらリセット(しないと受信ができない)
            U1STAbits.OERR = 0;
        }
    }
    
    // -----------------------------------------------------------------
    // UART送信 モニタ用データ
    //------------------------------------------------------------------ */
    
    void tx_uart_monitor(){
        static UINT counter = 0;
        static UINT data_kind = 0x20;
        static UINT data = 0;
      
        //PC用送信データ 必要に応じてマスク
        //volatile char* buff[20];
        //sprintf(buff,"0%d,%d,%d,%d \r\n",T1,vac,time_inj,deg_cr);
        //putsUART1( (unsigned int*)buff);
        //PC用送信データここまで
      
    
        if(counter==0){
            data = 0xB0;    //初回送信は送信開始記号を送る
            WriteUART1(data);
            counter++;
        }
        else if (counter==1){
            WriteUART1(data_kind);
            counter++;
        }
        else if (counter<=3){
            if (counter==2){        //データ上位桁送信
                switch (data_kind){
                    case 0x20:
                        data = T1;
                        break;
                    case 0x21:
                        data = vac_level;
                        break;
                    case 0x22:
                        data = time_inj-invalid_inj1;
                        break;
                    case 0x23:
                        data = deg_cr;
                        break;
                    case 0x24:
                        data = vac;
                        break;
                }
            //16bitデータを8bitに分割する  
                UINT datah = (data&0xFF00)>>8;   //上位8bit抜き出してdatahへ
                data = data&0x00FF;             //下位8bitはdataへ
                WriteUART1(datah);
            }
            else if (counter==3){        //データ下位桁送信
                WriteUART1(data);
            }
            counter++;
        }
        else{                     //データ送信完了記号を送る
            WriteUART1(0xA1);
            counter = 0;
            data_kind++;
            if (data_kind==0x25) data_kind = 0x20;
        }
    }
    
    // -----------------------------------------------------------------
    // UART送信 各種設定データ エンジン停止時にしか送らない
    // ので、1バイトずつでなく一気に送る
    //------------------------------------------------------------------ */
    
    void tx_uart_debug(UINT data_kind){
        WriteUART1(0xB0); //送信開始記号を送る
        UINT data = 0;
    
        switch (data_kind) {
            case 0x10:
                data = RPM_MAX;
                break;
            case 0x11:
                data = TIME_DWELL;
                break;
            case 0x12:
                data = DEG_IDLE;
                break;
            case 0x13:
                data = START_REVISION_TIME;
                break;
            case 0x14:
                data = invalid_inj1;
                break;
            case 0x15:
                data = invalid_inj2;
                break;
            case 0x16:
                data = invalid_inj3;
                break;
            case 0x17:
                data = invalid_inj4;
                break;
            case 0x18:
                data = idle_inj_time;
                break;
            case 0x19:
                data = ulow_inj_time;
                break;
        }
    
        __delay_us(100);
        WriteUART1(data_kind); //データ種類番号送る
    
        //16bitデータを8bitに分割する  
        UINT datah = (data&0xFF00)>>8; //上位8bit抜き出してdatahへ
        data = data&0x00FF;
        data = data&0x00FF; //下位8bitはdataへ
        WriteUART1(datah);
       __delay_us(100);
        WriteUART1(data);
        __delay_us(100);
        WriteUART1(0xA1); //送信完了記号を送る
    }
    
    // -----------------------------------------------------------------
    // 全設定値送信
    //------------------------------------------------------------------ */
    
    void tx_all_debug_data(void){
        volatile UINT data_num = 0x10;
        static UINT i=0, j=0;   //staticにしとかないと使われちゃう
    
        WriteUART1(0xB0); //テーブルデータを一気に送る  
        __delay_us(100);
        WriteUART1(0x10);
        i=0;
        j=0;
        for (j = 0; j<18; j++) {
            for (i = 0; i<8; i++) {
                __delay_us(100);
                WriteUART1(deg_fire[i][j]);
            }
        }
        WriteUART1(0xA1); //点火データ送信完了
    
        __delay_ms(100);
    
        WriteUART1(0xB0); //テーブルデータを一気に送る  
        __delay_us(100);
        WriteUART1(0x11);
        for (j = 0; j<18; j++) {
            for (i = 0; i<8; i++) {
                __delay_us(100);
                WriteUART1(table_inj[i][j]);
            }
        }
        WriteUART1(0xA1); //噴射時間データ送信完了
      
        __delay_ms(100);
          
         WriteUART1(0xB0); //テーブルデータを一気に送る    ミスするのでもう一回送っとく
        __delay_us(100);
        WriteUART1(0x10);
        i=0;
        j=0;
        for (j = 0; j<18; j++) {
            for (i = 0; i<8; i++) {
                __delay_us(100);
                WriteUART1(deg_fire[i][j]);
            }
        }
        WriteUART1(0xA1); //点火データ送信完了
    
        __delay_ms(100);
    
        for (data_num = 0x10; data_num<0x20; data_num++) {
            tx_uart_debug(data_num);
            __delay_ms(100); //これくらい待たないとデータ送信ミスする
        }
    }
    
    // -----------------------------------------------------------------
    // 全FLASHデータ読み込み
    //------------------------------------------------------------------ */
    void read_flash_all(void){
      
        //点火時期読み出し
        _init_prog_address(p, flash_deg1);          //ram_dataにFLASHからデータを読みだす
        _memcpy_p2d16(&ram_data, p, PAGE_ALIGN);
        
        UINT k=0,i=0,n=0;                           //ramから実際に使うテーブルにデータを移す
        for(k=0;k<=2;k++){
            for(n=0;n<=19;n++){
                deg_fire[k][n] = ram_data.data[i];
                i+=1;
            }
        }                                  
      
        _init_prog_address(p, flash_deg2);        
        _memcpy_p2d16(&ram_data, p, PAGE_ALIGN);
      
        i = 0;
        for(k=3;k<=5;k++){
            for(n=0;n<=19;n++){
                deg_fire[k][n] = ram_data.data[i];
                i+=1;
            }
        }  
      
        _init_prog_address(p, flash_deg3);        
        _memcpy_p2d16(&ram_data, p, PAGE_ALIGN);
      
        i = 0;
        for(k=6;k<=7;k++){
            for(n=0;n<=19;n++){
                deg_fire[k][n] = ram_data.data[i];
                i+=1;
            }
        }      
      
        //噴射時間読み出し
        _init_prog_address(p, flash_inj1);          //ram_dataにFLASHからデータを読みだす
        _memcpy_p2d16(&ram_data, p, PAGE_ALIGN);
        
        i = 0;
        for(k=0;k<=2;k++){
            for(n=0;n<=19;n++){
                table_inj[k][n] = ram_data.data[i];
                i+=1;
            }
        }
      
        _init_prog_address(p, flash_inj2);          //ram_dataにFLASHからデータを読みだす
        _memcpy_p2d16(&ram_data, p, PAGE_ALIGN);
      
        i = 0;
        for(k=3;k<=5;k++){
            for(n=0;n<=19;n++){
                table_inj[k][n] = ram_data.data[i];
                i+=1;
            }
        }                                  
          
        _init_prog_address(p, flash_inj3);          //ram_dataにFLASHからデータを読みだす
        _memcpy_p2d16(&ram_data, p, PAGE_ALIGN);
      
        i = 0;
        for(k=6;k<=7;k++){
            for(n=0;n<=19;n++){
                table_inj[k][n] = ram_data.data[i];
                i+=1;
            }
        }      
    
        //各種設定値の読み出し
        _init_prog_address(p, flash_config);          //ram_dataにFLASHからデータを読みだす
        _memcpy_p2d16(&ram_config, p, PAGE_ALIGN);
    
        RPM_MAX = ram_config.data[0];
        TIME_DWELL = ram_config.data[1];
        DEG_IDLE = ram_config.data[2];
        START_REVISION_TIME = ram_config.data[3];
        invalid_inj1 = ram_config.data[4];
        invalid_inj2 = ram_config.data[5];
        invalid_inj3 = ram_config.data[6];
        invalid_inj4 = ram_config.data[7];
        idle_inj_time = ram_config.data[8];  
        ulow_inj_time = ram_config.data[9];
      
    }
    
          
    // -----------------------------------------------------------------
    // 全FLASHデータ書き込み
    //------------------------------------------------------------------ */      
    void write_flash_all(void){
        //点火時期書き込み
        UINT k=0,n=0,i=0;
        for(k=0;k<=2;k++){
            for(n=0;n<=19;n++){
                ram_data.data[i] = deg_fire[k][n];
                i+=1;
            }
        }  
        _init_prog_address(p, flash_deg1);
        _erase_flash(p); // erase a page      
        _write_flash16(p, (int*)&ram_data);    // write first row with 16-bit data
      
        i = 0;
        for(k=3;k<=5;k++){
            for(n=0;n<=19;n++){
                ram_data.data[i] = deg_fire[k][n];
                i+=1;
            }
        }  
        _init_prog_address(p, flash_deg2);
        _erase_flash(p); // erase a page      
        _write_flash16(p, (int*)&ram_data);    // write first row with 16-bit data  
      
        i = 0;
        for(k=6;k<=7;k++){
            for(n=0;n<=19;n++){
                ram_data.data[i] = deg_fire[k][n];
                i+=1;
            }
        }  
        _init_prog_address(p, flash_deg3);
        _erase_flash(p); // erase a page      
        _write_flash16(p, (int*)&ram_data);    // write first row with 16-bit data      
      
        //噴射時間書き込み
        i = 0;
        for(k=0;k<=2;k++){
            for(n=0;n<=19;n++){
                ram_data.data[i] = table_inj[k][n];
                i+=1;
            }
        }  
        _init_prog_address(p, flash_inj1);
        _erase_flash(p); // erase a page      
        _write_flash16(p, (int*)&ram_data);    // write first row with 16-bit data
      
        i = 0;
        for(k=3;k<=5;k++){
            for(n=0;n<=19;n++){
                ram_data.data[i] = table_inj[k][n];
                i+=1;
            }
        }  
        _init_prog_address(p, flash_inj2);
        _erase_flash(p); // erase a page      
        _write_flash16(p, (int*)&ram_data);    // write first row with 16-bit data  
      
        i = 0;
        for(k=6;k<=7;k++){
            for(n=0;n<=19;n++){
                ram_data.data[i] = table_inj[k][n];
                i+=1;
            }
        }  
        _init_prog_address(p, flash_inj3);
        _erase_flash(p); // erase a page      
        _write_flash16(p, (int*)&ram_data);    // write first row with 16-bit data      
      
        //各種設定値の書き込み
        ram_config.data[0] = RPM_MAX;
        ram_config.data[1] = TIME_DWELL;
        ram_config.data[2] = DEG_IDLE;
        ram_config.data[3] = START_REVISION_TIME;
        ram_config.data[4] = invalid_inj1;
        ram_config.data[5] = invalid_inj2;
        ram_config.data[6] = invalid_inj3;
        ram_config.data[7] = invalid_inj4;
        ram_config.data[8] = idle_inj_time;  
        ram_config.data[9] = ulow_inj_time;
      
        _init_prog_address(p, flash_config);
        _erase_flash(p); // erase a page      
        _write_flash16(p, (int*)&ram_config);    // write first row with 16-bit data      
      
    }  
    
    
    // -----------------------------------------------------------------
    // 500rpm以下処理
    //------------------------------------------------------------------ */
    
    void under500(void){
        UINT counter = 0;
        UINT counterh = 0;
        clr_ictmr();  //キャプチャタイマリセット&リスタート
      
        OC1R = (UINT)(period_pump/(100/DUTY_LOW));  //ポンプデューティ変更
    
        while (1) {
            while (1) {
                while (IFS0bits.IC1IF!=1&&IFS0bits.IC2IF!=1){//IC1かIC2のどちらかのピックアップ信号が入るまで待つ
                    counter++;
                    if (counter==0xFFFF){
                        counter = 0;
                        counterh++;
                        if (counterh==100){      //5秒間待っても信号が入らない場合は通電オフ
                            GATE14 = 0;
                            GATE23 = 0;
                            counterh = 0;
                        }
                    }
                }                              
                __delay_us(50); //50usたってまだオンならループを抜ける
                if (PU14==1||PU23==1) break;
            }
    
            clr_ictmr();
            clr_icbuf();   //タイマクリア&リスタート、バッファ空に
    
            T2CONbits.TON = 0; //噴射タイマリセット
            T3CONbits.TON = 0;
            T4CONbits.TON = 0;
            T5CONbits.TON = 0;
            TMR2 = 0;  
            TMR3 = 0;
            TMR4 = 0;
            TMR5 = 0;
    
            if (IFS0bits.IC1IF==1) { //IC1(14番)信号が入った
                GATE23 = 1; //23通電
                MARK_PU = ON_14; //14ピックアップ入力があったマークを付けておく
                GATE14 = 0; //14点火
                inj1 = 1;
                inj2 = 1;
                PR2 = (ulow_inj_time+invalid_inj1)*2;        //極低回転は非同期噴射
                PR3 = (ulow_inj_time+invalid_inj2)*2+10;
                T2CONbits.TON = 1;
                T3CONbits.TON = 1;
            }
            else { //IC2(23番)信号が入った
                GATE14 = 1; //14通電
                MARK_PU = ON_23; //23ピックアップ入力があったマークを付けておく
                GATE23 = 0; //23点火
                inj3 = 1;
                inj4 = 1;
                PR4 = (ulow_inj_time+invalid_inj1)*2;        //極低回転は非同期噴射
                PR5 = (ulow_inj_time+invalid_inj2)*2+10;
                T4CONbits.TON = 1;
                T5CONbits.TON = 1;
            }
    
            __delay_us(50); //点火後のノイズをやり過ごす
            IFS0 = 0; //フラグリセット
            clr_icbuf();
          
            while (1) { //IC1かIC2のどちらかのピックアップ信号が入るまで待つ
                while (IFS0bits.IC1IF!=1&&IFS0bits.IC2IF!=1) {
                    if (IC2TMR>=0x000F) break; //待っている間にまたタイマオーバーフローしたら最初から
                }
                if (IC2TMR>=0x000F) break; //待っている間にまたタイマオーバーフローしたら最初から
                __delay_us(50); //50usたってまだオンならループを抜ける
                if (PU14==1||PU23==1) break;
            }
            if (PU14==1||PU23==1) break; //ピックアップ入ったら抜ける
        }
    
        clr_ictmr();
    
        if (IFS0bits.IC1IF==1) { //IC1(14番)信号が入った
            MARK_PU = ON_14; //14ピックアップ入力があったマークを付けておく
            MARK_INTR = INTR_23; //23気筒点火ルーチンへ飛ぶマークを付けておく
        }
        else { //IC2(23番)信号が入った
            MARK_PU = ON_23; //23ピックアップ入力があったマークを付けておく
            MARK_INTR = INTR_14; //14気筒点火ルーチンへ飛ぶマークを付けておく
        }
    }
    
    // -----------------------------------------------------------------
    // 入力キャプチャ2割り込み(23気筒ピックアップ信号がオンになったとき)
    //------------------------------------------------------------------ */
    
    void _ISR _IC2Interrupt(void){
        __delay_us(10);
        IFS0bits.IC2IF = 0; //割り込みフラグリセット
        if (PU23==1) { //50us待ってまだオンの場合のみ以下を実行
            if (MARK_PU==ON_14) { //前回14ピックアップが入っていた場合のみ実行
                MARK_PU = ON_23; //23ピックアップがオンになったマークを付けておく
                T0_real = IC2BUF;
                if (T0_real<0x000F) {
                    T0_real = T0_real<<12;
                    T0_real += IC1BUF>>4;
                    clr_ictmr();
                    MARK_INTR = INTR_14; //14気筒点火用マークを付けておく
                }
                else {                  //500rpm以下ならここへ
                    under500();
                }
            }
            else { //前回14ピックアップを検知できていなかったときはここにくる  
                GATE14 = 1; //14通電                      
                MARK_PU = ON_23; //23ピックアップがオンになったマークを付けておく
                MARK_INTR = INTR_NO;
                clr_ictmr();
    
                GATE23 = 0; //23点火
    
                __delay_us(50); //点火後のノイズをやり過ごす
                IFS0 = 0; //フラグリセット
                clr_icbuf();
            }
            IFS0bits.T1IF = 0; //先回り通電カウント中に割り込んだ場合は
            T1CONbits.TON = 0; //リセットしてカウントをやめておく
            TMR1 = 0;
        }
        else {
            clr_icbuf();
        }
    }
    
    // -----------------------------------------------------------------
    // 入力キャプチャ1割り込み(14気筒ピックアップ信号がオンになったとき)
    //------------------------------------------------------------------ */
    
    void _ISR _IC1Interrupt(void){
        __delay_us(10);
        IFS0bits.IC1IF = 0; //割り込みフラグリセット
    
        if (PU14==1) { //50us待ってまだオンの場合のみ以下を実行
            if (MARK_PU==ON_23) { //前回23ピックアップが入っていた場合のみ実行
                MARK_PU = ON_14; //14ピックアップがオンになったマークを付けておく
                T0_real = IC2BUF;
                if (T0_real<0x000F) {
                    T0_real = T0_real<<12;
                    T0_real += IC1BUF>>4;
                    clr_ictmr();
                    MARK_INTR = INTR_23; //23気筒点火用マークを付けておく
                }
                else { //500rpm以下ならここへ
                    under500();
                }
            }
            else { //前回23ピックアップを検知できていなかったときはここにくる  
                GATE23 = 1; //23通電                      
                MARK_PU = ON_14; //14ピックアップがオンになったマークを付けておく
                MARK_INTR = INTR_NO;
                clr_ictmr();
    
                GATE14 = 0; //14点火
    
                __delay_us(50); //点火後のノイズをやり過ごす
                IFS0 = 0; //フラグリセット
                clr_icbuf();
            }
            IFS0bits.T1IF = 0; //先回り通電カウント中に割り込んだ場合は
            T1CONbits.TON = 0; //リセットしてカウントをやめておく
            TMR1 = 0;
        }
        else {
            clr_icbuf();
        }
    }
    
    // -----------------------------------------------------------------
    // 点火時期・噴射時間計算サブルーチン
    //------------------------------------------------------------------ */
    
    void calc(void){
        MARK_INJ += 1;              //噴射するインジェクタを選択
      
        if (MARK_INTR==INTR_23){
            get_vaccum();               //バキューム値を取得しておく    
            GATE14 = 0;
        }
        else if (MARK_INTR==INTR_14)  GATE23 = 0;        
          
        if (T0_old!=0){                    
            T0 = T0_real+((int) (T0_real-T0_old)/2); //加減速補正値を足しておく
        }
        else T0 = T0_real;
      
    
        if (T0<=RPM_MAX) {            
            inj1 = 0;                   //レブリミットを超えていたら燃料&点火カット
            inj2 = 0;
            inj3 = 0;
            inj4 = 0;
            GATE14 = 0;
            GATE23 = 0;
         }
        else {                          //レブリミット以下なら以下を実行
            if (T0<=RPM_IDLE) {                     //進角開始回転数を超えていたら以下を実行
                calc_time_fire(T0,&time_fire,&time_inj,&deg_cr, &vac_level); //点火時期を計算する
                duty_pump = DUTY_LOW-12.5+(T1/120);          
                //待ち時間零で即通電して点火  
                if (time_fire<=TIME_DWELL+3) {
                    if (MARK_INTR==INTR_14) {
                        MARK_FIRE = FIRE14;
                        GATE14 = 1;    
                    }
                    if (MARK_INTR==INTR_23) {
                        MARK_FIRE = FIRE23;
                        GATE23 = 1;
                    }
                    PR1 = time_fire*2;
                    MARK_ENGINE = HI_RPM;
                }
                //通電までの待ち時間あり  
                else {
                    volatile UINT time_dwell = time_fire-TIME_DWELL;
                    PR1 = time_dwell*2;
                    MARK_FIRE = DWELL;
                    MARK_ENGINE = MID_RPM;
                }
            }
          
            //進角開始回転数以下  
            else {
                duty_pump = DUTY_LOW;
                volatile UINT time_dwell = T0-TIME_DWELL-CALC_TIMEL;
                if (time_dwell>0x7FF0) PR1 = 0xFFFF;    //2倍したらオーバーフローしちゃう時は0xffffにしておく
                else PR1 = time_dwell*2;
                MARK_FIRE = DWELL;
                MARK_ENGINE = LOW_RPM;
                time_inj = idle_inj_time;
            }
            TMR1 = 0;
            T1CONbits.TON = 1;    
      
            //ここで噴射開始
    
            if (FIX_INJ==FIX_ON) time_inj = fix_inj_time*100;
    
            switch (MARK_INJ) {
                case INJ1:
                    inj1 = 1;           //噴射開始&インジェクタとタイマを紐付け
                    time_inj += invalid_inj1;
                    PR2 = time_inj*2;
                    T2CONbits.TON = 1;
                    break;
                case INJ2:
                    inj2 = 1;
                    time_inj += invalid_inj2;
                    PR3 = time_inj*2;
                    T3CONbits.TON = 1;
                    break;
                case INJ3:
                    inj3 = 1;
                    time_inj += invalid_inj3;
                    PR4 = time_inj*2;
                    T4CONbits.TON = 1;
                    break;
                case INJ4:
                    inj4 = 1;
                    time_inj += invalid_inj4;
                    PR5 = time_inj*2;
                    T5CONbits.TON = 1;
                    break;  
            }
        }
          
        MARK_INTR = INTR_NO;    //割り込みマークリセット
        T0_old = T0_real;       //今回T0を保存しておく
        tx_uart_monitor();
        OC1R = (UINT)((period_pump/100)*duty_pump);  //ポンプデューティ変更
    }
    
    // -----------------------------------------------------------------
    // 点火カウント用タイマ割り込み
    //------------------------------------------------------------------ */
    
    void _ISR _T1Interrupt(void){
        IFS0bits.T1IF = 0;
        T1CONbits.TON = 0;
        TMR1 = 0;        
      
        volatile int time_predwell = 0;
        
        if (MARK_FIRE==FIRE14 || MARK_FIRE==FIRE23) {
            if(MARK_FIRE==FIRE14) GATE14 = 0; //点火
            else if(MARK_FIRE==FIRE23) GATE23 = 0;
          
            DWELL_ADVANCE = OFF;                        //先回り通電マーク解除
            MARK_FIRE = DWELL;
    
            if (MARK_ENGINE==HI_RPM) {                   //点火後,次の点火でドエルタイムを確保するため先回り通電しておく  
                time_predwell = T0-TIME_DWELL;
                time_predwell -= 0x5;                    //ここまでの計算時間を引いておく
                DWELL_ADVANCE = ON;                      //先回り通電マーク
              
                if (time_predwell>0) PR1 = time_predwell*2;   //通電までの待ち時間がある時
                else PR1 = 3;                                //待ち時間なしなら3を入れる
                T1CONbits.TON = 1;
            }
        }      
      
        else if (MARK_PU==ON_23) {
            if(DWELL_ADVANCE==ON) {
                GATE23 = 1;
                MARK_FIRE = FIRE23;
                DWELL_ADVANCE = OFF;
            }
            else if (MARK_ENGINE==LOW_RPM) {
                GATE14 = 1;
                MARK_FIRE = FIRE14;
            }
            else{      
                GATE14 = 1; //通電
                MARK_FIRE = FIRE14;
                PR1 = TIME_DWELL*2; //点火までの待ち時間をいれておく
                T1CONbits.TON = 1; //タイマスタート
                DWELL_ADVANCE = OFF;                        //先回り通電マーク解除
            }
        }  
    
        else if (MARK_PU==ON_14) {
            if(DWELL_ADVANCE==ON) {
                GATE14 = 1;
                MARK_FIRE = FIRE14;
                DWELL_ADVANCE = OFF;
            }
            else if (MARK_ENGINE==LOW_RPM) {
                GATE23 = 1;
                MARK_FIRE = FIRE23;
            }
            else{
                GATE23 = 1; //通電
                MARK_FIRE = FIRE23;
                PR1 = TIME_DWELL*2; //点火までの待ち時間をいれておく
                T1CONbits.TON = 1; //タイマスタート
                DWELL_ADVANCE = OFF;                        //先回り通電マーク解除
            }
        }
    }
    
    // -----------------------------------------------------------------
    // 噴射カウント用タイマ割り込み
    //------------------------------------------------------------------ */
    
    void _ISR _T2Interrupt(void){
        inj1 = 0;
        IFS0bits.T2IF = 0;
        T2CONbits.TON = 0;
        TMR2 = 0;
    }
    
    void _ISR _T3Interrupt(void){
        inj2 = 0;
        IFS0bits.T3IF = 0;
        T3CONbits.TON = 0;
        TMR3 = 0;
    }
    
    void _ISR _T4Interrupt(void){
        inj3 = 0;
        IFS1bits.T4IF = 0;
        T4CONbits.TON = 0;
        TMR4 = 0;
    }
    
    void _ISR _T5Interrupt(void){
        inj4 = 0;
        IFS1bits.T5IF = 0;
        T5CONbits.TON = 0;
        TMR5 = 0;
    }
    
    //------------------------------------------------------------------
    // バキューム値取得用関数
    //------------------------------------------------------------------
    
    void get_vaccum(){
        static UINT vac_old = 1024;
        UINT vac_raw = 0;
    
       // while (1) {
            AD1CON1bits.SAMP = 1; //ADCサンプリング開始
            while (!AD1CON1bits.DONE); //サンプリング後変換待ち
            vac_raw = ADC1BUF0; //生データ取得  
    
            //バキューム進角オフの時は擬似的に負荷maxの時の値を入れておく
            if (VAC_ADV==VAC_OFF) {
                static UINT8 n = 0;
                n = n+1;
                if (n==1) {
                    vac_raw = 770;
                }
                else if (n==2) {
                    vac_raw = 870;
                    n = 0;
                }
            }
           // if (vac_raw<900&&vac_raw>200) break;
    //   }
    
        if (vac_raw<vac_old) { //今回値の方が低ければ今回3番吸気下死点であるのでvacを更新
            vac = vac_raw;
            MARK_INJ = INJ4;
        }
        vac_old = vac_raw; //今回のデータをvac_oldに入れておく
    }
    //------------------------------------------------------------------
    // 点火時期&噴射時間計算用関数
    //------------------------------------------------------------------
    
    void calc_time_fire(UINT T0s, UINT* ptime_fire, UINT* ptime_inj, UINT* pdeg_cr ,UINT8* pvac_level){
        static UINT deg[3],inj[2],vac_cal;
        UINT8 row = 0;
        UINT8 k = 0;
        static UINT eng_brake = 0;                  //エンブレ中判別用
    
        T1 = __builtin_divud(30000000UL, T0s);       //固定値/T0で回転数を算出(32/16bitのXC16ビルトイン関数)
        UINT8 column = (60000U/T0s)-3;               //1500~2000なら0,2000~2500なら1になるように除算して回転域判別
      
        while(1){
            if(vac<=table_vac[k]) break;            //バキューム域判別
            k++;                                    //
        }
    
        if (k==0){
            row = 0;
            vac_cal = 351;
            eng_brake += 1;
        }
        else if (k==8){
            row = 7;
            vac_cal = 752;
            eng_brake = 0;
        }
        else{
            row = k-1;
            vac_cal = vac;
            eng_brake = 0;
        }
        *pvac_level = row;
      
        for (k = 0; k<=1; k++) {
            UINT8 degl = deg_fire[row+k][column];
            UINT8 degh = deg_fire[row+k][column+1]; //前後の点火時期読み出し
            UINT rpml = table_rpm[column];
            //UINT rpmh = table_rpm[column+1];
    
            deg[k] = (degl*100)+__builtin_mulss((T1-rpml)/5,degh-degl); //degには100倍された点火時期が二つ入る
        } //あとはバキューム値からこの二つの内挿を取る
    
        deg[2] = deg[0]+__builtin_divsd(
        __builtin_mulss((vac_cal-table_vac[row]),(deg[1]-deg[0])), (table_vac[row+1]-table_vac[row])); //deg[2]に確定した点火時期が入る
    
        *ptime_fire = __builtin_divud(((DWORD)
                (18000-(deg[2]-DEG_IDLE))*T0s), 18000U); //ここで点火までの待ち時間が求まる  
    
       //噴射時間の計算
       for (k = 0; k<=1; k++) {
            UINT injtl = table_inj[row+k][column]*100;
            UINT injth = table_inj[row+k][column+1]*100; //前後の噴射時間読み出し
            UINT rpml = table_rpm[column];
            //UINT rpmh = table_rpm[column+1];
          
            inj[k] = injtl+__builtin_mulss((T1-rpml)/500,injth-injtl); //injには噴射時間が2つ入る
        } //あとはバキューム値からこの二つの内挿を取る  
    
        *ptime_inj = inj[0]+__builtin_divsd(
        __builtin_mulss((vac_cal-table_vac[row]),(inj[1]-inj[0])), (table_vac[row+1]-table_vac[row]));   //inj[2]に確定した噴射時間が入る  
        *ptime_fire -= CALC_TIMEH; //ここまでの計算時間を引いておく
        *pdeg_cr = deg[2]/100;          //現在の点火時期を返しておく
      
        //if (eng_brake>=2) {     //2回連続アイドル以下のバキューム値であればエンブレ中と判断
          //  *ptime_inj = 0;     //燃料カット
            //eng_brake = 1;      
       // }
    }
    
    //------------------------------------------------------------------
    // 最初のスタート時始動待ち
    //------------------------------------------------------------------
    
    void wait_start(void){
        IEC0bits.T1IE = 0;      //割り込み禁止
        IEC0bits.T2IE = 0;
        IEC0bits.T3IE = 0;
        IEC1bits.T4IE = 0;
        IEC1bits.T5IE = 0;
        IEC0bits.IC1IE = 0;
        IEC0bits.IC2IE = 0;
        IFS0 = 0;
    
        while (IFS0bits.IC1IF!=1&&IFS0bits.IC2IF!=1); //IC1かIC2のどちらかのピックアップ信号が入るまで待つ
        clr_icbuf();
        clr_ictmr();
      
        if (IFS0bits.IC1IF==1) { //IC1(14番)信号が入った
            GATE23 = 1; //23コイルに通電
            MARK_PU = ON_14; //14ピックアップ入力があったマークを付けておく
        }
        else { //IC2(23番)信号が入った
            GATE14 = 1; //14コイルに通電
            MARK_PU = ON_23; //23ピックアップ入力があったマークを付けておく
        }
      
        //始動時インジェクタは4気筒固定時間噴射して始動性を上げる
        inj1 = 1;
        inj2 = 1;
        inj3 = 1;
        inj4 = 1;
        PR2 = START_REVISION_TIME*2;
        PR3 = START_REVISION_TIME*2+10;
        PR4 = START_REVISION_TIME*2+20;
        PR5 = START_REVISION_TIME*2+30;
        T2CONbits.TON = 1;
        T3CONbits.TON = 1;
        T4CONbits.TON = 1;
        T5CONbits.TON = 1;
      
        IFS0 = 0; //フラグリセット
        IFS1 = 0;
        IFS2 = 0;
        IFS3 = 0;
        IFS4 = 0;
        IEC0bits.T1IE = 1;      //割り込み許可
        IEC0bits.T2IE = 1;
        IEC0bits.T3IE = 1;
        IEC1bits.T4IE = 1;
        IEC1bits.T5IE = 1;
        IEC0bits.IC1IE = 1;
        IEC0bits.IC2IE = 1;
        IEC0bits.U1RXIE = 1;
    }
    
    //------------------------------------------------------------------
    //初期設定
    //------------------------------------------------------------------
    
    void initialize_system(void){
      
        // CF no clock failure; NOSC FRCPLL; SOSCEN disabled; POSCEN disabled; CLKLOCK unlocked; OSWEN Switch is Complete; IOLOCK not-active;
        __builtin_write_OSCCONL((uint8_t) (0x0100 & 0x00FF));
        // CPDIV 1:1; PLLEN enabled; RCDIV FRC; DOZE 1:8; DOZEN disabled; ROI disabled;
        CLKDIV = 0x3020;
        // TUN Center frequency;
        OSCTUN = 0x0000;
        // ROEN disabled; ROSEL disabled; RODIV Base clock value; ROSSLP disabled;
        REFOCON = 0x0000;
        // WDTO disabled; TRAPR disabled; SLEEP disabled; BOR disabled; DPSLP disabled; CM disabled; SWR disabled; SWDTEN disabled; EXTR disabled; POR disabled; IDLE disabled; IOPUWR disabled; VREGS disabled;
        RCON = 0x0000;
    
        //ポート設定
        TRISA = 0b0000000000000011;     //RA0,1のみ入力(ADREF,バキューム)
        TRISB = 0b0000110100000000;     //
        PORTA = 0;
        PORTB = 0;
    
        //ADC設定
        AD1PCFG = 0b1111111111111101; // AN1をアナログに指定
        AD1CON1 = 0b0010000011100000;
        AD1CON2 = 0b0010000000000000; //Vref,AVss,
        AD1CON3 = 0b0000010000000100; //4TAD,4Tcy
        AD1CHS = 0b0000000000000001; //正側AN1
        AD1CSSL = 0;
        AD1CON1bits.ADON = 1; //AD変換器オン
    
        //ペリフェラルポート設定  
        iPPSInput(IN_FN_PPS_IC1, IN_PIN_PPS_RP10);   //RP10を IC1のキャプチャとして使用(14PU)
        iPPSInput(IN_FN_PPS_IC2, IN_PIN_PPS_RP11);   //RP11を IC2のキャプチャとして使用(23PU)
        iPPSOutput( OUT_PIN_PPS_RP7, OUT_FN_PPS_U1TX ); // RP7を UART1のTXDとして使用
        iPPSInput(  IN_FN_PPS_U1RX,  IN_PIN_PPS_RP8  ); // RP8を UART1のRXDとして使用
        iPPSOutput( OUT_PIN_PPS_RP2, OUT_FN_PPS_OC1 ); // RP2をポンプモータ用PWM出力として使用
    
        //キャプチャ設定
        IC1CON1bits.ICM = 0;     //入力キャプチャ設定初期化
        IC1CON1bits.ICSIDL = 1; //CPUアイドル中はキャプチャオフ
        IC1CON1bits.ICTSEL = 0b111; //入力キャプチャはシステムクロック
        IC1CON2bits.SYNCSEL = 0;
        IC2CON2bits.SYNCSEL = 0;
        IC1CON2bits.ICTRIG = 1;
        IC2CON2bits.ICTRIG = 1;
        IC1CON1bits.ICI = 0; //毎キャプチャごとにわりこみ
        IC1CON2bits.IC32 = 1; //32bit mode
        IC2CON1bits.ICM = 0; //入力キャプチャ設定初期化
        IC2CON1bits.ICSIDL = 1; //CPUアイドル中はキャプチャオフ
        IC2CON1bits.ICTSEL = 0b111; //入力キャプチャはシステムクロック
        IC2CON2bits.IC32 = 1; //32bit mode
        IC2CON1bits.ICM = 0b011; //キャプチャ用タイマスタート
        IC1CON1bits.ICM = 0b011; //キャプチャ用タイマスタート
        IC1CON2bits.TRIGSTAT = 1;
        IC2CON2bits.TRIGSTAT = 1;
    
        //点火カウント用タイマ設定
        T1CONbits.TSIDL = 1; //アイドル中停止
        T1CONbits.TCKPS = 0b01; //プリスケーラ1:8 0.5usで1カウント
        T1CONbits.TCS = 0; //内部クロック使用  
        TMR1 = 0;
      
        //噴射カウント用タイマ設定
        T2CONbits.TSIDL = 1;    //アイドル中停止
        T2CONbits.TCKPS = 0b01; //プリスケーラ1:8 0.5usで1カウント
        T2CONbits.TCS = 0; //内部クロック使用  
        TMR2 = 0;
        T3CONbits.TSIDL = 1; //アイドル中停止
        T3CONbits.TCKPS = 0b01; //プリスケーラ1:8 0.5usで1カウント
        T3CONbits.TCS = 0; //内部クロック使用  
        TMR3 = 0;
        T4CONbits.TSIDL = 1;
        T4CONbits.TCKPS = 0b01;
        T4CONbits.TCS = 0;
        TMR4 = 0;
        T5CONbits.TSIDL = 1;
        T5CONbits.TCKPS = 0b01;
        T5CONbits.TCS = 0;
        TMR5 = 0;
      
        //ポンプ駆動PWM設定
        OC1CON1 = 0;
        OC1CON2 = 0;
        OC1CON1bits.OCTSEL = 0b111;  //クロック基準
        OC1CON2bits.SYNCSEL = 0b11111;
        OC1R = (UINT)(period_pump/(100/DUTY_LOW));  //デューティ
        OC1RS = period_pump;    //周期
        OC1CON1bits.OCM = 0b110; //エッジ整列PWM
      
        //割り込み設定  
        IPC0bits.IC1IP = 5;     //キャプチャ割り込み要因優先レベル設定
        IPC1bits.IC2IP = 5;    
        IPC0bits.T1IP = 6;      //点火割り込み要因レベル設定
        IPC1bits.T2IP = 7;      //インジェクタ割り込み要因優先レベル設定
        IPC2bits.T3IP = 7;
        IPC6bits.T4IP = 7;
        IPC7bits.T5IP = 7;
    
        PR2 = 0xFFFF;           //周期レジスタを最大値にしてオーバーフローで割り込みはいるようにする
        PR1 = 0xFFFF;
        PR3 = 0xFFFF;           //点火と噴射用カウンタはとりあえず最大値としておく
        PR4 = 0xFFFF;
        PR5 = 0xFFFF;
    
        //UART設定
        CloseUART1();  
        unsigned int config1 =  UART_EN &               // UART有効
                                UART_IDLE_CON &         // アイドル時も動作させる
                                UART_DIS_WAKE &         // スリープ時はWakeupさせない
                                UART_IrDA_DISABLE &
                                UART_DIS_LOOPBACK &     // ループバックさせない
                                UART_NO_PAR_8BIT &      // パリティなし8bit
                                UART_1STOPBIT &         // ストップビット1
                                UART_MODE_SIMPLEX  &    // フローコントロール無し
                                UART_UEN_00 &
                                UART_UXRX_IDLE_ONE &    // U1RXのアイドルを1にする
                                UART_BRGH_FOUR &        // 高速転送有効
                                UART_DIS_ABAUD;         // ボーレートの自動検出を無効
        unsigned int config2 =  UART_INT_TX_BUF_EMPTY &  // TXDバッファが空のとき割り込みを発生
                                UART_IrDA_POL_INV_ZERO & // U1TXアイドルを0とする
                                UART_TX_ENABLE &         // TXDを有効(同時にRXDも有効になる
                                UART_INT_RX_CHAR &       // RXD受信時に割り込みを発生
                                UART_ADR_DETECT_DIS &
                                UART_RX_OVERRUN_CLEAR;
                        
        UINT Baud = 34;    //115kbps@FCY16MHz
                              
        OpenUART1(config1, config2, Baud );
        ConfigIntUART1( UART_RX_INT_EN & UART_RX_INT_PR4 & UART_TX_INT_DIS );       //    
      
        VAC_ADV = VAC_ON;   //バキューム進角オン
        FIX_INJ = FIX_OFF;  //固定噴射モードオフ
    }
    
    //------------------------------------------------------------------
    // キャプチャバッファを空にする
    //------------------------------------------------------------------
    
    void clr_icbuf(void){
        while (IC1CON1bits.ICBNE==1||IC2CON1bits.ICBNE==1) {
            UINT temp = IC1BUF; //バッファの内容を抜いておく
            temp = IC2BUF;
            temp = IC1BUF; //バッファの内容を抜いておく
            temp = IC2BUF;
        }
    }
    //------------------------------------------------------------------
    // キャプチャタイマをリセット&リスタート
    //------------------------------------------------------------------
    
    void clr_ictmr(void){
        IC1CON1bits.ICM = 0b000; //
        IC2CON1bits.ICM = 0b000; //
        IC2CON1bits.ICM = 0b011; //
        IC1CON1bits.ICM = 0b011; //
    }
    

    Header files are here.

    Code:
    /****************************************************
    TITLE: TESLA_16bi コンフィグヘッダファイル
     PIC: 24FJ64GA002
    DATE: 2016.2.20
    CODED BY: ASHITAKA GIKEN
    OTHER:
    
    ****************************************************/
    #ifndef INCLUDED_TESLA_16BIT_CONFIG_H
    #define INCLUDED_TESLA_16BIT_CONFIG_H
    
        #include    "pic24f_def.h"    //pic24f汎用ヘッダファイル
    
    // CONFIG4
    #pragma config DSWDTPS = DSWDTPSF    // DSWDT Postscale Select->1:2,147,483,648 (25.7 days)
    #pragma config DSWDTOSC = LPRC    // Deep Sleep Watchdog Timer Oscillator Select->DSWDT uses Low Power RC Oscillator (LPRC)
    #pragma config RTCOSC = SOSC    // RTCC Reference Oscillator  Select->RTCC uses Secondary Oscillator (SOSC)
    #pragma config DSBOREN = ON    // Deep Sleep BOR Enable bit->BOR enabled in Deep Sleep
    #pragma config DSWDTEN = ON    // Deep Sleep Watchdog Timer->DSWDT enabled
    
    // CONFIG3
    #pragma config WPFP = WPFP63    // Write Protection Flash Page Segment Boundary->Highest Page (same as page 42)
    #pragma config SOSCSEL = IO    // Secondary Oscillator Pin Mode Select->SOSC pins in Default (high drive-strength) Oscillator Mode
    #pragma config WUTSEL = LEG    // Voltage Regulator Wake-up Time Select->Default regulator start-up time used
    #pragma config WPDIS = WPDIS    // Segment Write Protection Disable->Segmented code protection disabled
    #pragma config WPCFG = WPCFGDIS    // Write Protect Configuration Page Select->Last page and Flash Configuration words are unprotected
    #pragma config WPEND = WPENDMEM    // Segment Write Protection End Page Select->Write Protect from WPFP to the last page of memory
    
    // CONFIG2
    #pragma config POSCMOD = NONE    // Primary Oscillator Select->Primary Oscillator disabled
    #pragma config I2C1SEL = PRI    // I2C1 Pin Select bit->Use default SCL1/SDA1 pins for I2C1
    #pragma config IOL1WAY = ON    // IOLOCK One-Way Set Enable->Once set, the IOLOCK bit cannot be cleared
    #pragma config OSCIOFNC = ON    // OSCO Pin Configuration->OSCO pin functions as port I/O (RA3)
    #pragma config FCKSM = CSDCMD    // Clock Switching and Fail-Safe Clock Monitor->Sw Disabled, Mon Disabled
    #pragma config FNOSC = FRCPLL    // Initial Oscillator Select->Fast RC Oscillator with Postscaler and PLL module (FRCPLL)
    #pragma config PLL96MHZ = ON    // 96MHz PLL Startup Select->96 MHz PLL Startup is enabled automatically on start-up
    #pragma config PLLDIV = DIV2    // USB 96 MHz PLL Prescaler Select->Oscillator input divided by 2 (8 MHz input)
    #pragma config IESO = ON    // Internal External Switchover->IESO mode (Two-Speed Start-up) enabled
    
    // CONFIG1
    #pragma config WDTPS = PS32768    // Watchdog Timer Postscaler->1:32768
    #pragma config FWPSA = PR128    // WDT Prescaler->Prescaler ratio of 1:128
    #pragma config WINDIS = OFF    // Windowed WDT->Standard Watchdog Timer enabled,(Windowed-mode is disabled)
    #pragma config FWDTEN = OFF    // Watchdog Timer->Watchdog Timer is disabled
    #pragma config ICS = PGx1    // Emulator Pin Placement Select bits->Emulator functions are shared with PGEC1/PGED1
    #pragma config GWRP = OFF    // General Segment Write Protect->Writes to program memory are allowed
    #pragma config GCP = OFF    // General Segment Code Protect->Code protection is disabled
    #pragma config JTAGEN = OFF    // JTAG Port Enable->JTAG port is disabled
    
    
    
    
    #endif

    Code:
    /****************************************************
    TITLE: PIC24F 汎用セッティングヘッダ
     PIC: 24FJ64GA002
    DATE: 2016.2.20
    CODED BY: ASHITAKA GIKEN
    OTHER:
    
    ****************************************************/
    #ifndef INCLUDED_PIC24F_H
    #define INCLUDED_PIC24F_H
    
        #include    <xc.h>
        #include    <stdlib.h>
        #include    <libpic30.h>   // __delay_ms()が定義されている
        #include    <stdint.h>
        #include    <stdbool.h>
           #include    <stdio.h>
           #include    <GenericTypeDefs.h>
        #include    "uart.h"
        #include    "outcompare.h"
        #include "PPS.h"
    
    
    
    
    #endif
    
     
  11. MattiThundrrr

    MattiThundrrr Not a guru

    Messages:
    3,690
    Likes Received:
    1,665
    Trophy Points:
    113
    Location:
    America's friendly hat
    Everybody got all that? Good, then we can continue.

    I haven't got a clue what's going on here, but I can't wait to see the results!
     
    DeanXJ750 likes this.
  12. hogfiddles

    hogfiddles XJ-Wizard, Host-Central NY Carb Clinic Moderator Premium Member

    Messages:
    14,632
    Likes Received:
    5,012
    Trophy Points:
    113
    Location:
    near utica, new york
  13. MattiThundrrr

    MattiThundrrr Not a guru

    Messages:
    3,690
    Likes Received:
    1,665
    Trophy Points:
    113
    Location:
    America's friendly hat
    Yeah, I read it too, and couldn't fathom the complexity of adding computer controlled fuel delivery to a 30 year old bike. Like drive by wire throttle on Fred Flintstones car! Xj electronic system baffles me, add Japanese programming instructions and I'm gone... not that I disapprove, I'm amazed! Just not something I'll ever attempt!
     
  14. Yu Tanaka

    Yu Tanaka Active Member

    Messages:
    65
    Likes Received:
    102
    Trophy Points:
    33
    Location:
    Shizuoka, Japan
    He seems to be troubled with Microsquirt, being unable to fire.
    But I'm making ECUs myself, and it has been confirmed that it surely fire, and actually it is running over 10000 km.
    I have to check about fuel injection next time (It's working well on the desk test). So now I am working on hardware fitting.

    I have not confirmed all threads yet, but have anyone succeeded in EFI here?
     
    Last edited: Dec 25, 2016
  15. hogfiddles

    hogfiddles XJ-Wizard, Host-Central NY Carb Clinic Moderator Premium Member

    Messages:
    14,632
    Likes Received:
    5,012
    Trophy Points:
    113
    Location:
    near utica, new york
    The few that have started projects have usually dropped out. There's only one that I can recall actually supposedly working a bit, but that got parted out soon after, iirc......

    Maybe YOU'LL be the one to finally see it through!
     
    Yu Tanaka likes this.
  16. Yu Tanaka

    Yu Tanaka Active Member

    Messages:
    65
    Likes Received:
    102
    Trophy Points:
    33
    Location:
    Shizuoka, Japan
    [​IMG]
    Here is a PCB of test type ECU. It's little bit bigger (105 x 85 mm) than production type because this one has test ports and connectors to communicate PC for debug.


    [​IMG]
    Here is a production type. Its size is 85 x 85mm. It has FETs for drive injectors, ignition coils, and fuel pump.
    If I choose a surface mount part, it will be possible to further miniaturize it.
    When the test type works well, I plan to further miniaturize by replacing the MCU with a surface mounted part.
    Then the board should fit in 65 x 85mm.



    [​IMG]
    The schimatic is here. If you need more details, you can get pdf file.
     

    Attached Files:

    Last edited: Dec 26, 2016
    Shaynus likes this.
  17. hogfiddles

    hogfiddles XJ-Wizard, Host-Central NY Carb Clinic Moderator Premium Member

    Messages:
    14,632
    Likes Received:
    5,012
    Trophy Points:
    113
    Location:
    near utica, new york
    very interesting--- keep going !!:D:D
     
  18. Shaynus

    Shaynus Member

    Messages:
    35
    Likes Received:
    2
    Trophy Points:
    8
    Location:
    Mandurah, Western Austalia
    Great work - very impressive!
     
  19. Yu Tanaka

    Yu Tanaka Active Member

    Messages:
    65
    Likes Received:
    102
    Trophy Points:
    33
    Location:
    Shizuoka, Japan


    Injection test result is OK.
     
    Herta, sybe, Quixote and 2 others like this.
  20. hogfiddles

    hogfiddles XJ-Wizard, Host-Central NY Carb Clinic Moderator Premium Member

    Messages:
    14,632
    Likes Received:
    5,012
    Trophy Points:
    113
    Location:
    near utica, new york
    Freeeekin' awesome
     
    k-moe likes this.

Share This Page