最終更新日:2023年6月27日
作成日:2023年6月5日
ここでは、W5500-EVB-PICO + Grove Shield for Pi Picoを使用した、ModbusTCPSlaveユニットを紹介します。
基本的な仕様はSTM32miniShield版に準拠しています。STM32Fのマイコンが本当に入手困難です。BluePillも一気に入手困難となりました。
そんなこともあり、比較的流通が安定してきたマイコンRP2040を積んだ開発ボードでModbusTCPSlaveユニットを構築し直すことを検討しました。(01)Coil接点 16点 ※内部では32点(2word)分確保していますが、外部端子としては16点とします。
フォトカプラによる絶縁出力(オープンコレクタ) 24Vが掛かることを想定しており、16bit分のフォトカブラ入力ボードを用意する必要があります。I2CのIOエキスパンダ経由で接続します。(02)Read接点 16点 ※内部では32点(2word)分確保していますが、外部端子としては16点とします。
入力レジスタ値に対するアラート表示もします。
フォトカプラ入力 24V入力を想定しており、22KΩの制限抵抗を入れることを検討ください。(03)保持レジスタ 16ワード
プログラムの追加で入力レジスタ値に対するアラート設定値やDAC出力値、カウンタ設定値等を入力設定出来ます。(04)入力レジスタ 16ワード デバイスの情報や特定の入力値を表示します。
M5Stack社のENV3ユニットを接続し、気温、湿度、大気圧、及びCPUボードの温度を定期的に登録します。
Coil(01) | ||
アドレス | 機能 | 備考 |
00 | 外部出力OUTPUT_0 | フォトカプラ出力0-0 |
01 | 外部出力OUTPUT_1 | フォトカプラ出力0-1 |
02 | 外部出力OUTPUT_2 | フォトカプラ出力0-2 |
03 | 外部出力OUTPUT_3 | フォトカプラ出力0-3 |
04 | 外部出力OUTPUT_4 | フォトカプラ出力0-4 |
05 | 外部出力OUTPUT_5 | フォトカプラ出力0-5 |
06 | 外部出力OUTPUT_6 | フォトカプラ出力0-6 |
07 | 外部出力OUTPUT_7 | フォトカプラ出力0-7 |
08 | 外部出力OUTPUT_8 | フォトカプラ出力1-0 |
09 | 外部出力OUTPUT_9 | フォトカプラ出力1-1 |
10 | 外部出力OUTPUT_10 | フォトカプラ出力1-2 |
11 | 外部出力OUTPUT_11 | フォトカプラ出力1-3 |
12 | 外部出力OUTPUT_12 | フォトカプラ出力1-4 |
13 | 外部出力OUTPUT_13 | フォトカプラ出力1-5 |
14 | 外部出力OUTPUT_14 | フォトカプラ出力1-6 |
15 | 外部出力OUTPUT_15 | フォトカプラ出力1-7 |
16 | 内部出力OUTPUT_0 | |
17 | 内部出力OUTPUT_1 | |
18 | 内部出力OUTPUT_2 | |
19 | 内部出力OUTPUT_3 | |
20 | 内部出力OUTPUT_4 | |
21 | 内部出力OUTPUT_5 | |
22 | 内部出力OUTPUT_6 | |
23 | 内部出力OUTPUT_7 | |
24 | 内部出力OUTPUT_8 | |
25 | 内部出力OUTPUT_9 | |
26 | 内部出力OUTPUT_10 | |
27 | 内部出力OUTPUT_11 | |
28 | 内部出力OUTPUT_12 | |
29 | 内部出力OUTPUT_13 | |
30 | 内部出力OUTPUT_14 | |
31 | 内部出力OUTPUT_15 |
Input(02) | ||
アドレス | 機能 | 備考 |
00 | 外部入力PUT_0 | フォトカプラ入力0-0 |
01 | 外部入力PUT_1 | フォトカプラ入力0-1 |
02 | 外部入力PUT_2 | フォトカプラ入力0-2 |
03 | 外部入力PUT_3 | フォトカプラ入力0-3 |
04 | 外部入力PUT_4 | フォトカプラ入力0-4 |
05 | 外部入力PUT_5 | フォトカプラ入力0-5 |
06 | 外部入力PUT_6 | フォトカプラ入力0-6 |
07 | 外部入力PUT_7 | フォトカプラ入力0-7 |
08 | 外部入力PUT_8 | フォトカプラ入力1-0 |
09 | 外部入力PUT_9 | フォトカプラ入力1-1 |
10 | 外部入力PUT_10 | フォトカプラ入力1-2 |
11 | 外部入力PUT_11 | フォトカプラ入力1-3 |
12 | 外部入力PUT_12 | フォトカプラ入力1-4 |
13 | 外部入力PUT_13 | フォトカプラ入力1-5 |
14 | 外部入力PUT_14 | フォトカプラ入力1-6 |
15 | 外部入力PUT_15 | フォトカプラ入力1-7 |
16 | 内部入力INPUT_0 | 入力値_0_アラート |
17 | 内部入力INPUT_1 | 入力値_1_アラート |
18 | 内部入力INPUT_2 | 入力値_2_アラート |
19 | 内部入力INPUT_3 | 入力値_3_アラート |
20 | 内部入力INPUT_4 | 入力値_4_アラート |
21 | 内部入力INPUT_5 | 入力値_5_アラート |
22 | 内部入力INPUT_6 | 入力値_6_アラート |
23 | 内部入力INPUT_7 | 入力値_7_アラート |
24 | 内部入力INPUT_8 | |
25 | 内部入力INPUT_9 | |
26 | 内部入力INPUT_10 | |
27 | 内部入力INPUT_11 | |
28 | 内部入力INPUT_12 | |
29 | 内部入力INPUT_13 | |
30 | 内部入力INPUT_14 | |
31 | 内部入力INPUT_15 |
Hold(03) | ||||
アドレス | 機能 | ByteH | ByteL | 備考 |
00 |
|
|||
01 |
|
|||
02 |
|
|||
03 |
|
|||
04 |
|
|||
05 |
|
|||
06 |
|
|||
07 |
|
|||
08 |
|
|||
09 |
|
|||
10 |
|
|||
11 |
|
|||
12 |
|
|||
13 |
|
|||
14 |
|
|||
15 |
|
|||
16 |
|
|||
17 |
|
|||
18 |
|
|||
19 |
|
|||
20 |
|
|||
21 |
|
|||
22 |
|
|||
23 |
|
|||
24 | 入力値_0_上限値 |
|
この値を入力値0と比較してアラートとして設定 上限>下限が不成立の場合は比較せずアラートFALSE |
|
25 | 入力値_0_下限値 |
|
||
26 | 入力値_1_上限値 |
|
この値を入力値1と比較してアラートとして設定 上限>下限が不成立の場合は比較せずアラートFALSE |
|
27 | 入力値_1_下限値 |
|
||
28 | 入力値_2_上限値 |
|
この値を入力値2と比較してアラートとして設定 上限>下限が不成立の場合は比較せずアラートFALSE |
|
29 | 入力値_2_下限値 |
|
||
30 | 入力値_3_上限値 |
|
この値を入力値3と比較してアラートとして設定 上限>下限が不成立の場合は比較せずアラートFALSE |
|
31 | 入力値_3_下限値 |
|
||
32 | 入力値_4_上限値 |
|
この値を入力値4と比較してアラートとして設定 上限>下限が不成立の場合は比較せずアラートFALSE |
|
33 | 入力値_4_下限値 |
|
||
34 | 入力値_5_上限値 |
|
この値を入力値5と比較してアラートとして設定 上限>下限が不成立の場合は比較せずアラートFALSE |
|
35 | 入力値_5_下限値 |
|
||
36 | 入力値_6_上限値 |
|
この値を入力値6と比較してアラートとして設定 上限>下限が不成立の場合は比較せずアラートFALSE |
|
37 | 入力値_6_下限値 |
|
||
38 | 入力値_7_上限値 |
|
この値を入力値7と比較してアラートとして設定 上限>下限が不成立の場合は比較せずアラートFALSE |
|
39 | 入力値_7_下限値 |
|
Input(04) | ||||
アドレス | 機能 | ByteH | ByteL | 備考 |
00 | 入力データ_0 |
|
温度 25.45℃ => 2545 |
|
01 | 入力データ_1 |
|
湿度 50.89% => 5089 |
|
02 | 入力データ_2 |
|
気圧 1033.25hPa => 1033 |
|
03 | 入力データ_3 |
|
ボード温度 25.45℃ => 2545 | |
04 | 入力データ_4 |
|
0-3.3V 10bit (0-1023) GPIO26を使用 | |
05 | 入力データ_5 |
|
サンプルプログラムでは割付なし | |
06 | 入力データ_6 |
|
サンプルプログラムでは割付なし | |
07 | 入力データ_7 |
|
サンプルプログラムでは割付なし | |
08 | 入力データ_8 | サンプルプログラムでは割付なし | ||
09 | 入力データ_9 | サンプルプログラムでは割付なし | ||
10 | 入力データ_10 | サンプルプログラムでは割付なし | ||
11 | 入力データ_11 | サンプルプログラムでは割付なし | ||
12 | 入力データ_12 |
|
現在時刻 TZ:タイムゾーン 日本の場合+9=90ハワイ-8=-80 59分01秒=59×256+01=15105(0x5901) |
|
13 | 入力データ_13 |
|
|
|
14 | 入力データ_14 |
|
|
|
15 | 入力データ_15 |
|
|
|
16 | VenderString_0_1 | ‘\0’ | ‘’ | ベンタ名31max文字+\0 |
17 | VenderString_2_3 | ‘’ | ‘’ | |
18 | VenderString_4_5 | ‘’ | ‘’ | |
19 | VenderString_6_7 | ‘’ | ‘’ | |
20 | VenderString_8_9 | ‘’ | ‘’ | |
21 | VenderString_10_11 | ‘’ | ‘’ | |
22 | VenderString_12_13 | ‘’ | ‘’ | |
23 | VenderString_14_15 | ‘’ | ‘’ | |
24 | VenderString_16_17 | ‘’ | ‘’ | |
25 | VenderString_18_19 | ‘’ | ‘’ | |
26 | VenderString_20_21 | ‘’ | ‘’ | |
27 | VenderString_22_23 | ‘’ | ‘’ | |
28 | VenderString_24_25 | ‘’ | ‘’ | |
29 | VenderString_26_27 | ‘’ | ‘’ | |
30 | VenderString_28_29 | ‘’ | ‘’ | |
31 | VenderString_30_31 | ‘’ | ‘’ | |
32 | ProductString_0_1 | ‘\0’ | ‘’ | 製品名31max文字+\0 |
33 | ProductString_2_3 | ‘’ | ‘’ | |
34 | ProductString_4_5 | ‘’ | ‘’ | |
35 | ProductString_6_7 | ‘’ | ‘’ | |
36 | ProductString_8_9 | ‘’ | ‘’ | |
37 | ProductString_10_11 | ‘’ | ‘’ | |
38 | ProductString_12_13 | ‘’ | ‘’ | |
39 | ProductString_14_15 | ‘’ | ‘’ | |
40 | ProductString_16_17 | ‘’ | ‘’ | |
41 | ProductString_18_19 | ‘’ | ‘’ | |
42 | ProductString_20_21 | ‘’ | ‘’ | |
43 | ProductString_22_23 | ‘’ | ‘’ | |
44 | ProductString_24_25 | ‘’ | ‘’ | |
45 | ProductString_26_27 | ‘’ | ‘’ | |
46 | ProductString_28_29 | ‘’ | ‘’ | |
47 | ProductString_30_31 | ‘’ | ‘’ | |
48 | SystemVerValue0_1 | ‘\1’ | ‘\0’ |
システムバージョン表記 バイト単位で0/1/2/3 |
49 | SystemVerValue2_3 | ‘\0’ | ‘\0’ | |
50 | FirmwareVerVarlue0_1 | ‘\1’ | ‘\0’ |
ファームウエアバージョン表記 バイト単位で0/1/2/3 |
51 | FirmwareVerVarlue2_3 | ‘\0’ | ‘\0’ | |
52 | 予約 | ‘’ | ‘’ | |
53 | 予約 | ‘’ | ‘’ | |
54 | 予約 | ‘’ | ‘’ | |
55 | 予約 | ‘’ | ‘’ | |
56 | 予約 | ‘’ | ‘’ | |
57 | 予約 | ‘’ | ‘’ | |
58 | 予約 | ‘’ | ‘’ | |
59 | 予約 | ‘’ | ‘’ | |
60 | 予約 | ‘’ | ‘’ | |
61 | 予約 | ‘’ | ‘’ | |
62 | 予約 | ‘’ | ‘’ | |
63 | 予約 | ‘’ | ‘’ |
ソースコードも添えておきます。
このコードを実行するに当たり追加が必要なライブラリは、
W5500-EVB-PICO_ModbusSlave1_2_0.ino
/* * 2023/5/30 T.Wanibe * 1.2.1 * バグの修正版 * 1.2.0 * ModbusSlaveを新規に構築することにした。 * WIZ5500-ENV-PICO+ENV3+TM1637 * IP=192.168.0.213 MAC:0xE3 ID = 0xA2 * 1.1.4 * Operating time:の表示値にバグがあった。1/2にしなくてはいけない * Vstrのごみ対策 * 内部時計が2か月で4分進んでしまった。1日一回の時刻同期が必要と感じ対策 * 1.1.3 * メモリ内容の見直し * 1.1.2 * 4-7SEGLEDのドット対策 * Pin割り当て再考 * 1.1 * W5500-EVB-PICOを入手したのでPINアサインを見直してビルド * 1.03 * 1.02のHTML未修正部分の手直し * メモリもフラッシュも可成り余裕があるのでこちらも見直す * 1.02 * 1.01がすんなり動いたので更に以下の機能を追加する * EEPROMによるパラメータ登録 * WebServer機能の追加 * 1.01 * 1.0 で とりあえずModbusMasterとの通信が出来るSlaveが作成出来ました。 * これまでにArduino-Picoに実装してきたコードを移植してもう少し肉付けしたいと思う * Timer割込を追加してCP25のLEDを500msec毎の点滅にしたい。 * NTPクライアントによる時刻同期 及びTM1637に時刻表示 * 最大2093056バイトのフラッシュメモリのうち、スケッチが99432バイト(4%)を使っています。 * 最大262144バイトのRAMのうち、グローバル変数が11080バイト(4%)を使っていて、ローカル変数で251064バイト使うことができます。 */ #define TIMER_INTERRUPT_DEBUG 1 #define _TIMERINTERRUPT_LOGLEVEL_ 4 #include <TimeLib.h> #include "TM1637.h" #include "RPi_Pico_TimerInterrupt.h" #include <SPI.h> #include "MgsModbus.h" //このSketchと同じ階層に置く #include <EEPROM.h> //#include <Adafruit_NeoPixel.h> #include <Wire.h> #include "Adafruit_SHT31.h" #include "QMP6988.h" //UNIT_ENV3に含まれています。 extern "C" { #include <hardware/watchdog.h> }; #define MbCoilDataLen 2 // length of the MbCoilDataLen array (Equivalent16bit*2) #define MbDiscreteDataLen 2 // length of the MbDiscreteDataLen array(Equivalent16bit*2) #define MbHoldDataLen 32 // length of the MbHoldDataLen array #define MbInputDataLen 64 // length of the MbInputDataLen array #define OK 0 #define NG 1 #define BAUDRATE 115200 #define CLK 28 //A2ソケット #define DIO 27 //A2ソケット #define NICReset 20 #define NICInit 21 #define SPI_SCK 18 #define SPI_RX 16 #define SPI_TX 19 #define SPI_CS 17 #define I2C0_SCL 9 #define I2C0_SDA 8 //#define LED_PIN 28 //NeoPixelsが接続されているPINを指定します。 #define LED_COUNT 1 //NeoPixelsが連結されている数を登録します。 #define BRIGHTNESS 50 // NeoPixelの明るさ設定です 0 (min) to 255 (max) #define TIMER0_INTERVAL_MS 1000 #define HttpPort 80 //WebServer #define SEG_DP 0x80 #define vers "RPiPicoModbusTCP_Slave_1.0" #define webTitle "RP2040版 ModbusTCP_Slave メニュー" #define topMenu1 "設定メニュー" #define topMenu2 "Modbus表示" const char titleStr[] = "RPiPicoModbusTCP"; const char VenderString[] = "ToolsBox"; char outputSTR[9]; const char FVirsion[] = "1.2.3"; //フォーマット厳守 x.x.x const char SVirsion[] = "1.2.3"; //フォーマット厳守 x.x.x ソースコードのバージョン // uint32_t delay_ms = 8000; //8秒 最大8.3秒 const int NTPport = 123; const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets // Ethernet settings (depending on MAC and Local network) byte mac[] = {0x00,0x08,0xDC,0x54,0x4D,0xE3}; //WIZNET byte ip[] = {192, 168, 0, 213}; byte dns_server[] = {192, 168, 0, 1}; byte gateway[] = {192, 168, 0, 1}; byte subnet[] = {255, 255, 255, 0}; byte NTPip[] = {192,168,0,199}; //char*timeServerへの変換が必要内部管理は配列にする。 bool gMBusConnect = false; //Modbus接続中はWebServer接続を502で逃げる byte fTogle1 = LOW; bool gRTCOK; //WebServer String HTTP_req; char MacAddressStr[20]; char IPAddressStr[20]; char SubnetMaskStr[20]; char GatewayStr[20]; char NTPserverStr[20]; char DateTimeStr[20]; //内部カウンタ unsigned long gNTPqueryCount = 0; long gLoopCount = 3; //1時間毎に更新予定 最初は1分後に更新したくて初期値を調整 long gLoopTime = 0; //Loop()の実行時間を求める long gResetCount = 0; long gPreTime,gNowTime; unsigned long OperatingTime = 0; //稼働時間 Count2で1秒 int LinkStatus; int gHardwareStatus; float unit = 2.33E-7; unsigned long baseMilis = millis(); unsigned long miliTime; struct time_tm *tm; //STM32dinoとRP2040の構造体が異なる time_t currentTime,recieveTime; unsigned long currentHour,currentMin,currentSec; int8_t TimeDisp[] = {0x00,0x00,0x00,0x00}; uint32_t timestamp, tempval,microVal,fractions; float timezone = 9.0; time_t TimeZoneSec = long(timezone * 3600); const unsigned long seventyYears = 2208988800UL; char buf80[80]; char buf32[32]; // これは、HTMLコードを「流す」ためのバッファーです。 // ””を含む最長の文字チェーン+1と同じ大きさでなければなりません。 char buffer[256]; byte preday; byte nowday; static int8_t tube_tab[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71 }; //0~9,A,b,C,d,E,F //物理接続要素 int dOsPins[] = {0,1}; int dIsPins[] = {22}; int aIsPins[] = {26}; byte preData = 255; byte preR = 255; byte preG = 255; byte preB = 255; bool preShow = true; //物理接続配列要素数を求めておく int DObits = sizeof(dOsPins)/sizeof(int); int DIbits = sizeof(dIsPins)/sizeof(int); int AIbits = sizeof(aIsPins)/sizeof(int); //ENV3用パラメータ float ENV3_tmp = 0.0; //なぜかNaNが認められない float ENV3_hum = 0.0; float ENV3_pressure = 0.0; float tmpOnPico = 0.0; int count = 0; // const byte ID = 0xA2; //オブジェクトコンストラクタ MgsModbus Mb; TM1637 tm1637(CLK,DIO); EthernetUDP Udp; RPI_PICO_Timer ITimer0(0); EthernetServer webServer(HttpPort); EthernetClient client; Adafruit_SHT31 sht30(&Wire); QMP6988 qmp6988; //Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRBW + NEO_KHZ800); // 引数 1 = NeoPixel ストリップのピクセル数 // 引数 2 = Arduino のピン番号 (ほとんどが有効) // 引数 3 = ピクセル タイプ フラグ、必要に応じて追加: // NEO_KHZ800 800 KHz ビットストリーム (ほとんどの NeoPixel 製品 w/WS2812 LED) // NEO_KHZ400 400 KHz (従来の「v1」(v2 ではない) FLORA ピクセル、WS2811 ドライバー) // NEO_GRB ピクセルは GRB ビットストリーム用に配線されています (ほとんどの NeoPixel 製品) // NEO_RGB ピクセルは RGB ビットストリーム用に配線されています (v2 ではなく v1 FLORA ピクセル) // NEO_RGBW ピクセルは GRBW ビットストリーム用に配線されています (NeoPixel RGBW 製品) //------------EEPROM.read void ReadID(){ for (int i = 0; i < 6; i++){ //mac[i] = EEPROM.read(i+1); mac[i] = EEPROM[i+1]; if(Serial) Serial.print("R_mac=");Serial.println(mac[i]); } for (int i = 0; i < 4; i++){ //ip[i] = EEPROM.read(i+7); ip[i] = EEPROM[i+7]; if(Serial) Serial.print("R_ip=");Serial.println(ip[i]); } for (int i = 0; i < 4; i++){ //subnet[i] = EEPROM.read(i+11); subnet[i] = EEPROM[i+11]; if(Serial) Serial.print("R_subnet=");Serial.println(subnet[i]); } for (int i = 0; i < 4; i++){ //gateway[i] = EEPROM.read(i+15); gateway[i] = EEPROM[i+15]; if(Serial) Serial.print("R_gateway=");Serial.println(gateway[i]); } for (int i = 0; i < 4; i++){ //NTPip[i] = EEPROM.read(i+19); NTPip[i] = EEPROM[i+19]; if(Serial) Serial.print("R_NTPip=");Serial.println(NTPip[i]); } //timezone = float(EEPROM.read(23)) / 10.0; timezone = float(EEPROM[23]) / 10.0; if(Serial) Serial.print("R_timezone=");Serial.println(timezone); } //------------EEPROM.write void WriteID(){ for (int i = 0 ; i < 6; i++){ //EEPROM.write(i + 1,mac[i]); EEPROM[i + 1] = mac[i]; if(Serial) Serial.print("W_mac=");Serial.println(mac[i]); } for (int i = 0 ; i < 4; i++){ //EEPROM.write(i + 7, ip[i]); EEPROM[i + 7] = ip[i]; if(Serial) Serial.print("W_ip=");Serial.println(ip[i]); } for (int i = 0 ; i < 4; i++){ //EEPROM.write(i + 11, subnet[i]); EEPROM[i + 11] = subnet[i]; if(Serial) Serial.print("W_subnet=");Serial.println(subnet[i]); } for (int i = 0 ; i < 4; i++){ //EEPROM.write(i + 15, gateway[i]); EEPROM[i + 15] = gateway[i]; if(Serial) Serial.print("W_gateway=");Serial.println(gateway[i]); } for (int i = 0; i < 4; i++){ //EEPROM.write(i + 19, NTPip[i]); EEPROM[i + 19] = NTPip[i]; if(Serial) Serial.print("W_NTPip=");Serial.println(NTPip[i]); } //EEPROM.write(23,char(timezone * 10)); EEPROM[23] = char(timezone * 10); if(Serial) Serial.print("W_timezone=");Serial.println(timezone); // IDを既知のビットに設定します。したがって、Arduinoをリセットすると、EEPROM値が使用されます。 //EEPROM.write(256, ID); EEPROM[256] = ID; EEPROM.commit(); //2.5.5.2で追加 if(Serial) Serial.print("W_ID=");Serial.println(ID,HEX); } //---------------------------------- void LANSetup(){ EEPROM.begin(512); //int idcheck = EEPROM.read(256); int idcheck = EEPROM[256]; if(Serial) Serial.print("R_ID=");Serial.println(idcheck,HEX); Serial.print(F("LocalID = 0x"));Serial.println(idcheck,HEX); if (idcheck == ID){ //idがIDと同じ値の場合、 //これは、このスケッチがシールドを設定するために使用されたことを意味します。 //EERPOMの値を読み取ってシールドを設定します。 ReadID(); }else{ //idが一致しない場合、初期値を書き込む事にします。 WriteID(); } EEPROM.end(); sprintf(MacAddressStr,"%02x.%02x.%02x.%02x.%02x.%02x",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]); sprintf(IPAddressStr,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]); sprintf(SubnetMaskStr,"%d.%d.%d.%d",subnet[0],subnet[1],subnet[2],subnet[3]); sprintf(GatewayStr,"%d.%d.%d.%d",gateway[0],gateway[1],gateway[2],gateway[3]); } //----------------------------MODBUS int GetDeviceInfo(){ for (int i=0;i<DIbits;i++){ Mb.SetBit(MB_FC_READ_DISCRETE_INPUT,i,!digitalRead(dIsPins[i])); //bit 論理反転 } int j=0; for (j=0;j<AIbits;j++){ Mb.MbInputData[j]=analogRead(aIsPins[j]); //U16 } Mb.MbInputData[j] = int(analogReadTemp()*100.0); ENV3_pressure = qmp6988.calcPressure(); //qmp6988のデータを取得します。 Mb.MbInputData[j+1] = int(ENV3_pressure); ENV3_tmp = sht30.readTemperature(); //SHT30のデータを取得します。 Mb.MbInputData[j+2] = int(ENV3_tmp*100.0); ENV3_hum = sht30.readHumidity(); //SHT30から得られた湿度を代入します。 Mb.MbInputData[j+3] = int(ENV3_hum*100.0); return OK; } //----------------------------MODBUS int SetDeviceInfo(){ for (int i=0;i<DObits;i++){ digitalWrite(dOsPins[i],!Mb.GetBit(MB_FC_READ_COILS,i)); //LEDはLOWで点灯 } return OK; } //-------------- void custom_display(uint8_t bit_addr, uint8_t seg_data) { tm1637.start(); tm1637.writeByte( 0x44 ); tm1637.stop(); tm1637.start(); tm1637.writeByte(bit_addr | 0xc0); tm1637.writeByte(seg_data); tm1637.stop(); tm1637.start(); tm1637.writeByte(tm1637.cmd_disp_ctrl); tm1637.stop(); } //-------------タイマ割込で呼ばれるルーチン クロック表示 500msec毎 bool TimerHandler0(struct repeating_timer *t){ OperatingTime++; currentTime = now(); if(Serial) Serial.println(currentTime); currentTime %= 86400; currentHour = currentTime / 3600; currentMin = (currentTime % 3600)/60; TimeDisp[0] = currentHour/ 10; TimeDisp[1] = currentHour % 10; TimeDisp[2] = currentMin / 10; TimeDisp[3] = currentMin % 10; //if(fTogle1) tm1637.point(POINT_OFF); //else tm1637.point(POINT_ON); //tm1637.display(TimeDisp); if(fTogle1){ custom_display( 0, tube_tab[TimeDisp[0]]); custom_display( 1, tube_tab[TimeDisp[1]] | SEG_DP); custom_display( 2, tube_tab[TimeDisp[2]]); custom_display( 3, tube_tab[TimeDisp[3]]); }else{ custom_display( 0, tube_tab[TimeDisp[0]]); custom_display( 1, tube_tab[TimeDisp[1]]); custom_display( 2, tube_tab[TimeDisp[2]]); custom_display( 3, tube_tab[TimeDisp[3]]); } Mb.MbInputData[12] = year(currentTime); nowday = day(currentTime); Mb.MbInputData[13] = month(currentTime)*256 + nowday; Mb.MbInputData[14] = int(timezone * 2560) + currentHour; Mb.MbInputData[15] = currentMin * 256 + currentSec; digitalWrite(LED_BUILTIN, fTogle1); fTogle1 = !fTogle1; if (preday != nowday) { preday = nowday; sendNTPpacket(buf32); // NTPパケットをタイムサーバーに送信します delay(100); gRTCOK = parseNTPpacket(); } return true; } //--------------------- bool processNTP() { //利用可能なデータがある場合は、パケットを読み取ります //https://blog.goo.ne.jp/hiro239415/e/c426a545863921a13a9d6a70b7ae4484 //NTP_Packet (48Byte) bool req = false; int packetSize = Udp.parsePacket(); if(packetSize){ digitalWrite(LED_BUILTIN,HIGH); //要求があったときにBuiltInLEDを点灯 miliTime = millis() - baseMilis; fractions = uint32_t(float(miliTime % 1000) / unit); sprintf(buf32,"■%d\t%d\n",packetSize,fractions); if(Serial) Serial.print(buf32); Udp.read(packetBuffer,NTP_PACKET_SIZE); if(Serial){ for (int i =0;i<48;i++){ Serial.print(packetBuffer[i],HEX); } Serial.println(); } IPAddress Remote = Udp.remoteIP(); int PortNum = Udp.remotePort(); //受信タイムスタンプ = サーバが受け取った時刻を予めセットしておく JSTなのでGMTに変換 timestamp = now() - TimeZoneSec; miliTime = millis() - baseMilis; fractions = uint32_t(float(miliTime % 1000) / unit); tempval = timestamp; packetBuffer[32] = (tempval >> 24) & 0XFF; tempval = timestamp; packetBuffer[33] = (tempval >> 16) & 0xFF; tempval = timestamp; packetBuffer[34] = (tempval >> 8) & 0xFF; tempval = timestamp; packetBuffer[35] = (tempval) & 0xFF; // microVal = fractions; packetBuffer[36] = (microVal >> 24) & 0xFF; microVal = fractions; packetBuffer[37] = (microVal >> 16) & 0xFF; microVal = fractions; packetBuffer[38] = (microVal >> 8) & 0xFF; microVal = fractions; packetBuffer[39] = microVal & 0xFF; //ヘッダーセット packetBuffer[0] = 0b00100100; // 閏秒警告なしLI, 4:SNTPサーバ(Version), 4:サーバ(Mode) packetBuffer[1] = 1 ; // 1:一次基準源(GPS等)(stratum packetBuffer[2] = 5 ; // ポーリング64秒デフォルト値 6(64秒)->5(32秒) packetBuffer[3] = 0xF6; // 精度 -3(0xFD)->-10(0xF6)に変更 msec packetBuffer[4] = 0; // ルート遅延 packetBuffer[5] = 0; packetBuffer[6] = 8; packetBuffer[7] = 0; packetBuffer[8] = 0; // ルート分散 packetBuffer[9] = 0; packetBuffer[10] = 0xC; packetBuffer[11] = 0; // packetBuffer[12] = 71; //"G"; ReferenceID packetBuffer[13] = 80; //"P"; ReferenceID packetBuffer[14] = 83; //"S"; ReferenceID packetBuffer[15] = 0; //"0"; ReferenceID // リファレンス時刻をセット(現在時間) timestamp = now() - TimeZoneSec; //UTC if(Serial){ Serial.print(timestamp);Serial.print(F(":Time synchronization Request received\n")); } tempval = timestamp; microVal = fractions; packetBuffer[16] = (tempval >> 24) & 0XFF; tempval = timestamp; packetBuffer[17] = (tempval >> 16) & 0xFF; tempval = timestamp; packetBuffer[18] = (tempval >> 8) & 0xFF; tempval = timestamp; packetBuffer[19] = (tempval) & 0xFF; packetBuffer[20] = (microVal >> 24) & 0xFF; microVal = fractions; packetBuffer[21] = (microVal >> 16) & 0xFF; microVal = fractions; packetBuffer[22] = (microVal >> 8) & 0xFF; microVal = fractions; packetBuffer[23] = microVal & 0xFF; //オリジナル時間をコピー(サーバに要求が届いた時間) packetBuffer[24] = packetBuffer[40]; packetBuffer[25] = packetBuffer[41]; packetBuffer[26] = packetBuffer[42]; packetBuffer[27] = packetBuffer[43]; packetBuffer[28] = packetBuffer[44]; packetBuffer[29] = packetBuffer[45]; packetBuffer[30] = packetBuffer[46]; packetBuffer[31] = packetBuffer[47]; //送信時刻をセット timestamp = now() - TimeZoneSec; //UTC miliTime = millis() - baseMilis; fractions = uint32_t(float(miliTime % 1000) / unit); tempval = timestamp; packetBuffer[40] = (tempval >> 24) & 0XFF; tempval = timestamp; packetBuffer[41] = (tempval >> 16) & 0xFF; tempval = timestamp; packetBuffer[42] = (tempval >> 8) & 0xFF; tempval = timestamp; packetBuffer[43] = (tempval) & 0xFF; //transmit_timestamp_fractions microVal = fractions; packetBuffer[44] = (microVal >> 24) & 0xFF; microVal = fractions; packetBuffer[45] = (microVal >> 16) & 0xFF; microVal = fractions; packetBuffer[46] = (microVal >> 8) & 0xFF; microVal = fractions; packetBuffer[47] = microVal & 0xFF; //NTP要求を送信したIPアドレスとポートに応答します Udp.beginPacket(Remote, PortNum); Udp.write(packetBuffer,NTP_PACKET_SIZE); Udp.endPacket(); digitalWrite(LED_BUILTIN,LOW); //処理完了で消灯 sprintf(buf32,"●%d\t%d\t%d\t%d\n",packetBuffer[20],packetBuffer[21],packetBuffer[22],packetBuffer[23]); if(Serial) Serial.print(buf32); req = true; gNTPqueryCount++; } return req; } //-----------------指定されたアドレスのタイムサーバーにNTP要求を送信します void sendNTPpacket(const char * address) { // バッファ内のすべてのバイトを0に設定します memset(packetBuffer, 0, NTP_PACKET_SIZE); // NTP要求を形成するために必要な値を初期化します(パケットの詳細については、上記のURLを参照してください) packetBuffer[0] = 0b11100011; // LI, Version, Mode packetBuffer[1] = 0; // Stratum, or type of clock packetBuffer[2] = 6; // ポーリング64秒デフォルト値 packetBuffer[3] = 0xEC; // 精度 // ルート遅延とルート分散の場合は8バイトのゼロ packetBuffer[12] = 0x31; // '1' packetBuffer[13] = 0x4E; // 'N' packetBuffer[14] = 0x31; // '1' packetBuffer[15] = 0x34; // '4' //すべてのNTPフィールドに値が指定されているため、タイムスタンプを要求するパケットを送信できます。 Udp.beginPacket(address, NTPport); // NTP要求はポート123に送信されます Udp.write(packetBuffer, NTP_PACKET_SIZE); Udp.endPacket(); } //-----------------受信したNTPパケットを解析してRTCにセットします bool parseNTPpacket(){ // 返信が利用可能かどうかを確認するのを待ちます bool result = false; if (Udp.parsePacket()) { // パケットを受信しました。そこからデータを読み取ります Udp.read(packetBuffer, NTP_PACKET_SIZE); // パケットをバッファに読み込みます // タイムスタンプは、受信したパケットのバイト40から始まり、4バイトです。 unsigned long secsSince1900; // 位置40から始まる4バイトを長整数に変換します secsSince1900 = (unsigned long)packetBuffer[40] << 24; secsSince1900 |= (unsigned long)packetBuffer[41] << 16; secsSince1900 |= (unsigned long)packetBuffer[42] << 8; secsSince1900 |= (unsigned long)packetBuffer[43]; Serial.print("Seconds since Jan 1 1900 = "); Serial.println(secsSince1900); // エピックタイムに変換します。(local) unsigned long epoch = secsSince1900 - seventyYears + TimeZoneSec; Serial.print("Unix time = "); Serial.println(epoch); setTime(epoch); //RTC登録(LocalTime) result = true; }else{ result = false; } return result; } //--------------------------Webserver //--------OK_200 String OK_200 = "HTTP/1.1 200 OK\n" "Content-Type: text/html\n"; //--------NG_404 String NG_404 = "HTTP/1.1 404 Not Found\n" "Content-Type: text/html\n" "Connnection: close\n"; //--------LoadUtilsJS String LoadUtilsJS1 = "'use strict';\n" "window.chartColors = {\n" "\tred: 'rgb(255, 99, 132)',\n" "\torange: 'rgb(255, 159, 64)',\n" "\tyellow: 'rgb(255, 205, 86)',\n" "\tgreen: 'rgb(75, 192, 192)',\n" "\tblue: 'rgb(54, 162, 235)',\n" "\tpurple: 'rgb(153, 102, 255)',\n" "\tgrey: 'rgb(201, 203, 207)'\n" "};\n" "(function(global) {\n" "\tvar MONTHS = [\n" "\t\t'January',\n" "\t\t'February',\n" "\t\t'March',\n" "\t\t'April',\n" "\t\t'May',\n" "\t\t'June',\n" "\t\t'July',\n" "\t\t'August',\n" "\t\t'September',\n" "\t\t'October',\n" "\t\t'November',\n" "\t\t'December'\n" "\t];\n" "\tvar COLORS = [\n" "\t\t'#4dc9f6',\n" "\t\t'#f67019',\n" "\t\t'#f53794',\n" "\t\t'#537bc4',\n" "\t\t'#acc236',\n" "\t\t'#166a8f',\n" "\t\t'#00a950',\n" "\t\t'#58595b',\n" "\t\t'#8549ba'\n" "\t];\n" "\tvar Samples = global.Samples || (global.Samples = {});\n" "\tvar Color = Chart.helpers.color;\n" "\tfunction applyDefaultNumbers(config) {\n" "\t\tvar cfg = config || {};\n" "\t\tcfg.min = cfg.min || 0;\n" "\t\tcfg.max = cfg.max || 1;\n" "\t\tcfg.from = cfg.from || [];\n" "\t\tcfg.count = cfg.count || 8;\n" "\t\tcfg.decimals = cfg.decimals || 8;\n" "\t\tcfg.continuity = cfg.continuity || 1;\n" "\t\treturn cfg;\n" "\t}\n"; String LoadUtilsJS2 = "\tSamples.utils = {\n" "\t\t// Adapted from http://indiegamr.com/generate-repeatable-random-numbers-in-js/\n" "\t\tsrand: function(seed) {\n" "\t\t\tthis._seed = seed;\n" "\t\t},\n" "\t\trand: function(min, max) {\n" "\t\t\tvar seed = this._seed;\n" "\t\t\tmin = min === undefined ? 0 : min;\n" "\t\t\tmax = max === undefined ? 1 : max;\n" "\t\t\tthis._seed = (seed * 9301 + 49297) % 233280;\n" "\t\t\treturn min + (this._seed / 233280) * (max - min);\n" "\t\t},\n" "\t\tnumbers: function(config) {\n" "\t\t\tvar cfg = applyDefaultNumbers(config);\n" "\t\t\tvar dfactor = Math.pow(10, cfg.decimals) || 0;\n" "\t\t\tvar data = [];\n" "\t\t\tvar i, value;\n" "\t\t\tfor (i = 0; i < cfg.count; ++i) {\n" "\t\t\t\tvalue = (cfg.from[i] || 0) + this.rand(cfg.min, cfg.max);\n" "\t\t\t\tif (this.rand() <= cfg.continuity) {\n" "\t\t\t\t\tdata.push(Math.round(dfactor * value) / dfactor);\n" "\t\t\t\t} else {\n" "\t\t\t\t\tdata.push(null);\n" "\t\t\t\t}\n" "\t\t\t}\n" "\t\t\treturn data;\n" "\t\t},\n" "\t\tlabels: function(config) {\n" "\t\t\tvar cfg = config || {};\n" "\t\t\tvar min = cfg.min || 0;\n" "\t\t\tvar max = cfg.max || 100;\n" "\t\t\tvar count = cfg.count || 8;\n" "\t\t\tvar step = (max - min) / count;\n" "\t\t\tvar decimals = cfg.decimals || 8;\n" "\t\t\tvar dfactor = Math.pow(10, decimals) || 0;\n" "\t\t\tvar prefix = cfg.prefix || '';\n" "\t\t\tvar values = [];\n" "\t\t\tvar i;\n" "\t\t\tfor (i = min; i < max; i += step) {\n" "\t\t\t\tvalues.push(prefix + Math.round(dfactor * i) / dfactor);\n" "\t\t\t}\n" "\t\t\treturn values;\n" "\t\t},\n" "\t\tmonths: function(config) {\n" "\t\t\tvar cfg = config || {};\n" "\t\t\tvar count = cfg.count || 12;\n" "\t\t\tvar section = cfg.section;\n" "\t\t\tvar values = [];\n" "\t\t\tvar i, value;\n" "\t\t\tfor (i = 0; i < count; ++i) {\n" "\t\t\t\tvalue = MONTHS[Math.ceil(i) % 12];\n" "\t\t\t\tvalues.push(value.substring(0, section));\n" "\t\t\t}\n" "\t\t\treturn values;\n" "\t\t},\n" "\t\tcolor: function(index) {\n" "\t\t\treturn COLORS[index % COLORS.length];\n" "\t\t},\n" "\t\ttransparentize: function(color, opacity) {\n" "\t\t\tvar alpha = opacity === undefined ? 0.5 : 1 - opacity;\n" "\t\t\treturn Color(color).alpha(alpha).rgbString();\n" "\t\t}\n" "\t};\n"; String LoadUtilsJS3 = "\t// DEPRECATED\n" "\twindow.randomScalingFactor = function() {\n" "\t\treturn Math.round(Samples.utils.rand(-100, 100));\n" "\t};\n" "\t// INITIALIZATION\n" "\tSamples.utils.srand(Date.now());\n" "\t// Google Analytics\n" "\t/* eslint-disable */\n" "\tif (document.location.hostname.match(/^(www\\.)?chartjs\\.org$/)) {\n" "\t\t(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n" "\t\t(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\n" "\t\tm=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n" "\t\t})(window,document,'script','//www.google-analytics.com/analytics.js','ga');\n" "\t\tga('create', 'UA-28909194-3', 'auto');\n" "\t\tga('send', 'pageview');\n" "\t}\n" "\t/* eslint-enable */\n" "}(this));\n"; //--------WebTopPage String WebTopPage1 = "<HTML>\n" "<HEAD>\n" "\t<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;CHARSET=UTF-8\">\n" "\t<TITLE>"; String WebTopPage11 = "</TITLE>\n" "</HEAD>\n" "<BODY BGCOLOR='#ffffff'>\n" "<H2><CENTER><FONT COLOR='#00ff00'>"; String WebTopPage12 = "</FONT></CENTER></H2>\n" "<P><CENTER><TABLE WIDTH='300' BORDER='0' CELLSPACING='0' CELLPADDING='0'>\n" "\t<TR>\n" "\t\t<TD WIDTH='100%'>\n" "\t\t<OL>\n" "\t\t\t<LI><FONT SIZE='+1'><A HREF=\"http://"; String WebTopPage2 = "/setup1\">"; String WebTopPage21 = "</A>\n" "\t\t\t<LI><A HREF=\"http://"; String WebTopPage3 = "/setup2\">"; String WebTopPage31 = "</A></FONT>\n" "\t\t</OL>\n" "\t\t</TD>\n" "\t</TR>\n" "</TABLE></CENTER>\n" "</BODY>\n" "</HTML>\n"; //-------------SetPage String SetPage1 = "<!DOCTYPE HTML PUBLIC \"\">\n<html>\n<HEAD>\n\t<META http-equiv=\"Content-Type\" charset=Shift_JIS\">\n" "\t<META http-equiv=\"Content-Style-Type\">\n\t<TITLE>"; String SetPage2 = " Setup Page</TITLE>\n" "\t<SCRIPT>\n\t\tfunction HP(w1){parent.window.open(w1,'_top')}\n\t</SCRIPT>\n</HEAD>\n" "<BODY marginwidth=\"0\" marginheight=\"0\" leftmargin=\"0\" style=\"margin: 0; padding: 0;\">\n<BLOCKQUOTE><BLOCKQUOTE>\n" "<table bgcolor=\"#17A1A5\" border=\"0\" width=\"100%\" cellpadding=\"1\" style=\"font-family:Verdana;color:#ffffff;font-size:12px;\">\n" "<tr><td>"; String SetPage3 = " Setup Page</td></tr></table><br>\n" "<script>\n\tfunction hex2num (s_hex) {\n\t\teval(\"var n_num=0X\" + s_hex);\n\t\treturn n_num;\n\t}\n</script>\n" "<tbody>\n<FORM><input type=\"hidden\" name=\"SBM\" value=\"1\">\n<table>\n<tr><td>MAC:</td><td>" "<input id=\"T1\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT1\" value=\""; String SetPage4 = "\">.<input id=\"T3\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT2\" value=\""; String SetPage5 = "\">.<input id=\"T5\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT3\" value=\""; String SetPage6 = "\">.<input id=\"T7\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT4\" value=\""; String SetPage7 = "\">.<input id=\"T9\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT5\" value=\""; String SetPage8 = "\">.<input id=\"T11\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT6\" value=\""; String SetPage9 = "\"><input id=\"T2\" type=\"hidden\" name=\"DT1\"><input id=\"T4\" type=\"hidden\" name=\"DT2\n" "\"><input id=\"T6\" type=\"hidden\" name=\"DT3\"><input id=\"T8\" type=\"hidden\" name=\"DT4\n" "\"><input id=\"T10\" type=\"hidden\" name=\"DT5\"><input id=\"T12\" type=\"hidden\" name=\"DT6\n" "\"></td></tr>\n<tr><td>IP:</td><td><input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT7\" value=\""; String SetPage10 = "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT8\" value=\""; String SetPage11 = "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT9\" value=\""; String SetPage12 = "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT10\" value=\""; String SetPage13 = "\"></td></tr>\n<tr><td>MASK: </td><td><input type= \"text\" size=\"3\" maxlength=\"3\" name=\"DT11\" value=\""; String SetPage14 = "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT12\" value=\""; String SetPage15 = "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT13\" value=\""; String SetPage16 = "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT14\" value=\""; String SetPage17 = "\"></td></tr>\n<tr><td>GW: </td><td><input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT15\" value=\""; String SetPage18 = "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT16\" value=\""; String SetPage19 = "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT17\" value=\""; String SetPage20 = "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT18\" value=\""; String SetPage21 = "\"></td></tr><tr><td COLSPAN='2'>\n<HR ALIGN=CENTER></td></tr>\n" "<tr><td>NTPip: </td><td><input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT19\" value=\""; String SetPage22 = "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT20\" value=\""; String SetPage23 = "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT21\" value=\""; String SetPage24 = "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT22\" value=\""; String SetPage25 = "\"></td></tr>\n" "<tr><td>TimeZone:</td><td><input type=\"text\" size=\"3\" maxlength=\"5\" name=\"DT23\" value=\""; String SetPage26 = "\"></td></tr>\n<tr><td><br></td></tr><tr><td COLSPAN='2'><P ALIGN=RIGHT>" "<INPUT TYPE=\"button\" VALUE=\"RETURN\" onClick=\"HP('http://"; String SetPage27 = "/index')\"/><input id=\"button1\"type=\"submit\" value=\"SUBMIT\" " "Onclick=\"" "document.getElementById('T2').value = hex2num(document.getElementById('T1').value);\n" "\t\tdocument.getElementById('T4').value = hex2num(document.getElementById('T3').value);\n" "\t\tdocument.getElementById('T6').value = hex2num(document.getElementById('T5').value);\n" "\t\tdocument.getElementById('T8').value = hex2num(document.getElementById('T7').value);\n" "\t\tdocument.getElementById('T10').value = hex2num(document.getElementById('T9').value);\n" "\t\tdocument.getElementById('T12').value = hex2num(document.getElementById('T11').value);\"" "></td></tr></tbody>\n</table>\n</BLOCKQUOTE></BLOCKQUOTE>\n</form>\n</BODY>\n</html>\n"; //-------------UtilPage String SetUtil1 = "<!DOCTYPE HTML PUBLIC \"\">\n<html>\n<HEAD>\n\t<META http-equiv=\"Content-Type\" charset=UTF-8\">\n" "\t<META http-equiv=\"Content-Style-Type\">\n\t<TITLE>Modbus "; String SetUtil2 = " Utility Page</TITLE>\n" "\t<SCRIPT>\n\t\tfunction HP(w1){parent.window.open(w1,'_top')}\n\t</SCRIPT>\n</HEAD>\n" "<BODY marginwidth=\"0\" marginheight=\"0\" leftmargin=\"0\" style=\"margin: 0; padding: 0;\" BGCOLOR=\"#ffffff\">\n" "<FORM>\n<BLOCKQUOTE><BLOCKQUOTE>\n" "<P><table bgcolor=\"#17A1A5\" border=\"0\" width=\"100%\" cellpadding=\"1\" style=\"font-family:Verdana;color:#ffffff;font-size:12px;\" CELLSPACING=\"2\">\n" "<tr><td>Modbus "; String SetUtil3 = " Utility Page</td></tr></table><br>\n" "<TABLE WIDTH=\"100%\" BORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\" style=\"table-layout: fixed\">" "<TR>\n\t<TD WIDTH=\"25%\"> </TD><TD WIDTH=\"20%\"> </TD><TD WIDTH=\"55%\"><P ALIGN=CENTER><INPUT TYPE=\"button\" VALUE=\"RETURN\" onClick=\"HP('http://"; String SetUtil4 = "/setup9')\"/></TD>\n" "<TR>\n\t<TD WIDTH=\"25%\">FirmwareVirsion:</TD>\n\t<TD WIDTH=\"11%\"></TD>\n\t<TD WIDTH=\"64%\">"; String SetUtil5 = "</TD>\n</TR>" "<TR>\n\t<TD WIDTH=\"25%\">SourceVirsion:</TD>\n\t<TD WIDTH=\"11%\"></TD>\n\t<TD WIDTH=\"64%\">"; String SetUtil6 = "</TD>\n</TR>" "<TR>\n\t<TD WIDTH=\"25%\">MacAddress:</TD>\n\t<TD WIDTH=\"11%\"></TD>\n\t<TD WIDTH=\"64%\">"; String SetUtil7 = "</TD>\n</TR>" "<TR>\n\t<TD WIDTH=\"25%\">IPAddress:</TD>\n\t<TD WIDTH=\"11%\"></TD>\n\t<TD WIDTH=\"64%\">"; String SetUtil8 = "</TD>\n</TR>" "<TR>\n\t<TD WIDTH=\"25%\">SubnetMask:</TD>\n\t<TD WIDTH=\"11%\"></TD>\n\t<TD WIDTH=\"64%\">"; String SetUtil9 = "</TD>\n</TR>" "<TR>\n\t<TD WIDTH=\"25%\">Data acquisition time:</TD>\n\t<TD WIDTH=\"11%\"></TD>\n\t<TD WIDTH=\"64%\">"; String SetUtil10 = "</TD>\n</TR>" "<TR>\n\t<TD WIDTH=\"25%\">Operating time:</TD>\n\t<TD WIDTH=\"11%\"></TD>\n\t<TD WIDTH=\"64%\">"; String SetUtil11 = "</TD>\n</TR></TABLE></P>\n" "<P><HR ALIGN=LEFT></P>\n<P><TABLE WIDTH=\"100%\" BORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\" HEIGHT=\"800\" style=\"table-layout: fixed\">" "\t<tbody>\n\t<TR>\n\t\t<TD ROWSPAN=\"2\" WIDTH=\"25%\">DI(02)InputStatus</TD>\n" "\t\t<TD COLSPAN=\"2\" HEIGHT=\"23\"></TD>\n" "\t\t<TD WIDTH=\"4%\" HEIGHT=\"23\" NOWRAP ALIGN=\"CENTER\">"; String SetUtil12 = "\t<TR>\n\t\t<TD WIDTH=\"4%\" HEIGHT=\"23\"><P ALIGN=RIGHT>0</TD>\n\t\t<TD WIDTH=\"7%\" HEIGHT=\"23\"></TD>\n" "\t\t<TD WIDTH=\"4%\" HEIGHT=\"23\" NOWRAP ALIGN=\"CENTER\">\n"; String SetUtil13 = "\t\t<INPUT TYPE=\"checkbox\" NAME=\"DI_15\" disabled=\"disabled\" "; String SetUtil14 = "></TD>\n\t</TR>\n\t<TR>\n\t\t<TD COLSPAN=\"19\" HEIGHT=\"5\"><HR ALIGN=LEFT></TD>\n\t</TR>\n" "\t<TR>\n\t\t<TD ROWSPAN=\"3\" WIDTH=\"25%\">Coil(01)CoilStatus</TD>\n" "\t\t<TD COLSPAN=\"2\" HEIGHT=\"23\"></TD>\n\t\t<TD WIDTH=\"4%\" HEIGHT=\"23\" NOWRAP ALIGN=\"CENTER\">"; String SetUtil15 = "\t\t<TD ROWSPAN=\"2\" WIDTH=\"4%\"><P ALIGN=RIGHT>0</TD>\n" "\t\t<TD WIDTH=\"7%\" HEIGHT=\"23\"><P ALIGN=RIGHT>T</TD>\n\t\t<TD WIDTH=\"4%\" HEIGHT=\"23\" NOWRAP ALIGN=\"CENTER\">\n"; String SetUtil16 = "\t</TR>\n\t<TR>\n\t\t<TD WIDTH=\"7%\" HEIGHT=\"23\" ALIGN=\"RIGHT\">F</TD>\n" "\t\t<TD WIDTH=\"4%\" HEIGHT=\"23\" NOWRAP ALIGN=\"CENTER\">\n"; String SetUtil17 = "\t</TR>\n\t<TR>\n\t\t<TD COLSPAN=\"2\" HEIGHT=\"23\"></TD><TD COLSPAN=\"16\" HEIGHT=\"23\"></TD>\n" "\t</TR>\n\t<TR>\n\t\t<TD COLSPAN=\"19\" HEIGHT=\"30\"><HR ALIGN=LEFT></TD>\n\t</TR>\n" "\t<TR>\n\t\t<TD ROWSPAN=\"12\" WIDTH=\"25%\">IR(04)InputRegistor</TD>\n"; String SetUtil18 = "\t\t<TD COLSPAN=\"2\" ALIGN=\"CENTER\">\n\t\tVstr</TD><TD COLSPAN=\"16\">"; String SetUtil19 = "</TD>\n\t\t</TR>\n\t\t<TR>\n" "\t\t<TD COLSPAN=\"2\" ALIGN=\"CENTER\">\n\t\tPstr</TD><TD COLSPAN=\"16\">"; String SetUtil20 = "</TD>\n\t\t</TR>\n\t\t<TR>\n" "\t\t<TD COLSPAN=\"2\" ALIGN=\"CENTER\">\n\t\tSver</TD><TD WIDTH=\"4%\">"; String SetUtil21 = "</TD>\n\t</TR></tbody>\n</TABLE>\n" "</BLOCKQUOTE></BLOCKQUOTE>\n</form>\n</BODY></html>"; //----------------------- void paramParse(String reqStr){ int Code; int len = reqStr.length(); char* HTTP_c = (char*)malloc(len+1); reqStr.toCharArray(HTTP_c, len); char bufff[10]; //DT1 mac[0] HEX int indexS = reqStr.indexOf("DT1="); int indexE = reqStr.indexOf("&",indexS); int k = 0; char c; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); mac[0]=int(strtol(bufff, NULL, 16)); //Serial.print(bufff);Serial.println(mac[0]); break; }else{ bufff[k++] = c; } } break; } } //DT2 mac[1] HEX indexS = reqStr.indexOf("DT2="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); mac[1]=int(strtol(bufff, NULL, 16)); //Serial.print(bufff);Serial.println(mac[1]); break; }else{ bufff[k++] = c; } } break; } } //DT3 mac[2] HEX indexS = reqStr.indexOf("DT3="); //Serial.print("Pos=");Serial.println(indexS); indexE = reqStr.indexOf("&",indexS); //Serial.print("Pos=");Serial.println(indexE); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); //Serial.println(c); if (c == '='){ int m = indexE - indexS; //Serial.print("m=");Serial.println(m); for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); mac[2]=int(strtol(bufff, NULL, 16)); //Serial.print(bufff);Serial.println(mac[2]); break; }else{ bufff[k++] = c; } } break; } } //DT4 mac[3] HEX indexS = reqStr.indexOf("DT4="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); mac[3]=int(strtol(bufff, NULL, 16)); //Serial.print(bufff);Serial.println(mac[3]); break; }else{ bufff[k++] = c; } } break; } } //DT5 mac[4] HEX indexS = reqStr.indexOf("DT5="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); mac[4]=int(strtol(bufff, NULL, 16)); //Serial.print(bufff);Serial.println(mac[4]); break; }else{ bufff[k++] = c; } } break; } } //DT6 mac[5] HEX indexS = reqStr.indexOf("DT6="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); mac[5]=int(strtol(bufff, NULL, 16)); //Serial.print(bufff);Serial.println(mac[5]); break; }else{ bufff[k++] = c; } } break; } } //DT7 ip[0] DEC indexS = reqStr.indexOf("DT7="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); ip[0]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(ip[0]); break; }else{ bufff[k++] = c; } } break; } } //DT8 ip[1] DEC indexS = reqStr.indexOf("DT8="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); ip[1]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(ip[1]); break; }else{ bufff[k++] = c; } } break; } } //DT9 ip[2] DEC indexS = reqStr.indexOf("DT9="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); ip[2]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(ip[2]); break; }else{ bufff[k++] = c; } } break; } } //DT10 ip[3] DEC indexS = reqStr.indexOf("DT10="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); ip[3]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(ip[3]); break; }else{ bufff[k++] = c; } } break; } } //DT11 subnet[0] DEC indexS = reqStr.indexOf("DT11="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); subnet[0]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(subnet[0]); break; }else{ bufff[k++] = c; } } break; } } //DT12 subnet[1] DEC indexS = reqStr.indexOf("DT12="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); subnet[1]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(subnet[1]); break; }else{ bufff[k++] = c; } } break; } } //DT13 subnet[2] DEC indexS = reqStr.indexOf("DT13="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); //Serial.println(bufff); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); subnet[2]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(subnet[2]); break; }else{ bufff[k++] = c; } } break; } } //DT14 subnet[3] DEC indexS = reqStr.indexOf("DT14="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = HTTP_req.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); subnet[3]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(subnet[3]); break; }else{ bufff[k++] = c; } } break; } } //DT15 gateway[0] DEC indexS = reqStr.indexOf("DT15="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); gateway[0]=int(strtol(bufff, NULL, 10));//Serial.print(bufff);Serial.println(gateway[0]); break; }else{ bufff[k++] = c; } } break; } } //DT16 gateway[1] DEC indexS = reqStr.indexOf("DT16="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); gateway[1]=int(strtol(bufff, NULL, 10));//Serial.print(bufff);Serial.println(gateway[1]); break; }else{ bufff[k++] = c; } } break; } } //DT17 gateway[2] DEC indexS = reqStr.indexOf("DT17="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); gateway[2]=int(strtol(bufff, NULL, 10));//Serial.print(bufff);Serial.println(gateway[2]); break; }else{ bufff[k++] = c; } } break; } } //DT18 gateway[3] DEC indexS = reqStr.indexOf("DT18="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); gateway[3]=int(strtol(bufff, NULL, 10));//Serial.print(bufff);Serial.println(gateway[3]); break; }else{ bufff[k++] = c; } } break; } } //DT19 NTPip[0] DEC indexS = reqStr.indexOf("DT19="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); NTPip[0]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(NTPip[0]); break; }else{ bufff[k++] = c; } } break; } } //DT120 NTPip[1] DEC indexS = reqStr.indexOf("DT20="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); NTPip[1]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(NTPip[1]); break; }else{ bufff[k++] = c; } } break; } } //DT21 NTPip[2] DEC indexS = reqStr.indexOf("DT21="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); NTPip[2]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(NTPip[2]); break; }else{ bufff[k++] = c; } } break; } } //DT22 NTPip[3] DEC indexS = reqStr.indexOf("DT22="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); NTPip[3]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(NTPip[3]); break; }else{ bufff[k++] = c; } } break; } } //DT23 timezone float indexS = reqStr.indexOf("DT23="); indexE = reqStr.indexOf("&",indexS); k = 0; for(int j = indexS;j<=indexE;j++){ c = reqStr.charAt(j); if (c == '='){ int m = indexE - indexS; for (int l = 1; l < m;l++){ c = reqStr.charAt(j+l); if(c == '&'){ bufff[k]='\0'; //Serial.println(bufff); timezone =int((strtof(bufff, NULL)*10)); break; }else{ bufff[k++] = c; } } break; } } } //------------------PrintSetUpPage void PrintSetUpPage( EthernetClient client){ client.println(OK_200); client.print(SetPage1); client.print(vers); client.print(SetPage2); client.print(vers); client.print(SetPage3); client.print(mac[0],HEX); client.print(SetPage4); client.print(mac[1],HEX); client.print(SetPage5); client.print(mac[2],HEX); client.print(SetPage6); client.print(mac[3],HEX); client.print(SetPage7); client.print(mac[4],HEX); client.print(SetPage8); client.print(mac[5],HEX); client.print(SetPage9); client.print(ip[0],DEC); client.print(SetPage10); client.print(ip[1],DEC); client.print(SetPage11); client.print(ip[2],DEC); client.print(SetPage12); client.print(ip[3],DEC); client.print(SetPage13); client.print(subnet[0],DEC); client.print(SetPage14); client.print(subnet[1],DEC); client.print(SetPage15); client.print(subnet[2],DEC); client.print(SetPage16); client.print(subnet[3],DEC); client.print(SetPage17); client.print(gateway[0],DEC); client.print(SetPage18); client.print(gateway[1],DEC); client.print(SetPage19); client.print(gateway[2],DEC); client.print(SetPage20); client.print(gateway[3],DEC); client.print(SetPage21); client.print(NTPip[0],DEC); client.print(SetPage22); client.print(NTPip[1],DEC); client.print(SetPage23); client.print(NTPip[2],DEC); client.print(SetPage24); client.print(NTPip[3],DEC); client.print(SetPage25); client.print(timezone,2); client.print(SetPage26); client.print(IPAddressStr); client.print(SetPage27); } //-------------PrintUtilPage void PrintUtilPage( EthernetClient client){ //sprintf(DateTimeStr,"%04u/%02u/%02u %02u:%02u:%02u",year(), month(), day()-1,hour(), minute(), second()); sprintf(DateTimeStr,"%04u/%02u/%02u %02u:%02u:%02u",year(), month(), day(),hour(), minute(), second()); client.println(OK_200); client.print(SetUtil1); client.print(titleStr); client.print(SetUtil2); client.print(titleStr); client.print(SetUtil3); client.print(IPAddressStr); client.print(SetUtil4); client.print(FVirsion); client.print(SetUtil5); client.print(SVirsion); client.print(SetUtil6); client.print(MacAddressStr); client.print(SetUtil7); client.print(IPAddressStr); client.print(SetUtil8); client.print(SubnetMaskStr); client.print(SetUtil9); client.print(DateTimeStr); client.print(SetUtil10); sprintf(buffer,"%d[sec]",int(OperatingTime / 2)); client.print(buffer); client.print(SetUtil11); for (int i = 0;i<15;i++){ sprintf(buffer,"%x</TD>\n\t\t<TD WIDTH=\"4%%\" HEIGHT=\"23\" ALIGN=\"CENTER\">",i); client.print(buffer); } sprintf(buffer,"%x</TD>\n\t</TR>\n",15); client.print(buffer); client.print(SetUtil12); for (int i = 0;i<15;i++){ sprintf(buffer,"\t\t<INPUT TYPE=\"checkbox\" NAME=\"DI_%d\" disabled=\"disabled\" ",i); client.print(buffer); if(Mb.GetBit(MB_FC_READ_DISCRETE_INPUT,i) == true) client.print(F("CHECKED")); client.print(F("></TD>\n\t\t<TD WIDTH=\"4%\" HEIGHT=\"23\" ALIGN=\"CENTER\">\n")); } client.print(SetUtil13); if(Mb.GetBit(MB_FC_READ_DISCRETE_INPUT,15) == true) client.print(F("CHECKED")); client.print(SetUtil14); for (int i = 0;i<15;i++){ sprintf(buffer,"%x</TD>\n\t\t<TD WIDTH=\"4%%\" HEIGHT=\"23\" ALIGN=\"CENTER\">",i); client.print(buffer); } sprintf(buffer,"%x</TD>\n\t</TR>\n",15); client.print(buffer); client.print(SetUtil15); for (int i = 0;i<16;i++){ sprintf(buffer,"\t\t<INPUT TYPE=\"radio\" NAME=\"CL_%02x\" disabled=\"disabled\" ",i); client.print(buffer); if(Mb.GetBit(MB_FC_READ_COILS,i) == true) client.print(F("CHECKED")); client.print(F("></TD>\n")); if(i<15) client.print(F("\t\t<TD WIDTH=\"4%\" HEIGHT=\"23\" ALIGN=\"CENTER\">\n")); } client.print(SetUtil16); for (int i = 0;i<16;i++){ sprintf(buffer,"\t\t<INPUT TYPE=\"radio\" NAME=\"CL_%02x\" disabled=\"disabled\" ",i); client.print(buffer); if(Mb.GetBit(MB_FC_READ_COILS,i) == false) client.print(F("CHECKED")); client.print(F("></TD>\n")); if(i<15) client.print(F("\t\t<TD WIDTH=\"4%\" HEIGHT=\"23\" ALIGN=\"CENTER\">\n")); } client.print(SetUtil17); for (int i = 0;i<8;i++){ sprintf(buffer,"\t\t<TD WIDTH=\"4%%\" ALIGN=\"RIGHT\" HEIGHT=\"23\">%d</TD>\n\t\t<TD WIDTH=\"4%%\" HEIGHT=\"23\"></TD><TD COLSPAN=\"16\" HEIGHT=\"23\">%d</TD>\n\t</TR>\n\t<TR>\n",i,Mb.MbInputData[i]); client.print(buffer); } client.print(SetUtil18); for (int i = 0;i<16;i++){ word q = Mb.MbInputData[i+16]; client.print(char(q/256)); client.print(char(q%256)); } client.print(SetUtil19); for (int i = 0;i<16;i++){ word q = Mb.MbInputData[i+32]; client.print(char(q/256)); client.print(char(q%256)); } client.print(SetUtil20); char mainVer,minorVer,Rev; //sscanf(SVirsion,"%1s.%1s.%1s",&mainVer,&minorVer,&Rev); client.print(char(Mb.MbInputData[48] / 256)); client.print(F("</TD><TD WIDTH=\"4%\">.</TD><TD WIDTH=\"4%\">")); client.print(char(Mb.MbInputData[48] % 256)); client.print(F("</TD><TD WIDTH=\"4%\">.</TD><TD WIDTH=\"4%\">")); client.print(char(Mb.MbInputData[49] / 256)); client.print(F("</TD><TD COLSPAN=\"11\"></TD>\n\t\t</TR>\n\t\t<TR>\n")); client.print(F("\t\t<TD COLSPAN=\"2\" ALIGN=\"CENTER\">\n\t\tFver</TD><TD WIDTH=\"4%\">")); //sscanf(FVirsion,"%1s.%1s.%1s",&mainVer,&minorVer,&Rev); client.print(char(Mb.MbInputData[50] / 256)); client.print(F("</TD><TD WIDTH=\"4%\">.</TD><TD WIDTH=\"4%\">")); client.print(char(Mb.MbInputData[50] % 256)); client.print(F("</TD><TD WIDTH=\"4%\">.</TD><TD WIDTH=\"4%\">")); client.print(char(Mb.MbInputData[51] / 256)); client.print(F("</TD><TD COLSPAN=\"11\"></TD>\n\t\t</TR>\n\t\t<TR>\n")); client.print(F("\t\t<TD COLSPAN=\"19\" HEIGHT=\"23\"><HR ALIGN=LEFT></TD>\n\t</TR>\n")); //HR client.print(F("\t<TR>\n\t<TD ROWSPAN=\"16\" WIDTH=\"25%\">HR(03)HolingRegistor</TD>\n")); for (int i = 0;i<16;i++){ sprintf(buffer,"\t\t<TD WIDTH=\"4%%\" ALIGN=\"RIGHT\" HEIGHT=\"23\">%d</TD>\n\t\t<TD WIDTH=\"4%%\" HEIGHT=\"23\"></TD>\n\t\t<TD COLSPAN=\"16\" HEIGHT=\"23\">%d",i,Mb.MbHoldData[i]); client.print(buffer); if(i<15) client.print(F("</TD>\n\t</TR>\n\t<TR>\n")); } client.print(SetUtil21); } //-------------WebPageTop void pageIntroduction( EthernetClient client){ client.println(OK_200); client.print(WebTopPage1); client.print(webTitle); client.print(WebTopPage11); client.print(webTitle); client.print(WebTopPage12); client.print(IPAddressStr); client.print(WebTopPage2); client.print(topMenu1); client.print(WebTopPage21); client.print(IPAddressStr); client.println(WebTopPage3); client.print(topMenu2); client.println(WebTopPage31); client.stop(); } //-------------LoadUtilsJS void pageLoadUtilsJS( EthernetClient client){ client.println(OK_200); client.println(LoadUtilsJS1); //バッファサイズを考慮して3分割しています。 client.println(LoadUtilsJS2); client.println(LoadUtilsJS3); client.stop(); } //------------PrintResponse404 void PrintResponse404( EthernetClient client ){ client.println(NG_404); client.stop(); } //-------------------------- void checkWebPage( EthernetClient client){ if(Serial) Serial.println(F("new webClient")); boolean restart = false; if (client) { // HTTPリクエスト空行(\r\n\r\n)で終わる。ので、空行を探す。 boolean currentLineIsBlank = true; while (client.connected()) { if( !client.available() ){ if(Serial) Serial.print(F(".")); continue; } char c = client.read(); HTTP_req += c; if(Serial) Serial.print(c); if( c == '\n' && currentLineIsBlank ){ // 空行発見。HTTPリクエスト終了。レスポンスを返す。 //Serial.print("RecieveLength=");Serial.println(HTTP_req.length()); if (HTTP_req.indexOf("/?")>0) { //setup?と/?を区別する必要がある if(Serial) Serial.print(F("CASE1:"));Serial.print(gLoopCount); /*if(gLoopCount % 2){ digitalWrite(LED_BUILTIN,HIGH); //Serial.println(F(" H")); }else{ digitalWrite(LED_BUILTIN,LOW); //Serial.println(F(" L")); }*/ delay(100); HTTP_req = ""; break; }else if(HTTP_req.indexOf("setup")>0){ //setup頁の場合 SBMが含まれていればEEPROMに書込、そうで無ければ表示のみ //setup?SBM=1&DT1=0&DT2=8&DT3=DC&DT4=54&DT5=4D&DT6=D0&DT1=0&DT2=8&DT3=220&DT4=84&DT5=77&DT6=208&DT7=192&DT8=168&DT9=0&DT10=200&DT11=255&DT12=255&DT13=255&DT14=0&DT15=192&DT16=168&DT17=0&DT18=1 //TextFinderを使うとHTMLの切り出しは比較的容易これをSTRING型のままどう扱うか? if(Serial) Serial.print(F("CASE2:"));Serial.println(gLoopCount); if (HTTP_req.indexOf("SBM")>0){ //Serial.println(F("Found_SBM")); if(Serial) Serial.print(F("CASE3:"));Serial.println(gLoopCount); paramParse(HTTP_req); // すべてのデータを取得したので、EEPROMに保存します。 EEPROM.begin(512); WriteID(); //データがEEPROMに書き込まれている場合は、arduinoをリセットする必要があります。 //読込直す //int idcheck = EEPROM.read(256); int idcheck = EEPROM[256]; if(Serial) Serial.print(F("R_ID="));Serial.println(idcheck,HEX); if (idcheck == ID){ //idがIDと同じ値の場合、 //これは、このスケッチがシールドを設定するために使用されたことを意味します。 //EERPOMの値を読み取ってシールドを設定します。 ReadID(); } EEPROM.end(); //ハードウェアリセットボタンを使用する必要があります HTTP_req = ""; client.stop(); delay(1000); watchdog_reboot(0,0,1); break; }else if(HTTP_req.indexOf("setup1")>0){ if(Serial) Serial.println(F("setup1")); PrintSetUpPage(client); HTTP_req = ""; break; }else if(HTTP_req.indexOf("setup2")>0){ if(Serial) Serial.println(F("setup2")); PrintUtilPage(client); HTTP_req = ""; break; }else if(HTTP_req.indexOf("setup3")>0){ if(Serial) Serial.println(F("setup3")); //pageLoadUtilsJS(client); HTTP_req = ""; break; }else if(HTTP_req.indexOf("setup9")>0){ if(Serial) Serial.println(F("setup9")); pageIntroduction(client); HTTP_req = ""; break; }else{ if(Serial) Serial.print(F("CASE404-1")); pageIntroduction(client); HTTP_req = ""; break; } }else if(HTTP_req.indexOf("\n")>0) { if(Serial) Serial.println(F("CASE4")); pageIntroduction(client); HTTP_req = ""; break; }else if(HTTP_req.indexOf("/index")>0) { if(Serial) Serial.println(F("CASE5")); pageIntroduction(client); HTTP_req = ""; break; }else{ if(Serial) Serial.print(F("CASE404-2")); PrintResponse404(client); HTTP_req = ""; break; } HTTP_req = ""; break; // ループを抜ける } if(c == '\n'){ // 新しい行の始まり。 currentLineIsBlank = true; } else if(c != '\r' ){ // この行は空行ではなかった。 currentLineIsBlank = false; } } delay(1); client.stop(); } } //-------------- void setup() { Serial.begin(BAUDRATE); /* while (!Serial) { ; // シリアルポートが接続されるのを待ちます。シリアルモニタを寄贈するまで待機します。 } Serial.println("Start Ethernet Modbus TCP Example"); */ pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); Wire.setSDA(I2C0_SDA); //RP2040にはI2C0の組み合わせが6通りあるので設定しておくのが無難です。 Wire.setSCL(I2C0_SCL); Wire.begin(); //ENV IIのgroveコネクタ接続pin設定 sht30.begin(0x44); // sht30 I2C address: 0x44 or 0x45 qmp6988.init(0x70,&Wire); qmp6988.setpPowermode(QMP6988_NORMAL_MODE); qmp6988.setFilter(QMP6988_FILTERCOEFF_OFF); Serial.println(qmp6988.deviceCheck()); Serial.println(F("ENV Unit III test")); SPI.setSCK(SPI_SCK); SPI.setRX(SPI_RX); SPI.setTX(SPI_TX); SPI.setCS(SPI_CS); SPI.begin(); //Ethernet3で使用可能なAPI pinMode(SPI_CS, OUTPUT); //NIC_CS出力設定 Ethernet.setCsPin(SPI_CS); //NIC_CSアサイン Ethernet.setRstPin(NICReset); //NIC_RSTアサイン //NICリセット処理 pinMode(NICReset, OUTPUT); digitalWrite(NICReset, LOW); delay(10); //10msecパルス幅で初期化 digitalWrite(NICReset, HIGH); // start Ethernet and UDP LANSetup(); Ethernet.begin(mac, ip); delay(100); Serial.print(F("My IP address: "));Serial.println(Ethernet.localIP()); // print your local IP address: Udp.begin(NTPport); webServer.begin(); //最初にNTPサーバから時刻を取得する sprintf(buf32,"%d.%d.%d.%d",NTPip[0],NTPip[1],NTPip[2],NTPip[3]); sendNTPpacket(buf32); // NTPパケットをタイムサーバーに送信します delay(1000); gRTCOK = parseNTPpacket(); tm1637.init(); tm1637.set(BRIGHT_TYPICAL); //BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7; // //ModBusメモリ 初期化 for(int i = 0;i<MbCoilDataLen;i++) Mb.MbCoilData[i]=0x0000; //メモリ初期化 for(int i = 0;i<MbDiscreteDataLen;i++) Mb.MbDiscreteData[i]=0; //メモリ初期化 for(int i = 0;i<MbHoldDataLen;i++) Mb.MbHoldData[i]=0; //メモリ初期化 for(int i = 0;i<MbInputDataLen;i++) Mb.MbInputData[i]=0; //メモリ初期化 //Serial.println(F("ModBusメモリ 初期化")); //出力LED初期化 for (int i=0;i<DObits;i++){ Mb.SetBit(MB_FC_READ_COILS,i,false); //メモリマップはMb.MbData[0] pinMode(dOsPins[i],OUTPUT); digitalWrite(dOsPins[i], LOW); //LEDはHIGHで点灯 } //入力pin初期化 for (int i=0;i<DIbits;i++){ pinMode(dIsPins[i],INPUT); Mb.SetBit(MB_FC_READ_DISCRETE_INPUT,i,!digitalRead(dIsPins[i])); //bit メモリマップはMb.MbData[1] } for (int i=0;i<AIbits;i++){ Mb.MbInputData[i] = analogRead(aIsPins[i]); //U16 } preShow = Mb.GetBit(MB_FC_READ_COILS,2); for (int i = 0;i<16;i++){ buf32[i] = 0;} int VstrLen = strlen(VenderString); strcpy(buf32,VenderString); for (int i = 0;i<16;i++){ Mb.MbInputData[i+16] = char(buf32[2 * i]) * 256 + char(buf32[2 * i + 1]); } for (int i = 0;i<16;i++){ buf32[i] = 0;} strcpy(buf32,titleStr); for (int i = 0;i<16;i++){ Mb.MbInputData[i+32] = char(buf32[2 * i]) * 256 + char(buf32[2 * i + 1]); } char mainVer,minorVer,Rev; sscanf(SVirsion,"%1s.%1s.%1s",&mainVer,&minorVer,&Rev); Mb.MbInputData[48] = mainVer * 256 + minorVer; Mb.MbInputData[49] = Rev * 256; sscanf(FVirsion,"%1s.%1s.%1s",&mainVer,&minorVer,&Rev); Mb.MbInputData[50] = mainVer * 256 + minorVer; Mb.MbInputData[51] = Rev * 256; //マイクロ秒単位の間隔 if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 500, TimerHandler0)){ if(Serial){ Serial.print(F("Starting ITimer0 OK, millis() = ")); Serial.println(millis()); } }else{ if(Serial){ Serial.println(F("Can't set ITimer0. Select another freq. or timer")); } } watchdog_reboot(0,0,delay_ms); gPreTime = millis(); if(Serial) Serial.println(F("EndSetup")); } //------------------- void loop() { //1秒のループ WDT8秒 if (watchdog_caused_reboot()){ if(Serial) Serial.print("Rebooted by Watchdog!\n"); }else{ if(Serial) Serial.print("Clean boot\n"); } watchdog_update(); // listen for incoming clients GetDeviceInfo(); // start the Modbus TCP server gMBusConnect = Mb.MbsRun(); //SlaveServer Serial.print("gMBusConnect=");Serial.println(gMBusConnect); SetDeviceInfo(); client = webServer.available(); //HTTP要求確認 if(client) checkWebPage(client); client.stop(); gNowTime = millis(); gLoopTime = gNowTime - gPreTime; gPreTime = gNowTime; }
MgsModbus.h
/* * 2021/04/23 T.Wanibe Retouch * 20191029 T.Wanibe 保持メモリを個別に持たないとうまくゆかない * 個別に4つのメモリを保持するように変更 * 20191028 T.Wanibe 一般的なModbusデバイスとして構築出来るように * MgsModbusをレタッチすることにした。『ModbusPoll』とかLabVIEWの * Modbusライブラリを元に調査したところ、MgsModbusはスレーブサーバ * としてちゃんと機能するライブラリだと云う事が確認出来た。 * STM32duinoとしてコンパイル出来ないライブラリが殆ど。ライブラリ側で * Arduinoしか意識していない為と思われる。 * MgsModbusはシンプルであるが故にSTM32duinoでもコンパイルが通り実行 * 可能となる。 * が、アドレスマップがゼロベースであったり、4つのブロックの内Coilブロック * しかうまくアクセス出来ない点も確認出来た。 * 一般的なModbusデバイスとして認識出来るように大胆なデバッグを実施する * ことにした。 * まず、Localな扱いとした。inoと同じフォルダに配置すること。 * Slave機能のコードのみ残して(Masterのコードは削除) * * MgsModbus.h-Modbus TCPマスターおよびスレーブ用のArduinoライブラリ。 * V-0.1.1著作権(C)2013 Marco Gerritse * Arduino 1.0で作成およびテスト済み * * このライブラリは、 * MgsModbus.h-Modbus TCPマスターおよびスレーブ用のArduinoライブラリ。 * を原点としています。 * * テストに使用される外部ソフトウェア: * ★Modbus Poll * Modbus Poll x64 version 9.1.0 Build 1286, self-installing * ★LabVIEW Modbusライブラリ * NI Modbus Library v1.1.5.39 by National Instruments * ?? * このライブラリは、すべてのmodbusデータ(mbData []配列)に単一のメモリブロック * を使用します。 * 16ビットアクセスまたはアクセスビットを介して、いくつかのmodbus機能を介して同じ * データに到達できます。 MbDataの長さは少なくとも1でなければなりません。 * ●スレーブの場合、次のmodbus機能が実装されます:1、2、3、4、5、6、15、16 * ●内部および外部アドレスは1ベースに修正しています。 * ●EtherNetライブラリは『Ethernet3』を採用しています。W5500を安定して使用する為です。 */ #include "Arduino.h" #include <SPI.h> #include <Ethernet3.h> #ifndef MgsModbus_h #define MgsModbus_h #define MbCoilDataLen 2 // length of the MbCoilDataLen array (Equivalent16bit*2) #define MbDiscreteDataLen 2 // length of the MbDiscreteDataLen array(Equivalent16bit*2) #define MbHoldDataLen 64 // length of the MbHoldDataLen array #define MbInputDataLen 40 // length of the MbInputDataLen array #define MB_PORT 502 enum MB_FC { MB_FC_NONE = 0, MB_FC_READ_COILS = 1, MB_FC_READ_DISCRETE_INPUT = 2, MB_FC_READ_REGISTERS = 3, MB_FC_READ_INPUT_REGISTER = 4, MB_FC_WRITE_COIL = 5, MB_FC_WRITE_REGISTER = 6, MB_FC_WRITE_MULTIPLE_COILS = 15, MB_FC_WRITE_MULTIPLE_REGISTERS = 16 }; enum MB_XC { MB_XC_NONE = 0, MB_XC_Illegal_Function = 1, MB_XC_Illegal_Data_Address = 2, MB_XC_Illegal_Data_Value = 3, MB_XC_Slave_Device_Failure = 4, MB_XC_Acknowledge = 5, MB_XC_Slave_Device_Busy = 6, MB_XC_Negative_Acknowledge = 7, MB_XC_Memory_Parity_Error = 8, MB_XC_Gateway_Path_Unavailable = 10, MB_XC_Gateway_Target_Failed = 11 }; class MgsModbus { public: // general MgsModbus(); word MbCoilData[MbCoilDataLen]; // memory block that holds all the modbus user data word MbDiscreteData[MbDiscreteDataLen]; // memory block that holds all the modbus user data word MbHoldData[MbHoldDataLen]; // memory block that holds all the modbus user data word MbInputData[MbInputDataLen]; // memory block that holds all the modbus user data boolean GetBit(MB_FC fc,word Number); boolean SetBit(MB_FC fc,word Number,boolean Data); // returns true when the number is in the MbData range // modbus master //void Req(MB_FC FC, word Ref, word Count, word Pos); //void MbmRun(); //IPAddress remSlaveIP; // modbus slave bool MbsRun(); word GetDataLen(); private: // general MB_FC SetFC(int fc); // modbus master //uint8_t MbmByteArray[260]; // send and recieve buffer //MB_FC MbmFC; //int MbmCounter; //void MbmProcess(); //word MbmPos; //word MbmBitCount; //modbus slave uint8_t MbsByteArray[260]; // send and recieve buffer MB_FC MbsFC; MB_XC MbsXC; }; #endif
/* * 2021/04/23 T.Wanibe Retouch */ #include "MgsModbus.h" // EthernetServer MbServer(MB_PORT); EthernetClient MbmClient; #define DEBUG 1 MgsModbus::MgsModbus() { } char buf[32]; //****************** Recieve data for ModBusSlave **************** // 2021/3/5 接続が有った場合はtrueをない場合はfalseを返すように変更 bool MgsModbus::MbsRun() { bool flagConnected = false; MbsXC = MB_XC_NONE; //****************** Read from socket **************** EthernetClient client = MbServer.available(); flagConnected = client.available(); if(flagConnected){ digitalWrite(LED_BUILTIN, LOW); delay(1); int i = 0; while(client.available()){ MbsByteArray[i] = client.read(); i++; } MbsFC = SetFC(MbsByteArray[7]); //Byte 7 of request is FC #if DEBUG Serial.print(F("\nREQUEST:")); for(int j = 0;j<i;j++){ sprintf(buf,"%02x ",MbsByteArray[j]); Serial.print(buf); } Serial.println(F("")); digitalWrite(LED_BUILTIN, HIGH); #endif } int Start, WordDataLength, ByteDataLength, CoilDataLength, MessageLength; //SwitchCaseに変更しようとしたがコンパイルエラーが発生するので諦めた if(MbsFC == MB_FC_READ_COILS) { //****************** Read Coils (1) ********************** Start = word(MbsByteArray[8],MbsByteArray[9]); //StartAddress確認 CoilDataLength = word(MbsByteArray[10],MbsByteArray[11]); //データ長の確認 #if DEBUG sprintf(buf,"01StartADRS=%d Length=%d",Start,CoilDataLength); Serial.println(buf); #endif if((Start<0) || ((CoilDataLength + Start) > (MbCoilDataLen * 16))){ //Exception MB_XC_Illegal_Data_Address MbsXC = MB_XC_Illegal_Data_Address; MbsByteArray[7] = 0x10 + MbsByteArray[7]; MbsByteArray[8] = MbsXC; MessageLength = 9; }else{ ByteDataLength = CoilDataLength / 8; if(ByteDataLength * 8 < CoilDataLength) ByteDataLength++; CoilDataLength = ByteDataLength * 8; MbsByteArray[5] = ByteDataLength + 3; //Number of bytes after this one. MbsByteArray[8] = ByteDataLength; //Number of bytes after this one (or number of bytes of data). for(int i = 0; i < ByteDataLength ; i++){ MbsByteArray[9 + i] = 0; // To get all remaining not written bits zero for(int j = 0; j < 8; j++){ bitWrite(MbsByteArray[9 + i], j, GetBit(MB_FC_READ_COILS,Start + i * 8 + j)); } } MessageLength = ByteDataLength + 9; } // }else if(MbsFC == MB_FC_READ_DISCRETE_INPUT) { //****************** Read Coils (2) ********************** Start = word(MbsByteArray[8],MbsByteArray[9]); //StartAddress確認 CoilDataLength = word(MbsByteArray[10],MbsByteArray[11]); //データ長の確認 #if DEBUG sprintf(buf,"02StartADRS=%d Length=%d",Start,CoilDataLength); Serial.println(buf); #endif if((Start<0) || ((CoilDataLength + Start) > (MbDiscreteDataLen * 16))){ //Exception MB_XC_Illegal_Data_Address MbsXC = MB_XC_Illegal_Data_Address; MbsByteArray[7] = 0x10 + MbsByteArray[7]; MbsByteArray[8] = MbsXC; MessageLength = 9; }else{ ByteDataLength = CoilDataLength / 8; if(ByteDataLength * 8 < CoilDataLength) ByteDataLength++; CoilDataLength = ByteDataLength * 8; MbsByteArray[5] = ByteDataLength + 3; //Number of bytes after this one. MbsByteArray[8] = ByteDataLength; //Number of bytes after this one (or number of bytes of data). for(int i = 0; i < ByteDataLength ; i++){ MbsByteArray[9 + i] = 0; // To get all remaining not written bits zero for(int j = 0; j < 8; j++){ bitWrite(MbsByteArray[9 + i], j, GetBit(MB_FC_READ_DISCRETE_INPUT,Start + i * 8 + j)); } } MessageLength = ByteDataLength + 9; } // }else if(MbsFC == MB_FC_READ_REGISTERS) { //****************** Read Registers (3) ****************** Start = word(MbsByteArray[8],MbsByteArray[9]); WordDataLength = word(MbsByteArray[10],MbsByteArray[11]); if((Start<0) || ((WordDataLength + Start) > MbInputDataLen)){ //Exception MB_XC_Illegal_Data_Address MbsXC = MB_XC_Illegal_Data_Address; MbsByteArray[7] = 0x10 + MbsByteArray[7]; MbsByteArray[8] = MbsXC; MessageLength = 9; }else{ ByteDataLength = WordDataLength * 2; MbsByteArray[5] = ByteDataLength + 3; //Number of bytes after this one. MbsByteArray[8] = ByteDataLength; //Number of bytes after this one (or number of bytes of data). for(int i = 0; i < WordDataLength; i++){ MbsByteArray[ 9 + i * 2] = highByte(MbHoldData[Start + i]); MbsByteArray[10 + i * 2] = lowByte(MbHoldData[Start + i]); } MessageLength = ByteDataLength + 9; } // }else if(MbsFC == MB_FC_READ_INPUT_REGISTER) { //****************** Read Registers (4) ****************** Start = word(MbsByteArray[8],MbsByteArray[9]); WordDataLength = word(MbsByteArray[10],MbsByteArray[11]); if((Start<0) || ((WordDataLength + Start) > MbHoldDataLen)){ //Exception MB_XC_Illegal_Data_Address MbsXC = MB_XC_Illegal_Data_Address; MbsByteArray[7] = 0x10 + MbsByteArray[7]; MbsByteArray[8] = MbsXC; MessageLength = 9; }else{ ByteDataLength = WordDataLength * 2; MbsByteArray[5] = ByteDataLength + 3; //Number of bytes after this one. MbsByteArray[8] = ByteDataLength; //Number of bytes after this one (or number of bytes of data). for(int i = 0; i < WordDataLength; i++){ MbsByteArray[ 9 + i * 2] = highByte(MbInputData[Start + i]); MbsByteArray[10 + i * 2] = lowByte(MbInputData[Start + i]); } MessageLength = ByteDataLength + 9; } // }else if(MbsFC == MB_FC_WRITE_COIL) { //****************** Write Coil (5) ********************** Start = word(MbsByteArray[8],MbsByteArray[9]); #if DEBUG sprintf(buf,"05StartADRS=%d",Start); Serial.println(buf); #endif if((Start<0) || (Start > (MbCoilDataLen * 16))){ //Exception MB_XC_Illegal_Data_Address MbsXC = MB_XC_Illegal_Data_Address; MbsByteArray[7] = 0x10 + MbsByteArray[7]; MbsByteArray[8] = MbsXC; MessageLength = 9; }else{ if (word(MbsByteArray[10],MbsByteArray[11]) == 0xFF00){SetBit(MB_FC_WRITE_COIL,Start,true);} if (word(MbsByteArray[10],MbsByteArray[11]) == 0x0000){SetBit(MB_FC_WRITE_COIL,Start,false);} MbsByteArray[5] = 2; //Number of bytes after this one. MessageLength = 8; } // }else if(MbsFC == MB_FC_WRITE_REGISTER) { //****************** Write Register (6) ****************** Start = word(MbsByteArray[8],MbsByteArray[9]); if((Start<0) || (Start > MbHoldDataLen)){ //Exception MB_XC_Illegal_Data_Address MbsXC = MB_XC_Illegal_Data_Address; MbsByteArray[7] = 0x10 + MbsByteArray[7]; MbsByteArray[8] = MbsXC; MessageLength = 9; }else{ MbHoldData[Start] = word(MbsByteArray[10],MbsByteArray[11]); MbsByteArray[5] = 6; //Number of bytes after this one. MessageLength = 12; } // }else if(MbsFC == MB_FC_WRITE_MULTIPLE_COILS) { //****************** Write Multiple Coils (15) ********************** Start = word(MbsByteArray[8],MbsByteArray[9]); CoilDataLength = word(MbsByteArray[10],MbsByteArray[11]); //データ長の確認 if((Start<0) || ((CoilDataLength + Start) > (MbCoilDataLen * 16))){ //Exception MB_XC_Illegal_Data_Address MbsXC = MB_XC_Illegal_Data_Address; MbsByteArray[7] = 0x10 + MbsByteArray[7]; MbsByteArray[8] = MbsXC; MessageLength = 9; }else{ MbsByteArray[5] = 6; for(int i = 0; i < CoilDataLength; i++){ SetBit(MB_FC_WRITE_MULTIPLE_COILS,Start + i,bitRead(MbsByteArray[13 + (i/8)],i-((i/8)*8))); } MessageLength = 12; } // }else if(MbsFC == MB_FC_WRITE_MULTIPLE_REGISTERS) { //****************** Write Multiple Registers (16) ****************** Start = word(MbsByteArray[8],MbsByteArray[9]); WordDataLength = word(MbsByteArray[10],MbsByteArray[11]); if((Start<0) || ((WordDataLength + Start) > MbHoldDataLen)){ //Exception MB_XC_Illegal_Data_Address MbsXC = MB_XC_Illegal_Data_Address; MbsByteArray[7] = 0x10 + MbsByteArray[7]; MbsByteArray[8] = MbsXC; MessageLength = 9; }else{ ByteDataLength = WordDataLength * 2; MbsByteArray[5] = 6; for(int i = 0; i < WordDataLength; i++){ MbHoldData[Start + i] = word(MbsByteArray[ 13 + i * 2],MbsByteArray[14 + i * 2]); } MessageLength = 12; } }else{ //Exception 01:IllegalFunction MbsXC = MB_XC_Illegal_Function; ByteDataLength = 0; MbsByteArray[7] = 0x10 + MbsByteArray[7]; MbsByteArray[8] = MbsXC; MessageLength = 9 + ByteDataLength; } // MbsFC = MB_FC_NONE; client.write(MbsByteArray, MessageLength); #if DEBUG Serial.print(F("\nRESPONS:")); for(int i = 0;i<MessageLength;i++){ sprintf(buf,"%02x ",MbsByteArray[i]); Serial.print(buf); } Serial.println(F("")); #endif return flagConnected; } //****************** ?? ****************** 20210423 retouch MB_FC MgsModbus::SetFC(int fc){ MB_FC FC; switch(fc){ case 1: FC = MB_FC_READ_COILS; break; case 2: FC = MB_FC_READ_DISCRETE_INPUT; break; case 3: FC = MB_FC_READ_REGISTERS; break; case 4: FC = MB_FC_READ_INPUT_REGISTER; break; case 5: FC = MB_FC_WRITE_COIL; break; case 6: FC = MB_FC_WRITE_REGISTER; break; case 15: FC = MB_FC_WRITE_MULTIPLE_COILS; break; case 16: FC = MB_FC_WRITE_MULTIPLE_REGISTERS; break; default: FC = MB_FC_NONE; } return FC; } //--------------------- word MgsModbus::GetDataLen(){ int MbDataLen; switch(MbsFC){ case MB_FC_READ_COILS: case MB_FC_WRITE_COIL: case MB_FC_WRITE_MULTIPLE_COILS: MbDataLen = MbCoilDataLen; break; case MB_FC_READ_DISCRETE_INPUT: MbDataLen = MbDiscreteDataLen; break; case MB_FC_READ_REGISTERS: case MB_FC_WRITE_REGISTER: case MB_FC_WRITE_MULTIPLE_REGISTERS: MbDataLen = MbHoldDataLen; break; case MB_FC_READ_INPUT_REGISTER: MbDataLen = MbInputDataLen; break; default: MbDataLen = 0; } return MbDataLen; } //--------------------- boolean MgsModbus::GetBit(MB_FC fc,word Number){ boolean Tmp; int ArrayPos = Number / 16; int BitPos = Number - ArrayPos * 16; if(fc == MB_FC_READ_DISCRETE_INPUT){ Tmp = bitRead(MbDiscreteData[ArrayPos],BitPos); }else{ Tmp = bitRead(MbCoilData[ArrayPos],BitPos); } return Tmp; } //--------------------- boolean MgsModbus::SetBit(MB_FC fc,word Number,boolean Data){ boolean Overrun; int ArrayPos = Number / 16; int BitPos = Number - ArrayPos * 16; if(fc == MB_FC_READ_DISCRETE_INPUT){ Overrun = ArrayPos > MbDiscreteDataLen * 16; // check for data overrun if (!Overrun){ bitWrite(MbDiscreteData[ArrayPos],BitPos,Data); } }else{ Overrun = ArrayPos > MbCoilDataLen * 16; // check for data overrun if (!Overrun){ bitWrite(MbCoilData[ArrayPos],BitPos,Data); } } return Overrun; } |
オブジェクト自体はベクター殿のストレージをお借りしています。
https://www.vector.co.jp/vpack/browse/person/an051501.html 免責事項
本ソフトウエアは、あなたに対して何も保証しません。本ソフトウエアの関係者(他の利用者も含む)は、あなたに対して一切責任を負いません。
あなたが、本ソフトウエアを利用(コンパイル後の再利用など全てを含む)する場合は、自己責任で行う必要があります。本ソフトウエアの著作権はToolsBoxに帰属します。
本ソフトウエアをご利用の結果生じた損害について、ToolsBoxは一切責任を負いません。
ToolsBoxはコンテンツとして提供する全ての文章、画像等について、内容の合法性・正確性・安全性等、において最善の注意をし、作成していますが、保証するものではありません。
ToolsBoxはリンクをしている外部サイトについては、何ら保証しません。
ToolsBoxは事前の予告無く、本ソフトウエアの開発・提供を中止する可能性があります。
商標・登録商標
Microsoft、Windows、WindowsNTは米国Microsoft Corporationの米国およびその他の国における登録商標です。
Windows Vista、Windows XPは、米国Microsoft Corporation.の商品名称です。
LabVIEW、National Instruments、NI、ni.comはNational Instrumentsの登録商標です。
I2Cは、NXP Semiconductors社の登録商標です。
その他の企業名ならびに製品名は、それぞれの会社の商標もしくは登録商標です。
すべての商標および登録商標は、それぞれの所有者に帰属します。