Added DN23E08 arduino code and added chaser.py

This commit is contained in:
Geens 2024-08-07 12:45:46 +02:00
parent 4329650116
commit a221cd04b7
14 changed files with 511 additions and 84 deletions

30
DN23E08/DN23E08.ino Normal file
View File

@ -0,0 +1,30 @@
#include <ModbusSerial.h>
#include "coils.h"
#include "discrete_inputs.h"
#include "input_registers.h"
#define BAUD_RATE 57600
#define SLAVE_ID 1
ModbusSerial mb (Serial, SLAVE_ID);
uint8_t led;
void setup() {
Serial.begin (BAUD_RATE);
while (! Serial);
mb.config(BAUD_RATE);
setupCoils(mb);
setupDiscreteInputs(mb);
setupInputRegisters(mb);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
digitalWrite(LED_BUILTIN, led > 128);
led++;
discreteInputsTask(mb);
inputRegistersTask(mb);
mb.task();
coilsTask(mb);
}

125
DN23E08/coils.cpp Normal file
View File

@ -0,0 +1,125 @@
#include "coils.h"
void mbToCoils(ModbusSerial& mb);
void coilsToShiftOutRegisters(size_t i);
void outputShiftOutRegisters();
Coils coils;
ShiftOutRegistersUnion shiftOutRegisters;
size_t digitIndex;
void setupCoils(ModbusSerial& mb) {
pinMode(DATA_PIN_595, OUTPUT);
pinMode(OE_PIN_595, OUTPUT);
pinMode(LATCH_PIN_595, OUTPUT);
pinMode(CLOCK_PIN_595, OUTPUT);
digitalWrite(OE_PIN_595, LOW);
for (size_t i = 0; i < COIL_COUNT; i++)
mb.addCoil (i);
}
void coilsTask(ModbusSerial& mb) {
mbToCoils(mb);
coilsToShiftOutRegisters(digitIndex);
digitIndex = (digitIndex + 1) % 4;
outputShiftOutRegisters();
}
void mbToCoils(ModbusSerial& mb) {
coils.relays.J1 = mb.coil(0);
coils.relays.J2 = mb.coil(1);
coils.relays.J3 = mb.coil(2);
coils.relays.J4 = mb.coil(3);
coils.relays.J5 = mb.coil(4);
coils.relays.J6 = mb.coil(5);
coils.relays.J7 = mb.coil(6);
coils.relays.J8 = mb.coil(7);
coils.digit0.A = mb.coil(8);
coils.digit0.B = mb.coil(9);
coils.digit0.C = mb.coil(10);
coils.digit0.D = mb.coil(11);
coils.digit0.E = mb.coil(12);
coils.digit0.F = mb.coil(13);
coils.digit0.G = mb.coil(14);
coils.digit0.H = mb.coil(15);
coils.digit1.A = mb.coil(16);
coils.digit1.B = mb.coil(17);
coils.digit1.C = mb.coil(18);
coils.digit1.D = mb.coil(19);
coils.digit1.E = mb.coil(20);
coils.digit1.F = mb.coil(21);
coils.digit1.G = mb.coil(22);
coils.digit1.H = mb.coil(23);
coils.digit2.A = mb.coil(24);
coils.digit2.B = mb.coil(25);
coils.digit2.C = mb.coil(26);
coils.digit2.D = mb.coil(27);
coils.digit2.E = mb.coil(28);
coils.digit2.F = mb.coil(29);
coils.digit2.G = mb.coil(30);
coils.digit2.H = mb.coil(31);
coils.digit3.A = mb.coil(32);
coils.digit3.B = mb.coil(33);
coils.digit3.C = mb.coil(34);
coils.digit3.D = mb.coil(35);
coils.digit3.E = mb.coil(36);
coils.digit3.F = mb.coil(37);
coils.digit3.G = mb.coil(38);
coils.digit3.H = mb.coil(39);
}
void coilsToShiftOutRegisters(size_t i) {
switch(i) {
case 0:
shiftOutRegisters.shiftOutRegisters.u6 = coils.digit0;
shiftOutRegisters.shiftOutRegisters.u8.G1 = 0;
shiftOutRegisters.shiftOutRegisters.u8.G2 = 1;
shiftOutRegisters.shiftOutRegisters.u8.G3 = 1;
shiftOutRegisters.shiftOutRegisters.u8.G4 = 1;
shiftOutRegisters.shiftOutRegisters.u5 = coils.relays;
break;
case 1:
shiftOutRegisters.shiftOutRegisters.u6 = coils.digit1;
shiftOutRegisters.shiftOutRegisters.u8.G1 = 1;
shiftOutRegisters.shiftOutRegisters.u8.G2 = 0;
shiftOutRegisters.shiftOutRegisters.u8.G3 = 1;
shiftOutRegisters.shiftOutRegisters.u8.G4 = 1;
shiftOutRegisters.shiftOutRegisters.u5 = coils.relays;
break;
case 2:
shiftOutRegisters.shiftOutRegisters.u6 = coils.digit2;
shiftOutRegisters.shiftOutRegisters.u8.G1 = 1;
shiftOutRegisters.shiftOutRegisters.u8.G2 = 1;
shiftOutRegisters.shiftOutRegisters.u8.G3 = 0;
shiftOutRegisters.shiftOutRegisters.u8.G4 = 1;
shiftOutRegisters.shiftOutRegisters.u5 = coils.relays;
break;
default:
shiftOutRegisters.shiftOutRegisters.u6 = coils.digit3;
shiftOutRegisters.shiftOutRegisters.u8.G1 = 1;
shiftOutRegisters.shiftOutRegisters.u8.G2 = 1;
shiftOutRegisters.shiftOutRegisters.u8.G3 = 1;
shiftOutRegisters.shiftOutRegisters.u8.G4 = 0;
shiftOutRegisters.shiftOutRegisters.u5 = coils.relays;
break;
}
}
void outputShiftOutRegisters() {
digitalWrite(LATCH_PIN_595, LOW);
shiftOut(DATA_PIN_595, CLOCK_PIN_595, MSBFIRST, shiftOutRegisters.bytes[2]);
shiftOut(DATA_PIN_595, CLOCK_PIN_595, MSBFIRST, shiftOutRegisters.bytes[1]);
shiftOut(DATA_PIN_595, CLOCK_PIN_595, MSBFIRST, shiftOutRegisters.bytes[0]);
digitalWrite(LATCH_PIN_595, HIGH);
}

63
DN23E08/coils.h Normal file
View File

@ -0,0 +1,63 @@
#pragma once
#include <Arduino.h>
#include <ModbusSerial.h>
#define COIL_COUNT 40
#define DATA_PIN_595 9
#define OE_PIN_595 10
#define LATCH_PIN_595 11
#define CLOCK_PIN_595 12
struct U6 {
bool A: 1;
bool B: 1;
bool C: 1;
bool D: 1;
bool E: 1;
bool F: 1;
bool G: 1;
bool H: 1;
};
struct U8 {
bool G1: 1;
bool G2: 1;
bool G3: 1;
bool G4: 1;
unsigned NC: 4;
};
struct U5 {
bool J1: 1;
bool J2: 1;
bool J3: 1;
bool J4: 1;
bool J5: 1;
bool J6: 1;
bool J7: 1;
bool J8: 1;
};
struct ShiftOutRegisters {
U6 u6;
U8 u8;
U5 u5;
};
union ShiftOutRegistersUnion {
ShiftOutRegisters shiftOutRegisters;
uint8_t bytes[3];
};
struct Coils {
U5 relays;
U6 digit0;
U6 digit1;
U6 digit2;
U6 digit3;
};
void setupCoils(ModbusSerial& mb);
void coilsTask(ModbusSerial& mb);

View File

@ -0,0 +1,61 @@
#include "discrete_inputs.h"
ShiftInRegisterUnion shiftInRegister;
Keys keys;
DiscreteInputs discreteInputs;
void setupDiscreteInputs(ModbusSerial& mb) {
pinMode(KEY_1_PIN, INPUT_PULLUP);
pinMode(KEY_2_PIN, INPUT_PULLUP);
pinMode(KEY_3_PIN, INPUT_PULLUP);
pinMode(KEY_4_PIN, INPUT_PULLUP);
pinMode(LOAD_PIN_165, OUTPUT);
pinMode(CLOCK_PIN_165, OUTPUT);
pinMode(DATA_PIN_165, INPUT);
for (size_t i = 0; i < DISCRETE_INPUT_COUNT; i++)
mb.addIsts(i);
}
void discreteInputsTask(ModbusSerial& mb) {
keys.KEY_1 = !digitalRead(KEY_1_PIN);
keys.KEY_2 = !digitalRead(KEY_2_PIN);
keys.KEY_3 = !digitalRead(KEY_3_PIN);
keys.KEY_4 = !digitalRead(KEY_4_PIN);
digitalWrite(CLOCK_PIN_165, HIGH);
digitalWrite(LOAD_PIN_165, LOW);
digitalWrite(LOAD_PIN_165, HIGH);
shiftInRegister.byte = shiftIn(DATA_PIN_165, CLOCK_PIN_165, MSBFIRST) ^ 0XFF;
discreteInputs.digitalInputs = shiftInRegister.shiftInRegister;
discreteInputs.keys = keys;
mb.setIsts(0, discreteInputs.digitalInputs.INPUT1);
mb.setIsts(1, discreteInputs.digitalInputs.INPUT2);
mb.setIsts(2, discreteInputs.digitalInputs.INPUT3);
mb.setIsts(3, discreteInputs.digitalInputs.INPUT4);
mb.setIsts(4, discreteInputs.digitalInputs.INPUT5);
mb.setIsts(5, discreteInputs.digitalInputs.INPUT6);
mb.setIsts(6, discreteInputs.digitalInputs.INPUT7);
mb.setIsts(7, discreteInputs.digitalInputs.INPUT8);
mb.setIsts(8, discreteInputs.keys.KEY_1);
mb.setIsts(9, discreteInputs.keys.KEY_2);
mb.setIsts(10, discreteInputs.keys.KEY_3);
mb.setIsts(11, discreteInputs.keys.KEY_4);
}

46
DN23E08/discrete_inputs.h Normal file
View File

@ -0,0 +1,46 @@
#pragma once
#include <Arduino.h>
#include <ModbusSerial.h>
#define DISCRETE_INPUT_COUNT 12
#define DATA_PIN_165 2
#define CLOCK_PIN_165 3
#define LOAD_PIN_165 4
#define KEY_1_PIN 5
#define KEY_2_PIN 6
#define KEY_3_PIN 7
#define KEY_4_PIN 8
struct U11 {
bool INPUT1: 1;
bool INPUT2: 1;
bool INPUT3: 1;
bool INPUT4: 1;
bool INPUT5: 1;
bool INPUT6: 1;
bool INPUT7: 1;
bool INPUT8: 1;
};
union ShiftInRegisterUnion {
U11 shiftInRegister;
uint8_t byte;
};
struct Keys {
bool KEY_1;
bool KEY_2;
bool KEY_3;
bool KEY_4;
};
struct DiscreteInputs {
U11 digitalInputs;
Keys keys;
};
void setupDiscreteInputs(ModbusSerial& mb);
void discreteInputsTask(ModbusSerial& mb);

View File

@ -0,0 +1,50 @@
#include "input_registers.h"
AnalogInputs analogInputs;
void setupInputRegisters(ModbusSerial& mb) {
pinMode(ADC_0_PIN, INPUT);
pinMode(ADC_1_PIN, INPUT);
pinMode(ADC_2_PIN, INPUT);
pinMode(ADC_3_PIN, INPUT);
pinMode(ADC_4_PIN, INPUT);
pinMode(ADC_5_PIN, INPUT);
pinMode(ADC_6_PIN, INPUT);
pinMode(ADC_7_PIN, INPUT);
for (size_t i = 0; i < INPUT_REGISTERS_COUNT; i++)
mb.addIreg(i);
}
void inputRegistersTask(ModbusSerial& mb) {
analogInputs.ADC_0 = analogRead(ADC_0_PIN);
analogInputs.ADC_1 = analogRead(ADC_1_PIN);
analogInputs.ADC_2 = analogRead(ADC_2_PIN);
analogInputs.ADC_3 = analogRead(ADC_3_PIN);
analogInputs.ADC_4 = analogRead(ADC_4_PIN);
analogInputs.ADC_5 = analogRead(ADC_5_PIN);
analogInputs.ADC_6 = analogRead(ADC_6_PIN);
analogInputs.ADC_7 = analogRead(ADC_7_PIN);
mb.setIreg(0, analogInputs.ADC_0);
mb.setIreg(1, analogInputs.ADC_1);
mb.setIreg(2, analogInputs.ADC_2);
mb.setIreg(3, analogInputs.ADC_3);
mb.setIreg(4, analogInputs.ADC_4);
mb.setIreg(5, analogInputs.ADC_5);
mb.setIreg(6, analogInputs.ADC_6);
mb.setIreg(7, analogInputs.ADC_7);
}

29
DN23E08/input_registers.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include <Arduino.h>
#include <ModbusSerial.h>
#define INPUT_REGISTERS_COUNT 8
#define ADC_0_PIN A0
#define ADC_1_PIN A1
#define ADC_2_PIN A2
#define ADC_3_PIN A3
#define ADC_4_PIN A4
#define ADC_5_PIN A5
#define ADC_6_PIN A6
#define ADC_7_PIN A7
struct AnalogInputs {
uint16_t ADC_0;
uint16_t ADC_1;
uint16_t ADC_2;
uint16_t ADC_3;
uint16_t ADC_4;
uint16_t ADC_5;
uint16_t ADC_6;
uint16_t ADC_7;
};
void setupInputRegisters(ModbusSerial& mb);
void inputRegistersTask(ModbusSerial& mb);

View File

@ -1,4 +1,5 @@
from .chaser import Chaser
from .hardware import Hardware
from .logic import loop
from .buttons_timers_and_relays import ButtonsTimersAndRelays
from .timed_relays import TimedRelays
from .util import parse_commandline_args, connect_modbus_client

65
src/chaser.py Normal file
View File

@ -0,0 +1,65 @@
from enum import Enum
import time
from src.hardware import Hardware
class Chaser:
"""
Manages the state machine for the chaser.
"""
class State(Enum):
"""
Possible states
Make sure each state has a unique value!
"""
IDLE = 0
CHASING = 1
def __init__(self):
"""Initialize to state IDLE."""
self.current_state = self.State.IDLE
self.current_led = 0
self.chaser_sequence = [
0, # First display top segment
8, # Second display top segment
16, # Third display top segment
24, 25, 26, 27, # Fourth display
19, # Third display bottom segment
11, # Second display bottom segment
3, 4, 5 # First display remaining segments
]
self.last_update_time = time.time()
def update_state_machine(self, hardware: Hardware) -> None:
"""
Execute one iteration of the state machine loop.
Args:
hardware (Hardware): The hardware interface object.
"""
next_state = self.current_state
# State transitions
match self.current_state:
case self.State.IDLE:
if hardware.get_button_3():
next_state = self.State.CHASING
self.current_led = 0
case self.State.CHASING:
if hardware.get_button_2():
next_state = self.State.IDLE
elif hardware.get_button_3():
next_state = self.State.CHASING
self.current_led = 0
elif time.time() - self.last_update_time > 0.1: # 100ms delay
self.current_led = (self.current_led + 1) % len(self.chaser_sequence)
self.last_update_time = time.time()
self.current_state = next_state
# Outputs
for i in range(32):
hardware.set_led(i, False)
if self.current_state == self.State.CHASING:
hardware.set_led(self.chaser_sequence[self.current_led], True)

View File

@ -2,12 +2,12 @@ from pymodbus.client import ModbusSerialClient
class Hardware:
"""
Represents the hardware interface for the Arduino Python Modbus Example.
Represents the hardware interface and syncs with the Modbus device.
"""
def __init__(self, client: ModbusSerialClient, slave_id: int):
"""
Initialize the Hardware object.
Initialize to default values.
Args:
client (ModbusSerialClient): The Modbus client for communication.
@ -17,8 +17,13 @@ class Hardware:
self.slave_id = slave_id
self.relay_0 = False
self.relay_1 = False
self.leds = [False for i in range(32)]
self.button_0 = False
self.button_1 = False
self.button_2 = False
self.button_3 = False
def sync_hardware_state(self) -> None:
"""
@ -26,10 +31,13 @@ class Hardware:
"""
try:
self.client.write_coils(0, [self.relay_0, self.relay_1], slave=self.slave_id)
input_response = self.client.read_discrete_inputs(0, 2, slave=self.slave_id)
self.client.write_coils(8, self.leds, slave=self.slave_id)
input_response = self.client.read_discrete_inputs(8, 4, slave=self.slave_id)
if not input_response.isError():
self.button_0 = input_response.bits[0]
self.button_1 = input_response.bits[1]
self.button_2 = input_response.bits[2]
self.button_3 = input_response.bits[3]
except Exception as e:
print(f"Modbus error: {e}")
@ -41,10 +49,22 @@ class Hardware:
"""Set the state of relay 1."""
self.relay_1 = value
def set_led(self, index: int, value: bool) -> None:
"""Set the state of an LED."""
self.leds[index] = value
def get_button_0(self) -> bool:
"""Get the state of button 0."""
return self.button_0
def get_button_1(self) -> bool:
"""Get the state of button 1."""
return self.button_1
return self.button_1
def get_button_2(self) -> bool:
"""Get the state of button 2."""
return self.button_2
def get_button_3(self) -> bool:
"""Get the state of button 3."""
return self.button_3

View File

@ -1,13 +1,17 @@
from src.buttons_timers_and_relays import ButtonsTimersAndRelays
from src.chaser import Chaser
from src.timed_relays import TimedRelays
from src.hardware import Hardware
buttons_timers_relays = ButtonsTimersAndRelays()
chaser = Chaser()
timed_relays = TimedRelays()
def loop(hardware: Hardware) -> None:
"""
Main logic loop for the Arduino Python Modbus Example.
One iteration of the main logic loop.
Calls both state machines.
Args:
hardware (Hardware): The hardware interface object.
"""
buttons_timers_relays.update_state_machine(hardware)
chaser.update_state_machine(hardware)
timed_relays.update_state_machine(hardware)

View File

@ -2,13 +2,16 @@ from enum import Enum
import time
from src.hardware import Hardware
class ButtonsTimersAndRelays:
class TimedRelays:
"""
Manages the state machine for buttons, timers, and relays.
Manages the state machine for the relays controlled by the first 2 buttons.
"""
class State(Enum):
"""Enumeration of possible states for the state machine."""
"""
Possible states
Make sure each state has a unique value!
"""
RELAY_0_LOW = 0
RELAY_0_HIGH = 1
BUTTON_1_PRESSED = 2
@ -17,7 +20,7 @@ class ButtonsTimersAndRelays:
RELAY_1_HIGH_2 = 5
def __init__(self):
"""Initialize the ButtonsTimersAndRelays object."""
"""Initialize to state RELAY_0_LOW."""
self.current_state = self.State.RELAY_0_LOW
self.state_change_time = time.time()
self.time_in_current_state = 0

View File

@ -21,7 +21,7 @@ def parse_commandline_args() -> argparse.Namespace:
Returns:
argparse.Namespace: Parsed command line arguments.
"""
parser = argparse.ArgumentParser(description='Arduino Python Modbus Example')
parser = argparse.ArgumentParser(description='DN23E08 Python Modbus Example')
parser.add_argument('--com_port', type=str, default=get_default_com_port(),
help='COM port for the Modbus connection')
parser.add_argument('--slave_id', type=int, default=1,

View File

@ -1,70 +0,0 @@
#include <ModbusSerial.h>
#define BAUD_RATE 57600
#define SLAVE_ID 1
#define COIL_COUNT 4
#define COIL_START 1
#define COIL_0 4
#define COIL_1 5
#define COIL_2 6
#define COIL_3 7
#define STATUS_0 12
#define STATUS_1 11
ModbusSerial mb (Serial, SLAVE_ID);
void setup() {
Serial.begin (BAUD_RATE);
while (! Serial);
mb.config(BAUD_RATE);
mb.addCoil (0);
mb.addCoil (1);
mb.addCoil (2);
mb.addCoil (3);
mb.addIsts(0);
mb.addIsts(1);
pinMode(COIL_0, OUTPUT);
pinMode(COIL_1, OUTPUT);
pinMode(COIL_2, OUTPUT);
pinMode(COIL_3, OUTPUT);
pinMode(STATUS_0, INPUT_PULLUP);
pinMode(STATUS_1, INPUT_PULLUP);
}
void loop() {
mb.task();
readCoilValues();
writeStatusValues();
}
void readCoilValues() {
digitalWrite(COIL_0, mb.coil(0));
digitalWrite(COIL_1, mb.coil(1));
digitalWrite(COIL_2, mb.coil(2));
digitalWrite(COIL_3, mb.coil(3));
}
void writeStatusValues() {
mb.setIsts(0, !digitalRead(STATUS_0));
mb.setIsts(1, !digitalRead(STATUS_1));
}