From: Manfred Steiner Date: Mon, 5 Aug 2024 05:25:17 +0000 (+0200) Subject: Test-Software fertig, alle Units auf Nano-644 und Arduino Nano getestet X-Git-Url: https://git.htl-mechatronik.at/public/?a=commitdiff_plain;h=6430d8c22b091b93b0e5f767c8a700da04d81e55;p=nano-x-base.git Test-Software fertig, alle Units auf Nano-644 und Arduino Nano getestet --- diff --git a/software/arduino-nano-5v/test_2024-07-23/src/main.cpp b/software/arduino-nano-5v/test_2024-07-23/src/main.cpp index f5b0f3e..23bcc90 100644 --- a/software/arduino-nano-5v/test_2024-07-23/src/main.cpp +++ b/software/arduino-nano-5v/test_2024-07-23/src/main.cpp @@ -13,20 +13,15 @@ #include "units/ieee485.hpp" #include "units/led.hpp" #include "units/lcd.hpp" - - -// #include "units/switch.hpp" -// #include "units/rgb.hpp" -// #include "units/seg7.hpp" -// #include "units/poti.hpp" -// #include "units/r2r.hpp" -// #include "units/motor.hpp" -// #include "units/portexp.hpp" -// #include "units/uart1.hpp" -// #include "units/modbus.hpp" - - - +#include "units/switch.hpp" +#include "units/rgb.hpp" +#include "units/seg7.hpp" +#include "units/poti.hpp" +#include "units/r2r.hpp" +#include "units/motor.hpp" +#include "units/portexp.hpp" +#include "units/uart1.hpp" +#include "units/modbus.hpp" extern "C" { void __cxa_pure_virtual () { @@ -87,17 +82,17 @@ extern "C" { static volatile int keyUart0 = EOF; Led led; - // Switch sw; - // Rgb rgb; - // Seg7 seg7; - // Poti poti; + Switch sw; + Rgb rgb; + Seg7 seg7; + Poti poti; Encoder encoder; - // R2r r2r; - // Motor motor; - // PortExp portExp; + R2r r2r; + Motor motor; + PortExp portExp; Lcd lcd; - // Uart1 uart1; - // Modbus modbus; + Uart1 uart1; + Modbus modbus; Ieee485 ieee485; I2c i2cSparkfun(I2c::SparkFunEnvCombo); I2c i2cMaster(I2c::Master); @@ -123,6 +118,7 @@ int wait (uint32_t ms) { int main () { + #ifdef __AVR_ATmega644P__ // Nano-644 LEDs (Green, Orange, Red) DDRC |= (1 << DDC4) | (1 << DDC3) | (1 << DDC2); PORTC &= ~((1 << PORT4) | (1 << PORT3) | (1 << PORT2)); @@ -130,6 +126,12 @@ int main () { // Nano-644 push button SW2 DDRC &= ~(1 << DDC5); PORTC |= (1 << PORT5); // enable internal pullup resistor + #endif + + #ifdef __AVR_ATmega328P__ + DDRB |= (1 << PB5); + PORTB &= ~(1 << PB5); + #endif // UART0 interface on Nano-644 UCSR0A = (1 << U2X0); @@ -148,15 +150,19 @@ int main () { sei(); - // TestUnit *unit[] = { - // &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp, &lcd, &uart1, &modbus, &ieee485, - // &i2cMaster, &i2cSlave, &i2cSparkfun - // }; + #ifdef __AVR_ATmega644P__ + TestUnit *unit[] = { + &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp, &lcd, &uart1, &modbus, &ieee485, + &i2cMaster, &i2cSlave, &i2cSparkfun + }; + #endif - TestUnit *unit[] = { - &led, &encoder, &lcd, - &i2cMaster, &i2cSlave, &i2cSparkfun - }; + #ifdef __AVR_ATmega328P__ + TestUnit *unit[] = { + &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &lcd, + &i2cMaster, &i2cSlave, &i2cSparkfun + }; + #endif while (1) { uint16_t i; @@ -176,9 +182,10 @@ int main () { } while (sscanf(s, "%x", &i) != 1 || i < 0 || i >= sizeof(unit) / sizeof(unit[0]) ); TestUnit *pu = unit[i]; - printf_P(PSTR("\n\n[%s]: "), pu->getName()); + printf_P(PSTR("\n\n[")); printf_P(pu->getName()); printf_P(PSTR("]: ")); keyUart0 = EOF; + pu->init(); for (uint8_t subtest = 0; subtest < 0xff; subtest++) { printf_P(PSTR("\n%4d: "), subtest); if (pu->run(subtest) < 0) { @@ -250,11 +257,9 @@ ISR (TIMER2_COMPA_vect) { // every 100us if (encoder.enabled) { encoder.tick100us(); } - #ifdef MOTOR_HPP - if (motor.enabled) { - motor.tick100us(); - } - #endif + if (motor.enabled) { + motor.tick100us(); + } timer100us++; if (timer100us >= 10) { @@ -270,7 +275,14 @@ ISR (TIMER2_COMPA_vect) { // every 100us timer500ms++; if (timer500ms >= 5000) { - PORTC ^= (1 << PORTC3); // orange LED blinking + #ifdef __AVR_ATmega644P__ + PORTC ^= (1 << PC3); // orange LED blinking + #endif + #ifdef __AVR_ATmega328P__ + if (!seg7.enabled) { + PORTB ^= (1 << PB5); // LED L + } + #endif timer500ms = 0; } } diff --git a/software/arduino-nano-5v/test_2024-07-23/src/main.hpp b/software/arduino-nano-5v/test_2024-07-23/src/main.hpp index f60ec89..bef51b6 100644 --- a/software/arduino-nano-5v/test_2024-07-23/src/main.hpp +++ b/software/arduino-nano-5v/test_2024-07-23/src/main.hpp @@ -13,6 +13,7 @@ extern uint64_t millis (); class TestUnit { public: virtual int8_t run (uint8_t subtest) = 0; + virtual void init () = 0; virtual void cleanup () = 0; virtual PGM_P getName () = 0; }; diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/encoder.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/encoder.cpp index bc84f48..975f358 100644 --- a/software/arduino-nano-5v/test_2024-07-23/src/units/encoder.cpp +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/encoder.cpp @@ -4,10 +4,6 @@ #include "encoder.hpp" #include "../main.hpp" -// PB0/T0 ... Encoder A -// PB1/T1 ... Encoder B -// PB2/INT2 ... push switch of encoder (pushed = 0) - // Encoder signals on rotation clockwise 1 step: // A -----____------ one char app. 1ms..2ms (rotation speed) // B -------___----- @@ -18,57 +14,113 @@ // B --______----- // one step when: A = 0, B= 0->1 +#ifdef __AVR_ATmega644P__ + + // Nano-644 + // --------------------------------------------------------------- + // PB0/T0 ... Encoder A + // PB1/T1 ... Encoder B + // PB2/INT2 ... push switch of encoder (pushed = 0) + + void Encoder::init () { + DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0)); + PORTB |= (1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0); // enable pullup + enabled = 1; + } + + void Encoder::cleanup () { + enabled = 0; + DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0)); + PORTB &= ~((1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0)); + } + + bool Encoder::isPressed () { + return (PINB & (1 << PB2)) == 0; + } + + bool Encoder::getA () { + return (PINB & (1 << PB0)) == 0; + } + + bool Encoder::getB () { + return (PINB & (1 << PB1)) == 0; + } + + +#endif + +#ifdef __AVR_ATmega328P__ + + // Arduino-Nano-5V + // --------------------------------------------------------------- + // PD4/T0 ... Encoder A + // PB0 ... Encoder B + // PD7 ... push switch of encoder (pushed = 0) + + void Encoder::init () { + DDRB &= ~(1 << PB0); + DDRD &= ~((1 << PD7) | (1 << PD4)); + PORTB |= (1 << PB0); // enable pullup + PORTD |= (1 << PD7) | (1 << PD4); // enable pullup + enabled = 1; + } + + void Encoder::cleanup () { + enabled = 0; + PORTB &= ~(1 << PB0); + PORTD &= ~((1 << PD7) | (1 << PD4)); + DDRB &= ~(1 << PB0); + DDRD &= ~((1 << PD7) | (1 << PD4)); + } + + bool Encoder::isPressed () { + return (PIND & (1 << PD7)) == 0; + } + + bool Encoder::getA () { + return (PIND & (1 << PD4)) == 0; + } + + bool Encoder::getB () { + return (PINB & (1 << PB0)) == 0; + } + +#endif -void Encoder::cleanup () { - DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0)); - PORTB &= ~((1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0)); - enabled = 0; -} int8_t Encoder::run (uint8_t subtest) { switch (subtest) { case 0: { - printf_P(PSTR("init")); - DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0)); - PORTB |= (1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0); // enable pullup - enabled = 1; - return 0; - } - - case 1: { while (wait(10) == EOF) { printf_P(PSTR("\r => Encoder (push to clear): ")); printf_P(PSTR("%5d (0x%02x) "), count, (uint8_t)count); - if ((PINB & (1 << PINB2)) == 0) { + if (isPressed()) { reset(); } } return 0; } - - case 2: { - printf_P(PSTR("end")); - break; - } } return -1; } struct EncoderState { - uint8_t a:1; // signal A - uint8_t b:1; // signal B + int8_t a:1; // signal A + int8_t b:1; // signal B }; void Encoder::tick100us () { static EncoderState lastState = { 1, 1 }; static EncoderState lastStableState = { 1, 1 }; - if ((DDRB & 0x03) || (PORTB & 0x07) != 0x07) { + if (!enabled) { count = 0; - return; // Enocder pins not configured + return; } - EncoderState nextState = { (PINB & 0x01) == 0x01, (PINB & 0x02) == 0x02 }; + EncoderState nextState; + nextState.a = getA() ? 1 : 0; + nextState.b = getB() ? 1 : 0; if (nextState.a == lastState.a && nextState.b == lastState.b) { if (lastStableState.a == 0 && nextState.b != lastStableState.b) { if (nextState.b == 0) { diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/encoder.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/encoder.hpp index 10bcc0f..9b0861b 100644 --- a/software/arduino-nano-5v/test_2024-07-23/src/units/encoder.hpp +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/encoder.hpp @@ -12,11 +12,17 @@ class Encoder : public TestUnit { public: Encoder () { reset(); enabled = 0; }; + virtual void init (); virtual void cleanup (); virtual int8_t run (uint8_t subtest); virtual PGM_P getName () { return PSTR("Encoder"); } void reset () { count = 0; } void tick100us (); + bool isPressed (); + + private: + bool getA (); + bool getB (); }; #endif \ No newline at end of file diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/i2c.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/i2c.cpp index 4c5934f..0c92e13 100644 --- a/software/arduino-nano-5v/test_2024-07-23/src/units/i2c.cpp +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/i2c.cpp @@ -23,6 +23,16 @@ PGM_P I2c::getName () { return "?"; } +void I2c::init () { + TWBR = 13; // 100kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 100000) / (2 * 100000 * 4); + TWBR = 28; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); + TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); + TWCR = (1 << TWEN); + ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V + ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 + enabled = true; +} + void I2c::cleanup () { enabled = false; TWCR = (1 << TWEN); @@ -32,17 +42,7 @@ void I2c::cleanup () { } int8_t I2c::run (uint8_t subtest) { - if (subtest == 0) { - TWBR = 13; // 100kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 100000) / (2 * 100000 * 4); - TWBR = 28; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); - TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); - TWCR = (1 << TWEN); - ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V - ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 - enabled = true; - printf_P(PSTR("init")); - - } else if (subtest == 1 && mode == I2c::SparkFunEnvCombo) { + if (subtest == 0 && mode == I2c::SparkFunEnvCombo) { printf_P(PSTR(" BM280 ... ")); if (!bm280.begin()) { printf_P(PSTR("E1")); @@ -156,7 +156,7 @@ int8_t I2c::run (uint8_t subtest) { } while (wait(1000) == EOF); - } else if (subtest == 1 && mode == I2c::Master) { + } else if (subtest == 0 && mode == I2c::Master) { if (!master.begin(0x01)) { printf_P(PSTR("E1")); return -1; @@ -180,7 +180,7 @@ int8_t I2c::run (uint8_t subtest) { } while (wait(1000) == EOF); master.end(); - } else if (subtest == 1 && mode == I2c::Slave) { + } else if (subtest == 0 && mode == I2c::Slave) { if (!slave.begin(0x01, false)) { printf_P(PSTR("E1")); return -1; @@ -214,87 +214,3 @@ void I2c::handleTwiIrq () { TWCR |= (1 << TWINT); // clear Interrupt Request } } - -// uint16_t I2c::startRead (uint8_t address) { -// TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition -// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done -// uint8_t sr = TWSR & 0xf8; -// if (sr != 0x08 && sr != 0x10) { -// return 0x0100 | sr; -// } - -// TWDR = (address << 1) | 0x01; // address + READ (R/W = 1) -// TWCR = (1 << TWINT) | (1 << TWEN); // send address/RW -// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done -// sr = TWSR & 0xf8; -// if (sr != 0x40) { -// return 0x0200 | sr; -// } -// return 0; -// } - -// uint16_t I2c::startWrite (uint8_t address) { -// TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition -// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done -// uint8_t sr = TWSR & 0xf8; -// if (sr != 0x08 && sr != 0x10) { -// return 0x0300 | sr; -// } - -// TWDR = (address << 1) | 0x00; // address + WRITE (R/W = 0) -// TWCR = (1 << TWINT) | (1 << TWEN); // send address/RW -// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done -// sr = TWSR & 0xf8; -// if (sr != 0x18) { -// return 0x0400 | sr; -// } -// return 0; -// } - -// void I2c::stop () { -// TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); -// } - -// uint16_t I2c::writeData (uint8_t size, const uint8_t *data) { -// while (size-- > 0) { -// TWDR = *data++; -// TWCR = (1 << TWINT) | (1 << TWEN); // send data byte -// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done -// uint8_t sr = TWSR & 0xf8; -// if (sr != 0x28) { -// return 0x0500 | sr; -// } -// } -// return 0; -// } - -// uint16_t I2c::writeByte (uint8_t data) { -// return writeData(1, &data); -// } - -// uint16_t I2c::readData (uint8_t size, uint8_t *data) { -// while (size-- > 0) { -// if (size > 0) { -// TWCR = (1 << TWEA) | (1 << TWINT) | (1 << TWEN); // read data byte with ACK enabled -// } else { -// TWCR = (1 << TWINT) | (1 << TWEN); // read data byte with ACK disabled -// } -// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done -// uint8_t sr = TWSR & 0xf8; -// if ((size > 0 && sr != 0x50) || (size == 0 && sr != 0x58)) { -// return 0x0600 | sr; -// } -// *data++ = TWDR; -// } -// return 0; -// } - -// int32_t I2c::compensateBm280T (int32_t adcT) { -// // int32_t var1, var2, t; -// // var1 = ((((adcT >> 3) - ((int32_t)bm280.digT[0] << 1))) * ((int32_t)bm280.digT[1])) >> 11; -// // var2 = (((((adcT >> 4) - ((int32_t)bm280.digT[0])) * ((adcT >> 4) - ((int32_t)bm280.digT[0]))) >> 12) * ((int32_t)bm280.digT[2])) >> 14; -// // bm280.tFine = var1 + var2; -// // t = (bm280.tFine * 5 + 128) >> 8; -// // return t; -// return -1; -// } diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/i2c.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/i2c.hpp index e1f1802..f039366 100644 --- a/software/arduino-nano-5v/test_2024-07-23/src/units/i2c.hpp +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/i2c.hpp @@ -26,6 +26,7 @@ class I2c : public TestUnit { public: I2c (I2cMode mode) { enabled = false; this->mode = mode; } void tick1ms () { master.tick1ms(); slave.tick1ms(); } + virtual void init (); virtual void cleanup (); virtual int8_t run (uint8_t subtest); virtual PGM_P getName (); diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/ieee485.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/ieee485.cpp index 414efb2..3d0bfca 100644 --- a/software/arduino-nano-5v/test_2024-07-23/src/units/ieee485.cpp +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/ieee485.cpp @@ -12,6 +12,7 @@ // ------------------------------------ // IEE485 not supported (no UART1) +void Ieee485::init () {} void Ieee485::cleanup () {} int8_t Ieee485::run (uint8_t subtest) { return -1; @@ -32,6 +33,29 @@ int8_t Ieee485::run (uint8_t subtest) { #define SET_DE (PORTB |= (1 << PB1)) #define CLR_DE (PORTB &= ~(1 << PB1)) +void Ieee485::init () { + // Poti + ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V + ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 + + // Modbus + 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 < +#include +#include + +#include "modbus.hpp" +#include "../main.hpp" + + +#ifdef __AVR_ATmega328P__ +void Modbus::init () {} +void Modbus::cleanup () {} +int8_t Modbus::run (uint8_t subtest) { return -1; } +void Modbus::handleRxByte (uint8_t b) {} +#endif + +#ifdef __AVR_ATmega644P__ + +// 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::init () { +} + +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_P(PSTR(" 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_P(PSTR("0x%02x received"), received[0]); + receivedBytes = 0; + } else { + printf_P(PSTR("no byte received")); + } + printf_P(PSTR(" ... 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_P(PSTR("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_P(PSTR(" 0x%02x"), frame[i]); + } + int k = wait(100); + + printf_P(PSTR("\n RxD1:")); + if (receivedBytes == 0) { + printf_P(PSTR("?")); + } else { + for (uint8_t i = 0; i < receivedBytes; i++) { + if (i == sizeof(frame)) { + printf_P(PSTR(" ")); + } + printf_P(PSTR(" 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_P(PSTR(" -> %4.8fV\n"), (double)f.value); + } + if (k != EOF) { + break; + } + + } while (wait(1000) == EOF); + + } else { + printf_P(PSTR("end")); + return -1; + } + wait(500); + return 0; +} + +void Modbus::handleRxByte (uint8_t b) { + if (receivedBytes < sizeof(received)) { + received[receivedBytes++] = b; + } +} + +#endif \ No newline at end of file diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/modbus.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/modbus.hpp new file mode 100644 index 0000000..44b6a9d --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/modbus.hpp @@ -0,0 +1,24 @@ +#ifndef MODBUS_HPP +#define MODBUS_HPP + +#include +#include "../main.hpp" +#include + +class Modbus : public TestUnit { + public: + uint8_t enabled; + uint8_t receivedBytes; + uint8_t received[16]; + + + public: + Modbus () { enabled = 0; receivedBytes = 0; } + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Modbus"); } + void handleRxByte (uint8_t); +}; + +#endif \ No newline at end of file diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/motor.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/motor.cpp new file mode 100644 index 0000000..eac61bb --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/motor.cpp @@ -0,0 +1,207 @@ +#include +#include +#include + +#include "motor.hpp" +#include "../main.hpp" + +#ifdef __AVR_ATmega644P__ + + // Nano-644 + // --------------------------------------------------------------- + // PB0 ..... rotation-sensor + // PB2 ..... nFault + // PB3 ..... PWM (OC0A) + // PB4 ..... EN + // PA3 ..... SW3 -> push button for Motor enable control + + #define ADC0K 64 + + void Motor::init () { + ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V + ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 + TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00); // Fast PWM on OC0A + // TCCR0B = (1 << CS02) | ( 1 << CS00); // f = 12 MHz / 1024 = 11,71875 kHz -> fPWM=45Hz + TCCR0B = (1 << CS02); // f = 12 MHz / 256 = 46,875 kHz -> fPWM=183,1Hz + DDRB |= (1 << PB4) | (1 << PB3); // Motor enable + PORTA |= (1 << PORTA3); // push button for Motor enable control + setEnable(); + enabled = 1; + } + + void Motor::cleanup () { + ADMUX = 0; + ADCSRA = 0; + TCCR0A = 0; + TCCR0B = 0; + DDRB &= ~((1 << PB4) | (1 << PB3)); + PORTA &= ~(1 << PORTA3); + enabled = 0; + } + + bool Motor::isSW3Pressed () { + return (PINA & (1 << PC3)) == 0; + } + + void Motor::clearEnable () { + PORTB &= ~(1 << PB4); + } + + void Motor::setEnable () { + PORTB |= (1 << PB4); + } + + bool Motor::isFaultLow () { + return (PINB & (1 << PB2)) == 0; + } + + bool Motor::isSensorHigh () { + return (PINB & (1 << PB0)) != 0; + } +#endif + +#ifdef __AVR_ATmega328P__ + + // Arduino-Nano-5V + // --------------------------------------------------------------- + // PD4 ..... rotation-sensor + // PD7 ..... nFault + // PD6/OC0A ..... PWM + // PB2 ..... EN + // PC3 ..... SW3 -> push button for Motor enable control + + #define ADC0K 91 + + void Motor::init () { + ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=5V + ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 + TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00); // Fast PWM on OC0A + // TCCR0B = (1 << CS02) | ( 1 << CS00); // f = 16 MHz / 1024 = 15,625 kHz -> fPWM=61.04Hz + TCCR0B = (1 << CS02); // f = 16 MHz / 256 = 62.5 kHz -> fPWM=244.14Hz + DDRB |= (1 << PB2); + DDRC &= ~(1 << PC3); + DDRD |= (1 << PD6); + DDRD &= ~((1 << PD4) | (1 << PD7)); + PORTC |= ( 1 << PC3); + PORTD |= (1 << PD7) | (1 << PD5); + setEnable(); + enabled = 1; + } + + void Motor::cleanup () { + enabled = 0; + ADMUX = 0; + ADCSRA = 0; + TCCR0A = 0; + TCCR0B = 0; + clearEnable(); + DDRB &= ~((1 << PB2)); + DDRC &= ~(1 << PC3); + DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4)); + PORTC &= ~( 1 << PC3); + PORTD &= ~((1 << PD7) | (1 << PD6)); + } + + bool Motor::isSW3Pressed () { + return (PINC & (1 << PC3)) == 0; + } + + void Motor::clearEnable () { + PORTB &= ~(1 << PB2); + } + + void Motor::setEnable () { + PORTB |= (1 << PB2); + } + + bool Motor::isFaultLow () { + return (PIND & (1 << PD7)) == 0; + } + + bool Motor::isSensorHigh () { + return (PIND & (1 << PD4)) != 0; + } + +#endif + +int8_t Motor::run (uint8_t subtest) { + switch (subtest) { + case 0: { + printf_P(PSTR("\n")); + while (wait(10) == EOF) { + + printf_P(PSTR("\r SW3=%d->"), isSW3Pressed() ? 0 : 1); + if (isSW3Pressed()) { + clearEnable(); + printf_P(PSTR("EN=0")); + } else { + setEnable(); + printf_P(PSTR("EN=1")); + } + + ADCSRA |= (1 << ADSC); // start ADC + while (ADCSRA & (1 << ADSC)) {} // wait for result + printf_P(PSTR("\r => ADC0=%3d"), ADCH); + + ADMUX = (1 << ADLAR) | (1 << REFS1) | (1 << REFS0) | 2; // ADC2, VREF=2.5V + + int16_t x = ((int16_t)(ADCH) - 5) * ADC0K / 64; + if (x < 0) x = 0; else if (x > 255) x = 255; + uint8_t dutyCycle = 0xff - (uint8_t)x; + if (dutyCycle <= 1) { + dutyCycle = 0; + } else if (dutyCycle > 254) { + dutyCycle = 255; + } + OCR0A = dutyCycle; + printf_P(PSTR(" PWM/OC0A=%3d"), dutyCycle); + + ADCSRA |= (1 << ADSC); // start ADC + while (ADCSRA & (1 << ADSC)) {} // wait for result + printf_P(PSTR(" ADC2=%3d"), ADCH); + ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V + + printf_P(PSTR(" nFAULT=%d"), isFaultLow() ? 0 : 1); + printf_P(PSTR(" SENSOR=%d "), isSensorHigh()); + uint16_t timer; + ATOMIC_BLOCK(ATOMIC_FORCEON) { + timer = rpmTimer; + } + float rpm = 60.0 / (float)timer / 0.0001; + if (timer > 0) { + printf_P(PSTR(" n= %4d U/min"), (int)rpm); + } else { + printf_P(PSTR(" no rotation ")); + } + + } + return 0; + } + } + + return -1; +} + +void Motor::tick100us () { + static uint16_t timerH = 0; + static uint16_t timerL = 0; + static bool lastSensorHigh = false; + + bool sensorHigh = isSensorHigh(); + if (!sensorHigh && sensorHigh != lastSensorHigh && timerL > 10) { + rpmTimer = timerL + timerH; + timerL = 0; + timerH = 0; + } + if (sensorHigh) { + timerH = timerH < 0x4000 ? timerH + 1 : 0x4000; + } else { + timerL = timerL < 0x4000 ? timerL + 1 : 0x4000; + } + if (timerH >= 0x4000 || timerL >= 0x4000) { + rpmTimer = 0; // no ratation detected + } + lastSensorHigh = sensorHigh; +} + + diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/motor.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/motor.hpp new file mode 100644 index 0000000..6dc68f0 --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/motor.hpp @@ -0,0 +1,29 @@ +#ifndef MOTOR_HPP +#define MOTOR_HPP + +#include +#include "../main.hpp" +#include + +class Motor : public TestUnit { + public: + uint8_t enabled; + uint16_t rpmTimer; + + public: + Motor () { enabled = 0; rpmTimer = 0; }; + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Motor"); } + void tick100us (); + + private: + bool isSW3Pressed (); + void clearEnable (); + void setEnable (); + bool isFaultLow (); + bool isSensorHigh (); +}; + +#endif \ No newline at end of file diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/portexp.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/portexp.cpp new file mode 100644 index 0000000..409d1f8 --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/portexp.cpp @@ -0,0 +1,169 @@ +#include +#include +#include + +#include "portexp.hpp" +#include "../main.hpp" + +// Port-Expander MCP23S17 + +// SN-Print Stecker IO16 +// MCP23S17 | IO16 (MEGA2560) | Ampel-Print | | MCP23S17 | IO16 (MEGA2560) | Ampel-Print | +// ------------------------------------------ -------------------------------------------- +// GPA0 | IO16O7 (PA7) | Taster RU | | GPB0 | IO16U7 (PC7) | Taster LU | +// GPA1 | IO16O6 (PA6) | Taster RO | | GPB1 | IO16U6 (PC6) | Taster LO | +// GPA2 | IO16O5 (PA5) | U-Gruen | | GPB2 | IO16U5 (PC5) | R-Gruen | +// GPA3 | IO16O4 (PA4) | U-Gelb | | GPB3 | IO16U4 (PC4) | R-Gelb | +// GPA4 | IO16O3 (PA3) | U-Rot | | GPB4 | IO16U3 (PC3) | R-Rot | +// GPA5 | IO16O2 (PA2) | L-Gruen | | GPB5 | IO16U2 (PC2) | O-Gruen | +// GPA6 | IO16O1 (PA1) | L-Gelb | | GPB6 | IO16U1 (PC1) | O-Gelb | +// GPA7 | IO16O0 (PA0) | L-Rot | | GPB7 | IO16U0 (PC0) | O-Rot | + +#ifdef __AVR_ATmega644P__ + + // Nano-644 + // -------------------------------------------------------- + // PA7 ... nCS + // PB5 ... MOSI + // PB6 ... MISO + // PB7 ... SCK + + void PortExp::init () { + PRR &= (1 << PRSPI); + PORTA |= (1 << PA7); + DDRA |= (1 << PA7); // SPI nCS + // PORTB/DDRB must be configured before SPCR !! + PORTB |= (1 << PB4); // nSS must be HIGH, otherwise SPI master will not become active!! + DDRB |= (1 << PB7) | (1 << PB5) | (1 << PB4); // SPI SCK (=PB7) and SPI MOSI (=PB5) + + // SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // SPI enable , Master, f=12MHz/128=93,75kHz + SPCR = (1 << SPE) | (1 << MSTR); // SPI enable , Master, f=12MHz/4 = 3MHz + } + + void PortExp::cleanup () { + DDRB &= ~(1 << PB6); // // SPI MISO (=PB6) + DDRB &= ~((1 << PB7) | (1 << PB5)); // SPI SCK (=PB7) and SPI MOSI (=PB5) + DDRA &= ~(1 << PA7); + PORTA &= ~(1 << PA7); // SPI nCS + SPCR = 0; + } + + void PortExp::setChipEnable () { + PORTA &= ~(1 << PA7); + } + + void PortExp::clearChipEnable () { + PORTA |= (1 << PA7); + } + + +#endif + +#ifdef __AVR_ATmega328P__ + + // Arduino-Nano-5V + // ------------------------------------ + // PC1 ... nCS (MANUAL (!) connection PA1 - PA7 required) + // PB3 ... MOSI + // PB4 ... MISO + // PB5 ... SCK + + void PortExp::init () { + PRR &= (1 << PRSPI); + PORTC |= (1 << PC1); + DDRC |= (1 << PC1); // SPI nCS + // PORTB/DDRB must be configured before SPCR !! + PORTB |= (1 << PB2); // nSS must be HIGH, otherwise SPI master will not become active!! + DDRB |= (1 << PB5) | (1 << PB3) | (1 << PB2); // SPI SCK (=PB5), SPI MOSI (=PB3), SPI nSS (=PB2) + + // SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // SPI enable , Master, f=16MHz/128=125kHz + SPCR = (1 << SPE) | (1 << MSTR); // SPI enable , Master, f=12MHz/4 = 3MHz + } + + void PortExp::cleanup () { + PORTC &= ~(1 << PC1); + DDRC &= ~(1 << PC1); + PORTB &= ~(1 << PB2); + DDRB &= ~((1 << PB5) | (1 << PB3) | (1 << PB2)); + SPCR = 0; + } + + void PortExp::setChipEnable () { + PORTC &= ~(1 << PC1); + } + + void PortExp::clearChipEnable () { + PORTC |= (1 << PC1); + } + +#endif + + + +int8_t PortExp::writeByte (uint8_t addr, uint8_t b) { + + setChipEnable(); + + SPDR = 0x40; // WRITE BYTE + while ((SPSR & (1 << SPIF)) == 0) {} + if (SPDR != 0) { + printf_P(PSTR("E1")); + clearChipEnable(); + return -1; + } + + SPDR = addr; // register address + while ((SPSR & (1 << SPIF)) == 0) {} + if (SPDR != 0) { + printf_P(PSTR("E2")); + clearChipEnable(); + return -1; + } + + SPDR = b; // value + while ((SPSR & (1 << SPIF)) == 0) {} + if (SPDR != 0) { + printf_P(PSTR("E3")); + clearChipEnable(); + return -1; + } + + clearChipEnable(); + + _delay_us(5); + return 0; +} + +int8_t PortExp::run (uint8_t subtest) { + if (subtest == 0) { + while (wait(500) == EOF) { + printf_P(PSTR("\n => start ...")); + for (uint8_t i = 0; i < 8; i++) { + writeByte(0, ~(1 << i)); // IODIRA (Bank = 0) + // writeByte(0, 0x00); // IODIRA (Bank = 0) - all output + writeByte(0x12, (1 << i)); // GPIOA (Bank = 0) + printf_P(PSTR("\n Bank0 - GPA%d = 1"), i); + wait(200); + writeByte(0x12, 0); // GPIOA (Bank = 0) + printf_P(PSTR("\n Bank0 - GPA%d = 0"), i); + writeByte(0, 0xff); // IODIRA (Bank = 0) + wait(200); + } + for (uint8_t i = 0; i < 8; i++) { + writeByte(1, ~(1 << i)); // IODIRB (Bank = 0) + // writeByte(1, 0x00); // IODIRB (Bank = 0) - all output + writeByte(0x13, (1 << i)); // GPIOB (Bank = 0) + printf_P(PSTR("\n Bank0 - GPB%d = 1"), i); + wait(200); + writeByte(0x13, 0); // GPIOB (Bank = 0) + printf_P(PSTR("\n Bank0 - GPB%d = 0"), i); + writeByte(1, 0xff); // IODIRB (Bank = 0) + wait(200); + } + } + return 0; + } + + return -1; +} + diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/portexp.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/portexp.hpp new file mode 100644 index 0000000..2fb665c --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/portexp.hpp @@ -0,0 +1,22 @@ +#ifndef PORTEXP_HPP +#define PORTEXP_HPP + +#include +#include "../main.hpp" +#include + +class PortExp : public TestUnit { + public: + PortExp () {}; + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("PortExp"); } + + private: + void setChipEnable (); + void clearChipEnable (); + int8_t writeByte (uint8_t addr, uint8_t b); +}; + +#endif \ No newline at end of file diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/poti.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/poti.cpp new file mode 100644 index 0000000..94fc5a4 --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/poti.cpp @@ -0,0 +1,34 @@ +#include +#include + +#include "poti.hpp" +#include "../main.hpp" + +void Poti::init () { + ADMUX = (1 << REFS0); // ADC0, VREF=AVCC=3.3V + ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 +} + +void Poti::cleanup () { + ADMUX = 0; + ADCSRA = 0; +} + +int8_t Poti::run (uint8_t subtest) { + switch (subtest) { + case 0: { + printf_P(PSTR("\n")); + while (wait(10) == EOF) { + printf_P(PSTR("\r => Measure ADC0: ")); + ADCSRA |= (1 << ADSC); // start ADC + while (ADCSRA & (1 << ADSC)) {} // wait for result + printf_P(PSTR("%4d (0x%03x)"), ADC, ADC); + } + return 0; + } + } + + return -1; +} + + diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/poti.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/poti.hpp new file mode 100644 index 0000000..b13dd29 --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/poti.hpp @@ -0,0 +1,17 @@ +#ifndef POTI_HPP +#define POTI_PP + +#include +#include "../main.hpp" +#include + +class Poti : public TestUnit { + public: + Poti () {}; + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Poti"); } +}; + +#endif \ No newline at end of file diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/r2r.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/r2r.cpp new file mode 100644 index 0000000..ef299ce --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/r2r.cpp @@ -0,0 +1,46 @@ +#include +#include + +#include "r2r.hpp" +#include "../main.hpp" + +#ifdef __AVR_ATmega644P__ + // AVCC=3.3, POTI Vmax=3.3V + #define K 1.0 +#endif + +#ifdef __AVR_ATmega328P__ + // AVCC=4.7V, POTI Vmax=3.3V + #define K (1023.0 / 738.0) +#endif + +void R2r::init () { + ADMUX = (1 << REFS0) | 2; // ADC2, VREF=AVCC=3.3V + ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 +} + +void R2r::cleanup () { + ADMUX = 0; + ADCSRA = 0; +} + +int8_t R2r::run (uint8_t subtest) { + switch (subtest) { + case 0: { + printf_P(PSTR("\n")); + while (wait(10) == EOF) { + printf_P(PSTR("\r => Measure ADC2: ")); + ADCSRA |= (1 << ADSC); // start ADC + while (ADCSRA & (1 << ADSC)) {} // wait for result + printf_P(PSTR("%4d (0x%03x)"), ADC, ADC); + uint8_t sw = (uint8_t)( ((float)(ADC) + 32.0) / 64.0 * K ); + printf_P(PSTR(" SW9:6 = %d %d% d %d "), sw >> 3, (sw >> 2) & 0x01, (sw >> 1) & 0x01, sw & 0x01 ); + } + return 0; + } + } + + return -1; +} + + diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/r2r.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/r2r.hpp new file mode 100644 index 0000000..84e97e6 --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/r2r.hpp @@ -0,0 +1,17 @@ +#ifndef R2R_HPP +#define R2R_PP + +#include +#include "../main.hpp" +#include + +class R2r : public TestUnit { + public: + R2r () {}; + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("R2R"); } +}; + +#endif \ No newline at end of file diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/rgb.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/rgb.cpp new file mode 100644 index 0000000..c52454d --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/rgb.cpp @@ -0,0 +1,152 @@ +#include +#include + +#include "rgb.hpp" +#include "../main.hpp" + +#ifdef __AVR_ATmega644P__ + + // Nano-644 + // --------------------------------------------------------------- + // PB0 ..... Red (inverse logic -> 0 = ON) + // PB1 ..... Green (inverse logic -> 0 = ON) + // PB2 ..... Blue (inverse logic -> 0 = ON) + + void Rgb::init () { + ledOff(RED); + ledOff(GREEN); + ledOff(BLUE); + DDRB |= (1 << PB2) | (1 << PB1) | (1 << PB0); + } + + void Rgb::cleanup () { + ledOff(RED); + ledOff(GREEN); + ledOff(BLUE); + DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0)); + } + + void Rgb::setLed (LED led, bool on) { + if (on) { + switch(led) { + case RED: PORTB |= (1 << PB0); break; + case GREEN: PORTB |= (1 << PB1); break; + case BLUE: PORTB |= (1 << PB2); break; + } + } else { + switch(led) { + case RED: PORTB &= ~(1 << PB0); break; + case GREEN: PORTB &= ~(1 << PB1); break; + case BLUE: PORTB &= ~(1 << PB2); break; + } + } + } + + void Rgb::ledToggle (LED led) { + switch(led) { + case RED: PORTB ^= (1 << PB0); break; + case GREEN: PORTB ^= (1 << PB1); break; + case BLUE: PORTB ^= (1 << PB2); break; + } + } + + +#endif + +#ifdef __AVR_ATmega328P__ + + // Arduino-Nano-5V + // --------------------------------------------------------------- + // PD4 ..... Red (inverse logic -> 0 = ON) + // PB0 ..... Green (inverse logic -> 0 = ON) + // PD7 ..... Blue (inverse logic -> 0 = ON) + + void Rgb::init () { + ledOff(RED); + ledOff(GREEN); + ledOff(BLUE); + DDRB |= (1 << PB0); + DDRD |= (1 << PD7) | (1 << PD4); + } + + void Rgb::cleanup () { + ledOff(RED); + ledOff(GREEN); + ledOff(BLUE); + DDRB &= ~(1 << PB0); + DDRD &= ~((1 << PD7) | (1 << PD4)); + } + + void Rgb::setLed (LED led, bool on) { + if (on) { + switch (led) { + case RED: PORTD &= ~(1 << PD4); break; + case GREEN: PORTB &= ~(1 << PB0); break; + case BLUE: PORTD &= ~(1 << PD7); break; + } + } else { + switch (led) { + case RED: PORTD |= (1 << PD4); break; + case GREEN: PORTB |= (1 << PB0); break; + case BLUE: PORTD |= (1 << PD7); break; + } + } + } + + void Rgb::ledToggle (LED led) { + switch (led) { + case RED: PORTD ^= (1 << PD4); break; + case GREEN: PORTB ^= ~(1 << PB0); break; + case BLUE: PORTD ^= (1 << PD7); break; + } + } + +#endif + +void Rgb::ledOn (LED led) { + setLed(led, true); +} + +void Rgb::ledOff (LED led) { + setLed(led, false); +} + +int8_t Rgb::run (uint8_t subtest) { + switch (subtest) { + case 0: { + ledOn(RED); + printf_P(PSTR("Red")); + wait(3000); + ledOff(RED); + return 0; + } + + case 1: { + ledOn(GREEN); + printf_P(PSTR("Green")); + wait(3000); + ledOff(GREEN); + return 0; + } + + case 2: { + ledOn(BLUE); + printf_P(PSTR("Blue")); + wait(3000); + ledOff(BLUE); + return 0; + } + + case 3: { + ledOn(RED); ledOn(GREEN); ledOn(BLUE); + printf_P(PSTR("All")); + wait(3000); + ledOff(RED); ledOff(GREEN); ledOff(BLUE); + return 0; + } + } + + return -1; +} + + diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/rgb.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/rgb.hpp new file mode 100644 index 0000000..12e9da4 --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/rgb.hpp @@ -0,0 +1,25 @@ +#ifndef RGB_HPP +#define RGB_PP + +#include +#include "../main.hpp" +#include + +class Rgb : public TestUnit { + public: + enum LED { RED, GREEN, BLUE }; + + public: + Rgb () {}; + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Rgb"); } + + void setLed (LED led, bool on); + void ledOn (LED led); + void ledOff (LED led); + void ledToggle (LED led); +}; + +#endif \ No newline at end of file diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/seg7.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/seg7.cpp new file mode 100644 index 0000000..42ae93b --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/seg7.cpp @@ -0,0 +1,210 @@ +#include +#include + +#include "seg7.hpp" +#include "../main.hpp" + +#ifdef __AVR_ATmega644P__ + + // Nano-644 + // --------------------------------------------------------------- + + // PA0 ... Cathode Char 1 + // PA1 ... Cathode Char 2 + // PA2 ... Cathode Char 3 + // PA3 ... Cathode Char 4 + + // PB0 ... Anode Segment A + // PB1 ... Anode Segment B + // PB2 ... Anode Segment C + // PB3 ... Anode Segment D + // PB4 ... Anode Segment E + // PB5 ... Anode Segment F + // PB6 ... Anode Segment G + // PB7 ... Anode DP + + // PD5 ... nOE (Output Enable) for all LEDs + // PD6 ... Anode L1:2 + // PD7 ... Anode L3 + +void Seg7::init () { + setAnodes(0); + setCathodes(0); + DDRA |= (1 << PA3) | (1 << PA2) | (1 << PA1) | (1 << PA0); + DDRB = 0xff; + DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD5); + } + + void Seg7::cleanup () { + setAnodes(0); + setCathodes(0); + DDRA &= ~((1 << PA3) | (1 << PA2) | (1 << PA1) | (1 << PA0)); + DDRB = 0x00; + DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5)); + } + + void Seg7::setAnodes (uint16_t a) { + if (a & 0x0001) PORTD |= (1 << PD4); else PORTD &= ~(1 << PD4); // Anode Char A + if (a & 0x0002) PORTB |= (1 << PB0); else PORTB &= ~(1 << PB0); // Anode Char B + if (a & 0x0004) PORTD |= (1 << PD7); else PORTD &= ~(1 << PD7); // Anode Char C + if (a & 0x0008) PORTD |= (1 << PD6); else PORTD &= ~(1 << PD6); // Anode Char D + if (a & 0x0010) PORTB |= (1 << PB2); else PORTB &= ~(1 << PB2); // Anode Char E + if (a & 0x0020) PORTB |= (1 << PB3); else PORTB &= ~(1 << PB3); // Anode Char F + if (a & 0x0040) PORTB |= (1 << PB4); else PORTB &= ~(1 << PB4); // Anode Char G + if (a & 0x0080) PORTB |= (1 << PB5); else PORTB &= ~(1 << PB5); // Anode Char DP + if (a & 0x0100) PORTD |= (1 << PD3); else PORTD &= ~(1 << PD3); // Anode L1/L2 + if (a & 0x0200) PORTD |= (1 << PD2); else PORTD &= ~(1 << PD2); // Anode L3 + } + + void Seg7::setCathodes (uint8_t c) { + if (c & 0x01) PORTC |= (1 << PC0); else PORTC &= ~(1 << PC0); // Chathode Char 1 (most left) + if (c & 0x02) PORTC |= (1 << PC1); else PORTC &= ~(1 << PC1); // Chathode Char 2 + if (c & 0x04) PORTC |= (1 << PC2); else PORTC &= ~(1 << PC2); // Chathode Char 3 + if (c & 0x08) PORTC |= (1 << PC3); else PORTC &= ~(1 << PC3); // Chathode Char 4 (most right) + } + + void Seg7::setOE (bool enabled) { + if (enabled) { + PORTB &= ~(1 << PB1); + } else { + PORTB |= (1 << PB1); + } + } + + void Seg7::init () { + + PORTB = 0; + DDRB = 0xff; + PORTD &= ~((1 < +#include "../main.hpp" +#include + +class Seg7 : public TestUnit { + public: + bool enabled; + + public: + Seg7 () { enabled = false; } + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Seg7"); } + + private: + void setAnodes (uint16_t); + void setCathodes (uint8_t mask); + void setOE (bool enabled); +}; + +#endif \ No newline at end of file diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/switch.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/switch.cpp new file mode 100644 index 0000000..45866a4 --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/switch.cpp @@ -0,0 +1,100 @@ +#include +#include +#include + +#include "switch.hpp" +#include "../main.hpp" + +#ifdef __AVR_ATmega644P__ + + // Nano-644 + // --------------------------------------------------------------- + // PA0 ..... SW1 + // PA1 ..... SW2 + // PA2 ..... SW3 + // PA3 ..... SW4 + + void Switch::init () { + DDRA &= ~((1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0)); + PORTA |= (1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0); + } + + void Switch::cleanup () { + PORTA &= ~((1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0)); + DDRA &= ~((1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0)); + } + + bool Switch::isPressed (SWITCH sw) { + switch (sw) { + case SW1: return (PINA & ( 1 << PA0)) == 0; + case SW2: return (PINA & ( 1 << PA1)) == 0; + case SW3: return (PINA & ( 1 << PA2)) == 0; + case SW4: return (PINA & ( 1 << PA3)) == 0; + default: return false; + } + } + +#endif + +#ifdef __AVR_ATmega328P__ + + // Arduino-Nano-5V + // --------------------------------------------------------------- + // PC0 ..... SW1 + // PC1 ..... SW2 + // PC2 ..... SW3 + // PC3 ..... SW4 + + void Switch::init () { + DDRC &= ~((1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0)); + PORTC |= (1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0); + } + + void Switch::cleanup () { + PORTC &= ~((1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0)); + DDRC &= ~((1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0)); + } + + bool Switch::isPressed (SWITCH sw) { + switch (sw) { + case SW1: return (PINC & ( 1 << PC0)) == 0; + case SW2: return (PINC & ( 1 << PC1)) == 0; + case SW3: return (PINC & ( 1 << PC2)) == 0; + case SW4: return (PINC & ( 1 << PC3)) == 0; + default: return false; + } + } + +#endif + +int8_t Switch::run (uint8_t subtest) { + if (subtest < 16) { + SWITCH sw = (SWITCH)(subtest / 4); + switch (subtest % 4) { + case 1: { + if (!isPressed(sw)) { + printf_P(PSTR("Press SW%d"), sw + 1); + while (!isPressed(sw) && wait(0) == EOF) {} + wait(10); + } + return 0; + } + + case 0: case 2: { + if (isPressed(sw)) { + printf_P(PSTR("Release SW%d "), sw + 1); + while (isPressed(sw) && wait(0) == EOF) {} + wait(10); + } + return 0; + } + + case 3: { + return 0; + } + } + + } + + return -1; +} diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/switch.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/switch.hpp new file mode 100644 index 0000000..03bf0b2 --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/switch.hpp @@ -0,0 +1,20 @@ +#ifndef SWITCH_HPP +#define SWITCH_HPP + +#include +#include "../main.hpp" +#include + +class Switch : public TestUnit { + typedef enum { SW1 = 0, SW2 = 1, SW3 = 2, SW4 = 3 } SWITCH; + + public: + Switch () {}; + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Switch"); } + bool isPressed (SWITCH sw); +}; + +#endif \ No newline at end of file diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/uart1.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/uart1.cpp new file mode 100644 index 0000000..aba6d92 --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/uart1.cpp @@ -0,0 +1,69 @@ +#include +#include +#include + +#include "uart1.hpp" +#include "../main.hpp" + +#ifdef __AVR_ATmega328P__ + void Uart1::init () {} + void Uart1::cleanup () {} + int8_t Uart1::run (uint8_t subtest) { return -1; } + void Uart1::handleRxByte (uint8_t b) {} +#endif + +#ifdef __AVR_ATmega644P__ + +int uart1_putchar(char c, FILE *stream) { + if (c == '\n') { + uart1_putchar('\r', stream); + } + loop_until_bit_is_set(UCSR1A, UDRE1); + UDR1 = c; + return 0; +} + +static FILE mystderr = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart1_putchar, NULL, 0 }; + +void Uart1::cleanup () { + enabled = 0; + UCSR1A = 0; + UCSR1B = 0; + UCSR1C = 0; + UBRR1H = 0; + UBRR1L = 0; + stderr = NULL; +} + +int8_t Uart1::run (uint8_t subtest) { + if (subtest == 0) { + // UART1 interface on Nano-644 + PORTD |= (1 << PD2); // enable RxD1 pullup + UCSR1A = (1 << U2X1); + UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 < send text via UART1 now...")); + fprintf_P(stderr, PSTR("Hello UART1, ECHO-Modus active\n")); + } while (wait(5000) == EOF); + + } else { + printf_P(PSTR("end")); + return -1; + } + wait(500); + return 0; +} + +void Uart1::handleRxByte (uint8_t b) { + uart1_putchar(b, stderr); +} + +#endif \ No newline at end of file diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/uart1.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/uart1.hpp new file mode 100644 index 0000000..40437e1 --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/uart1.hpp @@ -0,0 +1,21 @@ +#ifndef UART1_HPP +#define UART1_HPP + +#include +#include "../main.hpp" +#include + +class Uart1 : public TestUnit { + public: + uint8_t enabled; + + public: + Uart1 () { enabled = 0; } + virtual void init (); + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Uart1"); } + void handleRxByte (uint8_t); +}; + +#endif \ No newline at end of file