A pulse is the opposite of a permanent signal. This means there is no such thing as a "permanent pulse".
What does "change state" mean in your case.
You should post a description in normal words that describe the functionality that you want to have.
still not precise enough.
answer from deepseek
I took you post 1 to 1 and prompted deepseek with it.
Hi deepseek,
i want to install a relay system that flashes every time an impulse(push button) is applied , but the code does not work well , because only with permanent pulse can i change the state. What could be wrong ?
//input pins for arduino
//const int leftSignalInPin = 2;
//const int rightSignalInPin = 3;
//const int leftSignalOutPin = 4;
//const int rightSignalOutPin = 5;
//input pins for attiny85
const int leftSignalInPin = 1;
const int rightSignalInPin = 2;
const int leftSignalOutPin = 3;
const int rightSignalOutPin = 4;
int leftSignalVal = 0;
int leftSignalState = 0;
int rightSignalVal = 0;
int rightSignalState = 0;
int delayForHazard = 500; // delay in milliseconds for hazard light combination
unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
int delayForSignal = 400; // signal frequency in milliseconds
unsigned long signalMillis = 0;
int signalBlink = 0;
int relayLowOrHighTriggering = 0; // 0 - for relays with low level triggering | 1 - for relays with hight level triggering
void setup() {
pinMode(leftSignalInPin, INPUT);
pinMode(rightSignalInPin, INPUT);
pinMode(leftSignalOutPin, OUTPUT);
pinMode(rightSignalOutPin, OUTPUT);
// setting the pins to the correct state
if (relayLowOrHighTriggering == 0) {
digitalWrite(leftSignalOutPin, HIGH);
digitalWrite(rightSignalOutPin, HIGH);
} else {
digitalWrite(leftSignalOutPin, LOW);
digitalWrite(rightSignalOutPin, LOW);
}
}
void loop() {
leftSignalVal = digitalRead(leftSignalInPin);
rightSignalVal = digitalRead(rightSignalInPin);
currentMillis = millis();
if (leftSignalVal == 1) {
leftSignalState = 1;
previousMillis = currentMillis;
} else {
if (currentMillis - previousMillis >= delayForHazard && signalBlink == 0) {
leftSignalState = 0;
}
}
if (rightSignalVal == 1) {
rightSignalState = 1;
previousMillis = currentMillis;
} else {
if (currentMillis - previousMillis >= delayForHazard && signalBlink == 0) {
rightSignalState = 0;
}
}
if (leftSignalState == 1) {
if (signalBlink == 1) {
if (relayLowOrHighTriggering == 0) {
digitalWrite(leftSignalOutPin, LOW);
} else {
digitalWrite(leftSignalOutPin, HIGH);
}
} else {
if (relayLowOrHighTriggering == 0) {
digitalWrite(leftSignalOutPin, HIGH);
} else {
digitalWrite(leftSignalOutPin, LOW);
}
}
} else {
if (relayLowOrHighTriggering == 0) {
digitalWrite(leftSignalOutPin, HIGH);
} else {
digitalWrite(leftSignalOutPin, LOW);
}
}
if (rightSignalState == 1) {
if (signalBlink == 1) {
if (relayLowOrHighTriggering == 0) {
digitalWrite(rightSignalOutPin, LOW);
} else {
digitalWrite(rightSignalOutPin, HIGH);
}
} else {
if (relayLowOrHighTriggering == 0) {
digitalWrite(rightSignalOutPin, HIGH);
} else {
digitalWrite(rightSignalOutPin, LOW);
}
}
} else {
if (relayLowOrHighTriggering == 0) {
digitalWrite(rightSignalOutPin, HIGH);
} else {
digitalWrite(rightSignalOutPin, LOW);
}
}
if (leftSignalState == 1 || rightSignalState == 1) {
if (signalMillis + delayForSignal > currentMillis) {
signalBlink = 1;
} else {
signalBlink = 0;
if (signalMillis + delayForSignal + delayForSignal < currentMillis) {
signalMillis = currentMillis;
}
}
}
}
analysis from deepseek
Okay, let's take a look at this code. The user is having an issue where the relay only changes state when the button is held down, but they want it to toggle with each button press. Hmm.
First, I'll check the input handling. They're reading the button state with digitalRead, but there's no debouncing. That might cause multiple triggers if the button isn't debounced. But the main issue seems to be that the state is only active while the button is pressed. So instead of latching the state, it's only on during the press.
Looking at the code, when the button is pressed (leftSignalVal == 1), they set leftSignalState = 1. When released, after delayForHazard, it resets to 0. But that's more like a momentary switch, not a toggle. The user probably wants each button press to toggle the state, not hold it. So the problem is that the code is designed for momentary activation instead of toggling.
The logic for turning off the signal after delayForHazard is probably intended for auto-off after a certain time, but the way it's structured, it's not allowing the state to stay on unless the button is held.
Wait, maybe they want the signal to flash for a certain duration when the button is pressed, but the current code requires the button to be held for the entire duration. So the user wants a single press to trigger the flashing for delayForHazard time, then auto-off. But right now, if you release the button, the code checks if the elapsed time since the last press is over delayForHazard and turns it off. So pressing the button briefly sets the state to 1, but if the button is released, after delayForHazard milliseconds, it turns off. But maybe the delayForHazard is too long, or the way they're handling the timing is off.
Another thing is the signalBlink variable. It's used to control the blinking. The code checks if left or right signal is active, then uses signalBlink to alternate the output. But the way signalBlink is managed might be incorrect. Let me see the part where signalBlink is updated.
In the last if block, if either signal is active, they check if signalMillis + delayForSignal > currentMillis. If so, set signalBlink to 1. Else, set to 0 and reset signalMillis if enough time has passed. Wait, signalMillis is only updated when the signals are active, and delayForSignal is 400ms. So this part is supposed to handle the blinking by toggling signalBlink every 400ms. But the logic here might not be correctly tracking the time intervals for blinking. Maybe they should use a separate previousMillis for each signal's blink timing.
Also, the code doesn't use edge detection for the button presses. Since the user wants a momentary button press to trigger a state change, they need to detect the rising edge of the button press (when it transitions from low to high) and then toggle the state. The current code just checks if the button is currently pressed, so holding it down keeps toggling, which isn't desired.
Wait, the user says that the relay only changes state when the button is held. That suggests that the code is not latching the state. So pressing the button once should toggle the relay's flashing, but instead, you have to hold it to keep it on.
So, the main issue is that the code doesn't toggle the state on a button press but instead sets it active only while the button is held. The user needs to implement edge detection to toggle the state when the button is pressed and released, not just when it's held.
Possible fixes:
-
Implement button press detection using edge triggering. Check for a rising edge (button pressed) and toggle the state. This requires tracking the previous state of the button to detect changes.
-
Add debouncing to the button inputs to avoid multiple triggers from a single press.
-
Adjust the timing logic so that once the button is pressed, the state is toggled and remains active for the desired duration (like delayForHazard), then automatically turns off.
Looking at the code, in the current setup, when the button is pressed (leftSignalVal == 1), leftSignalState is set to 1. But when the button is released, after delayForHazard, it's set back to 0. So if the user presses the button briefly, leftSignalState becomes 1, and after delayForHazard milliseconds, it turns off. But perhaps delayForHazard is the duration for the hazard lights? Or maybe the code is intended to have the signals stay on for a certain time after pressing the button.
Alternatively, maybe the user wants the relay to flash each time the button is pressed, regardless of how long it's held. So each button press should start a new flashing cycle.
But according to the problem statement, the code requires a permanent pulse (holding the button) to change the state. That suggests that the current logic is only active when the button is held. Therefore, the code isn't latching the state change on a button press.
So the fix would be to change the way leftSignalState and rightSignalState are updated. Instead of setting them to 1 when the button is pressed and 0 after a delay, they should toggle when the button is pressed and then turn off after the delay.
But how to detect a button press? The current code doesn't track the previous state of the button. For example, when leftSignalVal goes from 0 to 1, that's a press. But the code just checks if it's 1. So if you hold the button, it keeps setting leftSignalState to 1 every loop iteration.
To fix this, they need to track the previous state of the button. Here's an example approach:
For each button:
-
Check if the current state is HIGH and the previous state was LOW (rising edge).
-
When a rising edge is detected, toggle the signal state (leftSignalState = !leftSignalState) and record the time.
-
Then, if the signal state is active, check if the current time minus the recorded time exceeds delayForHazard. If so, turn it off.
This way, a single press toggles the state on, and after delayForHazard, it turns off automatically.
So modifying the code to use edge detection and auto-off after a certain time.
Another thing is that in the current code, both left and right signals use the same previousMillis variable. That might cause interference between the two signals. For example, pressing the right button would reset the previousMillis, affecting the left signal's timing. They should have separate previousMillis variables for each signal.
Also, the signalBlink logic might not be correctly implemented. The blinking frequency is controlled by delayForSignal, but the code uses signalMillis and checks if the current time is within a delayForSignal window. It alternates signalBlink between 1 and 0 every delayForSignal interval. However, the way signalMillis is updated might not be accurate. Normally, for blinking, you would track the last toggle time and switch the state each interval.
Putting it all together, the main issues are:
-
Lack of edge detection for button presses, leading to state changes only while the button is held.
-
Shared previousMillis between left and right signals, causing timing interference.
-
Incorrect blinking logic for the relays.
So, to fix the primary issue (state change on button press, not hold), implementing edge detection with separate previousMillis for each signal and toggling the state on press.
Let's outline the steps needed:
-
Track the previous state of each button to detect rising edges.
-
When a rising edge is detected (button pressed), toggle the corresponding signal state and record the start time.
-
After delayForHazard, automatically turn off the signal.
-
Implement separate timers for each signal's auto-off.
-
Correct the blinking logic to use separate timers for each signal's blinking.
Here's how the code can be modified:
- Add variables to track previous button states:
int leftPrevState = LOW;
int rightPrevState = LOW;
- In loop(), for each button:
leftSignalVal = digitalRead(leftSignalInPin);
if (leftSignalVal == HIGH && leftPrevState == LOW) {
// Rising edge detected
leftSignalState = !leftSignalState; // Toggle the state
leftPreviousMillis = currentMillis; // Record the time of toggle
}
leftPrevState = leftSignalVal;
// Similar for right signal
Then, for auto-off:
if (leftSignalState == HIGH && (currentMillis - leftPreviousMillis >= delayForHazard)) {
leftSignalState = LOW;
}
This way, pressing the button toggles the state, and it stays on for delayForHazard milliseconds before turning off.
Additionally, for blinking, each signal should have its own blink timer and state. Currently, signalBlink is a shared variable, which might cause both signals to blink in sync. Instead, each signal should manage its own blink state and timer.
But given the code's complexity, perhaps focusing first on fixing the button handling to toggle on press and auto-off after delayForHazard. Then, handle the blinking correctly.
In the original code, the logic after setting leftSignalState and rightSignalState controls the outputs with signalBlink. Let's see:
If leftSignalState is 1, then in the output section, it checks signalBlink. signalBlink is toggled every delayForSignal. But the way signalBlink is updated might not be correct. The code checks if either signal is active, then manages signalBlink based on signalMillis and currentMillis. However, this approach may not properly alternate the blink state every delayForSignal interval.
A better approach for blinking is to track the last time the output was toggled and switch it every delayForSignal/2 interval. For example, if you want a 400ms period (200ms on, 200ms off), you toggle every 200ms. But the current code uses a single delayForSignal, so perhaps it's using a 400ms on and 400ms off, which would be a 800ms period. That might not be intended.
Alternatively, using a non-blocking approach with millis() to toggle the blink state each delayForSignal interval. For example:
if (currentMillis - previousBlinkMillis >= delayForSignal) {
blinkState = !blinkState;
previousBlinkMillis = currentMillis;
}
Then, when the signal is active, set the output based on blinkState.
But in the current code, the signalBlink is set to 1 if (signalMillis + delayForSignal > currentMillis), which seems inverted. Let me parse that part:
if(leftSignalState == 1 || rightSignalState == 1){
if(signalMillis+delayForSignal > currentMillis){
signalBlink = 1;
} else {
signalBlink = 0;
if(signalMillis+delayForSignal+delayForSignal < currentMillis){
signalMillis = currentMillis;
}
}
}
This is confusing. Let's see: when a signal is active, check if currentMillis is less than signalMillis + delayForSignal. If yes, signalBlink is 1. Otherwise, set to 0 and, if twice the delay has passed, reset signalMillis.
Wait, maybe this is trying to alternate signalBlink between 1 and 0 every delayForSignal. But the logic is flawed. For example, suppose signalMillis is set when a signal becomes active. Then, for the first delayForSignal ms, signalBlink is 1. After that, it's 0. But if twice the delay passes, signalMillis is reset. So the blinking would be on for delayForSignal, then off until the next cycle. But this doesn't create a regular blink; it's a single pulse per activation.
This is incorrect for blinking. Instead, the blink should toggle every delayForSignal/2 interval. The current approach only allows for a single on period followed by off, which is not blinking.
So the blinking logic is incorrect. To fix this, the code should track the blink state separately and toggle it at each interval. For example:
static unsigned long previousBlinkMillis = 0;
static bool blinkState = false;
if (currentMillis - previousBlinkMillis >= delayForSignal) {
blinkState = !blinkState;
previousBlinkMillis = currentMillis;
}
Then, when a signal is active, use blinkState to turn the output on or off.
But in the current code, the signalBlink variable is set based on the time since signalMillis. But signalMillis is only updated when the signal is active and the time has passed twice the delay. This isn't correct for regular blinking.
Putting this together, the main issues are:
-
Button handling needs edge detection to toggle the state on press, not while held.
-
Separate timers for each signal's auto-off period.
-
Correct blinking logic using a periodic toggle.
So, rewriting the code to address these points:
-
Implement edge detection for buttons.
-
Use separate previousMillis for each signal's auto-off.
-
Use a proper blink interval with a periodic toggle.
Here's a revised approach:
// Pins and variables
const int leftSignalInPin = 1;
const int rightSignalInPin = 2;
const int leftSignalOutPin = 3;
const int rightSignalOutPin = 4;
int leftSignalState = 0;
int rightSignalState = 0;
unsigned long leftPreviousMillis = 0;
unsigned long rightPreviousMillis = 0;
unsigned long blinkPreviousMillis = 0;
int delayForHazard = 500; // Time until auto-off
int delayForSignal = 400; // Blink interval (total cycle)
bool blinkState = false;
int relayLowOrHighTriggering = 0;
// Button previous states
int leftPrev = LOW;
int rightPrev = LOW;
void setup() {
// Pin setup
}
void loop() {
unsigned long currentMillis = millis();
// Read buttons with edge detection
int leftCurrent = digitalRead(leftSignalInPin);
if (leftCurrent == HIGH && leftPrev == LOW) {
// Left button pressed
leftSignalState = 1;
leftPreviousMillis = currentMillis;
}
leftPrev = leftCurrent;
// Auto-off left after delayForHazard
if (leftSignalState && (currentMillis - leftPreviousMillis >= delayForHazard)) {
leftSignalState = 0;
}
// Similar for right button...
// Handle blinking
if (currentMillis - blinkPreviousMillis >= delayForSignal / 2) {
blinkState = !blinkState;
blinkPreviousMillis = currentMillis;
}
// Control outputs
digitalWrite(leftSignalOutPin, (leftSignalState && blinkState) ? (relayLowOrHighTriggering ? HIGH : LOW) : (relayLowOrHighTriggering ? LOW : HIGH));
// Similar for right...
}
Wait, but in this approach, the blinkState toggles every delayForSignal/2 ms, creating a square wave with period delayForSignal. So the output blinks on/off every delayForSignal/2 ms. That would give a proper blink.
But in the original code, the user might have intended that when the signal is active, it blinks with a certain frequency. The revised code handles that with a global blinkState, so all active signals blink in sync. If individual blinking is needed, each signal would need its own blink state and timer, but that's more complex. However, for simplicity, a global blink state is acceptable.
So, combining all these changes:
-
Edge detection for button presses.
-
Auto-off after delayForHazard.
-
Proper blinking using a periodic toggle.
This should make the relay flash when the button is pressed once, and automatically turn off after delayForHazard, with proper blinking during that period.
Testing this approach should fix the issue where the relay only activates when the button is held.
To resolve the issue where the relay only activates while the button is held, we need to implement edge detection for button presses, manage auto-off timing, and correct the blinking logic. Here's the revised code:
const int leftSignalInPin = 1;
const int rightSignalInPin = 2;
const int leftSignalOutPin = 3;
const int rightSignalOutPin = 4;
int leftSignalState = 0;
int rightSignalState = 0;
unsigned long leftPressedTime = 0;
unsigned long rightPressedTime = 0;
unsigned long blinkPreviousMillis = 0;
int delayForHazard = 500; // Auto-off after 500ms
int delayForSignal = 400; // Blink every 400ms (200ms on/off)
bool blinkState = false;
int relayLowOrHighTriggering = 0; // 0 = Low trigger, 1 = High trigger
int leftPrevState = LOW;
int rightPrevState = LOW;
void setup() {
pinMode(leftSignalInPin, INPUT);
pinMode(rightSignalInPin, INPUT);
pinMode(leftSignalOutPin, OUTPUT);
pinMode(rightSignalOutPin, OUTPUT);
// Initialize relay states
digitalWrite(leftSignalOutPin, relayLowOrHighTriggering ? LOW : HIGH);
digitalWrite(rightSignalOutPin, relayLowOrHighTriggering ? LOW : HIGH);
}
void loop() {
unsigned long currentMillis = millis();
// Read left button with edge detection
int leftCurrent = digitalRead(leftSignalInPin);
if (leftCurrent == HIGH && leftPrevState == LOW) {
leftSignalState = 1;
leftPressedTime = currentMillis;
}
leftPrevState = leftCurrent;
// Auto-off left signal
if (leftSignalState && (currentMillis - leftPressedTime >= delayForHazard)) {
leftSignalState = 0;
}
// Read right button with edge detection
int rightCurrent = digitalRead(rightSignalInPin);
if (rightCurrent == HIGH && rightPrevState == LOW) {
rightSignalState = 1;
rightPressedTime = currentMillis;
}
rightPrevState = rightCurrent;
// Auto-off right signal
if (rightSignalState && (currentMillis - rightPressedTime >= delayForHazard)) {
rightSignalState = 0;
}
// Update blinking state
if (currentMillis - blinkPreviousMillis >= delayForSignal / 2) {
blinkState = !blinkState;
blinkPreviousMillis = currentMillis;
}
// Control left relay
if (leftSignalState) {
digitalWrite(leftSignalOutPin, (blinkState ? !relayLowOrHighTriggering : relayLowOrHighTriggering) ? HIGH : LOW);
} else {
digitalWrite(leftSignalOutPin, relayLowOrHighTriggering ? LOW : HIGH);
}
// Control right relay
if (rightSignalState) {
digitalWrite(rightSignalOutPin, (blinkState ? !relayLowOrHighTriggering : relayLowOrHighTriggering) ? HIGH : LOW);
} else {
digitalWrite(rightSignalOutPin, relayLowOrHighTriggering ? LOW : HIGH);
}
}
Key Improvements:
Edge Detection: The code now detects the rising edge of button presses, ensuring the signal toggles with a single press rather than requiring the button to be held.
Auto-Off Timing: Each signal (left and right) has its own timer (leftPressedTime and rightPressedTime) to track how long they've been active, turning them off after delayForHazard.
Blinking Logic: The blinkState toggles every delayForSignal/2 milliseconds, creating a consistent blinking pattern. Relays blink at the correct frequency while active.
Debouncing: While not explicitly added here, using edge detection inherently provides some debouncing. For more reliability, consider adding hardware debouncing or software debouncing with a small delay.
Usage:
Pressing either button once will activate the corresponding relay, causing it to blink.
The relay will automatically turn off after delayForHazard milliseconds.
Adjust delayForHazard and delayForSignal to control the auto-off time and blink speed.
This should now allow the relays to flash with each button press without needing to hold the button down.