プリント基板で製作2(ソフト)
ソフト
今回作った基板はPCなどと通信するために232C用端子があります。ここに秋月で売っている FT234X 超小型USBシリアル変換モジュール をつけて、まずはPCからリモートします。
PIC32のソフト
Harmonyの設定
Harmonyで設定するのは
- ADC
- TIMER
- I2C
- USART
- PinDiagram
- PinSettings
です。
※MPLABのプロジェクトの作り方はLEDぴかぴか
【ADC】

【Timer】

【I2C】

【USART】

【PinDiagram】

【PinSettings】

コードの編集
追加するコード
atc.h
Header Files-app のところに追加します。
//I2C用変数
DRV_HANDLE hi2c;
DRV_I2C_BUFFER_HANDLE bhi2c;
//USART用変数
DRV_HANDLE handleUSART0;
//16bitのINT型の上位H byte、下位L byte読み込み用共用体
union byte_access {
int INT; // Int Access
struct { // byte Access
unsigned char L;
unsigned char H;
} BYTE;
};
//位置情報の構造体
struct PSI_BIT {
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 */
};
struct STATUS_BIT {
unsigned char CHG : 1; //区間変化
unsigned char REV : 1; //逆転
unsigned char DUMY : 4; //DUMY
unsigned char SLOW : 1; //減速
unsigned char SAFE : 1; //安全
};
//列車の位置情報の構造体
struct st_position {
//現在位置
union { /* Position */
unsigned char BYTE; /* Byte Access */
struct PSI_BIT BIT; /* Bit Access */
} NOW;
//前の位置
union { /* Position */
unsigned char BYTE; /* Byte Access */
struct PSI_BIT BIT; /* Bit Access */
} BEFORE;
//次の位置
union { /* Position */
unsigned char BYTE; /* Byte Access */
struct PSI_BIT BIT; /* Bit Access */
} NEXT;
//次々の位置
union { /* Position */
unsigned char BYTE; /* Byte Access */
struct PSI_BIT BIT; /* Bit Access */
} 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; //読み取りスピード
unsigned char point;
unsigned char yard;
union byte_access speed_rx;
unsigned char REC_NOW;
unsigned char REC_NEXT;
unsigned char REC_BEFORE;
};
//監視区間設定用の共用体
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;
};
#define TR_COUNT 2 //列車数
#define ROSEN_NUM 0 //路線(ボード)番号
#define BOARD_COUNT 3 //ボード数
#define RX_BYTE 128 //RS232C受信バイト数
#define TX_BYTE 128 //RS232C送信バイト数
#define RX_DATA_BYTE 12 //1列車当たりの受信バイト数
#define TX_DATA_BYTE 12 //1列車当たりの送信バイト数
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 debug1; //ADC値
int gnd_adc;
//int gnd_sum;
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; //ポイントリクエスト
lcd.c
Source Files-app に追加します。
#include "system/common/sys_common.h"
#include "app.h"
#include "system_definitions.h"
#define ADR 0x7C
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 BSP_DelayMs(unsigned short);
void BSP_DelayUs(unsigned short);
uint8_t data[5];
//遅延調整用関数(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) {
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ならスペース
}
}
LCD_dat(decch[n[2]]);
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); // 横位置を加える
}
/*******************************************************************************
End of File
*/
timer_int.c
Source Files-app に追加します。
#include "system/common/sys_common.h"
#include "app.h"
#include "system_definitions.h"
void kukan_ON(unsigned char, unsigned char);
void kukan_OFF(unsigned char);
void speed_pulse_on(unsigned char);
void speed_pulse_off();
void section_change_monitor(unsigned char); //区間変化監視
void next_section_on(unsigned char); //次区間ON
void read_generated_voltage(unsigned char, unsigned char);
void speed_cont(unsigned char);
void section_change(void);
void board_comm(unsigned char, unsigned char*); //ボード間通信
void comm_data_set_tx(void); //通信データ設定TX
void comm_data_set_rx(void); //通信データ設定RX
void timer_int_func() {
unsigned char rec_bit; //受信BIT用
unsigned char send_flg; //送信PORT用
_RB10 = 0; //ext_int 同期パルス
rec_bit = _RB11;
//通信用comm_counterはインタラプトを0-0x3ffでカウントします。
if (++comm_counter > 0x3ff) {
comm_counter = 0;
} else
_RB10 = 1;
//int_counterはcomm_counterの下位9bitの0-0x1ffでカウントします。
int_counter = comm_counter & 0x1ff;
switch (int_counter) {
case 0:
section_change();
//インタラプトカウンタが0のときA相のspeedパルスON
if (cont_train[0] != 0xff) {
train_sou[0] = &train[cont_train[0]];
speed_pulse_on(0);
}
break;
case 2:
//インタラプトカウンタが0x2のときA相の区間変化監視(B相は0x102のとき)
section_change_monitor(0);
break;
case 3:
//インタラプトカウンタが3のときNEXT区間パルスON(B相は0x103のとき)
//区間変化確認後に次区間もON
next_section_on(0);
break;
case 0xfa:
//スピードコントロール
speed_cont(0);
break;
case 0xf8:
//スピード読み込み
read_generated_voltage(0, 0);
break;
case 0xf9:
//スピード読み込み
read_generated_voltage(1, 0);
break;
case 0x100:
//インタラプトカウンタが0x100のときB相のspeedパルスON
if (cont_train[1] != 0xff) {
train_sou[1] = &train[cont_train[1]];
//section_change(1);
speed_pulse_on(1);
}
break;
case 0x102:
//インタラプトカウンタが0x2のときA相の区間変化監視(B相は0x102のとき)
section_change_monitor(1);
break;
case 0x103:
//インタラプトカウンタが3のときNEXT区間パルスON(B相は0x103のとき)
//区間変化確認後に次区間もON
next_section_on(1);
break;
case 0x1f8:
//スピード読み込み
read_generated_voltage(0, 1);
break;
case 0x1f9:
//スピード読み込み
read_generated_voltage(1, 1);
break;
case 0x1fa:
speed_cont(1);
break;
}
//スピードパルスOFF
speed_pulse_off();
int i;
for (i = 0; i < 16; i++) {
comm_data[i] = i * 0x10 + i;
}
comm_data[0] = 0x55;
//ボード間の通信
board_comm(rec_bit, &send_flg);
//送信時OUTPUT
_TRISB11 = send_flg;
//幅広同期パルスOFF
if (comm_counter == 0) {
_RB10 = 1;
}
}
void speed_pulse_on(unsigned char sou) {
if (train_sou[sou]) {
kukan[sou] = 0; //kukan clr
//speed_pw[sou] = train_sou[sou]->speed;
speed_pw[sou] = train_sou[sou]->speed_cont.INT;
//区間メモリに現・前位置の区間を設定し区間ON
if (train_sou[sou]->NOW.BIT.ROSEN == ROSEN_NUM) {
kukan[sou] = EnableBit[train_sou[sou]->NOW.BIT.KUKAN];
kanshi_now[sou] = train_sou[sou]->NOW.BIT.KUKAN;
}
if (train_sou[sou]->BEFORE.BIT.ROSEN == ROSEN_NUM) {
kukan[sou] |= EnableBit[train_sou[sou]->BEFORE.BIT.KUKAN];
kanshi_before[sou] = train_sou[sou]->BEFORE.BIT.KUKAN;
}
// 区間ON
kukan_ON(kukan[sou], train_sou[sou]->NOW.BIT.DIR);
}
}
//区間ON用
void kukan_ON(unsigned char kukan, unsigned char d) {
// d=0:正回転, 1:負回転
if (d == 0) {
LATB |= kukan;
_LATB12 = 0; //Port RB12は共通側
} else {
LATB &= ~kukan;
_LATB12 = 1;
}
TRISB &= ~kukan;
_TRISB12 = 0;
}
//区間OFF用
void kukan_OFF(unsigned char kukan) {
if (kukan) {
TRISB |= kukan;
_TRISB12 = 1;
}
}
void speed_pulse_off() {
//インタラプトごとにspeedをマイナス1して0になったらパルスOFF
unsigned char n;
for (n = 0; n < 2; n++) {
if (train_sou[n]) {
if (speed_pw[n] == 0) {
//speedが0で区間パルスOFF
if (kukan[n]) {
TRISB |= kukan[n];
if ((TRISB & 0xff) == 0xff)
_TRISB12 = 1;
kukan[n] = 0;
}
} else {
speed_pw[n]--; //speedをマイナス1
}
}
}
}
void section_change_monitor(unsigned char sou) {
static char sum_count;
static int gnd_sum;
if (train_sou[sou]) {
if (train_sou[sou]->STATUS.BIT.SAFE)
if (!train_sou[sou]->henka) {
if (train_sou[sou]->NEXT.BIT.ROSEN == ROSEN_NUM) {
//次位置区間の監視
kanshi.BIT.KUKAN = train_sou[sou]->NEXT.BIT.KUKAN;
LATA &= 0xC3;
LATA |= kanshi.BYTE;
//ADC読み込み
PLIB_ADC_SamplingStart(ADC_ID_1);
while (!PLIB_ADC_ConversionHasCompleted(ADC_ID_1));
adc_ret.INT = PLIB_ADC_ResultGetByIndex(ADC_ID_1, 0);
if (train_sou[sou]->NOW.BIT.DIR == 0) {
//正方向のとき
if (adc_ret.INT >= 0x2c0) {
train_sou[sou]->henka = 0x80; //区間変化
if (sou == 0)debug1.INT = adc_ret.INT;
}
} else {
//逆方向のとき
if (adc_ret.INT < 0x140) {
train_sou[sou]->henka = 0x80; //区間変化
if (sou == 0)debug1.INT = adc_ret.INT;
}
}
//区間変化でないときGND値とする。
if (!train_sou[sou]->henka) {
gnd_adc = adc_ret.INT;
//区間変更なしのときのADC値をGND Levelにします。
//16回たして4bit右シフトで平均をとります。
gnd_sum += adc_ret.INT;
if (sum_count++ == 15) {
gnd_level.INT = gnd_sum >> 4;
sum_count = 0;
gnd_sum = 0;
}
}
}
}
}
}
void next_section_on(unsigned char sou) {
//次区間をON
if (train_sou[sou]) {
if (train_sou[sou]->STATUS.BIT.SAFE) {
//安全でないときは次区間に他の列車がかかっているのでONしない。
if (train_sou[sou]->NEXT.BIT.ROSEN == ROSEN_NUM)
kukan[sou] |= EnableBit[train_sou[sou]->NEXT.BIT.KUKAN];
kukan_ON(kukan[sou], train_sou[sou]->NOW.BIT.DIR);
}
}
}
void read_generated_voltage(unsigned char n, unsigned char sou) {
static char count[2], p[2];
static int speed_buf[2][16];
static int read_speed[2];
if (train_sou[sou]) {
//現位置と前位置を交互に読み込み
if (n == 0) {
kanshi.BIT.KUKAN = kanshi_now[sou];
} else {
kanshi.BIT.KUKAN = kanshi_before[sou];
}
LATA &= 0xC3;
LATA |= kanshi.BYTE;
//ADC読み込み
PLIB_ADC_SamplingStart(ADC_ID_1);
while (!PLIB_ADC_ConversionHasCompleted(ADC_ID_1));
adc_ret.INT = PLIB_ADC_ResultGetByIndex(ADC_ID_1, 0);
//ADC値からGND値を引いて絶対値をとります。
adc_ret.INT = adc_ret.INT - gnd_level.INT;
if (adc_ret.INT < 0)
adc_ret.INT = -adc_ret.INT;
//8回のピーク値をスピードデータにします。
if (count[sou]++ == 7) {
read_speed[sou] = adc_ret.INT;
count[sou] = 0;
} else if (adc_ret.INT > read_speed[sou])
read_speed[sou] = adc_ret.INT;
//train_sou[sou]->speed_peak = read_speed;
speed_buf[sou][++p[sou] & 0xf] = read_speed[sou];
//移動平均
char m;
unsigned int avr = 0;
for (m = 0; m < 16; m++) {
avr += speed_buf[sou][m];
}
train_sou[sou]->speed_ret.INT = avr >> 4;
}
}
void speed_cont(unsigned char sou) {
int err; //スピードのエラー
int err_abs; //err絶対値
int err_def; //errの差
int k1 = 0x55; //感度1 0x10
int d; //エラー補正値
static char count[2];
if (!train_sou[sou])return;
// スピード設定値と実際スピードの比較
err = train_sou[sou]->speed - train_sou[sou]->speed_ret.INT;
//エラーの絶対値をとります
if (err < 0)
err_abs = -err;
else
err_abs = err;
//前回のエラーと比較
err_def = err_abs - train_sou[sou]->speed_err;
train_sou[sou]->speed_err = err_abs;
k1 += err_def;
//エラー補正値の計算
d = (err * k1) / 0x100;
//スピード設定が0のとき補正値が負でない場合
//完全に停止させるため補正値を-1にします
if (train_sou[sou]->speed == 0) {
if (d>-0x5)
d = -0x5;
}
//スピードコントロール値をエラー補正値で補正
if (++count[sou] > 10) {
count[sou] = 0;
train_sou[sou]->speed_cont.INT += d;
} else {
return;
}
//結果が負にならないようにする
if (train_sou[sou]->speed_cont.INT < 0)
train_sou[sou]->speed_cont.INT = 0;
//接触不良時の制限(0x90)
if (train_sou[sou]->speed_ret.INT < 0x8)
if (train_sou[sou]->speed_cont.INT > 0x90)
train_sou[sou]->speed_cont.INT = 0x90;
//Speedの最大値を制限(0x1F0)
if (train_sou[sou]->speed_cont.INT > 0xc0) //1f0
train_sou[sou]->speed_cont.INT = 0xc0;
}
void section_change() {
char n;
for (n = 0; n < TR_COUNT; n++) {
if (train[n].STATUS.BIT.CHG == 1) {
//受信データに置き換え
train[n].BEFORE.BYTE = train[n].REC_BEFORE;
train[n].NOW.BYTE = train[n].REC_NOW;
train[n].NEXT.BYTE = train[n].REC_NEXT;
if ((train[n].NOW.BIT.ROSEN == ROSEN_NUM)
|| (train[n].NEXT.BIT.ROSEN == ROSEN_NUM)
|| (train[n].BEFORE.BIT.ROSEN == ROSEN_NUM)) {
//各相の列車登録
cont_train[train[n].NOW.BIT.SOU] = n;
train_sou[train[n].NOW.BIT.SOU] = &train[n];
} else {
train[n].speed_cont.INT = 0;
}
train[n].STATUS.BIT.CHG = 0;
}
}
}
void board_comm(unsigned char rec_bit, unsigned char* send_flg) {
unsigned char bit_p;
unsigned int data_p;
//ボード間データ通信
data_p = comm_counter & 0x3ff;
bit_p = EnableBit[data_p & 7]; //bit位置set
data_p >>= 3;
board_num = data_p;
board_num >>= 4;
#if ROSEN_NUM == 0
//親ボードのみポイントなどのボードに送信
if (board_num == ROSEN_NUM || board_num == 6) {
#else
if (board_num == ROSEN_NUM) {
#endif
//データ送信
*send_flg = 0; //port_output
data_p = comm_counter;
bit_p = EnableBit[data_p & 7]; //bit位置set
data_p >>= 3;
send_data = comm_data[data_p];
//送信PORTデータセット
if (send_data & bit_p)
_RB11 = 1;
else
_RB11 = 0;
} else {
//データ受信
*send_flg = 1; //port_input
data_p = (comm_counter - 1) & 0x3ff;
bit_p = EnableBit[data_p & 7]; //bit位置set
data_p >>= 3;
if (rec_bit)
receive_data |= bit_p;
else
receive_data &= ~bit_p;
if (bit_p == 0x80) {
comm_data[data_p] = receive_data;
}
}
}
void comm_data_set_tx() {
unsigned char n;
unsigned int data_p;
//comm_data 送信データSET
data_p = ROSEN_NUM << 4;
//A相
n = cont_train[0];
if (n != 0xff) {
comm_data[data_p] = n + 0xA0;
comm_data[data_p + 1] = train[n].speed_ret_tx.BYTE.H;
comm_data[data_p + 2] = train[n].speed_ret_tx.BYTE.L;
comm_data[data_p + 3] = train[n].henka;
comm_data[data_p + 4] = train[n].speed_cont.BYTE.H;
comm_data[data_p + 5] = train[n].speed_cont.BYTE.L;
comm_data[data_p + 6] = train[n].NOW.BYTE;
} else
comm_data[data_p] = 0xFF;
//B相
n = cont_train[1];
data_p += 0x8;
if (n != 0xff) {
comm_data[data_p] = n + 0xA0;
comm_data[data_p + 1] = train[n].speed_ret_tx.BYTE.H;
comm_data[data_p + 2] = train[n].speed_ret_tx.BYTE.L;
comm_data[data_p + 3] = train[n].henka;
comm_data[data_p + 4] = train[n].speed_cont.BYTE.H;
comm_data[data_p + 5] = train[n].speed_cont.BYTE.L;
comm_data[data_p + 6] = train[n].NOW.BYTE;
} else
comm_data[data_p] = 0xFF;
}
void comm_data_set_rx() {
//受信データSET
unsigned char n;
unsigned int data_p;
for (board_num = 0; board_num < BOARD_COUNT; board_num++) {
if (board_num != ROSEN_NUM) {
//自ボード以外受信
data_p = board_num << 4;
//A相
n = comm_data[data_p];
if ((n & 0xF0) == 0xA0) {
n &= 0xF;
train[n].speed_ret_rx.BYTE.H = comm_data[data_p + 1];
train[n].speed_ret_rx.BYTE.L = comm_data[data_p + 2];
if (train[n].NOW.BIT.ROSEN != ROSEN_NUM) {
if (train[n].NOW.BIT.ROSEN == train[n].BEFORE.BIT.ROSEN)
//現位置および前位置が他路線のとき実スピード受信
train[n].speed_ret.INT = train[n].speed_ret_rx.INT;
}
if (ROSEN_NUM == 0)//Masterボードのみ区間変化受信
if (train[n].NEXT.BIT.ROSEN != 0) {
//NextがMasterボード以外のとき受信
if (train[n].NEXT.BIT.ROSEN == board_num)//次区間のボードの区間変化を受信
train[n].henka = comm_data[data_p + 3];
}
train[n].speed_rx.BYTE.H = comm_data[data_p + 4];
train[n].speed_rx.BYTE.L = comm_data[data_p + 5];
}
//B相
data_p += 0x8;
n = comm_data[data_p];
if ((n & 0xF0) == 0xA0) {
n &= 0xF;
train[n].speed_ret_rx.BYTE.H = comm_data[data_p + 1];
train[n].speed_ret_rx.BYTE.L = comm_data[data_p + 2];
if (train[n].NOW.BIT.ROSEN != ROSEN_NUM) {
if (train[n].NOW.BIT.ROSEN == train[n].BEFORE.BIT.ROSEN)
//現位置および前位置が他路線のとき実スピード受信
train[n].speed_ret.INT = train[n].speed_ret_rx.INT;
}
if (ROSEN_NUM == 0)//Masterボードのみ区間変化受信
if (train[n].NEXT.BIT.ROSEN != 0) {
//NextがMasterボード以外のとき受信
if (train[n].NEXT.BIT.ROSEN == board_num)//次区間のボードの区間変化を受信
train[n].henka = comm_data[data_p + 3];
}
train[n].speed_rx.BYTE.H = comm_data[data_p + 4];
train[n].speed_rx.BYTE.L = comm_data[data_p + 5];
}
}
}
#if ROSEN_NUM == 0
//point_request
if (point_req) {
if (!comm_data[0x70]) {
//ready
comm_data[0x60] = point_req; //point_data
} else
//busy
if (comm_data[0x60]) {
//リクエストクリア
point_req = 0;
comm_data[0x60] = 0;
}
}
//yardt_request
if (yard_req) {
if (!comm_data[0x71]) {
//ready
comm_data[0x61] = yard_req; //point_data
} else
//busy
if (comm_data[0x61]) {
//リクエストクリア
yard_req = 0;
comm_data[0x61] = 0;
}
}
#endif
}
/* *****************************************************************************
End of File
*/
app.hの編集
#include “atc.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"//追加
app.c の編集
丸ごとすげ替えます。
/*******************************************************************************
MPLAB Harmony Application Source File
Company:
Microchip Technology Inc.
File Name:
app.c
Summary:
This file contains the source code for the MPLAB Harmony application.
Description:
This file contains the source code for the MPLAB Harmony application. It
implements the logic of the application's state machine and it may call
API routines of other MPLAB Harmony modules in the system, such as drivers,
system services, and middleware. However, it does not call any of the
system interfaces (such as the "Initialize" and "Tasks" functions) of any of
the modules in the system or make any assumptions about when those functions
are called. That is the responsibility of the configuration-specific system
files.
*******************************************************************************/
// DOM-IGNORE-BEGIN
/*******************************************************************************
Copyright (c) 2013-2014 released Microchip Technology Inc. All rights reserved.
Microchip licenses to you the right to use, modify, copy and distribute
Software only when embedded on a Microchip microcontroller or digital signal
controller that is integrated into your product or third party product
(pursuant to the sublicense terms in the accompanying license agreement).
You should refer to the license agreement accompanying this Software for
additional information regarding your rights and obligations.
SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER
CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR
OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR
CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF
SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
*******************************************************************************/
// DOM-IGNORE-END
// *****************************************************************************
// *****************************************************************************
// Section: Included Files
// *****************************************************************************
// *****************************************************************************
#include "app.h"
// *****************************************************************************
// *****************************************************************************
// Section: Global Data Definitions
// *****************************************************************************
// *****************************************************************************
// *****************************************************************************
/* Application Data
Summary:
Holds application data
Description:
This structure holds the application's data.
Remarks:
This structure should be initialized by the APP_Initialize function.
Application strings and buffers are be defined outside this structure.
*/
APP_DATA appData;
// *****************************************************************************
// *****************************************************************************
// Section: Application Callback Functions
// *****************************************************************************
// *****************************************************************************
/* TODO: Add any necessary callback functions.
*/
// *****************************************************************************
// *****************************************************************************
// Section: Application Local Functions
// *****************************************************************************
// *****************************************************************************
/* TODO: Add any necessary local functions.
*/
// *****************************************************************************
// *****************************************************************************
// Section: Application Initialization and State Machine Functions
// *****************************************************************************
// *****************************************************************************
/*******************************************************************************
Function:
void APP_Initialize ( void )
Remarks:
See prototype in app.h.
*/
void APP_Initialize(void) {
/* Place the App state machine in its initial state. */
appData.state = APP_STATE_INIT;
/* TODO: Initialize your application's state machine and other
* parameters.
*/
}
/******************************************************************************
Function:
void APP_Tasks ( void )
Remarks:
See prototype in app.h.
*/
void ini_train(void);
void train_set(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char);
void APP_Tasks(void) {
/* Check the application's current state. */
switch (appData.state) {
/* Application's initial state. */
case APP_STATE_INIT:
{
bool appInitialized = true;
DRV_TMR0_Start(); //TimerStart
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");
}
//-----ATC-------
cont_train[0] = 0xff;
cont_train[1] = 0xff;
train_sou[0] = NULL;
train_sou[1] = NULL;
ini_train();
//列車A相
// train[0].mascon = 0x18; //スピードを変える時はここを変更
// train_set(0, 0, 1, 0, 0); //n,rosen,section,dir,sou
//列車B相
// train[1].mascon = 0x1c; //スピードを変える時はここを変更
// train_set(1, 0, 5, 0, 1); //n,rosen,section,dir,sou
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);
}
if (rx_data[1] == 0xAA) {
//ヘッダー正常(0x55 0xAA)
time_out.INT = count;
for (n = 0; n < TR_COUNT; n++) {
p = n * RX_DATA_BYTE + 2;
train[n].mascon = rx_data[p];
train[n].speed = train[n].mascon;
train[n].REC_NOW = rx_data[p + 1];
train[n].REC_BEFORE = rx_data[p + 2];
train[n].REC_NEXT = rx_data[p + 3];
//区間変更フラグクリア
if (rx_data[p + 4] & 1) {
train[n].henka = 0;
train[n].STATUS.BIT.CHG = 1;
}
//安全フラグ
if (rx_data[p + 4] & 0x80)
train[n].STATUS.BIT.SAFE = 0x1;
else
train[n].STATUS.BIT.SAFE = 0;
}
//232送信
tx_data[0] = 0x55;//ヘッダー0x55,0xAA
tx_data[1] = 0xAA;
for (n = 0; n < TR_COUNT; n++) {
p = n * TX_DATA_BYTE + 2;
//スピード読み取り値の送信
tx_data[p] = train[n].speed_ret.BYTE.H;
tx_data[p + 1] = train[n].speed_ret.BYTE.L;
//区間変化情報の送信
tx_data[p + 2] = train[n].henka;
tx_data[p + 3] = train[n].point;
tx_data[p + 4] = train[n].yard;
if (train[n].NOW.BIT.ROSEN == ROSEN_NUM) {
tx_data[p + 5] = train[n].speed_cont.BYTE.H;
tx_data[p + 6] = train[n].speed_cont.BYTE.L;
} else {
//他のボードのときcomm_dataのcont_speedを送る
tx_data[p + 5] = train[n].speed_rx.BYTE.H;
tx_data[p + 6] = train[n].speed_rx.BYTE.L;
}
}
// 送信用メモリデータをPCに転送します
for (n = 0; n < TX_BYTE; n++) {
DRV_USART_WriteByte(DRV_USART_INDEX_0, tx_data[n]);
}
}
BSP_DelayMs(20);
//Debug用LCD表示
LCD_posyx(0, 0);
LCD_hex(train[0].mascon);
LCD_str(" ");
LCD_hex(train[1].mascon);
LCD_posyx(1, 0);
LCD_hex(train[0].NOW.BYTE);
LCD_hex(train[0].NEXT.BYTE);
LCD_hex(train[1].NOW.BYTE);
LCD_hex(train[1].NEXT.BYTE);
}
/* TODO: implement your application state machine.*/
/* The default state should never be executed. */
default:
{
/* TODO: Handle error in application's state machine. */
break;
}
}
}
void ini_train() {
char n;
for (n = 0; n < TR_COUNT; 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) {
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].BEFORE.BYTE = train[n].NOW.BYTE;
train[n].NEXT.BYTE = train[n].NOW.BYTE;
train[n].ANEXT.BYTE = train[n].NOW.BYTE;
if (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 = 0;
train[n].STATUS.BIT.SAFE = 1;
}
/*******************************************************************************
End of File
*/
SourceFiles-app-system_config-defaultにあるsystem_interrupt.cの編集
最後の方のTIMERインタラプトの部分に timer_int_func();を一行追加します。
void __ISR(_TIMER_1_VECTOR, ipl7AUTO) IntHandlerDrvTmrInstance0(void)
{
PLIB_INT_SourceFlagClear(INT_ID_0,INT_SOURCE_TIMER_1);
timer_int_func();//追加
}
/*******************************************************************************
End of File
*/
以上です。
PC側のソフト
PCのソフトはVisualStudioのVBで作ります。

スピードメーターには列車にかけているパワーと実際の速度が表示されます。
VisualStudioでVBのWindowsフォームアプリケーションのプロジェクトを作成します。プロジェクト名はpc_remoteにしました。

フォームにツールボックスから
- ComboBox
- Buttonを2つ
- Timer
- SerialPort
を追加します。

・プロジェクトのユーザーコントロールの追加でContPanel.vbを追加します。

・ContPanelにコントロールを追加します。

コードの編集
Form1.vbデザインでF7を押すとコードが開くので、すべて削除して以下のコードを入れます。
Imports System.IO.Ports
Public Class Form1
Const Tx_Byte As Integer = 128
Const Rx_Byte As Integer = 128
Const TxData数 As Integer = 12
Const RxData数 As Integer = 12
Private 列車数 As Integer = 2
Const 最大列車数 As Integer = 8
Public ポイント数 As Integer
Const yard数 As Integer = 1
Private TM As Boolean
Private Remcon As List(Of ContPanel) = New List(Of ContPanel)()
Class 位置情報
Public 区間 As Integer
Public 路線 As Integer
Public 方向 As Integer
Public 相 As Integer
Sub New(ByVal 区 As Integer, ByVal 路 As Integer, ByVal 向 As Integer, ByVal sou As Integer)
区間 = 区
路線 = 路
方向 = 向
相 = sou
End Sub
Public ReadOnly Property Byte情報() As Byte
Get
Return 区間 + 路線 * 8 + 方向 * &H80 + 相 * &H40
End Get
End Property
Sub 次区間()
If 方向 = 0 Then
区間 = (区間 + 1) And &H7
Else
区間 = (区間 - 1) And &H7
End If
End Sub
Sub 前区間()
If 方向 = 0 Then
区間 = (区間 - 1) And &H7
Else
区間 = (区間 + 1) And &H7
End If
End Sub
Function copy()
Return New 位置情報(区間, 路線, 方向, 相)
End Function
Sub 逆転()
If 方向 = 0 Then
方向 = 1
Else
方向 = 0
End If
End Sub
' = 演算子をオーバーロード
Public Shared Operator =(ByVal c1 As 位置情報, ByVal c2 As 位置情報) As Boolean
If (c1.路線 = c2.路線) And (c1.区間 = c2.区間) And (c1.方向 = c2.方向) Then
Return True
Else
Return False
End If
End Operator
Public Shared Operator <>(ByVal c1 As 位置情報, ByVal c2 As 位置情報) As Boolean
Return Not c1 = c2
End Operator
End Class
Class train
Public 現位置 As 位置情報
Public 前位置 As 位置情報
Public 次位置 As 位置情報
Public 次々位置 As 位置情報
Public 区間変化 As Boolean
Public 安全 As Boolean
Public speed As Single
Public 逆転 As Integer
Public 設定speed As Integer
Public ポイント As Integer
'Public point処理状況 As p処理
'Public yard処理状況 As y処理
Public ポイント番号 As Integer
Public yard番号 As Integer
Public 相変更FLAG As Boolean
Public Power As Integer
Public yard As Integer
Sub New()
'Dummyで登録(路線=7)
現位置 = New 位置情報(0, 7, 0, 0)
前位置 = 現位置.copy
次位置 = 現位置.copy
次々位置 = 現位置.copy
End Sub
Sub New(ByVal 現 As 位置情報)
現位置 = 現
前位置 = 現位置.copy
前位置.前区間()
次位置 = 現位置.copy
次位置.次区間()
次々位置 = 次位置.copy
次々位置.次区間()
区間変化 = True
End Sub
Sub New(ByVal 現 As 位置情報, ByVal 前 As 位置情報, ByVal 次 As 位置情報, ByVal 次々 As 位置情報)
現位置 = 現
前位置 = 前
次位置 = 次
次々位置 = 次々
End Sub
Sub 区間変更()
前位置 = 現位置.copy
現位置 = 次位置.copy
次位置 = 次々位置.copy
次々位置.次区間()
区間変化 = True
End Sub
Sub 逆転処理()
'現位置を前位置に、前位置を現位置に
現位置.逆転()
前位置.逆転()
次位置 = 現位置.copy '前位置に入れるため
現位置 = 前位置.copy
前位置 = 次位置.copy
次位置 = 現位置.copy
次位置.次区間()
次々位置 = 次位置.copy
次々位置.次区間()
End Sub
Sub 相変更()
If 現位置.相 = 0 Then
現位置.相 = 1
前位置.相 = 1
次位置.相 = 1
次々位置.相 = 1
Else
現位置.相 = 0
前位置.相 = 0
次位置.相 = 0
次々位置.相 = 0
End If
相変更FLAG = True
End Sub
Public ReadOnly Property Status As Byte
Get
Dim ret As Byte
If 区間変化 Then ret = 1
If Not 相変更FLAG Then
'相変更中は区間変更しない
If 安全 Then ret += &H80
End If
Return ret
End Get
End Property
Public ReadOnly Property Enable As Boolean
'列車運転中Enable
Get
If 現位置.路線 = 7 Then
Return False
Else
Return True
End If
End Get
End Property
End Class
Private 列車(8) As train
'デリゲートの宣言
Public Delegate Sub RsDelegate()
'データーの受信
Private Sub DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _
Handles SerialPort1.DataReceived
'データの受信はマルチスレッドで行われる為にデリゲートを使用して
'メインのスレッドでデータ処理の必要があります。
Me.Invoke(New RsDelegate(AddressOf receive_data), New Object() {})
End Sub
'受信データー
Public Sub receive_data()
Dim byteArray(SerialPort1.BytesToRead - 1) As Byte
Static GND_Level(9) As Integer
Static p As Integer
If byteArray.Length <> Rx_Byte Then
Exit Sub
End If
'ポートのバッファから読み込み
SerialPort1.Read(byteArray, 0, SerialPort1.BytesToRead)
'ヘッダーチェック
If (byteArray(0) <> &H55) Or (byteArray(1) <> &HAA) Then Exit Sub
'Label3.Text = String.Format("{0:X}", byteArray(4))
Dim 変化 As Byte = byteArray(4)
For n = 0 To 列車数 - 1
Dim pos As Integer = RxData数 * n
Dim speed As Integer = 0
Dim power As Integer = 0
If 列車(n).Enable Then
'スピードメータ-
speed = byteArray(pos + 2) * 256 + byteArray(pos + 3)
power = byteArray(pos + 7) * 256 + byteArray(pos + 8)
End If
Remcon(n).Speed_Meter = speed
Remcon(n).Power_Meter = power
Remcon(n).区間表示 = 列車(n).現位置.Byte情報
列車(n).Power = power
'区間変化の確認
If byteArray(pos + 4) = &H80 Then
列車(n).区間変更()
'全ての列車の情報更新
For m = 0 To 列車数 - 1
列車(n).区間変化 = True
Next
Else
'区間変化フラグクリア
列車(n).区間変化 = False
End If
Next
Dim 減速時スピード = 20
'安全確認
For n = 0 To 列車数 - 1
If 列車(n).Enable Then
Select Case 安全確認(n)
Case "停止"
列車(n).安全 = False
列車(n).設定speed = 0
Remcon(n).信号 = "赤"
Case "減速"
Dim 減速速度 As Integer = 減速時スピード '減速時のスピード
列車(n).安全 = True
If Remcon(n).Speed_Cont > 減速速度 Then
列車(n).設定speed = 減速速度
Else
列車(n).設定speed = Remcon(n).Speed_Cont
End If
Remcon(n).信号 = "黄"
Case "安全"
Remcon(n).信号 = "緑"
列車(n).安全 = True
If 列車(n).逆転 = 1 Then
'逆転フラグが1なら逆転のため停止
列車(n).設定speed = 0
'ElseIf 列車(n).point処理状況 = p処理.通過待ち Then
' 'ポイント通過待ちのため停止
' 列車(n).設定speed = 0
'ElseIf 列車(n).yard処理状況 = y処理.Yard停止 Then
' 'Yardで停止
' 列車(n).設定speed = 0
' Remcon(n).Speed_Cont = 0
Else
列車(n).設定speed = Remcon(n).Speed_Cont
End If
Case "向合停止"
列車(n).安全 = False
列車(n).設定speed = 0
Remcon(n).信号 = "赤"
Remcon(n).CheckBox1.Checked = True '強制逆転
End Select
Else
Remcon(n).信号 = "灰"
End If
Next
End Sub
Function 安全確認(ByVal n As Integer) As String
Dim 停止 As Boolean = False
Dim 減速 As Boolean = False
Dim 向合停止 As Boolean = False
For m As Integer = 0 To 列車数 - 1
If m <> n Then
'次位置が他の列車の現、前、次位置と同じなら停止
If (列車(n).次位置.路線 = 列車(m).現位置.路線) And
(列車(n).次位置.区間 = 列車(m).現位置.区間) Then 停止 = True
If (列車(n).次位置.路線 = 列車(m).前位置.路線) And
(列車(n).次位置.区間 = 列車(m).前位置.区間) Then 停止 = True
If (列車(n).次位置.路線 = 列車(m).次位置.路線) And
(列車(n).次位置.区間 = 列車(m).次位置.区間) Then 停止 = True
'次々位置が他の列車の現、前、次位置と同じなら減速
If (列車(n).次々位置.路線 = 列車(m).現位置.路線) And
(列車(n).次々位置.区間 = 列車(m).現位置.区間) Then 減速 = True
If (列車(n).次々位置.路線 = 列車(m).前位置.路線) And
(列車(n).次々位置.区間 = 列車(m).前位置.区間) Then 減速 = True
If (列車(n).次々位置.路線 = 列車(m).次位置.路線) And
(列車(n).次々位置.区間 = 列車(m).次位置.区間) Then 減速 = True
If 停止 Then
If (n > m) And (列車(n).現位置.方向 <> 列車(m).現位置.方向) Then
向合停止 = True '方向逆で優先順位低いとき
Return "向合停止"
End If
Exit For
End If
End If
Next
If 停止 Then Return "停止"
If 減速 Then Return "減速"
Return "安全"
End Function
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
'ポート接続処理
SerialPort1.PortName = ComboBox1.Text
SerialPort1.BaudRate = 115200
SerialPort1.Parity = IO.Ports.Parity.None
SerialPort1.DataBits = 8
SerialPort1.StopBits = IO.Ports.StopBits.One
SerialPort1.ReceivedBytesThreshold = Rx_Byte
SerialPort1.ReadTimeout = 500
SerialPort1.WriteTimeout = 500
SerialPort1.Open()
Timer1.Enabled = True
Button1.Enabled = False
Button2.Enabled = True
ComboBox1.Enabled = False
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
'ポート切断処理
Timer1.Enabled = False
SerialPort1.Close()
ComboBox1.Enabled = True
Button1.Enabled = True
Button2.Enabled = False
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Dim Txdata(Tx_Byte) As Byte
Dim 加速 As Single = 0.3
'ヘッダーとして&H55,&HAAを送る
Txdata(0) = &H55
Txdata(1) = &HAA
For n = 0 To 列車数 - 1
If 列車(n).Enable Then
'speed 加速・減速
If 列車(n).設定speed - 列車(n).speed < 0 Then
加速 = 0.5 '減速時
End If
列車(n).speed += (列車(n).設定speed - 列車(n).speed) * 加速
'逆転フラグ確認
If 列車(n).逆転 = 1 Then
If Int(列車(n).speed) = 0 Then
If 列車(n).Power = 0 Then
'列車が停止したら逆転
列車(n).逆転処理()
列車(n).逆転 = 0
列車(n).区間変化 = True '位置情報更新の為
'逆転ボタン戻し
Remcon(n).CheckBox1.Checked = False
Remcon(n).CheckBox1.Enabled = True
End If
End If
End If
End If
Next
For n = 0 To 最大列車数 - 1
Dim p As Integer = n * TxData数 + 2
Txdata(p) = Int(列車(n).speed) 'speed data
Txdata(p + 1) = 列車(n).現位置.Byte情報
Txdata(p + 2) = 列車(n).前位置.Byte情報
Txdata(p + 3) = 列車(n).次位置.Byte情報
Txdata(p + 4) = 列車(n).Status
Txdata(p + 5) = 列車(n).ポイント
Txdata(p + 6) = 列車(n).yard
Next
Try
SerialPort1.Write(Txdata, 0, Tx_Byte) 'データ送信
Catch ex As Exception
'エラーのとき
Button2_Click(Nothing, Nothing) '切断
MsgBox(ex.Message)
End Try
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim ports As String() = SerialPort.GetPortNames()
If ports.Count = 0 Then
MsgBox("シリアルポートが見つかりません。")
Button1.Enabled = False
Else
'使用可能なシリアルポートをコンボボックスに登録
ComboBox1.Items.AddRange(ports)
ComboBox1.SelectedIndex = 0
End If
'ComboBox1.Text = "COM5"
Me.Text = "PC Remote"
Me.FormBorderStyle = Windows.Forms.FormBorderStyle.Fixed3D
Me.MinimizeBox = False
Me.MaximizeBox = False
Button1.Text = "接続"
Button2.Text = "切断"
Button2.Enabled = False '切断ボタンdisable
Timer1.Interval = 200 'タイマーインターバル200ms
'Dummy Data
For n = 0 To 最大列車数 - 1
列車(n) = New train()
Next
'列車情報設定
列車(0) = New train(New 位置情報(1, 0, 0, 0))
列車(1) = New train(New 位置情報(4, 0, 0, 1))
For n As Integer = 0 To 列車数 - 1
Remcon.Add(New ContPanel(n))
Remcon(n).Top = 10
Remcon(n).Left = Remcon(0).Width * n + 2
Controls.Add(Remcon(n))
AddHandler Remcon(n).逆転_Click, AddressOf 逆転_Click
'AddHandler Remcon(n).ポイント_Click, AddressOf ポイント_Click
'AddHandler Remcon(n).Yard_Click, AddressOf Yard_Click
'Remcon(n).add_point(ポイント) 'リモコンにポイント番号登録
Next
End Sub
Private Sub 逆転_Click(ByVal index As Integer)
'逆転ボタン確認
If Remcon(index).CheckBox1.Checked Then
'列車逆転のため停止させる
列車(index).逆転 = 1
Remcon(index).CheckBox1.Enabled = False
End If
End Sub
Private Sub Button3_Click(sender As Object, e As EventArgs)
列車(0).区間変化 = True
列車(1).区間変化 = True
End Sub
End Class
・同様にContPanel.vbデザインでF7を押してコードを以下と入れ替えます。
Public Class ContPanel
Public Index As Integer
Public Event 逆転_Click(ByVal index As Integer)
Public Sub New(id As Integer)
' この呼び出しはデザイナーで必要です。
InitializeComponent()
' InitializeComponent() 呼び出しの後で初期化を追加します。
Index = id
End Sub
Public Property Speed_Cont() As Integer 'Speed コントローラ
Get
Return TrackBar1.Value
End Get
Set(ByVal Value As Integer)
TrackBar1.Value = Value
End Set
End Property
Public WriteOnly Property 信号() As String
Set(ByVal value As String)
Select Case value
Case "緑"
Label1.BackColor = Color.LightGreen
Case "黄"
Label1.BackColor = Color.Yellow
Case "赤"
Label1.BackColor = Color.LightPink
Case "灰"
Label1.BackColor = Color.LightGray
End Select
End Set
End Property
Public WriteOnly Property 区間表示() As Byte
Set(ByVal value As Byte)
Dim 区間 = value And &H7
Dim 路線 = (value And &H18) / 8
Label1.Text = String.Format("路線:{0}" + vbCrLf + "区間:{1}", 路線, 区間)
End Set
End Property
Public WriteOnly Property Speed_Meter() As Integer 'Speed メーター
Set(ByVal Value As Integer)
Dim speed_max As Integer = &H80
Dim sp As Integer = (1 - Value / speed_max) * PictureBox1.Height
Dim g As Graphics = Graphics.FromImage(PictureBox1.Image)
g.Clear(Color.White)
Dim pen As Pen = New Pen(Color.Red, 3)
Dim brush As Brush = Brushes.Pink
Dim p1 As Point = New Point(0, sp)
Dim p2 As Point = New Point(PictureBox1.Width, sp)
Dim rect As Rectangle = New Rectangle(p1, New Size(PictureBox1.Width, PictureBox1.Height - sp))
g.FillRectangle(brush, rect)
'PictureBox1.Refresh()
End Set
End Property
Public WriteOnly Property Power_Meter() As Integer 'Power メーター
Set(ByVal Value As Integer)
Dim speed_max As Integer = &HC0
Dim sp As Integer = (1 - Value / speed_max) * PictureBox1.Height
Dim g As Graphics = Graphics.FromImage(PictureBox1.Image)
'g.Clear(Color.White)
Dim pen As Pen = New Pen(Color.Red, 3)
Dim brush As Brush = Brushes.Pink
Dim p1 As Point = New Point(0, sp)
Dim p2 As Point = New Point(PictureBox1.Width, sp)
g.DrawLine(pen, p1, p2)
PictureBox1.Refresh()
End Set
End Property
Private Sub ContPanel_Load(sender As Object, e As EventArgs) Handles MyBase.Load
TrackBar1.Maximum = 50
'スピードメーター用
Dim bmp As New Bitmap(PictureBox1.Size.Width, PictureBox1.Size.Height)
PictureBox1.Image = bmp
End Sub
Private Sub CheckBox1_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox1.CheckedChanged
RaiseEvent 逆転_Click(Index)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'停止ボタンでスライダーを0にする()
TrackBar1.Value = 0
End Sub
End Class
以上です。
