コントローラの製作

今まではPCに接続してコントロールしていましたが、今度は運転台のようなコントローラを作ります。

【製作中】

メインのマイコンにPIC32MX120F032Bを使用してドライブボードと232Cで通信します。

LDC表示器に秋月のAQM1602Y-RN-GBWを使用します。

スピードメーターには秋月の赤色バーLEDアレイOSX10201-Rを2個使い、20のLEDバーで速度と実際に駆動しているパワーをLEDの点滅で表示します。LEDバーのコントロールにPIC16F1933を使用して、I2CのSlaveモードでPIC32と通信します。

・列車1は運転の記録・再生が出来ます。I2CのEEPROM 24LC64にプログラム運転を記録します。

動画です。
3Dプリンタでフレームを作って仮組

3Dプリンタでパネルを作ったところ

 

 

 

 

プリント基板で製作中

 

LEDバー表示用 PIC16F1933のコード
//*********************************************************
//2020_02_11 LED_BAR
//*********************************************************
#include <xc.h>
#define _XTAL_FREQ 4000000

#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
//#pragma config DEBUG = OFF
#pragma config FOSC =INTOSC //HS

#pragma config FCMEN = OFF
#pragma config MCLRE = OFF
#pragma config WDTE = OFF //ON
#pragma config CP = OFF
#pragma config LVP = OFF
#pragma config PWRTE = ON


#define RXBUFFER_SIZE 4 

#define STATE1      0b00001001 // 0x09 master write last was address
#define STATE2      0b00101001 // 0x29 master write last was data
#define STATE3      0b00001101 // 0x0d master read last was address
#define STATE4      0b00101100 // 0x2c master write last was data
#define STATE5      0b00101000 // 0x28

//PORTアクセス用共用体

union byte_access_long {
    long LNG; // Long Access

    struct { // byte Access
        unsigned char L1;
        unsigned char H1;
        unsigned char L2;
    } BYTE;

    struct {
        unsigned char PORTB : 8;
        unsigned char PORTA : 7;
        unsigned char PORTC1 : 3;
        unsigned char PORTC2 : 2;
    } BIT;
};

volatile unsigned char RXBuffer[RXBUFFER_SIZE];
volatile unsigned char RXBufferIndex = 0;


void setUpI2CSlave(void);
void I2CWrite(unsigned char);
long LED_BAR(unsigned char, unsigned char, char);

//********************************************************

void main(void) {
    //最高速32MHz
    OSCCONbits.SPLLEN = 1; //×4 PLL
    OSCCONbits.IRCF = 14; //8MHz

    ANSELA = 0; // アナログ入力 AN8からAN13 を無効
    ANSELB = 0; // アナログ入力 AN0からAN7 を無効

    PORTA = 0;
    PORTB = 0;

    TRISA = 0;
    TRISB = 0;
    TRISC = 0b11000;


    OPTION_REG = 0x0f; // WDT,Int Fall, pulup


    __delay_ms(10); // 10msec

    setUpI2CSlave(); //I2C SlaveMode setting

    while (1) {
        union byte_access_long speed_led;
       
        speed_led.LNG = LED_BAR(RXBuffer[0], 1, RXBuffer[1]);//i:speed d:明るさ1-10 b:powerの点滅
        PORTB = speed_led.BIT.PORTB;
        PORTA = speed_led.BIT.PORTA << 1;
        PORTC = speed_led.BIT.PORTC1 | (speed_led.BIT.PORTC2 << 5);

        //CLRWDT();

        __delay_ms(10); // 10msec
    }

}

//I2C ADDRESS main用 0x10, sub用 0x12
#define	I2C_ADDR	0x10	// I2C 7bit address

void setUpI2CSlave() {

    SSPCON2 = 0b00000001; //SEN is set to enable clock stretching 

    SSPCON3 = 0x00;
    SSPADD = I2C_ADDR << 1; //7-bit address is stored in the 7 MSB's of the SSP1ADD register**********
    SSPSTAT = 0x00;
    SSPCON1 = 0b00110110;

    /* Enable interrupts */
    SSPIF = 0; //Clear MSSP interrupt flag 
    SSPIE = 1; //I2C interrupt enable 
    //end I2C(1) setup---------------------------------------------------------------- 

    // Common Interrupt
    PEIE = 1; // Enable Peripheral interrupts 
    GIE = 1; // Enable global interrupts     
}

void checkStatAndMngI2c() {
    static char DAStatus = 0;
    unsigned char i2cStatus, value;
    i2cStatus = SSPSTAT;

    i2cStatus = (i2cStatus & 0b00101101); //Mask out unimportant bits 

    //
    switch (i2cStatus) {
        case STATE1:
            value = SSPBUF; //read buffer, clear BF 

            RXBufferIndex = 0; //clear index 
            DAStatus = 1; // next call is address inside memory

            if (SSPCON1bits.SSPOV)SSPCON1bits.SSPOV = 0; //clear receive overflow indicator
            if (SSPCON2bits.SEN) SSPCON1bits.CKP = 1; //release the SCL line 
            break;

        case STATE2:
            value = SSPBUF; //read buffer, clear BF

            if (DAStatus == 1) {
                RXBufferIndex = value;
                DAStatus = 2;
            } else {
                RXBuffer[RXBufferIndex] = value;
                RXBufferIndex++; //increment index 
                if (RXBufferIndex >= RXBUFFER_SIZE)
                    RXBufferIndex = 0;
            }

            if (SSPCON2bits.SEN) SSPCON1bits.CKP = 1; //release the SCL line 
            break;

        case STATE3:
            value = SSPBUF; //dummy read

            if (RXBufferIndex >= RXBUFFER_SIZE)
                RXBufferIndex = 0;

            I2CWrite(RXBuffer[RXBufferIndex]); //write back the index of status requested 
            RXBufferIndex++;
            break;

        case STATE4:
            if (RXBufferIndex >= RXBUFFER_SIZE)
                RXBufferIndex = 0;

            I2CWrite(RXBuffer[RXBufferIndex]); //write back the index of status requested 
            RXBufferIndex++;
            break;

        case STATE5:
            break;
        default:
            if (SSPCON2bits.SEN) SSPCON1bits.CKP = 1; //release the SCL line 
            break;
    }
}

void __interrupt() I2Cinterrupt() {
    if (SSPIF) {
        SSPIF = 0; // Clear interrupt flag
        checkStatAndMngI2c();
    }
}

//Byte送信

void I2CWrite(unsigned char data) {
    while (SSPSTATbits.BF); //wait while buffer is full 
    do {
        SSPCON1bits.WCOL = 0; //clear write collision flag 
        SSPBUF = data;
    } while (SSPCON1bits.WCOL); //do until write collision flag is clear 
    if (SSPCON2bits.SEN) SSPCON1bits.CKP = 1; //release the SCL line 
}

long LED_BAR(unsigned char i, unsigned char d, char b) {
    //i:speed d:明るさ1-10 b:powerの点滅
    unsigned char s;
    long ret = 1;
    long b_p = 1;

    static unsigned char blink;
    unsigned char blink_t = 50;

    static unsigned char dimmer;

    if (!dimmer--) {
        dimmer = 10;
        if (!blink--)
            blink = blink_t;
    }


    if (dimmer <= d) {//dimer
        s = i;

        ret <<= s;
        ret--;
    } else {
        ret = 0;
    }

    b_p <<= b;

    if (blink > (blink_t >> 1)) {
        //blink_kn半分の時間点灯
        ret |= b_p;
    } else {
        ret &= ~b_p;
    }

    return ret;
}
SWLED表示用 PIC16F1827のコード
//*********************************************************
//2020_03_20
//*********************************************************
#include <xc.h>
#define _XTAL_FREQ 4000000

#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
#pragma config FOSC =INTOSC //HS
#pragma config FCMEN = OFF
#pragma config MCLRE = OFF
#pragma config WDTE = OFF //ON
#pragma config CP = OFF
#pragma config LVP = OFF
#pragma config PWRTE = ON


#define RXBUFFER_SIZE 4 

#define STATE1      0b00001001 // 0x09 master write last was address
#define STATE2      0b00101001 // 0x29 master write last was data
#define STATE3      0b00001101 // 0x0d master read last was address
#define STATE4      0b00101100 // 0x2c master write last was data
#define STATE5      0b00101000 // 0x28


volatile unsigned char RXBuffer[RXBUFFER_SIZE];
volatile unsigned char RXBufferIndex = 0;


void setUpI2CSlave(void);
void I2CWrite(unsigned char);


//********************************************************

void main(void) {
    //最高速32MHz
    OSCCONbits.SPLLEN = 1; //×4 PLL
    OSCCONbits.IRCF = 14; //8MHz

    ANSELA = 0; // アナログ入力 AN8からAN13 を無効
    ANSELB = 0; // アナログ入力 AN0からAN7 を無効

    PORTA = 0;
    PORTB = 0;

    TRISA = 0;
    TRISB = 0b10010;


    OPTION_REG = 0x0f; // WDT,Int Fall, pulup


    __delay_ms(10); // 10msec

    setUpI2CSlave(); //I2C SlaveMode setting

    while (1) {
        //I2Cで受信したデータをポートに出力
        PORTB = RXBuffer[1];
        PORTA = RXBuffer[0];
        
        __delay_ms(10); // 10msec
    }

}


#define	I2C_ADDR	0x11	// I2C 7bit address

void setUpI2CSlave() {

    SSPCON2 = 0b00000001; //SEN is set to enable clock stretching 

    SSPCON3 = 0x00;
    SSPADD = I2C_ADDR << 1; //7-bit address is stored in the 7 MSB's of the SSP1ADD register**********
    SSPSTAT = 0x00;
    SSPCON1 = 0b00110110;

    /* Enable interrupts */
    SSP1IF = 0; //Clear MSSP interrupt flag 
    SSP1IE = 1; //I2C interrupt enable 
    //end I2C(1) setup---------------------------------------------------------------- 

    // Common Interrupt
    PEIE = 1; // Enable Peripheral interrupts 
    GIE = 1; // Enable global interrupts     
}

void checkStatAndMngI2c() {
    static char DAStatus = 0;
    unsigned char i2cStatus, value;
    i2cStatus = SSPSTAT;

    i2cStatus = (i2cStatus & 0b00101101); //Mask out unimportant bits 

    //
    switch (i2cStatus) {
        case STATE1:
            value = SSPBUF; //read buffer, clear BF 

            RXBufferIndex = 0; //clear index 
            DAStatus = 1; // next call is address inside memory

            if (SSPCON1bits.SSPOV)SSPCON1bits.SSPOV = 0; //clear receive overflow indicator
            if (SSPCON2bits.SEN) SSPCON1bits.CKP = 1; //release the SCL line 
            break;

        case STATE2:
            value = SSPBUF; //read buffer, clear BF

            if (DAStatus == 1) {
                RXBufferIndex = value;
                DAStatus = 2;
            } else {
                RXBuffer[RXBufferIndex] = value;
                RXBufferIndex++; //increment index 
                if (RXBufferIndex >= RXBUFFER_SIZE)
                    RXBufferIndex = 0;
            }

            if (SSPCON2bits.SEN) SSPCON1bits.CKP = 1; //release the SCL line 
            break;

        case STATE3:
            value = SSPBUF; //dummy read

            if (RXBufferIndex >= RXBUFFER_SIZE)
                RXBufferIndex = 0;

            I2CWrite(RXBuffer[RXBufferIndex]); //write back the index of status requested 
            RXBufferIndex++;
            break;

        case STATE4:
            if (RXBufferIndex >= RXBUFFER_SIZE)
                RXBufferIndex = 0;

            I2CWrite(RXBuffer[RXBufferIndex]); //write back the index of status requested 
            RXBufferIndex++;
            break;

        case STATE5:
            break;
        default:
            if (SSPCON2bits.SEN) SSPCON1bits.CKP = 1; //release the SCL line 
            break;
    }
}

void __interrupt() I2Cinterrupt() {
    if (SSP1IF) {
        SSP1IF = 0; // Clear interrupt flag
        checkStatAndMngI2c();
    }
}

//Byte送信

void I2CWrite(unsigned char data) {
    while (SSPSTATbits.BF); //wait while buffer is full 
    do {
        SSPCON1bits.WCOL = 0; //clear write collision flag 
        SSPBUF = data;
    } while (SSPCON1bits.WCOL); //do until write collision flag is clear 
    if (SSPCON2bits.SEN) SSPCON1bits.CKP = 1; //release the SCL line 
}

PIC32のコード
Harmonyの設定

 

 

 

Timerを2つ使います。

 

 

 

Debug中ですが

app.hに一行追加
// *****************************************************************************
// *****************************************************************************
// Section: Included Files
// *****************************************************************************
// *****************************************************************************

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include "system_config.h"
#include "system_definitions.h"
#include "atc.h" //追加
atc.h ( ヘッダーファイルに追加)
//
//2021_0821

#define TR_COUNT 3      //列車数
#define ROSEN_NUM 0   //路線(ボード)番号
#define BOARD_COUNT 3     //ボード数

#define RX_BYTE 230     //128//RS232C受信バイト数
#define TX_BYTE 128     //230     //RS232C送信バイト数
#define RX_DATA_BYTE 12 //1列車当たりの受信バイト数
#define TX_DATA_BYTE 12 //1列車当たりの送信バイト数

#define POINT_COUNT 4 //ポイント数
#define YARD_COUNT 2 //YARD数
#define STOP_POS_COUNT 2 //停止位置数

//I2C用変数    
DRV_HANDLE hi2c;
DRV_I2C_BUFFER_HANDLE bhi2c;
//USART用変数 
DRV_HANDLE handleUSART0;

bool ext_int_enable;

//16bitのINT型の上位H byte、下位L byte読み込み用共用体

union byte_access {
    int INT; // Int Access

    struct { // byte Access
        unsigned char L;
        unsigned char H;
    } BYTE;
};

//位置情報の構造体

union POSITION { //位置情報
    unsigned char BYTE; /* Byte Access */
    //struct PSI_BIT BIT; /* Bit  Access */

    struct {
        unsigned char KUKAN : 3; /* 区間 Bit 0-2 */
        unsigned char ROSEN : 3; /* 路線 Bit 3-5 */
        unsigned char SOU : 1; /* 相   Bit 6   */
        unsigned char DIR : 1; /* 方向 Bit 7   */
    } BIT;

};

struct STATUS_BIT {
    unsigned char CHG : 1; //区間変化
    unsigned char SP_MANU : 1; //speed manual
    unsigned char REV : 1; //逆転
    unsigned char CHG_RCV : 1; //chg flg
    unsigned char DUMY : 2; //DUMY
    unsigned char SLOW : 1; //減速
    unsigned char SAFE : 1; //安全
};

typedef enum {
    NONE = 0,
    P_SW_ON,
    SWITCH_REQ,
    SWITCHING,
    WAITING,
} POINT_STATE;

typedef enum {
    SAFE = 0,
    WAIT_PASS,
    IMPOSSIBLE,
} POINT_SAFE;

typedef enum {
    YARD_NONE = 0,
    Y_SW_ON,
    YARD_REQ,
    YARD_COMP,
    POINT_COMP,
    YARD_STOP,
    YARD_STOP_COMP,
    POINT_RET,
    POINT_RET_COMP,
    YARD_END,
    START_REQ,
    START_REQ_ACK,
    READY_START,
    EXIT_POS,

} YARD_STATE;

typedef enum {
    GO = 0,
    STOP,
    SLOW,
    STOP_REV,
    SLOW_POINT,
    SLOW_YARD,
} SAFE_FLAG;

//列車の位置情報の構造体

struct st_position {
    //現在位置
    union POSITION NOW;

    //前の位置
    union POSITION BEFORE;

    //次の位置
    union POSITION NEXT;

    //次々の位置
    union POSITION ANEXT;

    union {
        unsigned char BYTE; /* Byte Access */
        struct STATUS_BIT BIT; /* Bit  Access */
    } STATUS;

    int speed;

    union byte_access speed_cont;

    int speed_err;
    int speed_peak;

    int mascon;

    unsigned char henka;
    //unsigned char safe;
    union byte_access speed_ret; //読み取りスピード
    union byte_access speed_ret_rx; //読み取りスピード
    union byte_access speed_ret_tx; //読み取りスピード
    union byte_access power;

    unsigned char point;
    unsigned char point_num;
    unsigned char yard;
    unsigned char yard_num;
    unsigned char revers_req;

    union byte_access speed_rx;

    unsigned char REC_NOW;
    unsigned char REC_NEXT;
    unsigned char REC_BEFORE;

    POINT_STATE point_state;
    YARD_STATE yard_state;


};


//監視区間設定用の共用体

union scan_port {
    unsigned char BYTE; /* Byte Access */

    struct {
        unsigned char DUMMY : 2; /* Bit 0-1 */
        unsigned char KUKAN : 3; /* Bit 2-4 監視区間*/
        unsigned char DISABLE : 1; /* Bit 5   */
        unsigned char B6 : 1; /* Bit 6   */
    } BIT;

};



//ポイント用共用体

struct point {
    union POSITION approach;

    union POSITION exit;

    unsigned char num;
};

struct yard {
    union POSITION approach;
    union POSITION start;
    union POSITION exit;
    union POSITION approach_b;
    union POSITION start_b;
    union POSITION exit_b;

    unsigned char point_num;
    unsigned char line;
    unsigned char exist;
    unsigned char type;

    unsigned char y_cont;
    unsigned char p_cont;

};

//停止位置

struct stop_position {
    union POSITION pos;
    char point_num;
};

//操作盤用

struct ContPanel {

    struct {
        unsigned char POINT : 1;
        unsigned char REVERS : 1;
        unsigned char YARD : 1;

    } SW;

    struct {
        unsigned char POINT : 1;
        unsigned char REVERS : 1;
        unsigned char YARD : 1;

    } LED;

    char point_num;
    char yard;
    char line;
};

struct RecList {
    union POSITION pos;
    unsigned char speed;

    union {
        unsigned char BYTE; /* Byte Access */

        struct {
            unsigned char YARD : 3;
            unsigned char LINE : 3;
            unsigned char ENABLE : 1;
        } BIT;
    } yard;

    union {
        unsigned char BYTE; /* Byte Access */

        struct {
            unsigned char POINT_NUM : 3;
            unsigned char ENABLE : 1;
            unsigned char REVERS : 1;
        } BIT;
    } point;

    //unsigned char point;
};

struct RecList rec_list[128];
unsigned char step;
unsigned char step_stop;
unsigned char rec_status;

unsigned char EnableBit[] = {1, 2, 4, 8, 16, 32, 64, 128};
unsigned int int_counter; //インタラプトカウンタ
unsigned int speed_pw[2]; //スピードパルス幅
struct st_position train[TR_COUNT]; //列車位置情報
struct st_position* train_sou[2];
unsigned char cont_train[2]; //制御する列車番号
unsigned char kukan[2]; //区間
unsigned char kanshi_now[2]; //スピード読み込み用
unsigned char kanshi_before[2]; //スピード読み込み用
union scan_port kanshi; //区間監視用

union byte_access adc_ret; //ADC値
union byte_access adc_brk_ret; //ブレーキのADC値
union byte_access debug1; //ADC値

int gnd_adc;

union byte_access gnd_level;

unsigned char rx_data[RX_BYTE];
unsigned char tx_data[TX_BYTE];

unsigned char receive_data; //通信用受信データ
unsigned char send_data; //通信用送信データ
unsigned char comm_data[128]; //通信用メモリ
unsigned int comm_counter; //通信用インタラプトカウンタ
unsigned char board_num; //ボード番号

unsigned char point_req; //ポイントリクエスト
unsigned char yard_req; //ポイントリクエスト
unsigned char int_count; //interrupt count
unsigned char sw_input[4]; //sw
char key_on[20];
char key_count[20];
char key_down[20];
unsigned char r_enc;

struct point point[POINT_COUNT];
struct yard yard[YARD_COUNT];
struct stop_position stop_pos[STOP_POS_COUNT];

struct ContPanel cont_panel[TR_COUNT];
//Curser用
#define CUR_MAX 6 
char curser_pos;
char SetPos_y[] = {0, 1, 1, 0, 1, 1};
char SetPos_x[] = {2, 2, 4, 9, 9, 11};
char cont_sel;
char disp_mode;
char disp_page;
#define PAGE_MAX 3 

int Brake;
char speed_mode;
char test1;
char test2;

#define EEP_PAGE 32
unsigned char eep_data[256];
unsigned char eep_page_data[34]; //(2+32)
unsigned char prg_num;
unsigned char repeat;
unsigned char count_dwn;
unsigned char disp_pos; //debug monitor
unsigned char point_test;
lcd.c (SourceFiles appに追加)
//
//2021_0418
//
#include "system/common/sys_common.h"
#include "app.h"
#include "system_definitions.h"

#define ADR 0x7C
#define PIC_ADR 0x20 //PIC16F1827 slave

void LCD_cmd(char);
void LCD_int(void);
void LCD_str(char *);
void LCD_dat(char);
void LCD_hex(char);
void LCD_posyx(char, char);
void LCD_dec(int, char);

void PIC_dat(char, unsigned char, unsigned char, unsigned char);
unsigned char EEP_Read(int, unsigned char, unsigned char);
void EEP_Write(int, char, unsigned char);

void BSP_DelayMs(unsigned short);
void BSP_DelayUs(unsigned short);

uint8_t data[5];
uint8_t r_data[256];

//遅延調整用関数(ms)

void BSP_DelayMs(unsigned short milliseconds) {
    unsigned long time;
    time = _CP0_GET_COUNT(); //Read Core Timer
    time += (SYS_CLK_FREQ / 2 / 1000) * milliseconds; //calc the Stop Time
    while ((long) (time - _CP0_GET_COUNT()) > 0) {
    };
}

//遅延調整用関数(μs)

void BSP_DelayUs(unsigned short microseconds) {
    unsigned long time;
    time = _CP0_GET_COUNT(); //Read Core Timer
    time += (SYS_CLK_FREQ / 2 / 1000000) * microseconds; //calc the Stop Time
    while ((long) (time - _CP0_GET_COUNT()) > 0) {
    };
}

void LCD_cmd(char cmd) {
    data[0] = 0x80;
    data[1] = cmd;

    bhi2c = DRV_I2C_Transmit(hi2c, ADR, data, 2, NULL); //I2C送信
    while (DRV_I2C_TransferStatusGet(hi2c, bhi2c) != DRV_I2C_BUFFER_EVENT_COMPLETE); /*I2C完了待ち*/


    if (cmd & 0xFC) // LCDのコマンドにより待ち時間が違う
        BSP_DelayUs(60); // 60usec
    else
        BSP_DelayMs(3); // 3msec

}

void LCD_int(void) {
    BSP_DelayMs(100);

    LCD_cmd(0x38);
    LCD_cmd(0x39);
    LCD_cmd(0x14);
    LCD_cmd(0x73); //7A(forAQM1602)
    LCD_cmd(0x56); //54(forAQM1602)
    LCD_cmd(0x6C);

    BSP_DelayMs(200);

    LCD_cmd(0x0C); //Disp ON/OFF
    LCD_cmd(0x01); // Clear Display

    BSP_DelayUs(1100);

}

//文字列表示

void LCD_str(char *str) {
    while (*str) //0x00まで繰り返し
        LCD_dat(*str++); //1文字表示
}

//1文字表示

void LCD_dat(char chr) {
    data[0] = 0x40;
    data[1] = chr;

    //I2C送信
    bhi2c = DRV_I2C_Transmit(hi2c, ADR, data, 2, NULL);
    while (DRV_I2C_TransferStatusGet(hi2c, bhi2c) != DRV_I2C_BUFFER_EVENT_COMPLETE);

    BSP_DelayUs(60); // 60usec

}

//-------- 16進文字変換表示 ----------------

void LCD_hex(char c) {
    const char hexch[] = "0123456789ABCDEF";
    LCD_dat(hexch[c >> 4]); //上位4bit表示
    LCD_dat(hexch[c & 0xF]); //下位4bit表示
}

//--------3桁 10進文字表示 ----------------

void LCD_dec(int i, char c) {
    const char decch[] = "0123456789 ";
    char n[3];

    n[2] = i / 100;
    n[1] = (i % 100) / 10;
    n[0] = i % 10;

    if (n[2] == 0) {
        n[2] = 10; //100の桁は0ならスペース
        if (n[1] == 0) {
            n[1] = 10; //100の桁0で10の桁0ならスペース
        }
    }

    if (c > 2) LCD_dat(decch[n[2]]);
    if (c > 1) LCD_dat(decch[n[1]]);
    LCD_dat(decch[n[0]]);


}
//-------- カーソル位置指定 --------------------------------------

void LCD_posyx(char ypos, char xpos) {
    unsigned char pcode;
    switch (ypos & 0x03) { // 縦位置を取得
        case 0: pcode = 0x80;
            break; // 1行目
        case 1: pcode = 0xC0;
            break; // 2行目
        case 2: pcode = 0x94;
            break; // 3行目
        case 3: pcode = 0xD4;
            break; // 4行目
    }
    LCD_cmd(pcode += xpos); // 横位置を加える
}

void PIC_dat(char start, unsigned char d1, unsigned char d2, unsigned char adr) {
    data[0] = start;
    data[1] = d1;
    data[2] = d2;

    //I2C送信
    bhi2c = DRV_I2C_Transmit(hi2c, adr, data, 3, NULL);
    while (DRV_I2C_TransferStatusGet(hi2c, bhi2c) != DRV_I2C_BUFFER_EVENT_COMPLETE);

    BSP_DelayUs(60); // 60usec

}

void EEP_Write(int adr, char page, unsigned char i2c_adr) {
    char count = 3; //1byte write(2+1)
    if (page) count = 34; //page write(2+32) 24LC64は1page32byte
    
    eep_page_data[0] = adr >> 8;
    eep_page_data[1] = adr & 0xFF;

    //I2C送信
    bhi2c = DRV_I2C_Transmit(hi2c, i2c_adr, eep_page_data, count, NULL);
    while (DRV_I2C_TransferStatusGet(hi2c, bhi2c) != DRV_I2C_BUFFER_EVENT_COMPLETE);

    BSP_DelayMs(10); // 10msec
}

unsigned char EEP_Read(int adr, unsigned char count, unsigned char i2c_adr) {

    data[0] = adr >> 8;
    data[1] = adr & 0xFF;

    //I2C送信
    bhi2c = DRV_I2C_Transmit(hi2c, i2c_adr, data, 2, NULL);
    while (DRV_I2C_TransferStatusGet(hi2c, bhi2c) != DRV_I2C_BUFFER_EVENT_COMPLETE);

    BSP_DelayUs(60); // 60usec

    //DRV_I2C_BUFFER_HANDLE DRV_I2C_Receive ( DRV_HANDLE drvhandle, uint16_t deviceaddress, 
    //                                    void *rxBuffer, size_t size, void * context)

    bhi2c = DRV_I2C_Receive(hi2c, i2c_adr, eep_data, count, NULL);

    //DRV_I2C_TransmitThenReceive ( DRV_HANDLE drvhandle, uint16_t deviceaddress,
    //                                                void *txBuffer, size_t wsize, 
    //                                                void *rxBuffer, size_t rsize, void * context);
    //bhi2c = DRV_I2C_TransmitThenReceive(hi2c, adr + 1, data, 0, r_data, 1, NULL);

    while (DRV_I2C_TransferStatusGet(hi2c, bhi2c) != DRV_I2C_BUFFER_EVENT_COMPLETE);

    BSP_DelayUs(60); // 60usec

    return eep_data[0];

}
/*******************************************************************************
 End of File
 */
timer_int.c (SourceFiles appに追加)
//
//
//2020_0829
//
#include "system/common/sys_common.h"
#include "app.h"
#include "system_definitions.h"

void KeyIn(char);

void timer_int_func() {
    unsigned char n, p;
    static char enc_c[2];
    static char enc_on[2];
    unsigned char sw_pos = int_count++ >> 2 & 0b11;


    _RB2 = 0;
    _RA2 = 0;
    _RB3 = 0;
    _RA3 = 0;

    //    PORTB &= 0b11; //RB2,3=0
    //    PORTA &= 0b11; //RA2,3=0

    switch (sw_pos) {
        case 0:
            _RB2 = 1;
            break;
        case 1:
            _RB3 = 1;
            break;
        case 2:
            _RA2 = 1;
            break;
        case 3:
            _RA3 = 1;
            break;
    }

    KeyIn(sw_pos); //KeyInput

    //ロータリーエンコーダ入力

    if (_RB11 == 0) {
        if (enc_c[0]++ > 1) {
            enc_c[0] = 1;
            if (enc_on[0] == 0) {
                enc_on[0] = 1;
                if (_RB10 == 1) {
                    r_enc--;
                    if (train[cont_sel].mascon > 0)
                        train[cont_sel].mascon--;

                }

            }
        }
    } else if (--enc_c[0] < 0) {
        enc_c[0] = 0;
        enc_on[0] = 0;
    }

    if (_RB10 == 0) {
        if (enc_c[1]++ > 1) {
            enc_c[1] = 1;
            if (enc_on[1] == 0) {
                enc_on[1] = 1;
                if (_RB11 == 1) {
                    r_enc++;
                    if (train[cont_sel].mascon < 100)
                        train[cont_sel].mascon++;
                }

            }
        }
    } else if (--enc_c[1] < 0) {
        enc_c[1] = 0;
        enc_on[1] = 0;
    }



    //    if (enc_rise[0] == 1) {
    //        enc_rise[0] = 0;
    //        r_enc++;
    //    }



    //if (int_count++ & 0x3F)return;
    //以下64回に1回実行





}

void timer_int_func_rs() {
    unsigned char n, p;

    //ヘッダーとして&H55,&HAAを送る
    tx_data[0] = 0x55;
    tx_data[1] = 0xAA;

    for (n = 0; n < TR_COUNT; n++) {
        p = n * TX_DATA_BYTE + 2;
        union byte_access send_speed;
        send_speed.INT = train[n].speed;

        tx_data[p] = send_speed.BYTE.L;
        tx_data[p + 1] = train[n].NOW.BYTE;
        tx_data[p + 2] = train[n].BEFORE.BYTE;
        tx_data[p + 3] = train[n].NEXT.BYTE;
        tx_data[p + 4] = train[n].STATUS.BYTE;
        tx_data[p + 5] = train[n].point;
        tx_data[p + 6] = train[n].yard;
    }

    // 送信用メモリデータをPCに転送します
    for (n = 0; n < TX_BYTE; n++) {
        DRV_USART_WriteByte(DRV_USART_INDEX_0, tx_data[n]);
    }

    //ADC読み込み
    PLIB_ADC_MuxChannel0InputPositiveSelect(DRV_ADC_ID_1, ADC_MUX_A, ADC_INPUT_POSITIVE_AN0); //AN0:mainマスコンVR
    PLIB_ADC_SamplingStart(ADC_ID_1);
    while (!PLIB_ADC_ConversionHasCompleted(ADC_ID_1));
    adc_ret.INT = PLIB_ADC_ResultGetByIndex(ADC_ID_1, 0);

    //ブレーキVR読み込み
    PLIB_ADC_MuxChannel0InputPositiveSelect(DRV_ADC_ID_1, ADC_MUX_A, ADC_INPUT_POSITIVE_AN1); //AN1:ブレーキVR
    PLIB_ADC_SamplingStart(ADC_ID_1);
    while (!PLIB_ADC_ConversionHasCompleted(ADC_ID_1));
    adc_brk_ret.INT = PLIB_ADC_ResultGetByIndex(ADC_ID_1, 0);

}

void KeyIn(char row) {
    char p, n, key;

    for (p = 0; p < 5; p++) {
        n = row * 5 + p;

        if (p < 4) {
            key = PORTB & EnableBit[p + 4];
        } else {
            key = _RA4;
        }

        if (key) {//RB4-
            if (key_count[n]++ > 3) {
                key_count[n] = 3;
                if (!key_on[n]) {
                    key_on[n] = 1;
                    key_down[n] = 1;
                }

            }
        } else if (--key_count[n] < 0) {
            key_count[n] = 0;
            key_on[n] = 0;
        }
    }

}


/* *****************************************************************************
 End of File
 */
app.cの APP_Tasks 以下を挿げ替えます。
//
//2021_0829

/******************************************************************************
  Function:
    void APP_Tasks ( void )

  Remarks:
    See prototype in app.h.
 */
void ini_train(char);
void train_set(unsigned char, union POSITION p1);
void section_chg(unsigned char);
void reverse(unsigned char);
int speed_up_down(char, int, char);
int stoppage_time(char, int);
unsigned char safe_check(unsigned char);
void point_set(unsigned char, unsigned char, union POSITION, union POSITION);
union POSITION point_pos(unsigned char, union POSITION);
POINT_SAFE point_safe_check(unsigned char, union POSITION);
union POSITION position_set(unsigned char, unsigned char, unsigned char, unsigned char);
void point_process(void);
bool point_exit_position(unsigned char, union POSITION);
void yard_process(void);
void yard_set(unsigned char, union POSITION, unsigned char, unsigned char, unsigned char, unsigned char);
union POSITION next_position(union POSITION);
void LcdDisp(void);
void KeyCont(void);
char SelLED(char);
char yard_line_num(char, char, char, char);
void yard_set_line(char, char, char);
bool yard_exit_pos(unsigned char, union POSITION);
void stop_pos_set(char, union POSITION, char);
void stop_pos_process(void);
void rec_play(void);
void SavePlayList(unsigned char);
void LoadPlayList(unsigned char);
void DelPlayList(unsigned char);
unsigned char ExistList(unsigned char);
unsigned char NextList(unsigned char, char);
void ClrRecList(void);
POINT_SAFE yard_safe_check(unsigned char, union POSITION);

void APP_Tasks(void) {

    /* Check the application's current state. */
    switch (appData.state) {
            /* Application's initial state. */
        case APP_STATE_INIT:
        {
            bool appInitialized = true;

            char n;

            DRV_ADC_Open(); //Enable ADC

            //USART
            if (handleUSART0 == DRV_HANDLE_INVALID) {
                handleUSART0 = DRV_USART_Open(0, DRV_IO_INTENT_READWRITE | DRV_IO_INTENT_NONBLOCKING);
                appInitialized &= (DRV_HANDLE_INVALID != handleUSART0);
            }

            //I2C Open
            hi2c = DRV_I2C_Open(DRV_I2C_INDEX_0, DRV_IO_INTENT_READWRITE | DRV_IO_INTENT_NONBLOCKING);
            if (hi2c != DRV_HANDLE_INVALID) {
                //LCD初期化
                LCD_int();
                LCD_str("PC_REM");
                LCD_cmd(0x0F);
            }

            ini_train(-1);

            //列車A相
            //train[0].mascon = 0x18; //スピードを変える時はここを変更

            //union POSITION p1 = position_set(0, 1, 0, 0); //rose

            //train_set(0, p1); //n,rosen,section,dir,sou

            //train[0].STATUS.BIT.SP_MANU = 1;


            for (n = 0; n < TR_COUNT; n++) {
                train[n].mascon = 0;
                cont_panel[n].point_num = -1;
            }

            //列車B相
            //スピードを変える時はここを変更
            //train[2].mascon = 0;
            //train_set(1, 0, 5, 0, 1); //n,rosen,section,dir,sou

            //ポイント(0) = New PointClass(New 位置情報(4, 0, 0, 0), New 位置情報(5, 1, 1, 0), 0)
            //ポイント(1) = New PointClass(New 位置情報(4, 1, 0, 0), New 位置情報(5, 0, 1, 0), 0)

            //区,路,向,sou
            //ポイント(0) = New PointClass(New 位置情報(1, 0, 0, 0), New 位置情報(3, 1, 1, 0), 0)
            //ポイント(1) = New PointClass(New 位置情報(2, 1, 0, 0), New 位置情報(2, 0, 1, 0), 0)
            //ポイント(2) = New PointClass(New 位置情報(0, 1, 0, 0), New 位置情報(0, 2, 1, 0), 1)
            //ポイント(3) = New PointClass(New 位置情報(3, 2, 0, 0), New 位置情報(7, 0, 1, 0), 2)


            //ポイント情報設定
            union POSITION p1;
            union POSITION p2;

            //TEST レイアイウト
            //            p1 = position_set(0, 4, 0, 0); //rosen,section,dir,sou
            //            p2 = position_set(1, 5, 1, 0);
            //            point_set(0, 0, p1, p2);
            //            p1 = position_set(1, 4, 0, 0);
            //            p2 = position_set(0, 5, 1, 0);
            //            point_set(1, 0, p1, p2);


            //大 レイアイウト
            p1 = position_set(0, 1, 0, 0); //rosen,section,dir,sou
            p2 = position_set(1, 3, 1, 0);
            point_set(0, 0, p1, p2);
            p1 = position_set(1, 2, 0, 0);
            p2 = position_set(0, 2, 1, 0);
            point_set(1, 0, p1, p2);

            //ポイント(2) = New PointClass(New 位置情報(0, 1, 0, 0), New 位置情報(0, 2, 1, 0), 1)
            p1 = position_set(1, 0, 0, 0);
            p2 = position_set(2, 0, 1, 0);
            point_set(2, 1, p1, p2);
            //ポイント(3) = New PointClass(New 位置情報(3, 2, 0, 0), New 位置情報(7, 0, 1, 0), 2)
            p1 = position_set(2, 3, 0, 0);
            p2 = position_set(0, 7, 1, 0);
            point_set(3, 2, p1, p2);

            //yard(0) = New YardClass(New 位置情報(7, 1, 1, 0), 3, "11010101", "01010001", 0)
            //p1 = position_set(1, 1, 0, 0);
            p1 = position_set(1, 7, 1, 0);
            yard_set(0, p1, 3, 0b11010101, 0b1010001, 0); //n, p1, point, line, exist, type

            p1 = position_set(0, 0, 0, 0);
            yard_set(1, p1, 4, 0b11, 0b11, 1); //yard(1) = New YardClass(New 位置情報(0, 0, 0, 0), 4, "11", "01", 1)

            //停止位置設定
            //p1 = position_set(0, 5, 0, 0);
            //stop_pos_set(0, p1, -1);
            //行き止まり位置

            p1 = position_set(2, 0, 1, 0); //車止位置(0) = New 停止位置class(New 位置情報(0, 2, 1, 0), 1)
            stop_pos_set(0, p1, 1); //num,pos,point

            p1 = position_set(2, 3, 0, 0); //車止位置(1) = New 停止位置class(New 位置情報(3, 2, 0, 0), 2)
            stop_pos_set(1, p1, 2);

            disp_mode = 0;
            disp_page = 0;
            speed_mode = 0;
            count_dwn = 0;

            DRV_TMR0_Start(); //TimerStart
            DRV_TMR1_Start(); //TimerStart

            if (appInitialized) {

                appData.state = APP_STATE_SERVICE_TASKS;
            }
            break;
        }

        case APP_STATE_SERVICE_TASKS:
        {
            unsigned char n, p;
            unsigned char ret;
            union byte_access time_out;
            long count;

            rx_data[0] = 0;
            rx_data[1] = 0;
            time_out.INT = 0;

            U1STAbits.OERR = 0; //受信バッファ・エラークリア

            ret = 0;
            while (ret != 0x55) {
                //0x55が来るまでずーと待つ
                while (!DRV_USART_ReceiverBufferIsEmpty(DRV_USART_INDEX_0)) {
                    ret = DRV_USART_ReadByte(DRV_USART_INDEX_0);
                }
            }


            for (n = 1; n < RX_BYTE; n++) {
                count = 0;
                while (DRV_USART_ReceiverBufferIsEmpty(DRV_USART_INDEX_0)) {
                    if (count++ > 0xfffff)break;
                }
                if (count > 0xfffff)break; //TimeOutで外へ

                rx_data[n] = DRV_USART_ReadByte(DRV_USART_INDEX_0);
            }

            //区間変化
            for (n = 0; n < TR_COUNT; n++) {
                p = n * RX_DATA_BYTE + 2;
                if (rx_data[p + 2] == 0x80) {
                    if (train[n].STATUS.BIT.CHG_RCV == 0) {
                        section_chg(n);
                        train[n].STATUS.BIT.CHG_RCV = 1;

                        //Point SW
                        if (train[n].point_state == P_SW_ON) {
                            train[n].point_state = SWITCH_REQ;
                        }
                        //YARD SW
                        if (train[n].yard_state == Y_SW_ON) {
                            train[n].yard_state = YARD_REQ;
                        }
                        //Revers Request
                        if (train[n].revers_req == 1) {
                            train[n].STATUS.BIT.REV = 1;
                            train[n].revers_req = 0;
                        }

                    }


                } else {
                    train[n].STATUS.BIT.CHG_RCV = 0;
                }
                //return speed
                train[n].speed_ret.BYTE.L = rx_data[p + 1];
                train[n].power.BYTE.H = rx_data[p + 5];
                train[n].power.BYTE.L = rx_data[p + 6];

                //Point CLR
                if (train[n].point != 0) {
                    if (rx_data[p + 3] == train[n].point) {
                        train[n].point = 0;
                    }
                }
                //Yard CLR
                if (train[n].yard != 0) {
                    if (rx_data[p + 4] == train[n].yard) {
                        train[n].yard = 0;
                    }
                }



            }

            KeyCont();

            rec_play(); //記録再生

            point_process(); //ポイント処理

            yard_process(); //YARD処理

            stop_pos_process(); //停止位置処理

            char time = 0;


#define DEF_BRK 20
#define BRAKE 100
#define SLOW_BRAKE 30                    
#define SLOW_SPEED 0x2c 
#define SLOW_SPEED_P 0x38                    
#define SLOW_SPEED_Y 0x2c     

            int slow_speed = SLOW_SPEED;

            for (n = 0; n < TR_COUNT; n++) {
                if (train[n].NOW.BYTE != 0x38) {
                    //安全確認
                    switch (safe_check(n)) {
                        case STOP:
                            //停止
                            train[n].STATUS.BIT.SAFE = 0;
                            train[n].STATUS.BIT.SLOW = 0;
                            break;
                        case SLOW_POINT://point speed
                            slow_speed = SLOW_SPEED_P;
                            train[n].STATUS.BIT.SAFE = 1;
                            train[n].STATUS.BIT.SLOW = 1;
                            break;
                        case SLOW_YARD://yard speed   
                            slow_speed = SLOW_SPEED_Y;
                            train[n].STATUS.BIT.SAFE = 1;
                            train[n].STATUS.BIT.SLOW = 1;
                            break;
                        case SLOW:
                            //減速
                            train[n].STATUS.BIT.SAFE = 1;
                            train[n].STATUS.BIT.SLOW = 1;
                            break;
                        case STOP_REV:
                            //向き合い停止
                            train[n].STATUS.BIT.SAFE = 0;
                            train[n].STATUS.BIT.SLOW = 0;
                            train[n].STATUS.BIT.REV = 1; //逆転
                            break;

                        case GO:
                            //安全
                            train[n].STATUS.BIT.SAFE = 1;
                            train[n].STATUS.BIT.SLOW = 0;
                            break;
                    }



                    //SpeedMode==DIRECT
                    if (speed_mode == 2)
                        train[0].STATUS.BIT.SP_MANU = 1;
                    else
                        train[0].STATUS.BIT.SP_MANU = 0;

                    //REVERS
                    if (train[n].STATUS.BIT.REV == 1) {
                        //逆転命令
                        //減速
                        if (speed_up_down(n, 0, DEF_BRK) == 0) {
                            //完全停止
                            if (stoppage_time(n, 10) == 0) {
                                //一時停車後逆転
                                reverse(n);
                            }
                        }
                    } else if (train[n].point_state == WAITING) {
                        //ポイント通過待ち
                        //停止
                        speed_up_down(n, 0, DEF_BRK);

                    } else if (train[n].yard_state == YARD_STOP) {
                        train[n].STATUS.BIT.SAFE = 0;
                        if (speed_up_down(n, 0, BRAKE) == 0) {
                            time = stoppage_time(n, 10);
                            if (time == 0) {
                                train[n].yard_state = YARD_STOP_COMP;
                            }
                        }
                    } else if (train[n].yard_state == POINT_RET) {
                        time = stoppage_time(n, 10);
                        if (time == 0) {
                            train[n].yard_state = POINT_RET_COMP;
                        }
                    } else {
                        if (train[n].STATUS.BIT.SAFE == 1) {
                            //安全
                            if (train[n].STATUS.BIT.SLOW == 1) {
                                //SLOW
                                if (train[n].mascon > slow_speed) {
                                    speed_up_down(n, slow_speed, SLOW_BRAKE);
                                } else {
                                    speed_up_down(n, train[n].mascon, DEF_BRK);
                                }
                                //speed direct modeの時SPEED AUTOに戻す。
                                if (speed_mode == 2) train[0].STATUS.BIT.SP_MANU = 0;


                            } else {
                                //加速
                                if (n == 0) {
                                    if (speed_mode == 1)//マニュアルスピードの時ブレーキで減速
                                        speed_up_down(n, train[n].mascon, -1);
                                    else
                                        speed_up_down(n, train[n].mascon, DEF_BRK);
                                } else {
                                    speed_up_down(n, train[n].mascon, DEF_BRK);
                                }

                            }

                        } else {
                            //停止
                            speed_up_down(n, 0, BRAKE);
                        }
                    }

                }
            }




#define mascon_max 100
#define brake_max 30
            if (!(rec_status == 2))//PlayModeはマスコンきかない
                train[0].mascon = (adc_ret.INT >> 4) * mascon_max / 0x3F;

            Brake = (adc_brk_ret.INT >> 4) * brake_max / 0x3F; //ブレーキ
            Brake = brake_max - Brake; //値反転

            //train[0].speed = train[0].mascon;


            for (n = 2; n < 15; n++) {
                //LCD_hex(rx_data[n]);
            }

            LcdDisp();

            //            LCD_posyx(0, 8);
            //            LCD_dec(r_enc, 2);

            for (n = 0; n < TR_COUNT; n++) {
                train[n].power.INT = train[n].power.INT * 20 / 0xF0; //LED MAX
                train[n].speed_ret.INT = train[n].speed_ret.INT * 20 / 100; //LED MAX
            }

            //pic16f1827 slave

            //---speed meter---
            unsigned char led_pow = train[0].power.BYTE.L;
            if (train[0].STATUS.BIT.SP_MANU)
                led_pow = train[0].speed * 20 / 100;

            if (train[0].NOW.BYTE == 0x38)led_pow = 0;
            PIC_dat(0, train[0].speed_ret.BYTE.L, led_pow, 0x20);

            led_pow = train[cont_sel].power.BYTE.L;
            if (train[cont_sel].STATUS.BIT.SP_MANU)
                led_pow = train[cont_sel].speed * 20 / 100;
            if (train[cont_sel].NOW.BYTE == 0x38)led_pow = 0;
            PIC_dat(0, train[cont_sel].speed_ret.BYTE.L, led_pow, 0x24);

            //----demo----
            //PIC_dat(0, 10, 13, 0x20);
            //PIC_dat(0, 13, 10, 0x24);

            //MAIN Cont LED
            unsigned char led1 = cont_panel[0].LED.REVERS + cont_panel[0].LED.POINT * 2
                    + cont_panel[0].LED.YARD * 4;
            //SUB Cont LED
            led1 += cont_panel[cont_sel].LED.REVERS * 8 + cont_panel[cont_sel].LED.POINT * 16
                    + cont_panel[cont_sel].LED.YARD * 64;

            unsigned char led2 = SelLED(cont_sel);

            PIC_dat(0, led1, led2, 0x22);




            break;
        }

            /* TODO: implement your application state machine.*/


            /* The default state should never be executed. */
        default:
        {
            /* TODO: Handle error in application's state machine. */
            break;
        }
    }
}

char SelLED(char i) {

    if (i >= 2) i++;

    return EnableBit[i - 1];
}

void LcdDisp() {
    char n;

    switch (disp_mode) {
        case 0:
            LCD_posyx(0, 0);

            LCD_str("P:");
            if (cont_panel[0].point_num < 0)
                LCD_str("N"); //NextPoint
            else
                LCD_dec(cont_panel[0].point_num, 1);

            //LCD_str(" No:");
            //LCD_dec(train[cont_sel].mascon, 3);
            //LCD_hex(adc_brk_ret.BYTE.H);
            //LCD_hex(adc_brk_ret.BYTE.L);

            //LCD_dec(cont_sel, 1);

            LCD_str("    P:");
            if (cont_panel[cont_sel].point_num < 0)
                LCD_str("N"); //NextPoint
            else
                LCD_dec(cont_panel[cont_sel].point_num, 1);

            LCD_str("   SPD");


            LCD_posyx(1, 0);

            LCD_str("Y:");
            LCD_dec(cont_panel[0].yard, 1);
            LCD_str("-");
            if (cont_panel[0].line < 9)
                LCD_dec(cont_panel[0].line, 1);
            else
                LCD_str("X"); //不可表示

            LCD_str("  Y:");
            LCD_dec(cont_panel[cont_sel].yard, 1);
            LCD_str("-");
            if (cont_panel[cont_sel].line < 9)
                LCD_dec(cont_panel[cont_sel].line, 1);
            else
                LCD_str("X"); //不可表示

            LCD_str(" ");
            LCD_dec(train[cont_sel].mascon, 3);
            //LCD_hex(test2);
            //LCD_hex(test1);

            //Curser位置移動
            LCD_posyx(SetPos_y[curser_pos], SetPos_x[curser_pos]);

            break;
        case 1:
            switch (disp_page) {
                case 0:
                    LCD_posyx(0, 0);
                    switch (speed_mode) {
                        case 0:
                            LCD_str("SPEED_AUTO      ");
                            break;
                        case 1:
                            LCD_str("SPEED_MANUAL      ");
                            break;
                        case 2:
                            LCD_str("SPEED_DIRECT      ");
                            break;

                    }

                    LCD_posyx(1, 0);
                    LCD_str("                ");
                    break;
                case 1:
                    LCD_posyx(0, 0);
                    //                    if (rec_status == 1)
                    //                        LCD_str("RECORDING       ");
                    //                    else
                    //                        LCD_str("REC_STOP        ");

                    LCD_str("PLAY MODE       ");

                    LCD_posyx(1, 0);
                    LCD_str("REC MODE        ");
                    break;

                case 2:
                    LCD_posyx(0, 0);
                    if (rec_status == 0)
                        LCD_str("ERACE MODE      ");
                    else
                        LCD_str("                ");

                    LCD_posyx(1, 0);
                    LCD_str("POINT TEST           ");
                    break;
                case 3:
                    LCD_posyx(0, 0);
                    LCD_str("D:");
                    LCD_dec(train[0].NOW.BIT.DIR, 1);
                    LCD_str(" R:");
                    LCD_dec(train[0].NOW.BIT.ROSEN, 1);
                    LCD_str(" K:");
                    LCD_dec(train[0].NOW.BIT.KUKAN, 1);
                    LCD_str(" S:");
                    LCD_dec(train[0].NOW.BIT.SOU, 1);

                    LCD_posyx(1, 0);
                    LCD_str("D:");
                    LCD_dec(train[1].NOW.BIT.DIR, 1);
                    LCD_str(" R:");
                    LCD_dec(train[1].NOW.BIT.ROSEN, 1);
                    LCD_str(" K:");
                    LCD_dec(train[1].NOW.BIT.KUKAN, 1);
                    LCD_str(" S:");
                    LCD_dec(train[1].NOW.BIT.SOU, 1);
                    break;
                case 4:

                    LCD_posyx(0, 0);

                    for (n = disp_pos; n < disp_pos + 6; n++) {
                        LCD_hex(rec_list[n].pos.BYTE);
                        //LCD_hex(rec_list[n].speed);
                    }

                    LCD_dec(Brake, 3);
                    //LCD_dec(debug1.BYTE.H, 2);
                    //LCD_dec(debug1.BYTE.L, 2);
                    LCD_str("                ");
                    LCD_posyx(1, 0);
                    LCD_hex(step);
                    for (n = disp_pos; n < disp_pos + 6; n++) {
                        LCD_hex(rec_list[n].point);
                    }

                    //LCD_str("                ");
                    break;
            }

            break;


        case 10://階層2 PLAY MODE
            if (ExistList(prg_num) == 0)
                prg_num = NextList(prg_num, -1);

            if (rec_status == 0) {
                //1行目
                LCD_posyx(0, 0);
                LCD_str("PLAY   PRG No.");
                LCD_dec(prg_num, 2);
                //2行目
                LCD_posyx(1, 0);
                LCD_str("PLAY      CANCEL");
            } else if (rec_status == 2) {
                //1行目
                LCD_posyx(0, 0);
                LCD_str("PLAY:");
                LCD_dec(prg_num, 2);
                LCD_str(" ");
                LCD_dec(step, 2);
                LCD_str("/");
                LCD_dec(rec_list[0].pos.BYTE, 2);
                LCD_str(" ");
                LCD_dec(count_dwn, 2);

                //2行目
                LCD_posyx(1, 0);
                if (repeat) {
                    LCD_str("STOP     RPT OFF");
                    //LCD_dec(count_dwn, 2);
                } else {
                    LCD_str("STOP      RPT ON");
                }
            }

            break;

        case 11://階層2 REC MODE
            LCD_posyx(0, 0);
            LCD_str("REC MODE        ");
            LCD_posyx(1, 0);
            LCD_str("START     CANCEL");
            break;

        case 12://階層2 REC MODE
            LCD_posyx(0, 0);
            LCD_str("NOW RECORDIG... ");
            LCD_posyx(1, 0);
            LCD_str("STOP    ");
            LCD_dec(step, 2);
            LCD_hex(rec_list[step].pos.BYTE);
            LCD_hex(rec_list[step].yard.BYTE);
            LCD_hex(rec_list[step].point.BYTE);
            break;

        case 13://階層3 REC END & SAVE?
            LCD_posyx(0, 0);
            LCD_str("SAVE PRG   No.");
            LCD_dec(prg_num, 2);
            LCD_posyx(1, 0);
            if (ExistList(prg_num))
                LCD_str("(O/W)?    CANCEL");
            else
                LCD_str("SAVE?     CANCEL");
            break;

        case 14://階層2 ERACE
            LCD_posyx(0, 0);
            LCD_str("ERACE PRG  No.");
            LCD_dec(prg_num, 2);
            LCD_posyx(1, 0);
            LCD_str("OK?       CANCEL");
            break;

        case 15://階層2 POINT TEST
            LCD_posyx(0, 0);
            LCD_str("POINT TEST    ");
            LCD_dec(point_test, 2);
            LCD_posyx(1, 0);
            LCD_str("CHG         BACK");
            break;

    }


}

void KeyCont() {
    //sel Button
    if (cont_sel == 0) cont_sel = 1;
    if (key_down[3] == 1) {
        key_down[3] = 0;

        if (++disp_mode > 1) disp_mode = 0;
    }

    //SubCont select SW
    char n;
    for (n = 0; n < TR_COUNT - 1; n++) {
        if (key_down[n + 15] == 1) {
            key_down[n + 15] = 0;
            cont_sel = n + 1;
        }
    }

    //Reverse SW
    if (key_down[5] == 1) {
        key_down[5] = 0;
        if (train[0].NOW.BYTE == 0x38) {
            //停車時 YARD出発方向設定の為
            if (cont_panel[0].LED.REVERS == 0) {
                cont_panel[0].LED.REVERS = 1;
            } else {
                cont_panel[0].LED.REVERS = 0;
            }
        } else {
            //走行時
            train[0].revers_req = 1;
            //train[0].STATUS.BIT.REV = 1; //逆転
            cont_panel[0].LED.REVERS = 1;
        }

    }

    if (key_down[10] == 1) {
        key_down[10] = 0;
        if (train[cont_sel].NOW.BYTE == 0x38) {
            //停車時 YARD出発方向設定の為
            if (cont_panel[cont_sel].LED.REVERS == 0) {
                cont_panel[cont_sel].LED.REVERS = 1;
            } else {
                cont_panel[cont_sel].LED.REVERS = 0;
            }
        } else {
            //走行時
            train[cont_sel].revers_req = 1;
            //train[cont_sel].STATUS.BIT.REV = 1; //逆転
            cont_panel[cont_sel].LED.REVERS = 1;
        }


    }

    //Point SW
    if (key_down[6] == 1) {
        key_down[6] = 0;
        if (train[0].point_state == NONE) {
            cont_panel[0].LED.POINT = 1;
            train[0].point_state = P_SW_ON;

        } else if (train[0].point_state == SWITCH_REQ || train[0].point_state == P_SW_ON) {
            cont_panel[0].LED.POINT = 0;
            train[0].point_state = NONE;
        }
    }

    if (key_down[11] == 1) {
        key_down[11] = 0;
        if (train[cont_sel].point_state == NONE) {
            cont_panel[cont_sel].LED.POINT = 1;
            train[cont_sel].point_state = P_SW_ON;

        } else if (train[cont_sel].point_state == SWITCH_REQ || train[cont_sel].point_state == P_SW_ON) {
            cont_panel[cont_sel].LED.POINT = 0;
            train[cont_sel].point_state = NONE;
        }
    }


    //Yard SW
    if (key_down[7] == 1) {
        key_down[7] = 0;
        if (train[0].yard_state == YARD_NONE) {
            cont_panel[0].LED.YARD = 1;

            if (train[0].NOW.BYTE == 0x38)
                train[0].yard_state = START_REQ; //登録なし
            else
                train[0].yard_state = Y_SW_ON; //走行中

            //cont_panel[0].line = 7;
        } else if (train[0].yard_state == YARD_REQ || train[0].yard_state == Y_SW_ON) {
            cont_panel[0].LED.YARD = 0;
            train[0].yard_state = YARD_NONE;
        }
    }


    if (key_down[12] == 1) {
        key_down[12] = 0;
        if (train[cont_sel].yard_state == YARD_NONE) {
            cont_panel[cont_sel].LED.YARD = 1;

            if (train[cont_sel].NOW.BYTE == 0x38)
                train[cont_sel].yard_state = START_REQ; //登録なし
            else
                train[cont_sel].yard_state = Y_SW_ON; //走行中

            //cont_panel[cont_sel].line = 7;
        } else if (train[cont_sel].yard_state == YARD_REQ || train[cont_sel].yard_state == Y_SW_ON) {
            cont_panel[cont_sel].LED.YARD = 0;
            train[cont_sel].yard_state = YARD_NONE;
        }
    }

    switch (disp_mode) {
        case 0://操作MODE

            //Right Button
            if (key_down[0] == 1) {
                key_down[0] = 0;

                if (++curser_pos >= CUR_MAX) curser_pos = 0;

                //EEPROM TEST

                //PIC_dat(0, 0, test1, 0xA0);
                //                for (n = 0; n < 32; n++) {
                //                    eep_page_data[n + 2] = n;
                //                }
                //                EEP_Write(0, 1, 0xA0);
                //
                //                for (n = 0; n < 32; n++) {
                //                    eep_page_data[n + 2] = n + 32;
                //                }
                //                EEP_Write(32, 1, 0xA0);
                //LoadPlayList();

                test2 = 0;
            }

            //Left Button
            if (key_down[2] == 1) {
                key_down[2] = 0;

                if (--curser_pos < 0) curser_pos = CUR_MAX - 1;

                test1 = EEP_Read(test2++, 64, 0xA0);
            }

            //UP Button
            if (key_down[1] == 1) {
                key_down[1] = 0;
                switch (curser_pos) {
                    case 0:
                        if (++cont_panel[0].point_num > POINT_COUNT - 1) cont_panel[0].point_num = -1;
                        break;
                    case 1:
                        if (++cont_panel[0].yard > YARD_COUNT - 1) cont_panel[0].yard = YARD_COUNT - 1;
                        cont_panel[0].line = yard_line_num(cont_panel[0].yard, 0, cont_panel[0].line, 0);
                        break;
                    case 2:
                        //if (++cont_panel[0].line > 5) cont_panel[0].line = 5;
                        cont_panel[0].line = yard_line_num(cont_panel[0].yard, 1, cont_panel[0].line, 0);
                        break;
                    case 3:
                        if (++cont_panel[cont_sel].point_num > POINT_COUNT - 1) cont_panel[cont_sel].point_num = -1;
                        break;
                    case 4:
                        if (++cont_panel[cont_sel].yard > YARD_COUNT - 1) cont_panel[cont_sel].yard = YARD_COUNT - 1;
                        cont_panel[cont_sel].line = yard_line_num(cont_panel[cont_sel].yard, 0, cont_panel[cont_sel].line, cont_sel);
                        break;
                    case 5:
                        //if (++cont_panel[cont_sel].line > 5) cont_panel[cont_sel].line = 5;
                        cont_panel[cont_sel].line = yard_line_num(cont_panel[cont_sel].yard, 1, cont_panel[cont_sel].line, cont_sel);

                        break;

                }

            }

            //Down Button
            if (key_down[4] == 1) {
                key_down[4] = 0;
                switch (curser_pos) {
                    case 0:
                        if (--cont_panel[0].point_num < -1) cont_panel[0].point_num = -1;
                        break;
                    case 1:
                        if (--cont_panel[0].yard < 0) cont_panel[0].yard = 0;
                        cont_panel[0].line = yard_line_num(cont_panel[0].yard, 0, cont_panel[0].line, 0);
                        break;
                    case 2:
                        //if (--cont_panel[0].line < 0) cont_panel[0].line = 0;
                        cont_panel[0].line = yard_line_num(cont_panel[0].yard, -1, cont_panel[0].line, 0);
                        break;
                    case 3:
                        if (--cont_panel[cont_sel].point_num < -1) cont_panel[cont_sel].point_num = -1;
                        break;
                    case 4:
                        if (--cont_panel[cont_sel].yard < 0) cont_panel[cont_sel].yard = 0;
                        cont_panel[cont_sel].line = yard_line_num(cont_panel[cont_sel].yard, 0, cont_panel[cont_sel].line, cont_sel);
                        break;
                    case 5:
                        //if (--cont_panel[cont_sel].line < 0) cont_panel[cont_sel].line = 0;
                        cont_panel[cont_sel].line = yard_line_num(cont_panel[cont_sel].yard, -1, cont_panel[cont_sel].line, cont_sel);
                        break;
                }

            }


            break;

        case 1:
            //----------disp mode1----------
            //Right Button
            if (key_down[0] == 1) {
                key_down[0] = 0;
                if (disp_page < PAGE_MAX)
                    disp_page++;
            }
            //Left Button
            if (key_down[2] == 1) {
                key_down[2] = 0;
                if (--disp_page < 0)disp_page = 0;
            }

            switch (disp_page) {
                case 0://----SPEED MODE------

                    //Down Button
                    if (key_down[4] == 1) {
                        key_down[4] = 0;
                        if (++speed_mode > 2)speed_mode = 2; //speed_mode auto/manu

                    }
                    //Up Button
                    if (key_down[1] == 1) {
                        key_down[1] = 0;
                        if (--speed_mode < 0)speed_mode = 0; //speed_mode auto/manu

                    }

                    break;

                case 1://-----Play/Rec ModeSelect-----

                    if (rec_status == 0) {//通常
                        //Up Button   PLAY MODE
                        if (key_down[1] == 1) {
                            key_down[1] = 0;
                            disp_mode = 10; //DISP PLAY MODE 
                        }

                        //Down Button  REC MODE
                        if (key_down[4] == 1) {
                            key_down[4] = 0;
                            disp_mode = 11; //DISP REC MODE

                        }
                    } else if (rec_status == 2) {
                        //Playing
                        disp_mode = 10; //PlayMode
                    } else if (rec_status == 1) {
                        //Recording
                        disp_mode = 12; //NoeRecording
                    }
                    break;

                case 2://ERACE MODE Select
                    if (rec_status == 0) {//通常
                        //Up Button   ERACE MODE
                        if (key_down[1] == 1) {
                            key_down[1] = 0;
                            disp_mode = 14; //DISP ERACE MODE 
                        }

                        //Down Button  POINT TEST
                        if (key_down[4] == 1) {
                            key_down[4] = 0;
                            disp_mode = 15; //POINT TEST
                        }
                    }

                    break;

                case 4://Debug Monitor
                    if (rec_status == 0) {//通常
                        //Up Button   ERACE MODE
                        if (key_down[1] == 1) {
                            key_down[1] = 0;
                            disp_pos++;
                        }

                        //Down Button  AUX
                        if (key_down[4] == 1) {
                            key_down[4] = 0;
                            if (disp_pos > 0)disp_pos--;

                        }
                    }

                    break;


            }
            break;

        case 10://PLAY MODE
            //階層2

            //R Button //Cancel Repeat
            if (key_down[0] == 1) {
                key_down[0] = 0;

                if (rec_status == 0) {
                    //CANCEL
                    disp_mode = 1; //表示戻し
                } else if (rec_status == 2) {
                    //REPEAT
                    if (repeat)repeat = 0;
                    else repeat = 1;
                }


            }
            //L Button PLAY START STOP
            if (key_down[2] == 1) {
                key_down[2] = 0;

                if (rec_status == 0) {
                    //START
                    LoadPlayList(prg_num);
                    rec_status = 2;
                } else if (rec_status == 2) {
                    //STOP
                    rec_status = 0;
                }
            }

            //Up Button   PRG No. +
            if (key_down[1] == 1) {
                key_down[1] = 0;
                prg_num = NextList(prg_num, 1);

            }
            //Down Button  Prg No. -
            if (key_down[4] == 1) {
                key_down[4] = 0;
                prg_num = NextList(prg_num, -1);
            }

            break;
        case 11://REC MODE
            //階層2
            if (rec_status == 0) {
                //R Button
                if (key_down[0] == 1) {
                    key_down[0] = 0;
                    //CANCEL
                    disp_mode = 1; //表示戻し
                }
                //L Button REC START
                if (key_down[2] == 1) {
                    key_down[2] = 0;

                    rec_status = 1;
                    ClrRecList();
                    //disp_mode = 12; //DISP NOW RECORDING
                }
            } else if (rec_status == 1) {
                disp_mode = 12; //DISP NOW RECORDING
            }


            break;

        case 12://NOW RECORDING
            //L Button REC STOP
            if (key_down[2] == 1) {
                key_down[2] = 0;

                if (rec_status == 1) rec_status = 0;
                disp_mode = 13; //REC END SAVE?
            }

            break;

        case 13://REC END SAVE?
            //階層3
            //R Button
            if (key_down[0] == 1) {
                key_down[0] = 0;
                //CANCEL
                disp_mode = 1; //表示戻し
            }
            //L Button 
            if (key_down[2] == 1) {
                key_down[2] = 0;

                //Save Play List
                SavePlayList(prg_num);
                disp_mode = 1; //表示戻し
            }
            //Up Button   PRG No. +
            if (key_down[1] == 1) {
                key_down[1] = 0;
                prg_num++;
            }
            //Down Button  Prg No. -
            if (key_down[4] == 1) {
                key_down[4] = 0;
                if (prg_num > 0) prg_num--;
            }
            break;

        case 14://ERACE MODE
            //階層2
            //R Button
            if (key_down[0] == 1) {
                key_down[0] = 0;
                //CANCEL
                disp_mode = 1; //表示戻し
            }
            //L Button 
            if (key_down[2] == 1) {
                key_down[2] = 0;

                //Delete Play List
                DelPlayList(prg_num);
                disp_mode = 1; //表示戻し
            }
            //Up Button   PRG No. +
            if (key_down[1] == 1) {
                key_down[1] = 0;
                prg_num = NextList(prg_num, 1);
            }
            //Down Button  Prg No. -
            if (key_down[4] == 1) {
                key_down[4] = 0;
                prg_num = NextList(prg_num, -1);
            }
            break;

        case 15://POINT TEST
            //階層2
            //R Button
            if (key_down[0] == 1) {
                key_down[0] = 0;
                //point 戻し
                train[0].point = 0x80 + point_test;
                //disp_mode = 1; //表示戻し
            }
            //L Button 
            if (key_down[2] == 1) {
                key_down[2] = 0;
                //point 切り替え
                train[0].point = 0xC0 + point_test;
                //disp_mode = 1; //表示戻し
            }
            //Up Button   point No. +
            if (key_down[1] == 1) {
                key_down[1] = 0;
                point_test++;
            }
            //Down Button  point No. -
            if (key_down[4] == 1) {
                key_down[4] = 0;
                if (point_test > 0)point_test--;
            }
            break;


    }

}

void ini_train(char i) {
    char n, st, ed;

    if (i == -1) {
        //全ての列車初期化
        st = 0;
        ed = TR_COUNT;
    } else {
        //指定の列車を初期化
        st = i;
        ed = i + 1;
    }

    for (n = st; n < ed; n++) {
        train[n].BEFORE.BYTE = 0x38;
        train[n].NOW.BYTE = 0x38;
        train[n].NEXT.BYTE = 0x38;
        train[n].ANEXT.BYTE = 0x38;
        train[n].STATUS.BYTE = 0;
        train[n].speed = 0;
        train[n].henka = 0;
    }
}


//void train_set(unsigned char n, unsigned char rosen, unsigned char sec, unsigned char dir, unsigned char sou) 

void train_set(unsigned char n, union POSITION p1) {

    //    train[n].NOW.BIT.ROSEN = rosen;
    //    train[n].NOW.BIT.KUKAN = sec;
    //    train[n].NOW.BIT.DIR = dir;
    //    train[n].NOW.BIT.SOU = sou;

    train[n].NOW.BIT.ROSEN = p1.BIT.ROSEN;
    train[n].NOW.BIT.KUKAN = p1.BIT.KUKAN;
    train[n].NOW.BIT.DIR = p1.BIT.DIR;
    train[n].NOW.BIT.SOU = p1.BIT.SOU;


    train[n].BEFORE.BYTE = train[n].NOW.BYTE;
    train[n].NEXT.BYTE = train[n].NOW.BYTE;
    train[n].ANEXT.BYTE = train[n].NOW.BYTE;

    if (p1.BIT.DIR) {
        //逆転 
        train[n].BEFORE.BIT.KUKAN++;
        train[n].NEXT.BIT.KUKAN--;
        train[n].ANEXT.BIT.KUKAN = train[n].NOW.BIT.KUKAN - 2;
    } else {
        //正転
        train[n].BEFORE.BIT.KUKAN--;
        train[n].NEXT.BIT.KUKAN++;
        train[n].ANEXT.BIT.KUKAN += 2;
    }

    train[n].STATUS.BIT.CHG = 1;
    train[n].STATUS.BIT.SAFE = 1;

}
//位置情報設定用

union POSITION position_set(unsigned char line, unsigned char section,
        unsigned char dir, unsigned char phase) {
    union POSITION ret;
    ret.BIT.ROSEN = line;
    ret.BIT.KUKAN = section;
    ret.BIT.DIR = dir;
    ret.BIT.SOU = phase;

    return ret;
}
//ポイント位置設定

void point_set(unsigned char n, unsigned char num, union POSITION p1, union POSITION p2) {
    point[n].approach = p1;
    point[n].exit = p2;
    point[n].num = num;

}

void yard_set(unsigned char n, union POSITION p1, unsigned char point, unsigned char line, unsigned char exist, unsigned char type) {

    //            進入位置 = 位置.copy
    //            停止位置 = 位置.copy
    //            出口位置 = 位置.copy
    //

    //            停止位置.逆転()
    //            停止位置.次区間() '停止位置は発車位置の逆の次区間

    //
    //            停止位置1 = 停止位置.copy
    //            出口位置1 = 出口位置.copy
    //
    //            進入位置2 = 停止位置.copy
    //            進入位置2.逆転()
    //            発車位置2 = 停止位置.copy
    //
    //            停止位置2 = 発車位置.copy
    //            出口位置2 = 発車位置2.copy
    //            出口位置2.次区間()


    yard[n].start = p1; //発車位置 = 位置.copy '位置は発車位置
    //yard[n].start.BIT.DIR = ~p1.BIT.DIR;
    yard[n].approach = p1;
    yard[n].approach.BIT.DIR = ~p1.BIT.DIR; //進入位置.逆転() '進入位置は発車位置の逆転

    yard[n].exit = next_position(yard[n].start); //出口位置.次区間() '出口位置は発車位置の次区間

    //yard[n].start_b = p1;
    yard[n].start_b = next_position(yard[n].approach); //発車位置Bは進入位置の次区間
    //yard[n].approach_b = next_position(yard[n].approach);
    yard[n].approach_b = yard[n].start_b; //進入位置Bは発車位置Bの逆転
    yard[n].approach_b.BIT.DIR = p1.BIT.DIR;

    yard[n].exit_b = next_position(yard[n].start_b); //出口位置.次区間() '出口位置は発車位置の次区間

    yard[n].point_num = point;
    yard[n].line = line;
    yard[n].exist = exist;
    yard[n].type = type;

    if (type == 0) {
        yard[n].approach_b.BYTE = 0xFF;
    }


}

void yard_set_line(char n, char p, char mode) {
    if (mode)
        yard[n].exist |= EnableBit[p];
    else
        yard[n].exist &= ~EnableBit[p];
}

char yard_line_num(char n, char s, char p, char t) {
    //n:yard um s:+- p:pos t:train_num

    char pos = p + s;
    pos &= 0b111;

    unsigned char bit_p = EnableBit[pos];

    //avl空き線
    unsigned char avl = yard[n].line ^ yard[n].exist;
    unsigned char line;

    char mode = 0;
    if (train[t].NOW.BYTE != 0x38) mode = 1;

    if (mode)
        line = avl;
    else
        line = yard[n].exist;

    if (!line)return 9; //該当なし

    while (!(line & bit_p)) {
        if (s < 0) {
            bit_p >>= 1;
            if (bit_p == 0)bit_p = 0x80;
        } else {
            bit_p <<= 1;
            if (bit_p == 0)bit_p = 1;
        }

    }

    char c = 0;
    while (!(bit_p == 1)) {
        bit_p >>= 1;
        c++;
    }

    return c;

}



//出口位置かどうか

bool point_exit_position(unsigned char n, union POSITION p) {
    p.BIT.SOU = 0; //相マスク
    p.BIT.DIR = ~p.BIT.DIR;

    if (p.BIT.DIR == 0) {
        if (point[n].approach.BYTE == p.BYTE)
            return true;
        else
            return false;
    } else {
        if (point[n].exit.BYTE == p.BYTE)
            return true;
        else
            return false;
    }


}

int speed_up_down(char n, int speed, char k) {
    //列車(n).speed += (列車(n).設定speed - 列車(n).speed) * 加速
    char down;
    int def = speed - train[n].speed;
    int d;
    char brk = 0;

    if (k > 0) {
        down = k;
        if (def > 0)down = 30;
        d = def * down / 100;
        if (def < 0 && d>-1) d = def;

        train[n].speed += d;
    } else {
        //Mnual Brake
        brk = Brake;

        if (def < 0) {
            train[n].speed -= brk;
            if (train[n].speed < 0)
                train[n].speed = 0;
        } else {
            down = 30;
            d = def * down / 100;

            train[n].speed += d;
        }

    }





    return train[n].power.INT;





    return train[n].power.INT;


}

void section_chg(unsigned char n) {
    train[n].BEFORE.BYTE = train[n].NOW.BYTE;
    train[n].NOW.BYTE = train[n].NEXT.BYTE;
    train[n].NEXT.BYTE = train[n].ANEXT.BYTE;

    if (train[n].NOW.BIT.DIR) {
        train[n].ANEXT.BIT.KUKAN--; //逆転
    } else {
        train[n].ANEXT.BIT.KUKAN++; //正転
    }


    //
    train[n].STATUS.BIT.CHG = 1;

}

void reverse(unsigned char n) {
    unsigned char before;

    unsigned char dir = train[n].NOW.BIT.DIR;
    if (dir) {
        dir = 0;
    } else {
        dir = 1;
    }
    train[n].NOW.BIT.DIR = dir;
    train[n].BEFORE.BIT.DIR = dir;

    before = train[n].BEFORE.BYTE;

    train[n].BEFORE.BYTE = train[n].NOW.BYTE;
    train[n].NOW.BYTE = before;
    train[n].NEXT.BYTE = before;
    train[n].ANEXT.BYTE = before;

    if (dir) {
        //逆転 
        train[n].NEXT.BIT.KUKAN--;
        train[n].ANEXT.BIT.KUKAN = train[n].NOW.BIT.KUKAN - 2;
    } else {
        //正転
        train[n].NEXT.BIT.KUKAN++;
        train[n].ANEXT.BIT.KUKAN += 2;
    }

    train[n].STATUS.BIT.REV = 0;
    train[n].STATUS.BIT.SAFE = 1;

    train[n].STATUS.BIT.CHG = 1;

    cont_panel[n].LED.REVERS = 0;

}

int stoppage_time(char n, int t) {
    //停車時間
    static int timer[TR_COUNT + 1]; //

    if (timer[n]-- == 0)
        timer[n] = t; //停車時間

    return timer[n];

}

unsigned char safe_check(unsigned char m) {
    //安全確認
    unsigned char n;
    unsigned char ret = GO;

    for (n = 0; n < TR_COUNT; n++) {
        if (n != m) {
            //次位置が他の列車の現、前、次位置と同じなら停止
            if ((train[m].NEXT.BYTE & 0x3f) == (train[n].NOW.BYTE & 0x3f)) {
                ret = STOP;
                break;
            }
            if ((train[m].NEXT.BYTE & 0x3f) == (train[n].BEFORE.BYTE & 0x3f)) {
                ret = STOP;
                break;
            }
            if ((train[m].NEXT.BYTE & 0x3f) == (train[n].NEXT.BYTE & 0x3f)) {
                ret = STOP;
                break;
            }

            //次々位置が他の列車の現、前、次位置と同じなら減速
            if ((train[m].ANEXT.BYTE & 0x3f) == (train[n].NOW.BYTE & 0x3f)) ret = SLOW;
            if ((train[m].ANEXT.BYTE & 0x3f) == (train[n].BEFORE.BYTE & 0x3f)) ret = SLOW;
            if ((train[m].ANEXT.BYTE & 0x3f) == (train[n].NEXT.BYTE & 0x3f)) ret = SLOW;


        }
    }

    //停止の時、相手と方向が逆の時は優先順位が低いほうが逆転
    if (ret == 1) {
        if ((m > n) && (train[m].NOW.BIT.DIR != train[n].NOW.BIT.DIR)) {
            ret = STOP_REV;
        }
    }


    //STOP位置
    for (n = 0; n < STOP_POS_COUNT; n++) {
        if (stop_pos[n].point_num < 0) {//            If p.ポイント番号 < 0 Then
            //ポイントのない停止位置
            if ((train[m].NOW.BYTE & 0xBF) == stop_pos[n].pos.BYTE) {//                If 列車(n).現位置 = p.位置 Then
                //現位置なら停止
                return STOP; //                    停止 = True
            } else if ((train[m].NEXT.BYTE & 0xBF) == stop_pos[n].pos.BYTE) {//                ElseIf 列車(n).次位置 = p.位置 Then
                //'次位置なら減速
                return SLOW_POINT; //                    減速 = True
            }
        }
    }

    //通過形ヤードで空き線なしは通過不可
    for (n = 0; n < YARD_COUNT; n++) {//For Each p As YardClass In yard
        if (yard[n].type == 1) {//If p.type = 1 Then
            //通過形ヤードの時
            if (yard[n].exist == yard[n].line) {//If p.空線.Length = 0 Then  
                //空線なしの時
                //If (列車(n).現位置 = p.進入位置) Or (列車(n).現位置 = p.進入位置2) Then
                if ((train[m].NOW.BYTE & 0xbf) == yard[n].approach.BYTE ||
                        (train[m].NOW.BYTE & 0xbf) == yard[n].approach_b.BYTE) {
                    return STOP_REV; //逆転
                }
            }
        }
    }
    
    //YARD進入待ち
    if (train[m].yard_state == YARD_APR_WAIT) return STOP;

    //Yard,Point進入  減速
    if (train[m].yard_state == YARD_COMP || train[m].yard_state == POINT_COMP) {
        return SLOW_YARD; //減速
    }

    if (train[m].point_state == SWITCHING) return SLOW_POINT; //減速


    return ret;
}

POINT_SAFE yard_safe_check(unsigned char n, union POSITION pos) {
    unsigned char c;

    for (c = 0; c < TR_COUNT; c++) {
        if (c != n) {
            //位置が他の列車の現、前、次位置と同じなら非安全
            if (pos.BIT.ROSEN == train[c].NOW.BIT.ROSEN && pos.BIT.KUKAN == train[c].NOW.BIT.KUKAN)
                return WAIT_PASS;
            if (pos.BIT.ROSEN == train[c].BEFORE.BIT.ROSEN && pos.BIT.KUKAN == train[c].BEFORE.BIT.KUKAN)
                return WAIT_PASS;
            if (pos.BIT.ROSEN == train[c].NEXT.BIT.ROSEN && pos.BIT.KUKAN == train[c].NEXT.BIT.KUKAN)
                return WAIT_PASS;
            if (pos.BIT.ROSEN == train[c].ANEXT.BIT.ROSEN && pos.BIT.KUKAN == train[c].ANEXT.BIT.KUKAN)
                return WAIT_PASS;
        }
    }

    return SAFE;
}

//ポイント位置かどうか

union POSITION point_pos(unsigned char p, union POSITION pos) {
    //出口位置を返す
    union POSITION ret;

    char sou = pos.BIT.SOU;
    pos.BIT.SOU = 0;

    if (pos.BYTE == point[p].approach.BYTE) {
        ret = point[p].exit;
        ret.BIT.DIR = ~ret.BIT.DIR;
        ret.BIT.SOU = sou;
        return ret;
    }

    if (pos.BYTE == point[p].exit.BYTE) {
        ret = point[p].approach;
        ret.BIT.DIR = ~ret.BIT.DIR;
        ret.BIT.SOU = sou;
        return ret;
    }

    ret.BYTE = 0xff; //ポイント位置でない
    return ret;
}

//次の区間

union POSITION next_position(union POSITION p) {
    union POSITION ret = p;
    unsigned char section = p.BIT.KUKAN;

    if (p.BIT.DIR == 0) {//If 方向 = 0 Then
        section = (section + 1)& 0b111; //                区間 = (区間 + 1) And &H7
    } else {
        section = (section - 1)& 0b111; //                区間 = (区間 - 1) And &H7
    }
    ret.BIT.KUKAN = section;

    return ret;
}

//ポイント処理

void point_process() {
    unsigned char n, p;
    union POSITION next_pos;

    for (n = 0; n < TR_COUNT; n++) {
        switch (train[n].point_state) {//point処理状況
            case SWITCH_REQ://Case p処理.切替要求, p処理.通過待ち
            case WAITING:
                //Point位置確認
                for (p = 0; p < POINT_COUNT; p++) {
                    next_pos = point_pos(p, train[n].NOW); //Dim 次位置 As 位置情報 = ポイント(p).進入位置(列車(n).現位置)
                    //ポイント番号確認
                    //Select Case Remcon(n).point_num
                    //Case -1, ポイント(p).番号 '-1は次のポイント
                    //If Not 次位置 Is Nothing Then
                    if (next_pos.BYTE != 0xff) {
                        //debug1.BYTE.L = point_safe_check(n, next_pos);
                        switch (point_safe_check(n, next_pos)) {//Select Case ポイント安全確認(n, 次位置)
                            case SAFE://Case "安全"
                                //ポイント切り替え
                                train[n].point = 0xC0 + point[p].num; //列車(n).ポイント = &HC0 + ポイント(p).番号
                                train[n].NEXT = next_pos; //列車(n).次位置 = 次位置.copy
                                //次位置.次区間()
                                train[n].ANEXT = next_position(next_pos); //列車(n).次々位置 = 次位置.copy
                                train[n].STATUS.BIT.CHG = 1; //列車(n).区間変化 = True
                                //
                                train[n].point_state = SWITCHING; //列車(n).point処理状況 = p処理.切替中
                                train[n].point_num = p; //列車(n).ポイント番号 = p
                                //Remcon(n).CheckBox2.Enabled = False 'ポイントボタン不可
                                //Remcon(n).DomainUpDown1.Enabled = False

                                break;
                            case IMPOSSIBLE://Case "不可"
                                train[n].point_state = NONE;
                                cont_panel[n].LED.POINT = 0;
                                break;

                            case WAIT_PASS://Case "通過待ち"
                                train[n].point_state = WAITING; //列車(n).point処理状況 = p処理.通過待ち
                                break;
                        }
                    }
                }

                //            case WAITING:
                //                break;
            case SWITCHING://Case p処理.切替中
                //出口位置確認
                if (point_exit_position(train[n].point_num, train[n].BEFORE)) { //If ポイント(列車(n).ポイント番号).出口位置(列車(n).現位置) Then
                    //ポイント戻し
                    train[n].point = 0x80 + point[train[n].point_num].num; //列車(n).ポイント = &H80 + ポイント(列車(n).ポイント番号).番号
                    train[n].point_state = NONE; //列車(n).point処理状況 = p処理.なし
                    cont_panel[n].LED.POINT = 0;
                    //Remcon(n).CheckBox2.Enabled = True 'ポイントボタン可
                    //Remcon(n).DomainUpDown1.Enabled = True 'ポイント選択可
                    //Remcon(n).CheckBox2.Checked = False 'ポイントボタン戻し
                    //                    End If
                }

                break;
        }



    }


    //            Yard処理(n)


}

bool yard_approach_pos(unsigned char n, union POSITION pos, unsigned char p) {
    //                Dim n = ポイント番号 - 3
    //
    //                Dim p = 番号位置変換(pos)
    //
    pos.BIT.SOU = 0;

    if (yard[n].type == 0) {//If type = 0 Then
        if (pos.BYTE == yard[n].approach.BYTE) {
            yard[n].y_cont = 0x88 + n * 0x10 + p; //y制御Byte = &H88 + n * &H10 + p
            yard[n].p_cont = 0xc0 + yard[n].point_num; //p制御Byte = &HC0 + ポイント番号
            return true; // Return 位置 = 進入位置
        }

    } else {
        //                    If 位置 = 進入位置 Then
        if (pos.BYTE == yard[n].approach.BYTE) {
            //                        停止位置 = 停止位置1.copy

            yard[n].y_cont = 0x80 + n * 0x10 + p * 2 + 1; //y制御Byte = &H80 + n * &H10 + &H1 + p * 2
            //pos=0で戻し側 pos=1で切り替え側
            yard[n].p_cont = 0x80 + p * 0x40 + yard[n].point_num; //p制御Byte = &H80 + p * &H40 + ポイント番号
            return true; // Return True
        } else {
            if (pos.BYTE == yard[n].approach_b.BYTE) {//                    ElseIf 位置 = 進入位置2 Then
                //                        '逆進入
                //                        停止位置 = 停止位置2.copy
                yard[n].y_cont = 0x80 + n * 0x10 + p * 2; //y制御Byte = &H80 + n * &H10 + p * 2
                //pos=0で戻し側 pos=1で切り替え側
                yard[n].p_cont = 0x80 + p * 0x40 + yard[n].point_num; //p制御Byte = &H80 + p * &H40 + ポイント番号


                return true; //                        Return True
            }

        }


    }

    return false;

}

bool yard_stop_pos(unsigned char n, union POSITION pos) {
    union POSITION next_pos = next_position(yard[n].approach);
    union POSITION next_pos_b = next_position(yard[n].approach_b);

    pos.BIT.SOU = 0;

    if (pos.BYTE == next_pos.BYTE) {
        return true;
    }

    if (yard[n].type == 1) {
        if (pos.BIT.DIR == 1) {
            if (pos.BYTE == next_pos.BYTE) {
                return true;
            }
        } else {
            if (pos.BYTE == next_pos_b.BYTE) {
                return true;
            }
        }
    }

    return false;
}

bool yard_exit_pos(unsigned char n, union POSITION pos) {
    pos.BIT.SOU = 0;

    if (yard[n].type == 0) {
        //type 0   
        if (pos.BYTE == yard[n].exit.BYTE) {
            return true;
        }
    } else {
        //type 1
        if (pos.BIT.DIR == 0) {
            if (pos.BYTE == yard[n].exit.BYTE) {
                return true;
            }
        } else {
            if (pos.BYTE == yard[n].exit_b.BYTE) {
                return true;
            }
        }
    }

    return false;
}

void yard_start_proc(unsigned char n, unsigned char pos, unsigned char d) {

    //            Dim n = ポイント番号 - 3
    //
    //            Dim p = 番号位置変換(pos)
    //
    //            If type = 0 Then
    //                y制御Byte = &H88 + n * &H10 + p
    //                p制御Byte = &HC0 + ポイント番号
    //            Else
    //                y制御Byte = &H80 + n * &H10 + p * 2 '*4
    //                p制御Byte = &H80 + p * &H40 + ポイント番号
    //
    //                If d = 1 Then
    //                    出口位置 = 出口位置2.copy
    //                Else
    //                    出口位置 = 出口位置1.copy
    //                End If
    //            End If



    if (yard[n].type == 0) {//If type = 0 Then
        yard[n].y_cont = 0x88 + n * 0x10 + pos; //y制御Byte = &H88 + n * &H10 + p
        yard[n].p_cont = 0xc0 + yard[n].point_num; //p制御Byte = &HC0 + ポイント番号
    } else {
        yard[n].y_cont = 0x80 + n * 0x10 + pos * 2; //y制御Byte = &H80 + n * &H10 + p * 2 '*4
        //pos=0で戻し側 pos=1で切り替え側
        yard[n].p_cont = 0x80 + pos * 0x40 + yard[n].point_num; //p制御Byte = &H80 + p * &H40 + ポイント番号
    }

    yard_set_line(n, pos, 0); //列車登録削除

}

void yard_end_proc(unsigned char n) {

    yard[n].p_cont ^= 0x40; //p制御Byte = p制御Byte Xor &H40

    if (yard[n].type == 0) {//If type = 0 Then
        yard[n].y_cont &= 0xF0; //y制御Byte = y制御Byte And &HF0
    } else {
        //                '反対側の線に切り替え
        //                y制御Byte = y制御Byte Xor &H2
        yard[n].y_cont ^= 0x2;
    }

}

void yard_start_end_proc(unsigned char n) {

    if (yard[n].type == 0) {//If type = 0 Then
        yard[n].y_cont &= 0xF0; //y制御Byte = y制御Byte And &HF0
        yard[n].p_cont ^= 0x40; //p制御Byte = p制御Byte Xor &H40

    } else {
        if (yard[n].exist == 0) {//If 列車 <> 3 Then !=0b11
            //0側空くときは0側へ切り替え (両側空きになるとき)
            yard[n].y_cont &= 0xF8; //y制御Byte = y制御Byte And &HF8 '***
            yard[n].p_cont &= 0xBF; //p制御Byte = p制御Byte And &HBF
        }
        //片側のみ空くときは何もしない。

    }

}

void yard_process() {
    unsigned char n, p;
    union POSITION next_pos;

    for (n = 0; n < TR_COUNT; n++) {
        switch (train[n].yard_state) {
            case YARD_REQ://Case y処理.Yard要求
            case YARD_APR_WAIT://進入待ち
                p = cont_panel[n].yard; //Dim p = Remcon(n).NumericUpDown1.Value - 1
                //If 列車(n).区間変化 Then
                if (yard_approach_pos(p, train[n].NOW, cont_panel[n].line)) {//If yard(p).進入位置確認(列車(n).現位置, Val(Remcon(n).DomainUpDown2.Text)) Then
                    if (yard_safe_check(n, train[n].NEXT) == SAFE) {//安全確認
                        //yard切り替え
                        //train[n].yard = 0x88 + p * 0x10 + cont_panel[n].line; //列車(n).yard = yard(p).y制御Byte
                        train[n].yard = yard[p].y_cont;
                        train[n].yard_state = YARD_COMP; //列車(n).yard処理状況 = y処理.Yard切替完了
                        train[n].yard_num = p; //                        列車(n).yard番号 = p
                        //                        Remcon(n).Yard_Cont = False 'yard cont desable
                    } else {
                        train[n].yard_state = YARD_APR_WAIT;
                    }
                }
                break;

            case YARD_COMP:
                //Case y処理.Yard切替完了
                //ポイント切り替え
                if (train[n].yard == 0) {//列車(n).yard = 0 Then 'yard 切り替え確認
                    //train[n].point = 0xc0 + yard[train[n].yard_num].point_num; //列車(n).ポイント = yard(列車(n).yard番号).p制御Byte
                    train[n].point = yard[train[n].yard_num].p_cont; //列車(n).ポイント = yard(列車(n).yard番号).p制御Byte
                    train[n].yard_state = POINT_COMP; //列車(n).yard処理状況 = y処理.Yardポイント切替完了
                }
                break;
                //            Case y処理.Yardポイント切替完了
            case POINT_COMP:

                if (yard_stop_pos(train[n].yard_num, train[n].NOW)) {//If 列車(n).現位置 = yard(列車(n).yard番号).停止位置 Then
                    //yard停止
                    train[n].yard_state = YARD_STOP; //列車(n).yard処理状況 = y処理.Yard停止
                }
                break;

            case YARD_STOP_COMP://            Case y処理.Yard完全停止
                //                'Yardポイント戻し
                yard_end_proc(train[n].yard_num); //yard(列車(n).yard番号).Yard終了処理()
                //train[n].point = 0x80 + yard[train[n].yard_num].point_num; //列車(n).ポイント = yard(列車(n).yard番号).p制御Byte
                train[n].point = yard[train[n].yard_num].p_cont; //列車(n).ポイント = yard(列車(n).yard番号).p制御Byte
                train[n].yard_state = POINT_RET; //列車(n).yard処理状況 = y処理.Yardポイント戻し完了
                //                'Timer2.Interval = 1000
                //                'Timer2.Enabled = True 'ポイント切り替え待ち
                //                TM(n) = 10
                break;

                //            Case y処理.Yardポイント戻し完了
            case POINT_RET_COMP:
                //                If TM(n) = 0 Then
                //                    'TM(n) = False
                //                    'yard戻し

                //train[n].yard = train[n].yard = 0x88 + train[n].yard_num * 0x10;
                train[n].yard = yard[train[n].yard_num].y_cont; //                    列車(n).yard = yard(列車(n).yard番号).y制御Byte
                //                    列車(n).yard処理状況 = y処理.Yard終了
                train[n].yard_state = YARD_END;
                //                End If

                break;

            case YARD_END://            Case y処理.Yard終了


                if (train[n].yard == 0) {//If 列車(n).yard = 0 Then 'yard 切り替え確認

                    yard_set_line(train[n].yard_num, cont_panel[n].line, 1); //yard(列車(n).yard番号).列車Set(True) = Val(Remcon(n).DomainUpDown2.Text)
                    ini_train(n); //列車(n) = New train() '列車Disable
                    train[n].STATUS.BIT.CHG = 1;
                    cont_panel[n].LED.YARD = 0; //                    Remcon(n).Yard_Cont = True 'yard cont enable
                    //                    RaiseEvent yard_chg()
                    train[n].yard_state = YARD_NONE;
                }

                break;

                //
                //            Case y処理.Yard発車要求
            case START_REQ:
                p = cont_panel[n].yard; //                Dim p = Remcon(n).NumericUpDown1.Value - 1
                //yard切り替え

                if (yard[p].type == 1) {//                If yard(p).type = 1 Then
                    if (cont_panel[n].LED.REVERS == 1) {//If Remcon(n).CheckBox4.Checked Then '発車方向
                        //列車(n) = New train(yard(p).発車位置2)
                        train_set(n, yard[p].start_b);
                    } else {
                        //列車(n) = New train(yard(p).発車位置)
                        train_set(n, yard[p].start);
                    }

                } else {
                    //列車(n) = New train(yard(p).発車位置)
                    train_set(n, yard[p].start);
                }
                //                If Yard安全確認(n) Then

                switch (point_safe_check(n, train[n].NOW)) {
                    case SAFE:
                        if (point_safe_check(n, train[n].BEFORE) == SAFE) {//前位置も確認
                            //                    If Remcon(n).CheckBox4.Checked Then
                            //                        '逆転戻し
                            //                        Remcon(n).CheckBox4.Checked = False
                            //                    End If
                            //
                            cont_panel[n].LED.REVERS = 0;

                            yard_start_proc(p, cont_panel[n].line, train[n].NOW.BIT.DIR); //yard(p).Yard発車処理(Val(Remcon(n).DomainUpDown2.Text), 列車(n).現位置.方向)
                            //yard_line_num(p, 0, cont_panel[n].line, n);

                            train[n].yard = yard[p].y_cont; //列車(n).yard = yard(p).y制御Byte
                            train[n].yard_state = START_REQ_ACK; //列車(n).yard処理状況 = y処理.Yard発車要求受付
                            train[n].yard_num = p; //列車(n).yard番号 = p
                            //                    Remcon(n).Yard_Cont = False 'yard cont desable
                        } else {
                            //WAIT_PASS
                            ini_train(n);
                        }

                        break;
                    case IMPOSSIBLE:

                    case WAIT_PASS:
                        //                Else
                        ini_train(n); //列車(n) = New train() '列車Disable
                        //列車(n).yard処理状況 = y処理.Yard発車要求
                        //                End If
                        break;
                }
                break;

                //            Case y処理.Yard発車要求受付
            case START_REQ_ACK:

                //ポイント切り替え
                if (train[n].yard == 0) {//If 列車(n).yard = 0 Then 'yard 切り替え確認
                    train[n].point = yard[train[n].yard_num].p_cont; //列車(n).ポイント = yard(列車(n).yard番号).p制御Byte
                    train[n].yard_state = READY_START; //列車(n).yard処理状況 = y処理.Yard発車準備完了
                }

                break;

            case READY_START://            Case y処理.Yard発車準備完了

                //                If 列車(n).現位置 = yard(列車(n).yard番号).出口位置 Then
                //if (train[n].NOW.BYTE == yard[train[n].yard_num].exit.BYTE) {
                if (yard_exit_pos(train[n].yard_num, train[n].NOW)) {
                    //                    If 列車(n).ポイント = 0 Then
                    if (train[n].point == 0) {
                        //Yardポイント戻し

                        yard_start_end_proc(train[n].yard_num); //yard(列車(n).yard番号).Yard発車終了処理()

                        train[n].point = yard[train[n].yard_num].p_cont; //列車(n).ポイント = yard(列車(n).yard番号).p制御Byte

                        train[n].yard_state = EXIT_POS; //列車(n).yard処理状況 = y処理.Yard発車出口
                        //                        'Timer2.Interval = 1000
                        //                        'Timer2.Enabled = True 'ポイント切り替え待ち
                        //                        TM(n) = 10
                    }
                }
                break;

            case EXIT_POS://            Case y処理.Yard発車出口

                if (stoppage_time(n, 10) == 0) {//If TM(n) = 0 Then
                    //                    'TM(n) = False
                    //yard戻し
                    train[n].yard = yard[train[n].yard_num].y_cont; //列車(n).yard = yard(列車(n).yard番号).y制御Byte
                    //                    yard(列車(n).yard番号).列車Set(False) = Val(Remcon(n).DomainUpDown2.Text)
                    train[n].yard_state = YARD_NONE; //列車(n).yard処理状況 = y処理.なし
                    //                    Remcon(n).Yard_Cont = True
                    //                    RaiseEvent yard_chg()
                    cont_panel[n].LED.YARD = 0;
                    //
                    //                End If
                }
                break;

        }


    }
}

//Sub 相変更()

void change_phase(unsigned char n) {
    if (train[n].NOW.BIT.SOU == 0) {//            If 現位置.相 = 0 Then
        train[n].NOW.BIT.SOU = 1; //                現位置.相 = 1
        train[n].BEFORE.BIT.SOU = 1; //                前位置.相 = 1
        train[n].NEXT.BIT.SOU = 1; //                次位置.相 = 1
        train[n].ANEXT.BIT.SOU = 1; //                次々位置.相 = 1
    } else {//Else
        train[n].NOW.BIT.SOU = 0; //                現位置.相 = 0
        train[n].BEFORE.BIT.SOU = 0; //                前位置.相 = 0
        train[n].NEXT.BIT.SOU = 0; //                次位置.相 = 0
        train[n].ANEXT.BIT.SOU = 0; //                次々位置.相 = 0
    }

    //            相変更FLAG = True
    train[n].STATUS.BIT.CHG = 1; //            区間変化 = True
    //
    //        End Sub
}


//   Function ポイント安全確認(ByVal n As Integer, ByVal 位置 As 位置情報) As String

POINT_SAFE point_safe_check(unsigned char n, union POSITION pos) {

    unsigned char opponent = 0; //        Dim 相手 As Integer
    unsigned char opponent_train_count = 0; //        Dim 相手路線列車数 As Integer
    unsigned char c;
    unsigned char unsafe = 0; //        Dim 停止 As Boolean

    for (c = 0; c < TR_COUNT; c++) {
        if (c != n) {
            //位置が他の列車の現、前、次位置と同じなら非安全
            if (pos.BIT.ROSEN == train[c].NOW.BIT.ROSEN && pos.BIT.KUKAN == train[c].NOW.BIT.KUKAN)
                unsafe = 1;
            if (pos.BIT.ROSEN == train[c].BEFORE.BIT.ROSEN && pos.BIT.KUKAN == train[c].BEFORE.BIT.KUKAN)
                unsafe = 1;
            if (pos.BIT.ROSEN == train[c].NEXT.BIT.ROSEN && pos.BIT.KUKAN == train[c].NEXT.BIT.KUKAN)
                unsafe = 1;
            if (pos.BIT.ROSEN == train[c].ANEXT.BIT.ROSEN && pos.BIT.KUKAN == train[c].ANEXT.BIT.KUKAN)
                unsafe = 1;

            //相手路線の列車数確認
            if (pos.BIT.ROSEN == train[c].NOW.BIT.ROSEN) {
                opponent_train_count++; //相手路線列車数 += 1
                opponent = c; //相手 = m
            }
        }
    }

    debug1.BYTE.H = opponent_train_count;
    debug1.BYTE.L = opponent;
    //
    //路線に列車が2台いるときはポイント切り替え不可
    if (opponent_train_count >= 2) return IMPOSSIBLE; //        If 相手路線列車数 >= 2 Then Return "不可"


    debug1.BYTE.L = 2;
    //
    if (unsafe == 1) return WAIT_PASS; // If 停止 Then Return "通過待ち"      


    debug1.BYTE.L = 3;
    //
    //列車が1台いるときは相手の相を確認
    if (opponent_train_count == 1) {//If 相手路線列車数 = 1 Then
        //相が同じなら相手の相を変更
        if (train[opponent].NOW.BIT.SOU == train[n].NOW.BIT.SOU) {//If 列車(相手).現位置.相 = 列車(n).現位置.相 Then 
            if (opponent < n) {
                if (train[opponent].NOW.BIT.DIR != train[n].NOW.BIT.DIR) {//相手の優先順位高く方向が違う時はポイント不可
                    return IMPOSSIBLE;
                }
            }
            change_phase(opponent); //列車(相手).相変更()
        }
        //        End If
    }
    debug1.BYTE.L = 5;

    return SAFE; //Return "安全"

}

void stop_pos_process() {
    char n, m;

    for (n = 0; n < TR_COUNT; n++) {//For n = 0 To 列車数 - 1
        if (train[n].point_state == NONE) {//If 列車(n).point処理状況 = p処理.なし Then
            for (m = 0; m < STOP_POS_COUNT; m++) {//For Each p As 停止位置class In 車止位置
                if ((train[n].NOW.BYTE & 0xbf) == stop_pos[m].pos.BYTE) {//If 列車(n).現位置 = p.位置 Then
                    if (stop_pos[m].point_num >= 0) {//If p.ポイント番号 >= 0 Then
                        //ポイント切り替えON
                        cont_panel[n].LED.POINT = 1; //Remcon(n).CheckBox2.Checked = True
                        train[n].point_state = SWITCH_REQ; //列車(n).point処理状況 = p処理.切替要求
                        cont_panel[n].point_num = stop_pos[m].point_num; //Remcon(n).DomainUpDown2.Text = p.ポイント番号
                    }
                }
            }
        }
    }

}

void stop_pos_set(char n, union POSITION p, char point) {
    stop_pos[n].pos = p;
    stop_pos[n].point_num = point;
}

void rec_play() {
    static char rise_edge;
    //区間変化
    if (train[0].STATUS.BIT.CHG_RCV == 1) {
        if (!rise_edge) {
            rise_edge = 1;
        }
    } else {
        rise_edge = 0;
    }


    switch (rec_status) {
        case 0:
            step = 0;
            step_stop = 0;
            break;
        case 1:
            //RecMode
            if (rise_edge == 1) {//区間変化
                rise_edge = 2;

                if (step < 127) step++;
                rec_list[step].pos.BYTE = train[0].NOW.BYTE;
                rec_list[step].speed = train[0].mascon;

                //Yard SW ON?
                if (train[0].yard_state == YARD_REQ) {
                    rec_list[step].yard.BIT.YARD = cont_panel[0].yard;
                    rec_list[step].yard.BIT.LINE = cont_panel[0].line;
                    rec_list[step].yard.BIT.ENABLE = 1; //EnaleBit
                }

                //POINT SW ON?
                if (train[0].point_state == SWITCH_REQ) {
                    rec_list[step].point.BIT.POINT_NUM = cont_panel[0].point_num;
                    rec_list[step].point.BIT.ENABLE = 1; //EnaleBit
                }

                //Revers
                if (train[0].STATUS.BIT.REV == 1) {
                    rec_list[step].point.BIT.REVERS = 1;
                }


                rec_list[0].pos.BYTE = step;
            }


            //停止中 Yard_Command
            if (train[0].yard_state == START_REQ) {
                if (step < 127) step++;
                rec_list[step].yard.BIT.YARD = cont_panel[0].yard;
                rec_list[step].yard.BIT.LINE = cont_panel[0].line;
                rec_list[step].yard.BIT.ENABLE = 1;
                rec_list[step].speed = train[0].mascon;
                rec_list[0].pos.BYTE = step;
            }

            //Yard_Stop
            if (train[0].yard_state == YARD_END) {
                if (step < 127) step++;
                rec_list[step].speed = 0xff;
                rec_list[0].pos.BYTE = step;
            }


            break;

        case 2:
            //playmode
            if (step > rec_list[0].pos.BYTE - 1) {
                if (repeat) {
                    if (cont_panel[0].LED.YARD == 0) {//Yard Comp
                        count_dwn = stoppage_time(TR_COUNT, 20);
                        if (count_dwn == 0) {
                            step = 0; //PLAY START
                            step_stop = 0;
                        }
                    }


                } else
                    rec_status = 0; //Play END
                break;
            }


            if (step == step_stop) {
                step++;

                cont_panel[0].yard = rec_list[step].yard.BIT.YARD;
                cont_panel[0].line = rec_list[step].yard.BIT.LINE;
                train[0].mascon = rec_list[step].speed;

                if (train[0].yard_state == YARD_NONE) {
                    cont_panel[0].LED.YARD = 1;

                    if (train[0].NOW.BYTE == 0x38)
                        train[0].yard_state = START_REQ; //登録なし
                    else
                        train[0].yard_state = Y_SW_ON; //走行中

                    step++;
                }
            } else {
                if (rise_edge == 1) {//区間変化
                    rise_edge = 2;
                    if (rec_list[step].pos.BYTE == train[0].NOW.BYTE) {

                        train[0].mascon = rec_list[step].speed;
                        if (rec_list[step].yard.BIT.ENABLE) {//YardEnable
                            if (train[0].yard_state == YARD_NONE) {
                                cont_panel[0].LED.YARD = 1;
                                train[0].yard_state = YARD_REQ; //走行中
                                cont_panel[0].yard = rec_list[step].yard.BIT.YARD;
                                cont_panel[0].line = rec_list[step].yard.BIT.LINE;
                            }
                        }
                        //Point
                        if (rec_list[step].point.BIT.ENABLE) {
                            if (train[0].point_state == NONE) {
                                cont_panel[0].LED.POINT = 1;
                                train[0].point_state = SWITCH_REQ;
                                cont_panel[0].point_num = rec_list[step].point.BIT.POINT_NUM;
                            }
                        }

                        //Revers
                        if (rec_list[step].point.BIT.REVERS) {
                            if (train[0].point_state == NONE) {
                                cont_panel[0].LED.REVERS = 1;
                                train[0].STATUS.BIT.REV = 1;
                            }
                        }


                        if (step < 127) step++;
                    }

                } else {
                    //---stop timer----
                    if (rec_list[step].speed == 0xff) {
                        if (cont_panel[0].LED.YARD == 0) {//Yard Comp
                            count_dwn = stoppage_time(TR_COUNT, 20);
                            if (count_dwn == 0) {
                                //step ++; //To Next Step
                                step_stop = step;
                            }
                        }
                    }


                }
            }


            break;

    }



}

void ClrRecList() {
    unsigned char n;

    for (n = 0; n < 128; n++) {
        rec_list[n].pos.BYTE = 0;
        rec_list[n].speed = 0;
        rec_list[n].yard.BYTE = 0;
        rec_list[n].point.BYTE = 0;
    }
}

void SavePlayList(unsigned char prg) {
    char bytes = sizeof rec_list[0];
    unsigned char n, p;
    unsigned char list_count = rec_list[0].pos.BYTE;

    for (n = 0; n < list_count + 1; n++) {
        p = n * bytes;
        eep_data[p] = rec_list[n].pos.BYTE;
        eep_data[p + 1] = rec_list[n].speed;
        eep_data[p + 2] = rec_list[n].yard.BYTE;
        eep_data[p + 3] = rec_list[n].point.BYTE;
    }


    //SAVE to EEP ROM 
    int start_adr = prg * 256;

    for (p = 0; p < 8; p++) {//write 8 pages
        for (n = 0; n < EEP_PAGE; n++) {
            eep_page_data[n + 2] = eep_data[p * EEP_PAGE + n ];
        }

        EEP_Write(start_adr + p*EEP_PAGE, 1, 0xA0);
    }


}

void LoadPlayList(unsigned char prg) {

    char bytes = sizeof rec_list[0];
    unsigned char n, p;
    unsigned char list_count;

    int start_adr = prg * 256;

    list_count = EEP_Read(start_adr, 255, 0xA0);

    for (n = 0; n < list_count + 1; n++) {
        p = n * bytes;
        rec_list[n].pos.BYTE = eep_data[p];
        rec_list[n].speed = eep_data[p + 1];
        rec_list[n].yard.BYTE = eep_data[p + 2];
        rec_list[n].point.BYTE = eep_data[p + 3];
    }

}

unsigned char ExistList(unsigned char prg) {
    //PRGのステップ数を返す。
    int start_adr = prg * 256;
    unsigned char list_count = EEP_Read(start_adr, 1, 0xA0);
    return list_count;
}

unsigned char NextList(unsigned char prg, char d) {
    //登録済の次のPRGを返す。
    unsigned char n = 0;
    char p = prg;

    for (n = 0; n < 10; n++) {
        p += d;
        if (p > 10) p = 0;
        if (p < 0) p = 10;

        if (ExistList(p) > 0) {
            break;
        }
    }

    return p;
}

void DelPlayList(unsigned char prg) {
    //DELETE PRG リストの頭に0  
    eep_data[0] = 0;

    int start_adr = prg * 256;

    EEP_Write(start_adr, 0, 0xA0); //1BYTE WRITE

}


/*******************************************************************************
 End of File
 */
system_interrrupt.cを編集  (SourceFiles➡app➡system_config➡default)
 

void __ISR(_TIMER_1_VECTOR, ipl7AUTO) IntHandlerDrvTmrInstance0(void)
{
    PLIB_INT_SourceFlagClear(INT_ID_0,INT_SOURCE_TIMER_1);
    
    timer_int_func();//追加
}
void __ISR(_TIMER_2_VECTOR, ipl6AUTO) IntHandlerDrvTmrInstance1(void)
{
    PLIB_INT_SourceFlagClear(INT_ID_0,INT_SOURCE_TIMER_2);
    
    timer_int_func_rs();//追加
}
 /*******************************************************************************
 End of File
*/

 

 

PIC32 Nゲージ自動運転

前の記事

信号機
未分類

次の記事

PWMの方式変更