Hallo zusammen,
ich versuche mich gerade an dem Setzen von Schieberegistern, gesteuert entweder über den COM-Port oder über ein Parallelinterface.
Im Grundzustand sollen die Schieberegister über den COM-Port kontrolliert werden.
Wenn der Latchpin des parallelen Interface auf high wechselt, soll entprellt das Bitmuster an den latchBitPins ausgelesen und der entsprechende Kanal gesetzt werden. Während der Latchpin high ist, soll das Bitmuster nicht weiter eingelesen werden und über den COM-Port sollen nur Hilfsbefehle ausgeführt werden können, aber kein setzen von Kanälen.
Diesen Code habe ich mir hierfür aus als mehr oder weniger gut funktionierend bekannten Codeschnipseln zusammengestückelt. Bevor ich jetzt an das große Debugging gehe, kann/sollte man das überhaupt so machen? Habe ich groben Unfug fabriziert? Geht es besser/eleganter/stabiler?
#define SCLK PIN_PC1
#define LATCH PIN_PB2
#define MOSI PIN_PE3
#define MISO PIN_PC0
const uint8_t shiftregistercount = 4;
const uint8_t channelcount = 18;
const uint8_t channelassignment[channelcount] = {
18, 19, 20, 21, 22, 23, 24, 25, 26,
13, 12, 11, 10, 9, 8, 7, 6, 5
};
uint8_t outputdata[shiftregistercount];
uint8_t routputdata[shiftregistercount];
uint8_t allon[shiftregistercount];
// Parallelinterface
const uint8_t latchBitPins[5] = {2, 3, 4, 5, 6}; // 5 Bitmuster-Pins
const uint8_t LATCHPIN = 7; // Latch-Signalpin
unsigned long lastLatchCheck = 0;
const uint16_t latchSampleInterval = 50;
uint8_t stableLatchCounter = 0;
uint8_t lastStablePattern = 255;
bool latchActive = false;
bool latchPending = false;
bool latchWasHigh = false;
void setup() {
pinMode(SCLK, OUTPUT);
pinMode(LATCH, OUTPUT);
pinMode(MOSI, OUTPUT);
pinMode(MISO, INPUT);
digitalWrite(SCLK, LOW);
digitalWrite(LATCH, LOW);
digitalWrite(MOSI, LOW);
for (uint8_t i = 0; i < channelcount; i++) {
uint8_t pointer = channelassignment[i];
allon[pointer >> 3] |= (1 << (pointer & 7));
}
for (int i = 0; i < 5; i++) pinMode(latchBitPins[i], INPUT);
pinMode(LATCHPIN, INPUT);
Serial.begin(115200);
}
void loop() {
// Parallelinterface mit Latch-Flankenerkennung und Bitmusterstabilität
bool latchNow = digitalRead(LATCHPIN) == HIGH;
if (millis() - lastLatchCheck >= latchSampleInterval) {
lastLatchCheck = millis();
if (latchNow && !latchWasHigh) {
latchPending = true;
stableLatchCounter = 0;
lastStablePattern = 255;
}
latchWasHigh = latchNow;
if (latchNow && latchPending) {
uint8_t currentPattern = 0;
for (int i = 0; i < 5; i++) {
if (digitalRead(latchBitPins[i])) {
currentPattern |= (1 << i);
}
}
if (currentPattern == lastStablePattern) {
stableLatchCounter++;
} else {
stableLatchCounter = 1;
lastStablePattern = currentPattern;
}
if (stableLatchCounter >= 4 && currentPattern < channelcount) {
latchActive = true;
latchPending = false;
resetalloutputs();
setoutput(currentPattern);
shiftoutdata();
}
}
if (!latchNow) {
latchActive = false;
latchPending = false;
stableLatchCounter = 0;
lastStablePattern = 255;
}
}
// USB-Kommandos
if (Serial.available()) {
String cmdStr = Serial.readStringUntil('\n');
cmdStr.trim();
processCommand(cmdStr.c_str());
}
}
void processCommand(const char* cmd) {
if (strlen(cmd) < 2) {
Serial.println(F("ERR: Command too short"));
return;
}
char cmd1 = cmd[0];
char cmd2 = cmd[1];
int ch = 0;
if (strlen(cmd) > 2) {
ch = atoi(cmd + 2); // Kanalnummer (optional)
}
uint16_t code = (cmd1 << 8) | cmd2;
// Sperre nur für schreibende Kommandos während latchActive
bool isWriteCommand = (code == ('S' << 8 | 'H')) || (code == ('S' << 8 | 'L')) ||
(code == ('A' << 8 | 'H')) || (code == ('A' << 8 | 'L')) ||
(code == ('S' << 8 | 'T'));
if (latchActive && isWriteCommand) {
Serial.println(F("ERR: Channel modification disabled during latch active"));
return;
}
switch (code) {
case ('S' << 8 | 'H'): // SH - Set HIGH (ein Kanal auf 1)
if (ch < 1 || ch > channelcount) {
Serial.println(F("ERR: Invalid channel"));
} else {
setoutput(ch - 1);
Serial.println(F("OK"));
}
break;
case ('S' << 8 | 'L'): // SL - Set LOW (ein Kanal auf 0)
if (ch < 1 || ch > channelcount) {
Serial.println(F("ERR: Invalid channel"));
} else {
resetoutput(ch - 1);
Serial.println(F("OK"));
}
break;
case ('A' << 8 | 'H'): // AH - Alle HIGH
setalloutputs();
Serial.println(F("ALL HIGH"));
break;
case ('A' << 8 | 'L'): // AL - Alle LOW
resetalloutputs();
Serial.println(F("ALL LOW"));
break;
case ('S' << 8 | 'T'): // ST - Shift & Test
shiftoutdata();
{
bool all_match = true;
for (uint8_t i = 0; i < shiftregistercount; i++) {
if (outputdata[i] != routputdata[i]) all_match = false;
}
Serial.println(all_match ? F("UPDATED OK") : F("ERROR: Mismatch"));
}
break;
case ('P' << 8 | 'H'): // PH - Print HIGH
Serial.print(F("HIGH: "));
for (uint8_t i = 0; i < channelcount; i++) {
if (readoutput(i)) {
Serial.print(i + 1);
Serial.print(' ');
}
}
Serial.println();
break;
case ('P' << 8 | 'L'): // PL - Print LOW
Serial.print(F("LOW: "));
for (uint8_t i = 0; i < channelcount; i++) {
if (!readoutput(i)) {
Serial.print(i + 1);
Serial.print(' ');
}
}
Serial.println();
break;
case ('H' << 8 | 'P'): // HP - Hilfe
Serial.println(F("Verfuegbare Kommandos:"));
Serial.println(F("SH[n] - Set channel HIGH (1-basiert)"));
Serial.println(F("SL[n] - Set channel LOW"));
Serial.println(F("AH - All HIGH"));
Serial.println(F("AL - All LOW"));
Serial.println(F("ST - Shift and verify"));
Serial.println(F("PH - Print HIGH channels"));
Serial.println(F("PL - Print LOW channels"));
Serial.println(F("HP - Help"));
break;
default:
Serial.println(F("ERR: Unknown command"));
break;
}
}
void shiftoutdata() {
digitalWrite(SCLK, LOW);
digitalWrite(LATCH, LOW);
digitalWrite(MOSI, LOW);
for (int j = shiftregistercount - 1; j >= 0; j--) {
for (int i = 7; i >= 0; i--) {
digitalWrite(SCLK, LOW);
digitalWrite(MOSI, (outputdata[j] >> i) & 1);
digitalWrite(SCLK, HIGH);
}
}
digitalWrite(SCLK, LOW);
digitalWrite(LATCH, HIGH);
digitalWrite(LATCH, LOW);
for (int j = shiftregistercount - 1; j >= 0; j--) {
for (int i = 7; i >= 0; i--) {
routputdata[j] = (routputdata[j] & ~(1 << i)) | (digitalRead(MISO) << i);
digitalWrite(SCLK, HIGH);
digitalWrite(SCLK, LOW);
}
}
}
void setoutput(uint8_t pointer) {
pointer = channelassignment[pointer];
outputdata[pointer >> 3] |= (1 << (pointer & 7));
}
void resetoutput(uint8_t pointer) {
pointer = channelassignment[pointer];
outputdata[pointer >> 3] &= ~(1 << (pointer & 7));
}
bool readoutput(uint8_t pointer) {
pointer = channelassignment[pointer];
return (outputdata[pointer >> 3] >> (pointer & 7)) & 1;
}
void setalloutputs() {
for (int i = 0; i < shiftregistercount; i++) {
outputdata[i] = allon[i];
}
}
void resetalloutputs() {
for (int i = 0; i < shiftregistercount; i++) {
outputdata[i] = 0;
}
}
Vielen Dank im voraus für eure Antworten ![]()
Beste Grüße
Dominic