From 51fd30674cd8ce7f1e1a5c927f7ec215a0b1a1dd Mon Sep 17 00:00:00 2001 From: Manfred Steiner Date: Mon, 29 Jul 2024 17:15:56 +0200 Subject: [PATCH] Test-Software Unit Modbus --- software/test_2024-07-23/Makefile | 4 +- software/test_2024-07-23/src/main.cpp | 81 +++++++--- software/test_2024-07-23/src/units/modbus.cpp | 145 ++++++++++++++++++ software/test_2024-07-23/src/units/modbus.hpp | 22 +++ 4 files changed, 232 insertions(+), 20 deletions(-) create mode 100644 software/test_2024-07-23/src/units/modbus.cpp create mode 100644 software/test_2024-07-23/src/units/modbus.hpp diff --git a/software/test_2024-07-23/Makefile b/software/test_2024-07-23/Makefile index 8f5c7f2..12a996a 100644 --- a/software/test_2024-07-23/Makefile +++ b/software/test_2024-07-23/Makefile @@ -12,10 +12,10 @@ DEVICE=atmega644p CC= avr-g++ CFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=12000000 -c -LFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=12000000 +LFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=12000000 -Wl,-u,vfprintf -lprintf_flt -lm CFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=12000000 -g -c -LFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=12000000 -g +LFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=12000000 -g -Wl,-u,vfprintf -lprintf_flt -lm all: dist/$(NAME).elf dist/$(NAME).s dist/$(NAME).hex sim/$(NAME).elf sim/$(NAME).s info diff --git a/software/test_2024-07-23/src/main.cpp b/software/test_2024-07-23/src/main.cpp index c9fa880..9023e1a 100644 --- a/software/test_2024-07-23/src/main.cpp +++ b/software/test_2024-07-23/src/main.cpp @@ -15,6 +15,7 @@ #include "units/motor.hpp" #include "units/portexp.hpp" #include "units/lcd.hpp" +#include "units/modbus.hpp" extern "C" { void __cxa_pure_virtual () { @@ -34,8 +35,36 @@ extern "C" { return 0; } - static FILE mystdout = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart_putchar, NULL, 0 } ; - static FILE mystderr = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart_putchar, NULL, 0 } ; + + uint8_t volatile uartBuffer[32]; + uint8_t volatile rIndex = 0; + uint8_t volatile wIndex = 0; + + int uart_getchar (FILE *stream) { + // if (rIndex == wIndex) { + // // nothing in buffer + // return EOF; + // } + // printf(" r%d", rIndex); + while (rIndex == wIndex) { + // wait for character + } + + // don't use "char c" because german special characters would lead to negative return -> stream error + // char c = uartBuffer[rIndex++]; + + uint8_t c = uartBuffer[rIndex++]; + // printf("(%02x) ", c); + if (c == '\r') { + c = '\n'; + } + putchar(c); // echo on terminal + return c; + } + + static FILE mystdout = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart_putchar, NULL, 0 }; + static FILE mystderr = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart_putchar, NULL, 0 }; + static FILE mystdin = { 0, 0, _FDEV_SETUP_READ , 0, 0, NULL, uart_getchar, 0 }; static volatile uint32_t timer1ms = 0; static volatile int keyUart0 = EOF; @@ -50,6 +79,7 @@ extern "C" { Motor motor; PortExp portExp; Lcd lcd; + Modbus modbus; } @@ -93,24 +123,29 @@ int main () { stdout = &mystdout; stderr = &mystderr; + stdin = &mystdin; sei(); - printf("\n\nTEST Nano-X-Base\n"); - printf("======================================"); - - - TestUnit *unit[] = { &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp, &lcd }; - - for (uint8_t i = 0; i < sizeof(unit) / sizeof(unit[0]); i++) { + TestUnit *unit[] = { &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp, &lcd, &modbus }; + + while (1) { + uint16_t i; + char s[4]; + do { + printf("\n\n=============================\n\n"); + printf("Available units:\n\n"); + for (i = 0; i < sizeof(unit) / sizeof(unit[0]); i++) { + TestUnit *pu = unit[i]; + printf("%3x ... %s\n", i, pu->getName()); + } + printf("\nSelect unit: "); + rIndex = 0; wIndex = 0; + fgets(s, sizeof(s), stdin); + } while (sscanf(s, "%x", &i) != 1 || i < 0 || i >= sizeof(unit) / sizeof(unit[0]) ); + TestUnit *pu = unit[i]; printf("\n\n[%s]: ", pu->getName()); - printf("Press >ESC< to skip unit, any other key to start\n"); - wait(0xffffffff); - if (keyUart0 == 27) { - keyUart0 = EOF; - continue; - } keyUart0 = EOF; for (uint8_t subtest = 0; subtest < 0xff; subtest++) { @@ -126,14 +161,24 @@ int main () { } pu->cleanup(); } - - printf("\n\nTest finished. \n"); - return 0; } ISR (USART0_RX_vect) { uint8_t b = UDR0; keyUart0 = b; + uartBuffer[wIndex++] = b; + // printf(" w%d(%02x)", wIndex, b); + if (wIndex == rIndex) { + // buffer overflow, kick out oldest byte + rIndex++; + } +} + +ISR (USART1_RX_vect) { + uint8_t b = UDR1; + if (modbus.enabled) { + modbus.handleRxByte(b); + } } ISR (TIMER2_COMPA_vect) { // every 100us diff --git a/software/test_2024-07-23/src/units/modbus.cpp b/software/test_2024-07-23/src/units/modbus.cpp new file mode 100644 index 0000000..28b1bca --- /dev/null +++ b/software/test_2024-07-23/src/units/modbus.cpp @@ -0,0 +1,145 @@ +#include +#include +#include + +#include "modbus.hpp" +#include "../main.hpp" + +// PB0 ... nRE .. Read enable +// PB1 ... DE .. Data enable + +#define SET_nRE (PORTB |= (1 << PB0)) +#define CLR_nRE (PORTB &= ~(1 << PB0)) +#define SET_DE (PORTB |= (1 << PB1)) +#define CLR_DE (PORTB &= ~(1 << PB1)) + + +void Modbus::cleanup () { + enabled = 0; + UCSR1A = 0; + UCSR1B = 0; + UCSR1C = 0; + UBRR1H = 0; + UBRR1L = 0; + PORTD &= ~(1 << PD2); + DDRB &= ~((1 << PB1) | (1 << PB0)); + PORTB &= ~((1 << PB1) | (1 << PB0)); +} + +int8_t Modbus::run (uint8_t subtest) { + if (subtest == 0) { + SET_nRE; + CLR_DE; + DDRB |= (1 << PB1) | (1 << PB0); + + // UART1 interface on Nano-644 + PORTD |= (1 << PD2); // enable RxD1 pullup + UCSR1A = (1 << U2X1); + UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 <= 1 && subtest <= 4) { + uint8_t nre, de, b; + switch (subtest) { + case 1: nre = 1; de = 0; b = 0x01; break; + case 2: nre = 1; de = 1; b = 0x8e; break; + case 3: nre = 0; de = 0; b = 0x55; break; + case 4: nre = 0; de = 1; b = 0xaa; break; + default: return -1; + } + printf(" DE=%u, nRE=%u send 0x%02x... ", de, nre, b); + if (nre) { + SET_nRE; + } else { + CLR_nRE; + } + if (de) { + SET_DE; + } else { + CLR_DE; + } + _delay_us(100); + receivedBytes = 0; + UDR1 = b; + _delay_ms(1); + if (receivedBytes > 0) { + printf("0x%02x received", received[0]); + receivedBytes = 0; + } else { + printf("no byte received"); + } + printf(" ... press key to proceed"); + while (wait(0xffffffff) == EOF) {} + CLR_DE; + SET_nRE; + + } else if (subtest == 5) { + static uint8_t frame[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x02, 0x71, 0xcb }; + printf("Modbus: lese Spannung von Eastron SDM-230 (Einphasenzähler)"); + SET_DE; + CLR_nRE; + _delay_us(100); + do { + SET_DE; + receivedBytes = 0; + for (uint8_t i = 0; i < sizeof(frame); i++) { + UCSR1A |= (1 << TXC1); + UDR1 = frame[i]; + while ((UCSR1A & (1 < Sending:"); + for (uint8_t i = 0; i < sizeof(frame); i++) { + printf(" 0x%02x", frame[i]); + } + int k = wait(100); + + printf("\n RxD1:"); + if (receivedBytes == 0) { + printf("?"); + } else { + for (uint8_t i = 0; i < receivedBytes; i++) { + if (i == sizeof(frame)) { + printf(" "); + } + printf(" 0x%02x", received[i]); + } + } + if (receivedBytes >= 16) { + union { + uint8_t b[4]; + float value; + } f; + f.b[0] = received[14]; + f.b[1] = received[13]; + f.b[2] = received[12]; + f.b[3] = received[11]; + printf(" -> %4.8fV\n", (double)f.value); + } + if (k != EOF) { + break; + } + + } while (wait(1000) == EOF); + + } else { + printf("end"); + return -1; + } + wait(500); + return 0; +} + +void Modbus::handleRxByte (uint8_t b) { + if (receivedBytes < sizeof(received)) { + received[receivedBytes++] = b; + } +} diff --git a/software/test_2024-07-23/src/units/modbus.hpp b/software/test_2024-07-23/src/units/modbus.hpp new file mode 100644 index 0000000..14580f8 --- /dev/null +++ b/software/test_2024-07-23/src/units/modbus.hpp @@ -0,0 +1,22 @@ +#ifndef MODBUS_HPP +#define MODBUS_HPP + +#include +#include "../main.hpp" + +class Modbus : public TestUnit { + public: + uint8_t enabled; + uint8_t receivedBytes; + uint8_t received[16]; + + + public: + Modbus () { enabled = 0; receivedBytes = 0; } + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual const char *getName () { return "Modbus"; } + void handleRxByte (uint8_t); +}; + +#endif \ No newline at end of file -- 2.39.5