EasyCAT LAB - EtherCAT master legacy example
Dependencies: SOEM SPI_STMPE610 SPI_TFT_ILI9341 TFT_fonts
The EasyCAT LAB is a complete educational and experimental EtherCAT® system, composed of one master and two slaves .
- It is provided as a kit by AB&T Tecnologie Informatiche, to allow everybody to have an educational EtherCAT® system up and running in a matter of minutes.
- This repository contains a demo software for the EtherCAT® master, that runs on the Nucleo STM32F767ZI board.
- It uses the SOEM (Simple Open EtherCAT® Master) library by rt-labs, that has been ported in the ecosystem by AB&T Tecnologie Informatiche.
- The slaves are based on the EasyCAT SHIELD and the Arduino UNO.
main.cpp
- Committer:
- info@bausano.net
- Date:
- 11 months ago
- Revision:
- 7:d71db73dcdd9
- Parent:
- 6:4b39b4dee215
- Child:
- 9:e43af5b19937
File content as of revision 7:d71db73dcdd9:
//******************************************************************************************** // * // This software is distributed as an example, "AS IS", in the hope that it could * // be useful, WITHOUT ANY WARRANTY of any kind, express or implied, included, but * // not limited, to the warranties of merchantability, fitness for a particular * // purpose, and non infringiment. In no event shall the authors be liable for any * // claim, damages or other liability, arising from, or in connection with this software. * // * //******************************************************************************************** // The AB&T EasyCAT LAB is a complete experimental EtherCAT® system, composed by // one master and two slaves. // The EasyCAT LAB software is provided free of charge and its pourpose is to allow // makers and educational institutes to experiment with the EtherCAT® protocol. // // The EasyCAT LAB is developed by "AB&T Tecnologie Informatiche" Via dell'About 2A Ivrea Italy. // www.bausano.net // www.easycatshield.com // // The EasyCAT LAB uses the SOEM library by rt:labs // https://rt-labs.com/products/soem-ethercat-master-stack/ // // EtherCAT® is a registered trademark and patented technology, licensed by Beckhoff Automation GmbH. // www.beckhoff.com // www.ethercat.org //****************************************************************************** // IMPORTANT!!! #define ADA_TFT // If your EasyCAT LAB uses the Adafruit TFT // you must uncomment this define //#define SEEED_TFT // If your EasyCAT LAB uses the Seeed Studio TFT // you must uncomment this define //#define PARA_TFT // If your EasyCAT LAB uses the parallel interface TFT // you must uncomment this define //****************************************************************************** #define ETH_TXBUFNB 16 #define ETH_RXBUFNB 16 #include "mbed.h" #ifndef __align #define __align MBED_ALIGN #endif #include "config.h" #include "SPI_TFT_ILI9341.h" #include "Arial12x12.h" #include "Arial24x23.h" #include "Arial28x28.h" #include "font_big.h" #include "soem_start.h" #include "SPI_STMPE610.h" #define CYCLE_TIME 1000 // master cycle time in uS // 1000 = 1mS #define SysMilliS() (uint32_t)Kernel::get_ms_count() UnbufferedSerial pc(USBTX,USBRX,115200); // set the debug serial line speed to 115200 //---- TFT with resistive touchscreen pins ------------------------------------- // the display used is the SeeedStudio 2.8 inch TFT v2.0 // http://wiki.seeedstudio.com/2.8inch_TFT_Touch_Shield_v2.0/ // // or the Adafruit 2.8" with resistive touchscreen // https://www.adafruit.com/product/1651 // // or the parallel interface ARD SHD 2,8TD #ifdef ADA_TFT // pins for the Adafruit TFT #define PIN_CS_TFT D10 // #define PIN_DC_TFT D9 // #define PIN_CS_TSC D8 // #define PIN_MOSI D11 // SPI #define PIN_MISO D12 // #define PIN_SCLK D13 // #endif #ifdef SEEED_TFT // pins for the SeeedStudio TFT #define PIN_CS_TFT D5 // #define PIN_DC_TFT D6 // #define PIN_MOSI D11 // SPI #define PIN_MISO D12 // #define PIN_SCLK D13 // #endif // #ifdef PARA_TFT // pins for the parallel interface TFT #define PIN_D0_TFT D8 // #define PIN_D1_TFT D9 // #define PIN_D2_TFT D2 // #define PIN_D3_TFT D3 // #define PIN_D4_TFT D4 // #define PIN_D5_TFT D5 // #define PIN_D6_TFT D6 // #define PIN_D7_TFT D7 // #define PIN_RD_TFT A0 // #define PIN_WR_TFT A1 // #define PIN_DC_TFT A2 // #define PIN_CS_TFT A3 // #define PIN_RES_TFT A4 // #endif #ifdef SEEED_TFT #define PIN_YP A3 // resistive touchscreen #define PIN_YM A1 // #define PIN_XM A2 // #define PIN_XP A0 // #else // #define PIN_XP A3 // #define PIN_YP A2 // #define PIN_XM D9 // #define PIN_YM D8 // #endif //---- touchscreen parameters -------------------------------------------------- #define TOUCH_SAMPLES 8 #define TOUCH_WINDOW 0.05 #define TOUCH_THRESHOLD 0.2 #define TOUCH_MAX_ROUNDS 16 #define TIME_TOUCH_RELEASED 300 #ifdef PARA_TFT #define TOUCH_X_OFFSET 0.075 #else #define TOUCH_X_OFFSET 0.118 #endif #define TOUCH_X_GAIN 402 #define TOUCH_Y_OFFSET 0.090 #define TOUCH_Y_GAIN 302 //---- side menu parameters ---------------------------------------------------- #define MENU_Y 0 #define MENU_WIDTH 83 #define MENU_HEIGHT 42 #define MENU_X (319-MENU_WIDTH) //---- slave parameters - LAB_1 EasyCAT with multifunction shield -------------- #define TERMO_X 55 #define TERMO_Y 185 #define ALARM_X 140 #define ALARM_Y 0 #define ALARM_WIDTH 83 #define ALARM_HEIGHT 42 #define TIME_BLINK 1000 #define TIME_AUTO_REP_START 1000 #define TIME_AUTO_REP_REPEAT 200 //---- slave parameters - LAB_2 EasyCAT with multifunction shield -------------- #define SEG_X 0 #define SEG_Y 0 #define SEG_WIDTH 42 #define SEG_HEIGHT 16 #define SEG_STEP 60 #define BUTTONS_X 38 #define BUTTONS_Y 80 #define BUTTONS_WIDTH 26 #define BUTTONS_R 3 #define BUTTONS_STEP 60 #define ANALOG_X 0 #define ANALOG_Y 120 #define ANALOG_WIDTH 222 #define ANALOG_HEIGHT 80 #define TIME_REP_SEG 300 #define TIME_POTENTIOMETER 100 //---- local functions --------------------------------------------------------- void DrawBanner(); void DrawSlaveFixedParts(); void DrawSideMenu (uint8_t Slave); void DrawTemperatureValue(float fValue); void DrawAlarmSettings(float fThreshold, bool OnOff, bool MinMax); void DrawOnlyThreshold(float fThreshold, bool OnOff, bool MinMax); void DrawAlarmStatus(bool Alarm); void DisplayInRect(int X, int Y, int X_off, int Y_off, char* Value, int BackColor, unsigned char* Font); void DrawButtonsValue(uint8_t Value); void DrawSegmentsValue(uint8_t Value); void DrawPotentiometerValue(uint16_t PotValue); float ReadAnalog(AnalogIn Ana); void Application(); void TouchScreenManagement(); bool TouchRead(uint16_t* X, uint16_t* Y); uint16_t TouchRead_X(); uint16_t TouchRead_Y(); bool TouchRead_Z(); //---- global variables -------------------------------------------------------- bool TouchWasReleased; bool FirstRound; //------------------------------------------------------------------------------ #ifdef PARA_TFT SPI_TFT_ILI9341 TFT(PIN_D0_TFT, PIN_D1_TFT, PIN_D2_TFT, PIN_D3_TFT, PIN_D4_TFT, PIN_D5_TFT, PIN_D6_TFT, PIN_D7_TFT, PIN_RD_TFT, PIN_WR_TFT, PIN_CS_TFT, PIN_DC_TFT, PIN_RES_TFT, "PARA"); #endif #ifdef ADA_TFT SPI_TFT_ILI9341 TFT(PIN_MOSI, PIN_MISO, PIN_SCLK, PIN_CS_TFT, NC, PIN_DC_TFT, 27000000, "ADA"); #endif #ifdef SEEED_TFT SPI_TFT_ILI9341 TFT(PIN_MOSI, PIN_MISO, PIN_SCLK, PIN_CS_TFT, NC, PIN_DC_TFT, 27000000, "SEEED"); #endif #ifdef ADA_TFT // touchscreen controller for the Adafruit TFT SPI_STMPE610 TSC(PIN_MOSI, PIN_MISO, PIN_SCLK, PIN_CS_TSC); #endif Ticker SampleTicker; Thread thread; DigitalOut Test_1(D1); // debug test points DigitalOut Test_2(D2); // DigitalOut Test_3(D3); // DigitalOut Test_4(D4); // //------------------------------------------------------------------------------ float fAlarmThreshold; bool AlarmOnOff; bool AlarmMinMax; uint16_t PotValue; uint16_t PrevPotValue; uint8_t Buttons; uint8_t PrevButtons; uint8_t Segments; uint8_t PrevSegments; int16_t Graph_x; uint8_t Outputs; uint8_t PrevOutputs; uint8_t Inputs; uint8_t PrevInputs; int8_t VisuSlave; //------------------------------------------------------------------------------ uint32_t Time; uint32_t TimeBlink; uint32_t TimeAutoRepeat; uint32_t TimeAutoRepRepeat; uint32_t TimePotentiometer; uint32_t TimeTouchReleased; bool Blink; uint8_t TouchAxes = 0; uint8_t Action = 0; uint16_t X; uint16_t Y; float fTemperature; float static fPrevTemperature; int ExpectWorkCounter; int WorkCounter; int WorkCounterSafe; bool NetworkError; bool NetworkErrorSafe; #define DATA_EXCHANGE_FLAG (1UL << 0) #define APPLICATION_FLAG (1UL << 1) EventFlags event_flags; Mutex IO_data; //---- data exchange thread ---------------------------------------------------- void ExchangeMaster() { while (true) { event_flags.wait_any(DATA_EXCHANGE_FLAG); // the thread waits for the synchronization flag //Test_1 = 1; IO_data.lock(); // Ethercat data exchange ec_send_processdata(); // WorkCounter = ec_receive_processdata(EC_TIMEOUTRET); if (WorkCounter != ExpectWorkCounter) NetworkError = true; else NetworkError = false; IO_data.unlock(); // event_flags.set(APPLICATION_FLAG); // synchronize the application //Test_1 = 0; } } //----- thicker generated sample time ------------------------------------------ void SampleIsr() // set the event that starts { // the data exchange event_flags.set(DATA_EXCHANGE_FLAG); // } // //****** initialization ******************************************************** int main() { int i; printf("Start \n"); Test_1 = 0; Test_2 = 0; Test_3 = 0; Test_4 = 0; #ifdef ADA_TFT TFT.set_orientation(1); #endif #ifdef SEEED_TFT TFT.set_orientation(3); #endif #ifdef PARA_TFT TFT.set_orientation(1); #endif TFT.background(Black); TFT.cls(); DrawBanner(); NetworkError = false; VisuSlave = LAB_1; AlarmOnOff = true; AlarmMinMax = false; fAlarmThreshold = 28.8; fTemperature = 0; TouchWasReleased = true; if (ec_init(NULL)) // init SOEM { printf("ec_init succeeded.\n"); printf("Scanning the network\n"); TFT.cls(); TFT.set_font((unsigned char*) Arial12x12); TFT.foreground(Green); TFT.locate(0, 0); TFT.printf("Scanning the network\n"); if (network_scanning()) { if (network_configuration()) // check network configuration { ec_config_map(&IOmap); // map the I/O MapLocalStructures(); printf("\nSlaves mapped, state to SAFE_OP.\n"); // wait for all slaves to reach SAFE_OP state ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE); printf("Request operational state for all slaves\n"); ec_slave[0].state = EC_STATE_OPERATIONAL; ec_send_processdata(); // send one valid process data to make outputs in slaves happy ExpectWorkCounter = ec_receive_processdata(EC_TIMEOUTRET); ec_writestate(0); // request OP state for all slaves // wait for all slaves to reach OP state ec_statecheck(0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE); if (ec_slave[0].state == EC_STATE_OPERATIONAL ) { printf("Operational state reached for all slaves.\n"); } else { printf("Not all slaves reached operational state.\n"); ec_readstate(); for(i = 1; i<=ec_slavecount ; i++) { if(ec_slave[i].state != EC_STATE_OPERATIONAL) { printf("Slave %d State=0x%04x StatusCode=0x%04x\n", i, ec_slave[i].state, ec_slave[i].ALstatuscode); } } TFT.foreground(Red); TFT.locate(0, 0); TFT.printf("Not all slaves reached operational state!"); while(1){} } DrawSlaveFixedParts(); thread.start(ExchangeMaster); thread.set_priority(osPriorityRealtime); SampleTicker.attach_us(&SampleIsr, CYCLE_TIME); Application(); } else { printf("Mismatch of network units!\n"); TFT.foreground(Red); TFT.locate(0, 0); TFT.printf("Mismatch of network units!"); while(1){} } } else { printf("No slaves found!\n"); TFT.foreground(Red); TFT.printf("No slaves found!"); while(1){} } } else { printf("Ethernet interface init failed!"); TFT.foreground(Red); TFT.locate(0, 0); TFT.printf("Ethernet interface init failed!"); while(1){} } } //****** user master application ********************************************** void Application() { while(1) { event_flags.wait_any(APPLICATION_FLAG); // the application waits for the synchronization flag //Test_2 = 1; IO_data.lock(); // copy the Ethercat data to a safe buffer memcpy(&IOmapSafe[0], &IOmap[0], IO_MAP_SIZE); // // if (NetworkError) // { // NetworkErrorSafe = NetworkError; // WorkCounterSafe = WorkCounter; // } // IO_data.unlock(); // if (NetworkErrorSafe) { TFT.rect(35,50, 285, 182, Red); TFT.fillrect(36,51, 284, 181, Black); TFT.foreground(Red); TFT.set_font((unsigned char*) Arial28x28); TFT.locate(58, 65); TFT.printf("Network error!"); printf("Network error!\n"); TFT.foreground(Magenta); TFT.set_font((unsigned char*) Arial12x12); TFT.locate(58, 106); if(WorkCounterSafe >= 0) { TFT.printf("Expected working counter %d", ExpectWorkCounter); TFT.locate(58, 118); TFT.printf("Actual working counter %d", WorkCounterSafe); printf("Expected working counter %d\n", ExpectWorkCounter); printf("Actual working counter %d\n", WorkCounterSafe); } else { TFT.printf("Timeout"); printf("Timeout\n"); } TFT.foreground(Green); TFT.locate(58, 142); TFT.printf("Please fix the error and"); TFT.locate(58, 154); TFT.printf("press the reset button"); printf("Please fix the error and press the reset button \n"); SampleTicker.detach(); // stop the sample interrupt while(1){} // and loop for ever } //----- slave 1 data management ------------ fTemperature = in_LAB_1->Temperature; // read the temperature if (fTemperature != fPrevTemperature) // check if the temperature has changed { fPrevTemperature = fTemperature; // remember the current temperature value if (VisuSlave == LAB_1) // if the HMI is setted to slave 1 { // visualize it DrawTemperatureValue (fTemperature); // } } bool AlarmStatus; if (AlarmOnOff) // check if we are in alarm { // if ((AlarmMinMax && (fTemperature < fAlarmThreshold)) || (!AlarmMinMax && (fTemperature > fAlarmThreshold))) { out_LAB_1->Alarm = 0x01; // signal the alarm condition to the slave AlarmStatus = true; // and to remember it } else { out_LAB_1->Alarm = 0x00; // signal the no alarm condition to the slave AlarmStatus = false; // and remember it } } else { out_LAB_1->Alarm = 0x00; // signal the no alarm condition to the slave AlarmStatus = false; // and remember it } if (VisuSlave == LAB_1) // if the HMI is set to slave 1 { // DrawAlarmStatus(AlarmStatus); // update the alarm status on the TFT } if (VisuSlave == LAB_1 && FirstRound) // if the HMI is set to slave 1 { // and it is the first time FirstRound = false; // DrawTemperatureValue (fTemperature); // draw the current temperature value DrawAlarmSettings(fAlarmThreshold, AlarmOnOff, AlarmMinMax); // draw the alarm settings } //----- end LAB_1 ------------------------ //----- slave 2 data management ------------ PotValue = in_LAB_2->Potentiometer; // read the potentiometer value if (VisuSlave == LAB_2) // if the HMI is setted to slave 2 { // Time = SysMilliS(); // and the visualization timer is elapsed if (Time-TimePotentiometer > TIME_POTENTIOMETER) // { // draw the potentiometer value TimePotentiometer = Time; // DrawPotentiometerValue(PotValue); // } // } Buttons = in_LAB_2->Buttons; // read the buttons status from the slave if (Buttons != PrevButtons) // check if the buttons value has changed { PrevButtons = Buttons; // remember the current buttons value if (VisuSlave == LAB_2) // if the HMI is setted to slave 2 { // DrawButtonsValue(Buttons); // draw the current buttons value } // } if (Segments != PrevSegments) // check if the segments value has changed { PrevSegments = Segments; // remember the current segments value if (VisuSlave == LAB_2) // if the HMI is setted to slave 2 { // DrawSegmentsValue(Segments); // draw the current segments value } // } if (VisuSlave == LAB_2 && FirstRound) // if the HMI is set to slave 2 { // and it is the first time FirstRound = false; // // DrawButtonsValue(Buttons); // draw the current buttons value DrawSegmentsValue(Segments); // draw the current segments value } out_LAB_2->Segments = Segments; // send the segments status to the slave //----- end LAB_2 ------------------------ TouchScreenManagement(); // check if the touchscreen is tapped // and handle it Time = SysMilliS(); // toggle the variable Blink every if ((Time-TimeBlink) > TIME_BLINK) // TIME_BLINK mS { // TimeBlink = Time; // we use it to blink a field on the TFT Blink = !Blink; // } IO_data.lock(); // copy the IO data from the safe area memcpy(&IOmap[0], &IOmapSafe[0], IO_MAP_SIZE); // to the EtherCAT buffer IO_data.unlock(); // //Test_2 = 0; } } //****************************************************************************** //******* general functions **************************************************** //------ touchscreen management ------------------------------------------------ void TouchScreenManagement() { uint16_t X; uint16_t Y; int i; #ifdef ADA_TFT // if the touchscreen has been tapped if (TSC.GetPoint(&X, &Y)) // #else // if (TouchRead(&X, &Y)) // #endif { TimeTouchReleased = SysMilliS(); if(TouchWasReleased) { // check if it is the side menu // decrement slave button if ((X>MENU_X) && (X>MENU_X+MENU_WIDTH/2) && (Y>MENU_HEIGHT) && (Y<MENU_HEIGHT*2)) { // VisuSlave--; if (VisuSlave == 0) // VisuSlave = SLAVE_NUM; // // the visualized slave has changed DrawSlaveFixedParts(); // draw the new slave fixed parts } // // check if it is the side menu // increment slave button if ((X>MENU_X) && (X<MENU_X+MENU_WIDTH/2) && (Y>MENU_HEIGHT) && (Y<MENU_HEIGHT*2)) { // VisuSlave++; if (VisuSlave > SLAVE_NUM) // VisuSlave = LAB_1; // // the visualized slave has changed DrawSlaveFixedParts(); // draw the new slave fixed parts } // } switch (VisuSlave) // check which slave is visualized on the TFT { case (LAB_1): //-------------- slave 1 ----------------------- if(TouchWasReleased) // first check if the touch was { // not tapped in the previous rounds TouchWasReleased = false; // because for the following fields TimeTouchReleased = SysMilliS(); // we don't want autorepeat TimeAutoRepeat = SysMilliS(); // reload the autorepeat time // handle taps on the ">" and "<" buttons if ((X>ALARM_X) && (X<ALARM_X+(ALARM_WIDTH/2)) && (Y>ALARM_Y+ALARM_HEIGHT) && (Y<ALARM_Y+ALARM_HEIGHT*2)) { // AlarmMinMax = true; // DrawAlarmSettings(fAlarmThreshold, AlarmOnOff, AlarmMinMax); } // if ((X>ALARM_X+(ALARM_WIDTH/2)) && (X<ALARM_X+(ALARM_WIDTH)) && (Y>ALARM_Y+ALARM_HEIGHT) && (Y<ALARM_Y+ALARM_HEIGHT*2)) // { // AlarmMinMax = false; // DrawAlarmSettings(fAlarmThreshold, AlarmOnOff, AlarmMinMax); } // handle taps on the "ON" and "OFF" buttons if ((X>ALARM_X) && (X<ALARM_X+(ALARM_WIDTH/2)) && (Y>ALARM_Y) && (Y<ALARM_Y+ALARM_HEIGHT)) { // AlarmOnOff = true; // DrawAlarmSettings(fAlarmThreshold, AlarmOnOff, AlarmMinMax); } // if ((X>ALARM_X+(ALARM_WIDTH/2)) && (X<ALARM_X+(ALARM_WIDTH)) && (Y>ALARM_Y) && (Y<ALARM_Y+ALARM_HEIGHT)) { // AlarmOnOff = false; // DrawAlarmSettings(fAlarmThreshold, AlarmOnOff, AlarmMinMax); } // handle taps on the "+" and "-" buttons // here we don't use the autorepeat to increment // or decrement the threshold by 0.1 if ((X>ALARM_X) && (X<ALARM_X+(ALARM_WIDTH/2)) && (Y>ALARM_Y+(ALARM_HEIGHT*3)) && (Y<ALARM_Y+(ALARM_HEIGHT*4))) { // fAlarmThreshold += 0.1; // DrawOnlyThreshold(fAlarmThreshold, AlarmOnOff, AlarmMinMax); } // if ((X>ALARM_X+(ALARM_WIDTH/2)) && (X<ALARM_X+(ALARM_WIDTH)) && (Y>ALARM_Y+(ALARM_HEIGHT*3)) && (Y<ALARM_Y+(ALARM_HEIGHT*4))) { // fAlarmThreshold -= 0.1; // DrawOnlyThreshold(fAlarmThreshold, AlarmOnOff, AlarmMinMax); } // } else // autorepeat management { // Time = SysMilliS(); // if (Time-TimeAutoRepeat > TIME_AUTO_REP_START) // { // if (Time-TimeAutoRepRepeat > TIME_AUTO_REP_REPEAT) { // TimeAutoRepRepeat = Time; // // handle taps on the "+" and "-" buttons // here we use the autorepeat to increment // or decrement the threshold by 1 if ((X>ALARM_X) && (X<ALARM_X+(ALARM_WIDTH/2)) && (Y>ALARM_Y+(ALARM_HEIGHT*3)) && (Y<ALARM_Y+(ALARM_HEIGHT*4))) { // fAlarmThreshold += 1; // DrawOnlyThreshold(fAlarmThreshold, AlarmOnOff, AlarmMinMax); } // if ((X>ALARM_X+(ALARM_WIDTH/2)) && (X<ALARM_X+(ALARM_WIDTH)) && (Y>ALARM_Y+(ALARM_HEIGHT*3)) && (Y<ALARM_Y+(ALARM_HEIGHT*4))) { // fAlarmThreshold -= 1; // DrawOnlyThreshold(fAlarmThreshold, AlarmOnOff, AlarmMinMax); } } } } break; //-------------- end slave 1 ------------------- case (LAB_2): //-------------- slave 2 ----------------------- if(TouchWasReleased) // first check if the touch was { // not tapped in the previous rounds TouchWasReleased = false; // because for the following fields TimeTouchReleased = SysMilliS(); // we don't want autorepeat uint8_t Mask = 0x08; // check if one of the segment is tapped // for (i=0; i<4; i++) // { // if ((X>SEG_X+(i*SEG_STEP)) && (X<SEG_X+(i*SEG_STEP)+SEG_WIDTH) && (Y>SEG_Y) && (Y<SEG_Y+SEG_HEIGHT*3)) { // Segments ^= Mask >> i; // } // } // } break; //----------------- end slave 2 ---------------- } } else { if ( SysMilliS()-TimeTouchReleased > TIME_TOUCH_RELEASED) // if the touchscreen was not { // tapped for enought time TouchWasReleased = true; // remember it } } } //----- draw the fixed part of the visualized slave ---------------------------- void DrawSlaveFixedParts() { int i; int Offset; TFT.cls(); // clear screen DrawSideMenu(VisuSlave); // draw the side menu switch (VisuSlave) // check which slave is visualized on the TFT { case (LAB_1): //-------------- slave 1 --------------------------- TFT.foreground(Yellow); // draw the thermometer TFT.circle(TERMO_X, TERMO_Y, 18, Yellow); // bowl TFT.fillcircle(TERMO_X, TERMO_Y, 17, Red); // // tube TFT.rect(TERMO_X-8, TERMO_Y-185, TERMO_X+8, TERMO_Y-18, Yellow); TFT.fillrect(TERMO_X-7, TERMO_Y-18, TERMO_X+7, TERMO_Y-16, Red); for (i=0; i<8; i++) // scale { // if (i <1) // Offset = 5; // else // Offset = 0; // // TFT.line(TERMO_X-8, (TERMO_Y-28)-(i *20), TERMO_X-18,(TERMO_Y-28)-(i*20), Yellow); TFT.locate(TERMO_X-48+Offset, TERMO_Y-(i*20)-32); // TFT.set_font((unsigned char*) Arial12x12); // TFT.printf("%3d",(i*10)-10); // } TFT.foreground(Green); // TFT.set_font((unsigned char*) Arial28x28); // TFT.locate(TERMO_X+25, TERMO_Y+28); // TFT.printf("C"); // // draw the alarm control panel // frame TFT.rect(ALARM_X, ALARM_Y, ALARM_X+ALARM_WIDTH, ALARM_Y+(ALARM_HEIGHT*4), Magenta); // for (i=0; i<3; i++) // { // TFT.line(ALARM_X, ALARM_Y+((i+1)*ALARM_HEIGHT) , ALARM_X+ALARM_WIDTH, ALARM_Y+((i+1)*ALARM_HEIGHT), Magenta); } // // TFT.line(ALARM_X+(ALARM_WIDTH/2), ALARM_Y, ALARM_X+(ALARM_WIDTH/2), ALARM_Y+(ALARM_HEIGHT*2), Magenta); TFT.line(ALARM_X+(ALARM_WIDTH/2), ALARM_Y+(ALARM_HEIGHT*3), ALARM_X+(ALARM_WIDTH/2), ALARM_Y+(ALARM_HEIGHT*4), Magenta); TFT.set_font((unsigned char*) Arial28x28); // "+" and "-" TFT.foreground(Green); // TFT.locate(ALARM_X+11, ALARM_Y+(ALARM_HEIGHT*3)+9); // TFT.printf("+"); // TFT.locate(ALARM_X+(ALARM_WIDTH/2)+14, ALARM_Y+(ALARM_HEIGHT*3)+9); TFT.printf("-"); // // alarm bar TFT.rect(ALARM_X-30, ALARM_Y, ALARM_X-25, ALARM_Y+168, Yellow); TFT.set_font((unsigned char*) Arial12x12); // draw "ALARM SETTINGS" TFT.foreground(Yellow); // TFT.locate(ALARM_X-35, ALARM_Y+14+(ALARM_HEIGHT*4)); // TFT.printf("ALARM SETTINGS"); // break; case (LAB_2): //-------------- slave 2 --------------------------- TFT.foreground(Yellow); for (i=0; i<4; i++) // draw the segments fixed parts { // TFT.rect(SEG_X+(i*SEG_STEP), SEG_Y, SEG_X+SEG_WIDTH+(i*SEG_STEP), SEG_Y+SEG_HEIGHT, Yellow); // TFT.set_font((unsigned char*) Arial12x12); // TFT.locate(SEG_X+44, SEG_Y+SEG_HEIGHT+12); // TFT.printf("MIDDLE SEGMENTS"); // } // for (i=0; i<3; i++) // draw the buttons fixed parts { // TFT.circle(BUTTONS_X+(i*BUTTONS_STEP), BUTTONS_Y, BUTTONS_R, Red); TFT.circle(BUTTONS_X+BUTTONS_WIDTH+(i*BUTTONS_STEP), BUTTONS_Y, BUTTONS_R, Red); // TFT.line(BUTTONS_X+(i*BUTTONS_STEP)-BUTTONS_R, BUTTONS_Y, BUTTONS_X+(i*BUTTONS_STEP)-BUTTONS_R-4, BUTTONS_Y, Red); TFT.line(BUTTONS_X+BUTTONS_WIDTH+(i*BUTTONS_STEP)+BUTTONS_R, BUTTONS_Y, BUTTONS_X+BUTTONS_WIDTH+(i*BUTTONS_STEP)+BUTTONS_R+4 , BUTTONS_Y, Red); } // // TFT.set_font((unsigned char*) Arial12x12); // TFT.locate(BUTTONS_X+38, BUTTONS_Y+12); // TFT.printf("BUTTONS"); // // draw the potentiometer window fixed parts TFT.rect(ANALOG_X, ANALOG_Y, ANALOG_X+ANALOG_WIDTH, ANALOG_Y+ANALOG_HEIGHT, Magenta); // TFT.set_font((unsigned char*) Arial12x12); // TFT.locate(ANALOG_X+35, ANALOG_Y+ANALOG_HEIGHT+12); // TFT.printf("POTENTIOMETER"); // Graph_x = 0; DrawSegmentsValue(Segments); // draw the segments status DrawButtonsValue (Buttons); // draw the buttons status DrawPotentiometerValue(PotValue); // draw the potentiometer value break; } FirstRound = true; } //---- draw the menu on the upper right part of the TFT ------------------------ void DrawSideMenu(uint8_t Slave) { // draw the side menu frame TFT.rect(MENU_X, MENU_Y, MENU_X+MENU_WIDTH, MENU_Y+MENU_HEIGHT*2, Green); TFT.line(MENU_X, MENU_HEIGHT, MENU_X+MENU_WIDTH, MENU_HEIGHT, Green); TFT.line(MENU_X+(MENU_WIDTH/2), MENU_Y+MENU_HEIGHT, MENU_X+(MENU_WIDTH/2), MENU_Y+(MENU_HEIGHT*2), Green); // draw the slave number TFT.fillrect(MENU_X+1, MENU_Y+1, MENU_X+MENU_WIDTH-1, MENU_Y+MENU_HEIGHT-1, Red); TFT.set_font((unsigned char*) Arial12x12); // TFT.foreground(Yellow); // TFT.locate(MENU_X+8 , MENU_Y+18); // TFT.background(Red); // TFT.printf("SLAVE %d", Slave); // TFT.background(Black); // TFT.set_font((unsigned char*) Arial28x28); // draw "+" and "-" TFT.foreground(Green); // TFT.locate (MENU_X+11, MENU_Y+MENU_HEIGHT+9); // TFT.printf("+"); // TFT.locate (MENU_X+(MENU_WIDTH/2)+14, MENU_Y+MENU_HEIGHT+9); // TFT.printf("-"); // TFT.set_font((unsigned char*) Arial12x12); // draw the slave name TFT.foreground(Red); // // TFT.locate(MENU_X, MENU_Y+(MENU_HEIGHT*2)+12); // TFT.printf("%.9s", ec_slave[Slave].name); // } //---- draw the starting banner ------------------------------------------------ void DrawBanner() { TFT.set_font((unsigned char*) Arial24x23); TFT.foreground(Red); TFT.locate(30, 50); TFT.printf("EasyCAT"); TFT.locate(30, 80); TFT.printf("SOEM MASTER"); TFT.set_font((unsigned char*) Arial12x12); TFT.foreground(Green); TFT.locate(30, 140); TFT.printf("www.bausano.net"); TFT.foreground(Green); TFT.locate(30, 160); TFT.printf("www.easycatshield.com"); TFT.locate(30, 180); TFT.printf("https://openethercatsociety.github.io/"); TFT.foreground(Red); TFT.locate(30, 220); #ifdef ADA_TFT TFT.printf("Adafruit TFT"); #endif #ifdef SEEED_TFT TFT.printf("Seeed Studio TFT"); #endif #ifdef PARA_TFT TFT.printf("Parallel TFT"); #endif } //****** slave 1 functions ***************************************************** //---- draw the temperature value both in analog and in digital form ------------ void DrawTemperatureValue(float fValue) { TFT.set_font((unsigned char*) Arial28x28); // digital visualization TFT.foreground(Green); // TFT.locate(TERMO_X-45, TERMO_Y+28); // TFT.printf("%4.1f", fValue); // if (fValue > 68) // limit the value for the fValue = 68; // analog visualization // if (fValue < -15) // fValue = -15; // int LenColonnina = fValue * 2; // analog visualization TFT.fillrect(TERMO_X-7, TERMO_Y-184, TERMO_X+7, TERMO_Y-18-LenColonnina-30-1, Black); TFT.fillrect(TERMO_X-7, TERMO_Y-18-LenColonnina-30, TERMO_X+7, TERMO_Y-18, Red); } //---- draw the current parameter of the temperature alarm --------------------- void DrawAlarmSettings(float fThreshold, bool OnOff, bool MinMax) { if (OnOff) // alarm on { // draw "ON" on red background // and "OFF"" on black background DisplayInRect (ALARM_X, ALARM_Y, 10, 14, "ON", Red, (unsigned char*)Arial12x12); DisplayInRect (ALARM_X+(ALARM_WIDTH/2), ALARM_Y, 10, 14, "OFF", Black, (unsigned char*)Arial12x12); } else // alarm off { // and "ON"" on black background // draw "OFF" on red background DisplayInRect (ALARM_X, ALARM_Y, 10, 14, "ON", Black, (unsigned char*)Arial12x12); DisplayInRect (ALARM_X+(ALARM_WIDTH/2), ALARM_Y, 10, 14, "OFF", Red, (unsigned char*)Arial12x12); } if (MinMax) // alarm when temperature < threshold { // draw ">" on red background // and ">"" on black background DisplayInRect (ALARM_X, ALARM_Y+ALARM_HEIGHT, 10, 9, ">", Red, (unsigned char*)Arial28x28); DisplayInRect (ALARM_X+(ALARM_WIDTH/2), ALARM_Y+ALARM_HEIGHT, 10, 9, "<", Black, (unsigned char*)Arial28x28); } else // alarm when temperature > threshold { // draw ">" on black background // and ">"" on red background DisplayInRect (ALARM_X, ALARM_Y+ALARM_HEIGHT, 10, 9, ">", Black, (unsigned char*)Arial28x28); DisplayInRect (ALARM_X+(ALARM_WIDTH/2), ALARM_Y+ALARM_HEIGHT, 10, 9, "<", Red, (unsigned char*)Arial28x28); } DrawOnlyThreshold(fThreshold, OnOff, MinMax); } //---- draw only the threshold setting ----------------------------------------- void DrawOnlyThreshold(float fThreshold, bool OnOff, bool MinMax) // this function is used to update { // only the threshold value not to // flicker the TFT, when "+" or // "-" are tapped TFT.foreground(Yellow); // draw the alarm threshold TFT.set_font((unsigned char*) Arial12x12); // in digital form TFT.locate(ALARM_X+26, ALARM_Y+14+(ALARM_HEIGHT*2)); // TFT.printf(" "); // TFT.locate(ALARM_X+26, ALARM_Y+14+(ALARM_HEIGHT*2)); // TFT.printf("%+3.1f", fThreshold); // if (fThreshold > 68) // limit the value for the fThreshold = 68; // analog visualization // if (fThreshold < -15) // fThreshold = -15; // int LenAlarmBar = fThreshold * 2; if (OnOff) // alarm on { // if (MinMax) // fill the threshold bar { // in accordance with the MinMax setting TFT.fillrect(ALARM_X-29, ALARM_Y+1, ALARM_X-26, ALARM_Y+167-LenAlarmBar-30, Green); TFT.fillrect(ALARM_X-29, ALARM_Y+167-LenAlarmBar-30, ALARM_X-26, ALARM_Y+167, Red); } // else // { // TFT.fillrect(ALARM_X-29, ALARM_Y+1, ALARM_X-26, ALARM_Y+167-LenAlarmBar-30, Red); TFT.fillrect(ALARM_X-29, ALARM_Y+167-LenAlarmBar-30, ALARM_X-26, ALARM_Y+167, Green); } // } else // alarm off { // // clear the threshold bar TFT.fillrect(ALARM_X-29, ALARM_Y+1, ALARM_X-26, ALARM_Y+167, Black); } // } //---- draw the blinking alarm signal ------------------------------------------ void DrawAlarmStatus(bool Alarm) { bool static PrevAlarmVisu; TFT.set_font((unsigned char*) Arial28x28); TFT.foreground(Red); TFT.locate(TERMO_X+90, TERMO_Y+28); if (Alarm && Blink && !PrevAlarmVisu) { TFT.printf("ALARM !"); PrevAlarmVisu = true; } else if ((!Alarm && PrevAlarmVisu) || (Alarm && !Blink && PrevAlarmVisu)) { TFT.printf(" "); PrevAlarmVisu = false; } } //----- draw a rectangle with text and colored background ---------------------- void DisplayInRect (int X, int Y, int X_off, int Y_off, char* Value, int BackColor, unsigned char* Font) { TFT.set_font(Font); TFT.foreground(Green); TFT.fillrect(X+1, Y+1, X+(MENU_WIDTH/2)-1, Y+MENU_HEIGHT-1, BackColor); TFT.locate(X+X_off , Y+Y_off); TFT.background(BackColor); TFT.printf("%s", Value ); TFT.background(Black); } //****** slave 2 functions ***************************************************** //------------------------------------------------------------------------------ void DrawButtonsValue (uint8_t Value) { uint8_t Slope; int i; for (i=0; i<3; i++) { if ((Value & 0x04) == 0x04) Slope = BUTTONS_R; else Slope = 16; TFT.fillrect(BUTTONS_X+(i*BUTTONS_STEP), BUTTONS_Y-16-1, BUTTONS_X+BUTTONS_WIDTH+(i*BUTTONS_STEP), BUTTONS_Y-BUTTONS_R-1, Black); TFT.line(BUTTONS_X+(i*BUTTONS_STEP), BUTTONS_Y-BUTTONS_R-1, BUTTONS_X+BUTTONS_WIDTH+(i*BUTTONS_STEP), BUTTONS_Y-Slope-1, Red); Value = Value << 1; } } //------------------------------------------------------------------------------ void DrawSegmentsValue(uint8_t Value) { int i; int Color; for (i=0; i<4; i++) { if ((Value & 0x08) == 0x08) Color = Red; else Color = Black; TFT.fillrect(SEG_X+(i*SEG_STEP)+1, SEG_Y+1, SEG_X+SEG_WIDTH+(i*SEG_STEP)-1, SEG_Y+SEG_HEIGHT-1, Color); Value = Value << 1; } } //---- draw the potentiometer value -------------------------------------------- void DrawPotentiometerValue (uint16_t PotValue) { if (PotValue != PrevPotValue) { PrevPotValue = PotValue; TFT.set_font((unsigned char*) Arial12x12); // TFT.foreground(Green); // TFT.locate(ANALOG_X+170, ANALOG_Y+ANALOG_HEIGHT+12); // TFT.printf("%4d", (int)PotValue); // } if (++Graph_x > ANALOG_WIDTH-3) { Graph_x = 0; } PotValue = PotValue / (1023/(ANALOG_HEIGHT-2)); TFT.pixel(ANALOG_X+Graph_x+1, ANALOG_Y+ANALOG_HEIGHT-PotValue-1, Green); int Overflow = (ANALOG_WIDTH-2) - (Graph_x+16); if (Overflow < 0) { TFT.fillrect(ANALOG_X+Graph_x+2, ANALOG_Y+1, ANALOG_X+Graph_x+16+Overflow, ANALOG_Y+ANALOG_HEIGHT-1, Black); TFT.fillrect(ANALOG_X+1, ANALOG_Y+1, ANALOG_X+1-Overflow, ANALOG_Y+ANALOG_HEIGHT-1, Black); } else { TFT.fillrect(ANALOG_X+Graph_x+2, ANALOG_Y+1, ANALOG_X+Graph_x+16, ANALOG_Y+ANALOG_HEIGHT-1, Black); } } //****** touchscreen functions ************************************************* //----- read touchscreen status ------------------------------------------------ bool TouchRead(uint16_t* X, uint16_t* Y) { bool Result = false; if (TouchRead_Z()) // if the touchscreen is tapped { // *X = TouchRead_X(); // read also the X and Y axis *Y = TouchRead_Y(); // wait_us (1000); if (TouchRead_Z()) // if the touchscreen is still tapped { // we assume that the result is good Result = true; // } } DigitalOut Ym_(PIN_YM); DigitalOut Xm_(PIN_XM); DigitalOut Xp_(PIN_XP); DigitalOut Yp_(PIN_YP); Xp_ = 1; Yp_ = 1; Xm_ = 1; Ym_ = 1; if (Result) //debug - draw the touched point on the TFT TFT.pixel (*X, *Y, White); // return Result; } //----- read touchscreen X axis ------------------------------------------------ uint16_t TouchRead_X() { float fValue; DigitalIn Ym(PIN_YM); // set the I/O Ym.mode(PullDown); // // DigitalOut Xp(PIN_XP); // Xp = 1; // // DigitalOut Xm(PIN_XM); // Xm = 0; // #ifdef PARA_TFT // reverse the X axis for the parallel TFT Xp = 0; // Xm = 1; // #endif // AnalogIn Yp(PIN_YP); // fValue = ReadAnalog(Yp); // read the axis fValue -= TOUCH_X_OFFSET; // rectify offsett and gain if (fValue <0 ) // fValue = 0; // // fValue *= TOUCH_X_GAIN; // //printf("X %f\n\n", fValue); // debug return (uint16_t)fValue; } //----- read touchscreen Y axis ------------------------------------------------ uint16_t TouchRead_Y() { float fValue; DigitalIn Xm(PIN_XM); // set the I/O Xm.mode(PullDown); // // DigitalOut Yp(PIN_YP); // Yp = 1; // // DigitalOut Ym(PIN_YM); // Ym = 0; // // AnalogIn Xp(PIN_XP); // fValue = ReadAnalog(Xp); // read the axis fValue -= TOUCH_Y_OFFSET; // rectify offset and gain if (fValue <0 ) // fValue = 0; // // fValue *= TOUCH_Y_GAIN; // //printf("Y %f\n", fValue); // debug return (uint16_t)fValue; } //----- read touchscreen Z axis ------------------------------------------------ bool TouchRead_Z() // read the Z axis to see if the { // touchscreen has been tapped float fValue = 0; bool Result; DigitalIn Ym(PIN_YM); // set the I/O Ym.mode(PullUp); // // AnalogIn Yp(PIN_YP); // // DigitalOut Xm(PIN_XM); // Xm = 0; // // DigitalOut Xp(PIN_XP); // Xp = 0; // for (int i = 0; i<TOUCH_SAMPLES; i++) // read the axis several times { // and average the result wait_us(10); // // fValue += Yp.read(); // } // fValue /= TOUCH_SAMPLES; // if (fValue < TOUCH_THRESHOLD) // compare the result with Result = true; // the threshold else // Result = false; // //printf("Z %f\n", fValue); // debug return Result; // } //----- read touchscreen X or Y axis with a window filter ---------------------- float ReadAnalog (AnalogIn AnaCh) // check that consecutive readings { // fall in the acceptance window float fArray[TOUCH_SAMPLES]; // float fResult; float fDiff; int Rounds = TOUCH_MAX_ROUNDS; // maximum number of attempts for (int i=0; i<TOUCH_SAMPLES; i++) { wait_us(10); fResult = AnaCh.read(); if (i>0) { fDiff = abs(fResult - fArray[i-1]); if (fDiff > TOUCH_WINDOW) i= -1; else fArray[i] = fResult; if (Rounds-- < 0) { fResult = 0; return fResult; } } else { fArray[i] = fResult; } } fResult =0; for (int i=0; i<TOUCH_SAMPLES; i++) { fResult += fArray[i]; } return fResult /= TOUCH_SAMPLES; }