Created
January 28, 2018 17:08
-
-
Save tuenhidiy/fb2bec2b09bbd5104f5c2f2cfaace35e to your computer and use it in GitHub Desktop.
NodeMCU control PLC through Wifi network
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*---------------------------------------------------------------------- | |
Thank to Davide Nardella | |
----------------------------------------------------------------------*/ | |
// Wifi -> #define S7WIFI | |
// Cable -> #define S7WIRED | |
#define S7WIFI | |
#include <SPI.h> | |
#include <Ethernet.h> | |
#ifdef S7WIFI | |
#include <ESP8266WiFi.h> | |
#endif | |
#include "Settimino.h" | |
#include <Wire.h> | |
// MPU6050 Slave Device Address | |
const uint8_t MPU6050SlaveAddress = 0x68; | |
// Select SDA and SCL pins for I2C communication | |
const uint8_t scl = D1; | |
const uint8_t sda = D2; | |
// sensitivity scale factor respective to full scale setting provided in datasheet | |
const uint16_t AccelScaleFactor = 16384; | |
const uint16_t GyroScaleFactor = 131; | |
// MPU6050 few configuration register addresses | |
const uint8_t MPU6050_REGISTER_SMPLRT_DIV = 0x19; | |
const uint8_t MPU6050_REGISTER_USER_CTRL = 0x6A; | |
const uint8_t MPU6050_REGISTER_PWR_MGMT_1 = 0x6B; | |
const uint8_t MPU6050_REGISTER_PWR_MGMT_2 = 0x6C; | |
const uint8_t MPU6050_REGISTER_CONFIG = 0x1A; | |
const uint8_t MPU6050_REGISTER_GYRO_CONFIG = 0x1B; | |
const uint8_t MPU6050_REGISTER_ACCEL_CONFIG = 0x1C; | |
const uint8_t MPU6050_REGISTER_FIFO_EN = 0x23; | |
const uint8_t MPU6050_REGISTER_INT_ENABLE = 0x38; | |
const uint8_t MPU6050_REGISTER_ACCEL_XOUT_H = 0x3B; | |
const uint8_t MPU6050_REGISTER_SIGNAL_PATH_RESET = 0x68; | |
int16_t AccelX, AccelY, AccelZ, Temperature, GyroX, GyroY, GyroZ; | |
#define DO_IT_SMALL | |
// Enter a MAC address and IP address for your controller below. | |
// The IP address will be dependent on your local network: | |
byte mac[] = { | |
0x90, 0xA2, 0xDA, 0x0F, 0x08, 0xE11 }; | |
IPAddress Local(192,168,0,70); // Local Address | |
IPAddress PLC(192,168,0,71); // PLC Address | |
// Following constants are needed if you are connecting via WIFI | |
// The ssid is the name of my WIFI network (the password obviously is wrong) | |
char ssid[] = "FPT-Telecom"; // Your network SSID (name) | |
char pass[] = "12345689"; // Your network password (if any) | |
IPAddress Gateway(192, 168, 0, 1); | |
IPAddress Subnet(255, 255, 255, 0); | |
int DBNum = 2; // This DB must be present in your PLC | |
byte Buffer[512]; | |
#ifdef S7WIFI | |
// S7Client will create a WiFiClient as TCP Client | |
S7Client Client(_S7WIFI); | |
#else | |
// S7Client will create an EthernetClient as TCP Client | |
S7Client Client(_S7WIRED); | |
#endif | |
unsigned long Elapsed; // To calc the execution time | |
//---------------------------------------------------------------------- | |
// Setup : Init Ethernet and Serial port | |
//---------------------------------------------------------------------- | |
void setup() { | |
// Open serial communications and wait for port to open: | |
Wire.begin(sda, scl); | |
MPU6050_Init(); | |
Serial.begin(9600); | |
while (!Serial) { | |
; // wait for serial port to connect. Needed for Leonardo only | |
} | |
#ifdef S7WIFI | |
//--------------------------------------------- ESP8266 Initialization | |
Serial.println(); | |
Serial.print("Connecting to "); | |
Serial.println(ssid); | |
WiFi.begin(ssid, pass); | |
WiFi.config(Local, Gateway, Subnet); | |
while (WiFi.status() != WL_CONNECTED) | |
{ | |
delay(500); | |
Serial.print("."); | |
} | |
Serial.println(""); | |
Serial.println("WiFi connected"); | |
Serial.print("Local IP address : "); | |
Serial.println(WiFi.localIP()); | |
#else | |
//--------------------------------Wired Ethernet Shield Initialization | |
// Start the Ethernet Library | |
Ethernet.begin(mac, Local); | |
// Setup Time, someone said me to leave 2000 because some | |
// rubbish compatible boards are a bit deaf. | |
delay(2000); | |
Serial.println(""); | |
Serial.println("Cable connected"); | |
Serial.print("Local IP address : "); | |
Serial.println(Ethernet.localIP()); | |
#endif | |
} | |
//---------------------------------------------------------------------- | |
// Connects to the PLC | |
//---------------------------------------------------------------------- | |
bool Connect() | |
{ | |
int Result=Client.ConnectTo(PLC, | |
0, // Rack (see the doc.) | |
2); // Slot (see the doc.) | |
Serial.print("Connecting to ");Serial.println(PLC); | |
if (Result==0) | |
{ | |
Serial.print("Connected ! PDU Length = ");Serial.println(Client.GetPDULength()); | |
} | |
else | |
Serial.println("Connection error"); | |
return Result==0; | |
} | |
//---------------------------------------------------------------------- | |
// Dumps a buffer (a very rough routine) | |
//---------------------------------------------------------------------- | |
void Dump(void *Buffer, int Length) | |
{ | |
int i, cnt=0; | |
pbyte buf; | |
if (Buffer!=NULL) | |
buf = pbyte(Buffer); | |
else | |
buf = pbyte(&PDU.DATA[0]); | |
Serial.print("[ Dumping ");Serial.print(Length); | |
Serial.println(" bytes ]=========================="); | |
for (i=0; i<Length; i++) | |
{ | |
cnt++; | |
if (buf[i]<0x10) | |
Serial.print("0"); | |
Serial.print(buf[i], HEX); | |
Serial.print(" "); | |
if (cnt==16) | |
{ | |
cnt=0; | |
Serial.println(); | |
} | |
} | |
Serial.println("==============================================="); | |
} | |
//---------------------------------------------------------------------- | |
// Prints the Error number | |
//---------------------------------------------------------------------- | |
void CheckError(int ErrNo) | |
{ | |
Serial.print("Error No. 0x"); | |
Serial.println(ErrNo, HEX); | |
// Checks if it's a Severe Error => we need to disconnect | |
if (ErrNo & 0x00FF) | |
{ | |
Serial.println("SEVERE ERROR, disconnecting."); | |
Client.Disconnect(); | |
} | |
} | |
//---------------------------------------------------------------------- | |
// Profiling routines | |
//---------------------------------------------------------------------- | |
void MarkTime() | |
{ | |
Elapsed=millis(); | |
} | |
//---------------------------------------------------------------------- | |
void ShowTime() | |
{ | |
// Calcs the time | |
Elapsed=millis()-Elapsed; | |
Serial.print("Job time (ms) : "); | |
Serial.println(Elapsed); | |
} | |
//---------------------------------------------------------------------- | |
// Main Loop | |
//---------------------------------------------------------------------- | |
void loop() | |
{ | |
int Size, Result; | |
void *Target; | |
double Ax, Ay, Az, T, Gx, Gy, Gz; | |
double roll = 0.00, pitch = 0.00; //Roll & Pitch are the angles which rotate by the axis X and y | |
Read_RawValue(MPU6050SlaveAddress, MPU6050_REGISTER_ACCEL_XOUT_H); | |
//divide each with their sensitivity scale factor | |
Ax = (double)AccelX/AccelScaleFactor; | |
Ay = (double)AccelY/AccelScaleFactor; | |
Az = (double)AccelZ/AccelScaleFactor; | |
T = (double)Temperature/340+36.53; //temperature formula | |
Gx = (double)GyroX/GyroScaleFactor; | |
Gy = (double)GyroY/GyroScaleFactor; | |
Gz = (double)GyroZ/GyroScaleFactor; | |
roll = atan2(Ay , Az) * 57.3; | |
pitch = atan2((- Ax) , sqrt(Ay * Ay + Az * Az)) * 57.3; | |
//Serial.print(" Roll: "); Serial.println(roll); | |
//Serial.print(" Pitch: "); Serial.println(pitch); | |
//Serial.print(" Az: "); Serial.print(Az); | |
//Serial.print(" T: "); Serial.print(T); | |
//Serial.print(" Gx: "); Serial.print(Gx); | |
//Serial.print(" Gy: "); Serial.print(Gy); | |
//Serial.print(" Gz: "); Serial.println(Gz); | |
delay(100); | |
//---------------------------------------------------------------------- | |
// Programm_for as to variable Int | |
//---------------------------------------------------------------------- | |
int write_data = (int)(map(roll, -180, 180, -1000, 1000)); //// Write roll to PLC | |
//Serial.print(" Write data prepare: ");Serial.println(write_data); | |
//delay(500); | |
//---------------------------------------------------------------------- | |
// Start connessione DB | |
//---------------------------------------------------------------------- | |
#ifdef DO_IT_SMALL | |
Size=2; | |
Target = NULL; // Uses the internal Buffer (PDU.DATA[]) | |
#else | |
Size=1024; | |
Target = &Buffer; // Uses a larger buffer | |
#endif | |
// Connection | |
while (!Client.Connected) | |
{ | |
if (!Connect()) | |
delay(500); | |
} | |
//---------------------------------------------------------------------- | |
// Little_Endian & Big_Endian convertion | |
//---------------------------------------------------------------------- | |
int write_data_var1 = write_data; | |
byte* bytes = (byte*)& write_data_var1; | |
//---------------------------------------------------------------------- | |
// Word/Int Correction | |
//---------------------------------------------------------------------- | |
void Correction(void *bytes); | |
{ | |
byte *pointerbyte; | |
byte temp; | |
pointerbyte=(byte*)(bytes); | |
// Swap byte | |
temp=*(pointerbyte+1); | |
*(pointerbyte+1) = *pointerbyte; | |
*pointerbyte = temp; | |
} | |
//---------------------------------------------------------------------- | |
// Serial check | |
//---------------------------------------------------------------------- | |
Serial.print("Write ");Serial.print(Size);Serial.println(" bytes from DB1.DBB0"); | |
// Put the current tick | |
MarkTime(); | |
Result=Client.WriteArea(S7AreaDB, // We are requesting DB access | |
1, // DB Number = 1 | |
0, // Start from byte N.0 | |
Size, // We need "Size" bytes | |
bytes); // Put them into our target (Buffer or PDU) | |
if (Result==0) | |
{ | |
ShowTime(); | |
Dump(Target, Size); | |
} | |
else | |
CheckError(Result); | |
delay(500); | |
} | |
void I2C_Write(uint8_t deviceAddress, uint8_t regAddress, uint8_t data){ | |
Wire.beginTransmission(deviceAddress); | |
Wire.write(regAddress); | |
Wire.write(data); | |
Wire.endTransmission(); | |
} | |
// read all 14 register | |
void Read_RawValue(uint8_t deviceAddress, uint8_t regAddress){ | |
Wire.beginTransmission(deviceAddress); | |
Wire.write(regAddress); | |
Wire.endTransmission(); | |
Wire.requestFrom(deviceAddress, (uint8_t)14); | |
AccelX = (((int16_t)Wire.read()<<8) | Wire.read()); | |
AccelY = (((int16_t)Wire.read()<<8) | Wire.read()); | |
AccelZ = (((int16_t)Wire.read()<<8) | Wire.read()); | |
Temperature = (((int16_t)Wire.read()<<8) | Wire.read()); | |
GyroX = (((int16_t)Wire.read()<<8) | Wire.read()); | |
GyroY = (((int16_t)Wire.read()<<8) | Wire.read()); | |
GyroZ = (((int16_t)Wire.read()<<8) | Wire.read()); | |
} | |
//configure MPU6050 | |
void MPU6050_Init(){ | |
delay(150); | |
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_SMPLRT_DIV, 0x07); | |
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_PWR_MGMT_1, 0x01); | |
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_PWR_MGMT_2, 0x00); | |
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_CONFIG, 0x00); | |
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_GYRO_CONFIG, 0x00);//set +/-250 degree/second full scale | |
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_ACCEL_CONFIG, 0x00);// set +/- 2g full scale | |
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_FIFO_EN, 0x00); | |
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_INT_ENABLE, 0x01); | |
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_SIGNAL_PATH_RESET, 0x00); | |
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_USER_CTRL, 0x00); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
nice, can you make code for LSIS plc?