From 6bb5bfe5ba209d464a4e67805ed169ba84b3800f Mon Sep 17 00:00:00 2001 From: Eggert Jung Date: Wed, 26 Jan 2022 19:48:06 +0100 Subject: [PATCH] make changes for anderen anlagenteil --- Makefile | 2 +- avrIOhelper/io-helper.h | 79 ++++-- main.c | 642 +++++++++++++++++++++++------------------------- modbus.c | 436 ++++++++++++++++++++++++++++++++ modbus.h | 421 +++++++++++++++++++++++++++++++ modbus_master.c | 55 +++++ modbus_master.h | 12 + mqtt.c | 4 +- 8 files changed, 1294 insertions(+), 357 deletions(-) create mode 100644 modbus.c create mode 100644 modbus.h create mode 100644 modbus_master.c create mode 100644 modbus_master.h diff --git a/Makefile b/Makefile index c666306..dbd02ec 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ fuse: avrdude -p $(PROGC) -c $(TOOL) -U lfuse:w:0xE8:m -U hfuse:w:0xD1:m load: $(BUILDDIR)/$(TARGET).hex - avrdude -p $(PROGC) -c $(TOOL) -U flash:w:$(BUILDDIR)/$(TARGET).hex -v -B 4MHz + avrdude -p $(PROGC) -c $(TOOL) -U flash:w:$(BUILDDIR)/$(TARGET).hex -v -B 1MHz program: clean load diff --git a/avrIOhelper/io-helper.h b/avrIOhelper/io-helper.h index ae09ed3..5f423f5 100644 --- a/avrIOhelper/io-helper.h +++ b/avrIOhelper/io-helper.h @@ -14,7 +14,7 @@ #define TOGGLE 3 -#define NUMBER_OF_INPUT_BYTES 2 +#define NUMBER_OF_INPUT_BYTES 4 extern volatile uint8_t outStates[NUMBER_OF_INPUT_BYTES]; extern volatile uint8_t outStatesBlinking[NUMBER_OF_INPUT_BYTES]; @@ -54,16 +54,43 @@ void ioHelperEdgeDetector(void); #define BitPB5 9 //D9 #define BitPB6 10 //D10 #define BitPB7 11 //D11 +#define BitPL7 12 //D12 +#define BitPL6 13 //D13 +#define BitPL5 14 //D14 +#define BitPL4 15 //D15 -#define LED_ROT_NOTAUS_SCHRANK BitPG5 -#define LED_GRN_NOTAUS_SCHRANK BitPE3 -#define LED_ROT_NOTAUS_ANLAGE BitPH3 -#define LED_GRN_NOTAUS_ANLAGE BitPH4 -#define LED_PLC_OK BitPB5 -#define LED_BUS_OK BitPB6 -#define LED_ZUMBACH BitPH5 -#define LED_LUEFTER BitPH6 -#define SCHUETZ_ZUMBACH BitPE5 +#define BitPL3 16 //D16 +#define BitPL2 17 //D17 +#define BitPL1 18 //D18 +#define BitPL0 19 //D19 +#define BitPD4 20 //D20 +#define BitPD5 21 //D21 +#define BitPD6 22 //D22 +#define BitPJ4 23 //D23 + +#define BitPC6 24 //R9 + +// Notäuse +#define LED_ROT_NOTAUS_SCHRANK BitPB4 +#define LED_GRN_NOTAUS_SCHRANK BitPJ4 + +#define LED_ROT_NOTAUS_ANLAGE BitPG5 +#define LED_GRN_NOTAUS_ANLAGE BitPD6 + +#define LED_ROT_NOTAUS_DISPLAY BitPL3 +#define LED_GRN_NOTAUS_DISPLAY BitPD5 + +// Status Lampen Schrank +#define LED_PLC_OK BitPL4 +#define LED_BUS_OK BitPL2 +#define LED_FEHLER BitPL5 + +// Ampel +#define AMPEL_ROT BitPL1 +#define AMPEL_GELB BitPL0 +#define AMPEL_GRUEN BitPD4 + +#define RELAY_INTERLOCK BitPC6 //Inputs @@ -79,18 +106,24 @@ void ioHelperEdgeDetector(void); #define BitPinK0 8 //A8 #define BitPinK1 9 //A9 -#define BitPinD3 10 //INO -#define BitPinD2 11 //IN1 - -#define BTN_ZUMBACH_EIN BitPinF2 -#define BTN_ZUMBACH_AUS BitPinF3 -#define BTN_LUEFTER_EIN BitPinF4 -#define BTN_LUEFTER_AUS BitPinF5 -#define BTN_LUEFTER_PLUS BitPinF6 -#define BTN_LUEFTER_MINUS BitPinF7 -#define BTN_ANLAGE_EIN BitPinD3 -#define IN_ANLAGE_EIN BitPinD2 -#define IN_NOTAUS_ANLAGE BitPinF0 -#define IN_NOTAUS_SCHRANK BitPinF1 +#define BitPinK2 10 //A10 +#define BitPinK3 11 //A11 +#define BitPinK4 12 //A12 +#define BitPinK5 13 //A13 +#define BitPinK6 14 //A14 +#define BitPinK7 15 //A15 + +#define BitPinD7 16 //I16 +#define BitPinG2 17 //I17 +#define BitPinG1 18 //I18 +#define BitPinD3 19 //INO +#define BitPinD2 20 //IN1 + +//#define BTN_ANLAGE_EIN BitPinD3 +//#define IN_ANLAGE_EIN BitPinD2 +#define IN_ANLAGE_EIN BitPinF3 +#define IN_NOTAUS_ANLAGE BitPinD3 +#define IN_NOTAUS_SCHRANK BitPinD2 +#define IN_NOTAUS_DISPLAY BitPinG1 #endif diff --git a/main.c b/main.c index d3bd9e5..371202d 100644 --- a/main.c +++ b/main.c @@ -1,331 +1,311 @@ -#include -#include -#include // WatchDog -#include - -#include "Ethernet/socket.h" -#include "Ethernet/wizchip_conf.h" - -#include "Internet/MQTT/mqtt_interface.h" -#include "Internet/MQTT/MQTTClient.h" - -#include "avrIOhelper/io-helper.h" -#include "millis.h" -#include "uart.h" -#include "spi.h" -#include "mqtt.h" - -#include "util/delay.h" - -#define PLC_MQTT_ENABLED 0 - -Client mqtt_client; - -//***********Prologue for fast WDT disable & and save reason of reset/power-up: BEGIN -uint8_t mcucsr_mirror __attribute__ ((section (".noinit"))); - -// This is for fast WDT disable & and save reason of reset/power-up -void get_mcusr(void) \ - __attribute__((naked)) \ - __attribute__((section(".init3"))); -void get_mcusr(void) -{ - mcucsr_mirror = MCUSR; - MCUSR = 0; - wdt_disable(); -} -//***********Prologue for fast WDT disable & and save reason of reset/power-up: END - - -//FUNC headers -static void avr_init(void); -void timer0_init(void); -void print_network_information(void); - -void IO_LIBRARY_Init(void) { - uint8_t bufSize[] = {2, 2, 2, 2, 2, 2, 2, 2}; - - reg_wizchip_cs_cbfunc(spi_select, spi_deselect); - reg_wizchip_spi_cbfunc(spi_read, spi_write); - //reg_wizchip_spiburst_cbfunc(spi_rb_burst, spi_wb_burst); - - wizchip_init(bufSize, bufSize); - wizchip_setnetinfo(&netInfo); - //wizchip_setinterruptmask(IK_SOCK_0); -} - -#define STEP_SIZE 5 -#define TOP_VALUE 40 -void do_luefter(){ - static uint8_t fan_value = TOP_VALUE*0.8; - static uint8_t fan_state = 0; - - if(!read_Input(IN_ANLAGE_EIN, LEVEL)){ - fan_state = 0; - ioHelperSetBit(outStates, LED_LUEFTER, 0); - } - else{ - if (read_Input(BTN_LUEFTER_EIN, RISING)) { -#if PLC_MQTT_ENABLED - mqtt_pub(&mqtt_client, "/Filamentanlage/04_Messmodul/state/Luefter", "ein", 3); -#endif - OCR3B = TOP_VALUE/2; - fan_state = 1; - ioHelperSetBit(outStates, LED_LUEFTER, 1); - } - - if (read_Input(BTN_LUEFTER_AUS, RISING)) { -#if PLC_MQTT_ENABLED - mqtt_pub(&mqtt_client, "/Filamentanlage/04_Messmodul/state/Luefter", "aus", 3); -#endif - fan_state = 0; - ioHelperSetBit(outStates, LED_LUEFTER, 0); - } - - if (read_Input(BTN_LUEFTER_PLUS, RISING) && (fan_value+STEP_SIZE <= TOP_VALUE)) { - fan_value += STEP_SIZE; -#if PLC_MQTT_ENABLED - char _msg[3]; - sprintf(_msg, "%d", fan_value); - mqtt_pub(&mqtt_client, "/Filamentanlage/04_Messmodul/state/Speed", _msg, 3); -#endif - printf("luefter %d\n\r", fan_value); - } - - if (read_Input(BTN_LUEFTER_MINUS, RISING) && (fan_value-STEP_SIZE >= STEP_SIZE)) { - fan_value -= STEP_SIZE; - printf("luefter %d\n\r", fan_value); - } - } - - if(fan_state) - OCR3B = fan_value; - else - OCR3B = 0; -} - -void do_zumbach(){ - - if (read_Input(BTN_ZUMBACH_EIN, RISING) && read_Input(IN_ANLAGE_EIN, LEVEL)) { - ioHelperSetBit(outStates, SCHUETZ_ZUMBACH, 1); - ioHelperSetBit(outStates, LED_ZUMBACH, 1); -#if PLC_MQTT_ENABLED - mqtt_pub(&mqtt_client, "/Filamentanlage/04_Messmodul/state/Zumbach", "ein", 3); -#endif - } - - if (read_Input(BTN_ZUMBACH_AUS, RISING) || read_Input(IN_ANLAGE_EIN, FALLING)) { - ioHelperSetBit(outStates, SCHUETZ_ZUMBACH, 0); - ioHelperSetBit(outStates, LED_ZUMBACH, 0); -#if PLC_MQTT_ENABLED - mqtt_pub(&mqtt_client, "/Filamentanlage/04_Messmodul/state/Zumbach", "aus", 3); -#endif - } -} - -void do_notaus(){ - if(read_Input(IN_NOTAUS_ANLAGE, LEVEL) || read_Input(IN_NOTAUS_SCHRANK, LEVEL)){ // NOTAUS - set_Output(LED_GRN_NOTAUS_SCHRANK, OFF); // disable green lamps - set_Output(LED_GRN_NOTAUS_ANLAGE, OFF); - } - - if(read_Input(IN_NOTAUS_ANLAGE, LEVEL) && read_Input(IN_NOTAUS_SCHRANK, LEVEL)){ // both activated - set_Output(LED_ROT_NOTAUS_ANLAGE, BLINK); - set_Output(LED_ROT_NOTAUS_SCHRANK, BLINK); - } - else if(read_Input(IN_NOTAUS_ANLAGE, LEVEL)){ // top one activated - set_Output(LED_ROT_NOTAUS_ANLAGE, BLINK); - set_Output(LED_ROT_NOTAUS_SCHRANK, ON); - } - else if(read_Input(IN_NOTAUS_SCHRANK, LEVEL)){ // bottom one activated - set_Output(LED_ROT_NOTAUS_SCHRANK, BLINK); - set_Output(LED_ROT_NOTAUS_ANLAGE, ON); - } - else{ // none activated - set_Output(LED_ROT_NOTAUS_SCHRANK, OFF); - set_Output(LED_ROT_NOTAUS_ANLAGE, OFF); - if(read_Input(IN_ANLAGE_EIN, LEVEL)){ - set_Output(LED_GRN_NOTAUS_ANLAGE, ON); - set_Output(LED_GRN_NOTAUS_SCHRANK, ON); - } - else{ - set_Output(LED_GRN_NOTAUS_ANLAGE, BLINK); - set_Output(LED_GRN_NOTAUS_SCHRANK, BLINK); - } - } -} - -int main() -{ - // INIT MCU - avr_init(); - spi_init(); //SPI Master, MODE0, 4Mhz(DIV4), CS_PB.3=HIGH - suitable for WIZNET 5x00(1/2/5) - //spi_speed_tst(); / Here on SPI pins: MOSI 400Khz freq out, on SCLK 3.2MhzOUT (Witk SPI CLK 4Mhz) - - ioHelperInitBuffer(); - ioHelperIoConf(); - - //Wizchip WIZ5500 Ethernet initialize - IO_LIBRARY_Init(); //After that ping must working - print_network_information(); - -#if PLC_MQTT_ENABLED - //****************MQTT client initialize - //Find MQTT broker and connect with it - uint8_t mqtt_buf[100]; - int32_t mqtt_rc = 0; - Network mqtt_network; - mqtt_network.my_socket = SOCK_MQTT; - - printf(">>Trying connect to MQTT broker: %d.%d.%d.%d ..\r\n", MQTT_targetIP[0], MQTT_targetIP[1], MQTT_targetIP[2], MQTT_targetIP[3]); - NewNetwork(&mqtt_network); - ConnectNetwork(&mqtt_network, MQTT_targetIP, 1883); - MQTTClient(&mqtt_client, &mqtt_network, 1000, mqtt_buf, 100, mqtt_readBuffer, MQTT_BUFFER_SIZE); - - //Connection to MQTT broker - MQTTPacket_connectData data = MQTTPacket_connectData_initializer; - data.willFlag = 0; - data.MQTTVersion = 4;//3; - data.clientID.cstring = (char*)"controllino"; - data.username.cstring = (char*)"Messmodul"; - data.password.cstring = (char*)"\0"; - data.keepAliveInterval = 10; - data.cleansession = 1; - mqtt_rc = MQTTConnect(&mqtt_client, &data); - if (mqtt_rc == SUCCESSS) - { - printf("++MQTT Connected SUCCESS: %ld\r\n", mqtt_rc); - } - else - { - printf("--MQTT Connected ERROR: %ld\r\n", mqtt_rc); - //while(1); //Reboot the board - } - - // Subscribe to all topics - char SubString[] = "/Filamentanlage/04_Messmodul/set/#"; - mqtt_rc = MQTTSubscribe(&mqtt_client, SubString, QOS0, messageArrived); - printf("Subscribed (%s) %ld\r\n", SubString, mqtt_rc); -#endif - - - ioHelperSetBit(outStatesBlinking, LED_PLC_OK, 1); - - uint32_t timer_blink_outs = millis(); - uint32_t timer_send_uptime = millis(); - - OCR3B = 127; - - while(1) - { - wdt_reset(); // WDT reset at least every sec - - //if (flag_refresh_inStates) { - ioHelperReadPins(); - ioHelperDebounce(); - ioHelperEdgeDetector(); - // flag_refresh_inStates = 0; - //} - - // Toggle all outs which are set to blinking - if(millis() - timer_blink_outs > 500){ - outStates[0] ^= outStatesBlinking[0]; - outStates[1] ^= outStatesBlinking[1]; - timer_blink_outs = millis(); - } - -#if PLC_MQTT_ENABLED - // send misc info - if(millis() - timer_send_uptime > 5000){ - timer_send_uptime += 5000; - char msg[64]; - sprintf(msg, "%ld", millis()/1000); - mqtt_pub(&mqtt_client, "/Filamentanlage/04_Messmodul/state/uptime", msg, strlen(msg)); - } -#endif - - - if(read_Input(BTN_ANLAGE_EIN, RISING)){ - printf("anlage in: %x\n\r", read_Input(IN_ANLAGE_EIN, LEVEL)); - } - // ioHelperSetBit(outStates, LED_GRN_NOTAUS_SCHRANK, 1); - //} - //else{ - // ioHelperSetBit(outStates, LED_GRN_NOTAUS_SCHRANK, 0); - //} - - do_luefter(); - do_notaus(); - do_zumbach(); - -#if PLC_MQTT_ENABLED - ioHelperSetBit(outStates, LED_BUS_OK, 1); - ioHelperSetOuts(); - MQTTYield(&mqtt_client, 10); //blocking call - ioHelperSetBit(outStates, LED_BUS_OK, 0); -#endif - ioHelperSetOuts(); - } - return 0; -} - -// Timer0 -// 1ms IRQ -// Used for millis() timing -void timer0_init(void) -{ - TCCR0A = (1<250kHz:250-=>1kHz) - TIMSK0 |= 1< +#include +#include // WatchDog +#include + +#include "Ethernet/socket.h" +#include "Ethernet/wizchip_conf.h" + +#include "Internet/MQTT/mqtt_interface.h" +#include "Internet/MQTT/MQTTClient.h" + +#include "avrIOhelper/io-helper.h" +#include "millis.h" +#include "uart.h" +#include "spi.h" +#include "mqtt.h" + +#include "util/delay.h" + +#include "modbus.h" +#include "modbus_master.h" + +#define PLC_MQTT_ENABLED 1 + +Client mqtt_client; + +//***********Prologue for fast WDT disable & and save reason of reset/power-up: BEGIN +uint8_t mcucsr_mirror __attribute__ ((section (".noinit"))); + +// This is for fast WDT disable & and save reason of reset/power-up +void get_mcusr(void) \ + __attribute__((naked)) \ + __attribute__((section(".init3"))); +void get_mcusr(void) +{ + mcucsr_mirror = MCUSR; + MCUSR = 0; + wdt_disable(); +} +//***********Prologue for fast WDT disable & and save reason of reset/power-up: END + + +//FUNC headers +static void avr_init(void); +void modbus_master_init(void); +void timer0_init(void); +void timer2_init(void); +void timer3_init(void); +void print_network_information(void); + +void IO_LIBRARY_Init(void) { + uint8_t bufSize[] = {2, 2, 2, 2, 2, 2, 2, 2}; + + reg_wizchip_cs_cbfunc(spi_select, spi_deselect); + reg_wizchip_spi_cbfunc(spi_read, spi_write); + //reg_wizchip_spiburst_cbfunc(spi_rb_burst, spi_wb_burst); + + wizchip_init(bufSize, bufSize); + wizchip_setnetinfo(&netInfo); + //wizchip_setinterruptmask(IK_SOCK_0); +} + +void modbus_master_init(){ + modbusSetAddress(1); //better set this to sth. + modbusInit(); + timer2_init(); // modbus tick timer +} + +static void avr_init() +{ + // Initialize device here. + // WatchDog INIT + wdt_enable(WDTO_8S); // set up wdt reset interval 2 second + wdt_reset(); // wdt reset ~ every <2000ms + + timer0_init();// Timer0 millis engine init + //timer3_init(); + uart_init(); + + sei(); //re-enable global interrupts + + return; +} + +void do_kraftsensor(){ + uint16_t m_data[4]; + char msg[64]; + + readReg(1,0,2); + if(wait_receive(2, m_data, 10)) + sprintf(msg, "n/a"); + else{ + int32_t tmp = (uint32_t)m_data[0]<<16; + tmp |= m_data[1]; + sprintf(msg, "%ld", tmp); + } + +#if PLC_MQTT_ENABLED + mqtt_pub(&mqtt_client, "/Filamentanlage/05_Abzug/state/kraft", msg, strlen(msg)); +#endif +} + +void do_notaus(){ + if(!read_Input(IN_NOTAUS_ANLAGE, LEVEL) || read_Input(IN_NOTAUS_SCHRANK, LEVEL) || read_Input(IN_NOTAUS_DISPLAY, LEVEL)){ + /* at least on pressed */ + ioHelperSetBit(outStates, AMPEL_ROT, 1); + ioHelperSetBit(outStates, AMPEL_GELB, 0); + ioHelperSetBit(outStates, AMPEL_GRUEN, 0); + + set_Output(LED_GRN_NOTAUS_SCHRANK, OFF); + set_Output(LED_GRN_NOTAUS_ANLAGE, OFF); + set_Output(LED_GRN_NOTAUS_DISPLAY, OFF); + } + else if(!read_Input(IN_ANLAGE_EIN, LEVEL)){ + /* nothing pressed, but power not on */ + ioHelperSetBit(outStates, AMPEL_ROT, 0); + ioHelperSetBit(outStates, AMPEL_GELB, 1); + ioHelperSetBit(outStates, AMPEL_GRUEN, 0); + + set_Output(LED_ROT_NOTAUS_ANLAGE, OFF); + set_Output(LED_ROT_NOTAUS_SCHRANK, OFF); + set_Output(LED_ROT_NOTAUS_DISPLAY, OFF); + + set_Output(LED_GRN_NOTAUS_SCHRANK, BLINK); + set_Output(LED_GRN_NOTAUS_ANLAGE, BLINK); + set_Output(LED_GRN_NOTAUS_DISPLAY, BLINK); + } + else{ + /* powered on */ + ioHelperSetBit(outStates, AMPEL_ROT, 0); + ioHelperSetBit(outStates, AMPEL_GELB, 0); + ioHelperSetBit(outStates, AMPEL_GRUEN, 1); + + set_Output(LED_GRN_NOTAUS_SCHRANK, ON); + set_Output(LED_GRN_NOTAUS_ANLAGE, ON); + set_Output(LED_GRN_NOTAUS_DISPLAY, ON); + } + + if(!read_Input(IN_NOTAUS_ANLAGE, LEVEL)){ + set_Output(LED_ROT_NOTAUS_ANLAGE, BLINK); + set_Output(LED_ROT_NOTAUS_SCHRANK, ON); + set_Output(LED_ROT_NOTAUS_DISPLAY, ON); + } + + if(read_Input(IN_NOTAUS_SCHRANK, LEVEL)){ + set_Output(LED_ROT_NOTAUS_ANLAGE, ON); + set_Output(LED_ROT_NOTAUS_SCHRANK, BLINK); + set_Output(LED_ROT_NOTAUS_DISPLAY, ON); + } + + if(read_Input(IN_NOTAUS_DISPLAY, LEVEL)){ + set_Output(LED_ROT_NOTAUS_ANLAGE, ON); + set_Output(LED_ROT_NOTAUS_SCHRANK, ON); + set_Output(LED_ROT_NOTAUS_DISPLAY, BLINK); + } +} + +int main() +{ + // INIT MCU + avr_init(); + spi_init(); //SPI Master, MODE0, 4Mhz(DIV4), CS_PB.3=HIGH - suitable for WIZNET 5x00(1/2/5) + modbus_master_init(); + + printf("moin!\n\r"); + + ioHelperInitBuffer(); + ioHelperIoConf(); + + + //Wizchip WIZ5500 Ethernet initialize + IO_LIBRARY_Init(); //After that ping must working + print_network_information(); + +#if PLC_MQTT_ENABLED + //****************MQTT client initialize + //Find MQTT broker and connect with it + uint8_t mqtt_buf[100]; + int32_t mqtt_rc = 0; + Network mqtt_network; + mqtt_network.my_socket = SOCK_MQTT; + + printf(">>Trying connect to MQTT broker: %d.%d.%d.%d ..\r\n", MQTT_targetIP[0], MQTT_targetIP[1], MQTT_targetIP[2], MQTT_targetIP[3]); + NewNetwork(&mqtt_network); + ConnectNetwork(&mqtt_network, MQTT_targetIP, 1883); + MQTTClient(&mqtt_client, &mqtt_network, 1000, mqtt_buf, 100, mqtt_readBuffer, MQTT_BUFFER_SIZE); + + //Connection to MQTT broker + MQTTPacket_connectData data = MQTTPacket_connectData_initializer; + data.willFlag = 0; + data.MQTTVersion = 4;//3; + data.clientID.cstring = (char*)"controllino"; + data.username.cstring = (char*)"Messmodul"; + data.password.cstring = (char*)"\0"; + data.keepAliveInterval = 10; + data.cleansession = 1; + mqtt_rc = MQTTConnect(&mqtt_client, &data); + if (mqtt_rc == SUCCESSS) + { + printf("++MQTT Connected SUCCESS: %ld\r\n", mqtt_rc); + } + else + { + printf("--MQTT Connected ERROR: %ld\r\n", mqtt_rc); + //while(1); //Reboot the board + } + + char SubString[] = "/Filamentanlage/04_Messmodul/set/#"; + mqtt_rc = MQTTSubscribe(&mqtt_client, SubString, QOS0, messageArrived); + printf("Subscribed (%s) %ld\r\n", SubString, mqtt_rc); +#endif + + ioHelperSetBit(outStates, RELAY_INTERLOCK, 1); + + ioHelperSetBit(outStatesBlinking, LED_PLC_OK, 1); + + uint32_t timer_blink_outs = millis(); + uint32_t timer_send_uptime = millis(); + uint32_t timer_modbus_poll = millis(); + + while(1) + { + wdt_reset(); // WDT reset at least every sec + + //if (flag_refresh_inStates) { + ioHelperReadPins(); + ioHelperDebounce(); + ioHelperEdgeDetector(); + // flag_refresh_inStates = 0; + //} + + // Toggle all outs which are set to blinking + if(millis() - timer_blink_outs > 500){ + outStates[0] ^= outStatesBlinking[0]; + outStates[1] ^= outStatesBlinking[1]; + outStates[2] ^= outStatesBlinking[2]; + outStates[3] ^= outStatesBlinking[3]; + timer_blink_outs = millis(); + } + +#if PLC_MQTT_ENABLED + // send misc info + if(millis() - timer_send_uptime > 5000){ + timer_send_uptime += 5000; + char msg[64]; + sprintf(msg, "%ld", millis()/1000); + mqtt_pub(&mqtt_client, "/Filamentanlage/04_Messmodul/state/uptime", msg, strlen(msg)); + } +#endif + if(millis() - timer_modbus_poll > 1000){ + timer_modbus_poll += 1000; + do_kraftsensor(); + } + + do_notaus(); + +#if PLC_MQTT_ENABLED + ioHelperSetBit(outStates, LED_BUS_OK, 1); + ioHelperSetOuts(); + MQTTYield(&mqtt_client, 10); //blocking call + ioHelperSetBit(outStates, LED_BUS_OK, 0); +#endif + ioHelperSetOuts(); + } + return 0; +} + +// Timer0 +// 1ms IRQ +// Used for millis() timing +void timer0_init() +{ + TCCR0A = (1<250kHz:250-=>1kHz) + TIMSK0 |= 1<10kHz) + TIMSK2|=(1< +#include "modbus.h" +#include + +volatile unsigned char BusState = 0; +volatile uint16_t modbusTimer = 0; +volatile unsigned char rxbuffer[MaxFrameIndex+1]; +volatile uint16_t DataPos = 0; +volatile unsigned char PacketTopIndex = 7; +volatile unsigned char modBusStaMaStates = 0; +volatile uint16_t modbusDataAmount = 0; +volatile uint16_t modbusDataLocation = 0; + +/* @brief: save address and amount +* +*/ +void modbusSaveLocation(void) +{ + modbusDataLocation=(rxbuffer[3]|(rxbuffer[2]<<8)); + if (rxbuffer[1]==fcPresetSingleRegister || rxbuffer[1]==fcForceSingleCoil) modbusDataAmount=1; + else modbusDataAmount=(rxbuffer[5]|(rxbuffer[4]<<8)); +} + +/* @brief: returns 1 if data location adr is touched by current command +* +* Arguments: - adr: address of the data object +* +*/ +uint8_t modbusIsInRange(uint16_t adr) +{ + if((modbusDataLocation <= adr) && (adr<(modbusDataLocation+modbusDataAmount))) + return 1; + return 0; +} + +/* @brief: returns 1 if range of data locations is touched by current command +* +* Arguments: - startAdr: address of first data object in range +* - lastAdr: address of last data object in range +* +*/ +uint8_t modbusIsRangeInRange(uint16_t startAdr, uint16_t lastAdr) +{ + if(modbusIsInRange(startAdr) && modbusIsInRange(lastAdr)) + return 1; + return 0; +} + +uint8_t modbusGetBusState(void) +{ + return BusState; +} + +#if ADDRESS_MODE == SINGLE_ADR +volatile unsigned char Address = 0x00; +uint8_t modbusGetAddress(void) +{ + return Address; +} + +void modbusSetAddress(unsigned char newadr) +{ + Address = newadr; +} +#endif + +#if PHYSICAL_TYPE == 485 +void transceiver_txen(void) +{ + TRANSCEIVER_ENABLE_PORT|=(1<>= 1; + if (carry) out ^= 0xA001; + } + } + //out=0x1234; + if ((ptrToArray[inputSize]==out%256) && (ptrToArray[inputSize+1]==out/256)) //check + { + return 1; + } else { + ptrToArray[inputSize]=out%256; //append Lo + ptrToArray[inputSize+1]=out/256; //append Hi + return 0; + } +} + +/* @brief: copies a single bit from one char to another char (or arrays thereof) +* +* +*/ +void listBitCopy(volatile uint8_t *source, uint16_t sourceNr,volatile uint8_t *target, uint16_t targetNr) +{ + if(*(source+(sourceNr/8))&(1<<(sourceNr-((sourceNr/8)*8)))) + { + *(target+(targetNr/8))|=(1<<(targetNr-((targetNr/8)*8))); + } else *(target+(targetNr/8))&=~(1<<(targetNr-((targetNr/8)*8))); +} + +/* @brief: Back to receiving state. +* +*/ +void modbusReset(void) +{ + BusState=(1< perform crc check + modbusSaveLocation(); + BusState=(1<MaxFrameIndex) modbusReset(); + else + { + rxbuffer[DataPos]=data; + DataPos++; //TODO: maybe prevent this from exceeding 255? + } + } else + // Bus state is Timed out.. + if (!(BusState & (1<> 8); + UBRRL = (unsigned char) _UBRR; + UART_STATUS = (1<> 8); + *(outreg+1+c*2) = (uint8_t)(*(inreg+c)); + } +} + +/* @brief: copies a single or multiple 16-bit-words from one array of integers to an array of bytes +* +*/ +void modbusRegisterToInt(volatile uint8_t *inreg, volatile uint16_t *outreg, uint8_t amount) +{ + for (uint8_t c=0; c=startAddress) && ((startAddress+size)>=(modbusDataAmount+modbusDataLocation))) { + + if ((rxbuffer[1]==fcReadHoldingRegisters) || (rxbuffer[1]==fcReadInputRegisters) ) + { + if ((modbusDataAmount*2)<=(MaxFrameIndex-4)) //message buffer big enough? + { + rxbuffer[2]=(unsigned char)(modbusDataAmount*2); + intToModbusRegister(ptrToInArray+(modbusDataLocation-startAddress),rxbuffer+3,modbusDataAmount); + modbusSendMessage(2+rxbuffer[2]); + return 1; + } else modbusSendException(ecIllegalDataValue); + } + else if (rxbuffer[1]==fcPresetMultipleRegisters) + { + if (((rxbuffer[6])>=modbusDataAmount*2) && ((DataPos-9)>=rxbuffer[6])) //enough data received? + { + modbusRegisterToInt(rxbuffer+7,ptrToInArray+(modbusDataLocation-startAddress),(unsigned char)(modbusDataAmount)); + modbusSendMessage(5); + return 1; + } else modbusSendException(ecIllegalDataValue);//too few data bytes received + } + else if (rxbuffer[1]==fcPresetSingleRegister) + { + modbusRegisterToInt(rxbuffer+4,ptrToInArray+(modbusDataLocation-startAddress),1); + modbusSendMessage(5); + return 1; + } + //modbusSendException(ecSlaveDeviceFailure); //inapropriate call of modbusExchangeRegisters + return 0; + } else { + modbusSendException(ecIllegalDataValue); + return 0; + } +} + +/* @brief: Handles single/multiple input/coil reading and single/multiple coil writing. +* +* Arguments: - ptrToInArray: pointer to the user's data array containing bits +* - startAddress: address of the first bit in the supplied array +* - size: input array size in the requested format (bits) +* +*/ +uint8_t modbusExchangeBits(volatile uint8_t *ptrToInArray, uint16_t startAddress, uint16_t size) +{ + if ((modbusDataLocation>=startAddress) && ((startAddress+size)>=(modbusDataAmount+modbusDataLocation))) + { + if ((rxbuffer[1]==fcReadInputStatus) || (rxbuffer[1]==fcReadCoilStatus)) + { + if (modbusDataAmount<=((MaxFrameIndex-4)*8)) //message buffer big enough? + { + rxbuffer[2]=(modbusDataAmount/8); + if (modbusDataAmount%8>0) + { + rxbuffer[(uint8_t)(modbusDataAmount/8)+3]=0x00; //fill last data byte with zeros + rxbuffer[2]++; + } + for (uint16_t c = 0; c=modbusDataAmount) && ((DataPos-9)>=rxbuffer[6])) //enough data received? + { + for (uint16_t c = 0; c +/** + * @code #include @endcode + * + * @brief Interrupt-based Modbus implementation for small avr microcontrollers. + * The Modbus implementation guidelines at modbus.org call for response + * timeouts in the range of several seconds , hence only timing critical + * parts have been implemented within ISRs. The actual handling of the Modbus + * frame can easily be done in the main while loop. + * + * @author Max Brueggemann www.maxbrueggemann.de + */ + +/* define baudrate of modbus */ +#ifndef BAUD +#define BAUD 38400L +#endif + +/* +* Definitions for transceiver enable pin. +*/ +#ifndef TRANSCEIVER_ENABLE_PORT +#define TRANSCEIVER_ENABLE_PORT PORTJ +#endif + +#ifndef TRANSCEIVER_ENABLE_PIN +#define TRANSCEIVER_ENABLE_PIN 6 +#define TRANSCEIVER_ENABLE_PIN_2 5 +#endif + +#ifndef TRANSCEIVER_ENABLE_PORT_DDR +#define TRANSCEIVER_ENABLE_PORT_DDR DDRJ +#endif + +/** + * @brief + * At the moment the user has to set the value for Baudrate and + * speed mode manually. The values depend on the operating frequency + * of your AVR and can be found in its datasheet. + */ +#if defined(__AVR_ATtiny2313__) +#define UART_TRANSMIT_COMPLETE_INTERRUPT USART_TX_vect +#define UART_RECEIVE_INTERRUPT USART_RX_vect +#define UART_TRANSMIT_INTERRUPT USART_UDRE_vect +#define UART_STATUS UCSRA +#define UART_CONTROL UCSRB +#define UART_DATA UDR +#define UART_UDRIE UDRIE + +#elif defined(__AVR_ATmega164P__) +#define UART_TRANSMIT_COMPLETE_INTERRUPT USART1_TX_vect +#define UART_RECEIVE_INTERRUPT USART1_RX_vect +#define UART_TRANSMIT_INTERRUPT USART1_UDRE_vect +#define UART_STATUS UCSR1A +#define UART_CONTROL UCSR1B +#define UART_DATA UDR1 +#define UART_UDRIE UDRIE1 +#define UCSRC UCSR1C +#define RXCIE RXCIE1 +#define TXCIE TXCIE1 +#define RXEN RXEN1 +#define TXEN TXEN1 +#define UCSZ0 UCSZ10 +#define U2X U2X1 +#define UBRRH UBRR1H +#define UBRRL UBRR1L + +#elif defined(__AVR_ATmega168PA__)|(__AVR_ATmega88PA__)|(__AVR_ATmega328P__)|(__AVR_ATmega168P__)|(__AVR_ATmega88P__) +#define UART_TRANSMIT_COMPLETE_INTERRUPT USART_TX_vect +#define UART_RECEIVE_INTERRUPT USART_RX_vect +#define UART_TRANSMIT_INTERRUPT USART_UDRE_vect +#define UART_STATUS UCSR0A +#define UART_CONTROL UCSR0B +#define UART_DATA UDR0 +#define UART_UDRIE UDRIE0 +#define UCSRC UCSR0C +#define RXCIE RXCIE0 +#define TXCIE TXCIE0 +#define RXEN RXEN0 +#define TXEN TXEN0 +#define UCSZ0 UCSZ00 +#define U2X U2X0 +#define UBRRH UBRR0H +#define UBRRL UBRR0L + +#elif defined(__AVR_ATmega328PB__) +#define UART_TRANSMIT_COMPLETE_INTERRUPT USART0_TX_vect +#define UART_RECEIVE_INTERRUPT USART0_RX_vect +#define UART_TRANSMIT_INTERRUPT USART0_UDRE_vect +#define UART_STATUS UCSR0A +#define UART_CONTROL UCSR0B +#define UART_DATA UDR0 +#define UART_UDRIE UDRIE0 +#define UCSRC UCSR0C +#define RXCIE RXCIE0 +#define TXCIE TXCIE0 +#define RXEN RXEN0 +#define TXEN TXEN0 +#define UCSZ0 UCSZ00 +#define U2X U2X0 +#define UBRRH UBRR0H +#define UBRRL UBRR0L + +#elif defined(__AVR_ATtiny441__) +#define UART_TRANSMIT_COMPLETE_INTERRUPT USART0_TX_vect +#define UART_RECEIVE_INTERRUPT USART0_RX_vect +#define UART_TRANSMIT_INTERRUPT USART0_UDRE_vect +#define UART_STATUS UCSR0A +#define UART_CONTROL UCSR0B +#define UART_DATA UDR0 +#define UART_UDRIE UDRIE0 +#define UCSRC UCSR0C +#define RXCIE RXCIE0 +#define TXCIE TXCIE0 +#define RXEN RXEN0 +#define TXEN TXEN0 +#define UCSZ0 UCSZ00 +#define U2X U2X0 +#define UBRRH UBRR0H +#define UBRRL UBRR0L + +#elif defined(__AVR_ATmega8__)|| defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) || defined(__AVR_ATmega323__) +#define UART_TRANSMIT_COMPLETE_INTERRUPT USART_TXC_vect +#define UART_RECEIVE_INTERRUPT USART_RXC_vect +#define UART_TRANSMIT_INTERRUPT USART_UDRE_vect +#define UART_STATUS UCSRA +#define UART_CONTROL UCSRB +#define UART_DATA UDR +#define UART_UDRIE UDRIE + +#elif defined(__AVR_AT90PWM3B__) +#define UART_TRANSMIT_COMPLETE_INTERRUPT USART_TX_vect +#define UART_RECEIVE_INTERRUPT USART_RX_vect +#define UART_TRANSMIT_INTERRUPT USART_UDRE_vect +#define UART_STATUS UCSRA +#define UART_CONTROL UCSRB +#define UART_DATA UDR +#define UART_UDRIE UDRIE + +#elif defined(__AVR_ATmega1284P__) +#define UART_TRANSMIT_COMPLETE_INTERRUPT USART0_TX_vect +#define UART_RECEIVE_INTERRUPT USART0_RX_vect +#define UART_TRANSMIT_INTERRUPT USART0_UDRE_vect +#define UART_STATUS UCSR0A +#define UART_CONTROL UCSR0B +#define UART_DATA UDR0 +#define UART_UDRIE UDRIE0 +#define UCSRC UCSR0C +#define RXCIE RXCIE0 +#define TXCIE TXCIE0 +#define RXEN RXEN0 +#define TXEN TXEN0 +#define UCSZ0 UCSZ00 +#define U2X U2X0 +#define UBRRH UBRR0H +#define UBRRL UBRR0L + +#elif defined(__AVR_ATmega2560__) +#define UART_TRANSMIT_COMPLETE_INTERRUPT USART3_TX_vect +#define UART_RECEIVE_INTERRUPT USART3_RX_vect +#define UART_TRANSMIT_INTERRUPT USART3_UDRE_vect +#define UART_STATUS UCSR3A +#define UART_CONTROL UCSR3B +#define UART_DATA UDR3 +#define UART_UDRIE UDRIE3 +#define UCSRC UCSR3C +#define RXCIE RXCIE3 +#define TXCIE TXCIE3 +#define RXEN RXEN3 +#define TXEN TXEN3 +#define UCSZ0 UCSZ30 +#define U2X U2X0 +#define UBRRH UBRR3H +#define UBRRL UBRR3L + +#else +#error "no definition available" +#endif + +#ifndef F_CPU +#error " F_CPU not defined " +#else + #define _UBRR (F_CPU / 8 / BAUD ) -1 +#endif /* F_CPU */ +/* + * Available address modes. +*/ +#define MULTIPLE_ADR 2 +#define SINGLE_ADR 1 + +/* +* Use SINGLE_ADR or MULTIPLE_ADR, default: SINGLE_ADR +* This is useful for building gateways, routers or clients that for whatever reason need multiple addresses. +*/ +#define ADDRESS_MODE SINGLE_ADR + +/* +* Use 485 or 232, default: 485 +* Use 232 for testing purposes or very simple applications that do not require RS485 and bus topology. +*/ +#define PHYSICAL_TYPE 485 //possible values: 485, 232 + +#if BAUD>=19200 +#define modbusInterFrameDelayReceiveStart 16 +#define modbusInterFrameDelayReceiveEnd 18 +#define modbusInterCharTimeout 7 +#else +#define modbusBlocksize 10 +#define modbusBlockTime ((float)modbusBlocksize*1000000)/((float) BAUD) //is 260 for 38400 +#define timerISROccurenceTime 100 //time in microseconds between two calls of modbusTickTimer +#define modbusInterFrameDelayReceiveStart (uint16_t)(modbusBlockTime*3.5/(float)timerISROccurenceTime) +#define modbusInterFrameDelayReceiveEnd (uint16_t)(modbusBlockTime*4/(float)timerISROccurenceTime) +#define modbusInterCharTimeout (uint16_t)(modbusBlockTime*1.5/(float)timerISROccurenceTime) +#endif + + +/** + * @brief Defines the maximum Modbus frame size accepted by the device. 255 is the default + * and also the maximum value. However, it might be useful to set this to lower + * values, with 8 being the lowest possible value, in order to save on ram space. + */ +#define MaxFrameIndex 255 + +/** + * @brief Modbus Function Codes + * Refer to modbus.org for further information. + * It's good practice to return exception code 01 in case you receive a function code + * that you haven't implemented in your application. + */ +#define fcReadCoilStatus 1 //read single/multiple coils +#define fcReadInputStatus 2 //read single/multiple inputs +#define fcReadHoldingRegisters 3 //read analog output registers +#define fcReadInputRegisters 4 //read analog input registers (2 Bytes per register) +#define fcForceSingleCoil 5 //write single bit +#define fcPresetSingleRegister 6 //write analog output register (2 Bytes) +#define fcForceMultipleCoils 15 //write multiple bits +#define fcPresetMultipleRegisters 16 //write multiple analog output registers (2 Bytes each) +#define fcReportSlaveID 17 //read device description, run status and other device specific information + +/** + * @brief Modbus Exception Codes + * Refer to modbus.org for further information. + * It's good practice to return exception code 01 in case you receive a function code + * that you haven't implemented in your application. + */ +#define ecIllegalFunction 1 +#define ecIllegalDataAddress 2 +#define ecIllegalDataValue 3 +#define ecSlaveDeviceFailure 4 +#define ecAcknowledge 5 +#define ecSlaveDeviceBusy 6 +#define ecNegativeAcknowledge 7 +#define ecMemoryParityError 8 + +/** + * @brief Internal bit definitions + */ +#define BusTimedOut 0 +#define Receiving 1 +#define Transmitting 2 +#define ReceiveCompleted 3 +#define TransmitRequested 4 +#define TimerActive 5 +#define GapDetected 6 + +/** +* @brief Configures the UART. Call this function only once. +*/ +extern void modbusInit(void); + +/** +* @brief receive/transmit data array +*/ +extern volatile unsigned char rxbuffer[MaxFrameIndex+1]; + +/** +* @brief Current receive/transmit position +*/ +extern volatile uint16_t DataPos; + +/** + * This only applies to single address mode. + */ +#if ADDRESS_MODE == SINGLE_ADR + /** + * @brief: Read the device address + */ + extern uint8_t modbusGetAddress(void); + + /** + * @brief: Set the device address + * Arguments: - newadr: the new device address + */ + extern void modbusSetAddress(unsigned char newadr); +#endif + +/* @brief: Sends a response. +* +* Arguments: - packtop, index of the last byte in rxbuffer +* that contains payload. Maximum value is +* MaxFrameIndex-2. +*/ +extern void modbusSendMessage(unsigned char packtop); + +/* @brief: Sends a Modbus exception. +* +* Arguments: - exceptionCode +*/ +extern void modbusSendException(unsigned char exceptionCode); + +/* @brief: Discards the current transaction. For MULTIPLE_ADR-mode and general +* testing purposes. Call this function if you don't want to reply at all. +*/ +void modbusReset(void); + +/** + * @brief Call this function whenever possible and check if its return value has the ReceiveCompleted Bit set. + * Preferably do this in the main while. I do not recommend calling this function within ISRs. + * @example if (modbusGetBusState() & (1< + +#include + +uint8_t wait_receive(uint8_t len, uint16_t dest[], uint8_t timeout){ + + uint8_t breaker = timeout; + while(!receiveOkay && breaker) { //wait for client response, time out after 1s + breaker--; + _delay_ms(10); + } + + if(receiveOkay) { //if this fails, there was either no response or a crc error + if(rxbuffer[1]&0x80) { //client responded with an error code + //handle the error + printf("error\n\r"); + return -1; + } + else { + for(uint8_t x=0;x 8 bytes). You might want to check this at this point. + dest[x]=(rxbuffer[3+x*2]<<8)+rxbuffer[4+x*2]; //do sth with the acquired data. + } + } + + } + return 0; +} + +void readReg(uint8_t slaveid, uint16_t address, uint8_t amount) { + _delay_ms(2); + rxbuffer[0]=slaveid; + modbusSetAddress(slaveid); + rxbuffer[1]=0x03; + rxbuffer[2]=(address>>8)&0xFF; + rxbuffer[3]=address&0xFF; + rxbuffer[4]=0x00; + rxbuffer[5]=amount; + modbusSendMessage(5); +} + +void writeReg(uint8_t slaveid, uint16_t address, uint16_t value) { + _delay_ms(2); + rxbuffer[0]=slaveid; + modbusSetAddress(slaveid); + rxbuffer[1]=0x06; + rxbuffer[2]=(address>>8)&0xFF; + rxbuffer[3]=address&0xFF; + rxbuffer[4]=(value>>8)&0xFF;; + rxbuffer[5]=value&0xFF; + modbusSendMessage(5); +} + + diff --git a/modbus_master.h b/modbus_master.h new file mode 100644 index 0000000..f666884 --- /dev/null +++ b/modbus_master.h @@ -0,0 +1,12 @@ +#ifndef _MODBUS_MASTER_H_ +#define _MODBUS_MASTER_H_ + +#include + +#define receiveOkay (modbusGetBusState() & (1<