Hallo,
Ich habe gerade ein Projekt für einen PC Controller. Das PC Programm benötigt für das ausführen einer Funktion einen Taster Impuls, da ich aber auch Schalter im Controller verbaut habe, möchte ich mit einem Arduino nutzen um die Schalter als Taster verwenden zu können.
Meine Anforderung ist:
Schalter wir angeschaltet = 1 Ausgabe Impuls
Schalter wird ausgeschaltet = 1 Ausgabe Impuls
Mein bisheriges Programm sieht folgendermaßen aus:
#define SWITCH 3 //Input 1 wird auf Pin D3 gelegt.
#define OUT 4 //Output 1 wird auf Pin D4 gelegt.
boolean switchChanged() {
static int oldState = LOW; // LOW oder HIGH, je nach Schalter (NO/NC)
int currentState = digitalRead(SWITCH);
if (currentState == oldState)
return false;
oldState = currentState;
return true;
}
void setup()
{
}
void loop()
{
if (switchChanged()) {
digitalWrite(OUT, HIGH); //Setzt den Ausgang auf 1
delay(500); //Verzögerung von 0,5s
digitalWrite(OUT, LOW); //Setzt den Ausgang auf 0
}
}
Mit der Statusabfrage des eingangs wird geprüft, ab der Schalter seinen zustand ändert, wenn dies der Fall ist, wird auf dem Ausgang ein Impuls ausgegeben.
Jetzt zu meinem Problem:
Wird der Schalter angeschaltet, kommt direkt der Impuls auf dem Output Pin, aber wenn ich den Schalter wieder ausschalte, dauert es ca. 8 Sekunden bis der Impuls kommt.
Warum dauert es so lange? Liegt das evtl an einer langen zykluszeit oder so was?
Habe leider bisher keine Idee dazu
Ich hoffe mir kann jemand weiterhelfen.
Der eingang wird angeschaltet und nach einem Delay wieder ausgeschaltet, das sorgt für einen Impuls von 0,5 Sekunden. Ich habe nach ausgibigen Tests nun auch herausgefunden, das mein Programm ohne verzögerungen funktioniert, wenn ich nur Digital PWM Pins als In/Output verwende. Woran liegt das?
Danke für die Tipps, kann aber jetzt gerade nichts damit anfangen da ich ansonsten keine Ahnung von der Arduino Materie habe, mein Programm habe ich mir auch nur aus Google zusammen kopiert und durch viel try & error zum laufen gebracht. Werde morgen aber mal schauen ob ich was davon verstehen kann.
Vieleischt weil analogWrite(255) den Pin automatisch als Ausgang defineirt. Bei Ansteuerung der digitalen Pins muß man das selbst zuerstmachen.
Definiere den Eingang als Eingang und aktiviere den internen Pullupwiderstand mit:
pinMode(Switch, INPUT_PULLUP);
Dann definere den Ausgang als Ausgang.
pinMode(OUT,OUTPUT);
int oldState = LOW; schreibst Du außerhalb der Funktionen am Anfang.
Du solltest schon mal ein Tutorial anschauen, da pinMode() die erste Funtion ist, auf die man trifft.
Hier kommt ein einfacher Sketch für einen monostabiler Multivibrator.
Viel Spass beim Testen und Spielen.
/* BLOCK COMMENT
Many thanks to LarryD
https://europe1.discourse-cdn.com/arduino/original/4X/7/e/0/7e0ee1e51f1df32e30893550c85f0dd33244fb0e.jpeg
https://forum.arduino.cc/t/schalter-als-taster-verwenden/1049993
Tested with Arduino: Mega[X] - UNO [ ] - Nano [ ]
*/
#define ProjectName "Schalter als Taster verwenden "
// YOU MAY NEED TO CHANGE THESE CONSTANTS TO YOUR HARDWARE AND NEEDS
constexpr byte ButtonPin {A0}; // portPin o---|button|---GND
constexpr byte LedPin{9}; // portPin o---|220|---|LED|---GND
constexpr unsigned long Blink512Hz {9}; // blinkrate for heartbeat function
// VARIABLE DECLARATION AND DEFINITION
unsigned long currentTime;
//// make some objects for all relevant information for data handling
struct TIMER
{ // has the following members
unsigned long duration; // memory for interval time
unsigned long stamp; // memory for actual time
int onOff; // control for stop/start
};
struct BUTTONLED
{ // has the following members
byte bPin; // port pin for button
byte lPin; // port pin for button
int stateOld; // current state
TIMER scan; // see timer struct
TIMER flash; // see timer struct
};
BUTTONLED knop {ButtonPin, LedPin, false, 20, 0, true, 1000, 0, false};
// services
void heartBeat(int rate)
{
bool myBlink {currentTime & bit(rate)};
digitalWrite(LED_BUILTIN, myBlink);
}
// -------------------------------------------------------------------
void setup()
{
Serial.begin(9600);
Serial.println(F("."));
Serial.print(F("File : ")), Serial.println(__FILE__);
Serial.print(F("Date : ")), Serial.println(__DATE__);
Serial.print(F("Project: ")), Serial.println(ProjectName);
pinMode (LED_BUILTIN, OUTPUT); // used as heartbeat indicator
pinMode(ButtonPin, INPUT_PULLUP);
pinMode(LedPin, OUTPUT);
}
void loop ()
{
currentTime = millis();
heartBeat(Blink512Hz);
// debounce button by scanning
if (currentTime - knop.scan.stamp >= knop.scan.duration)
{
knop.scan.stamp = currentTime;
int stateNew = !digitalRead(knop.bPin);
if (knop.stateOld != stateNew)
{
knop.stateOld = stateNew;
digitalWrite(knop.lPin, HIGH);
// start flash timer
knop.flash.onOff = true;
knop.flash.stamp = currentTime;
}
}
if (currentTime - knop.flash.stamp >= knop.flash.duration && knop.flash.onOff)
{
// switch flash timer off
knop.flash.onOff = false;
digitalWrite(knop.lPin, LOW);
}
}
Der PIN, den Du liest, hat einen sehr hohen Eingangswiderstand.
Wenn Du den PIN nach GND schaltest, dann wird das sofort festgestellt, da die Ladung auf dem PIN sofort abgeleitet wird.
Den anderen Weg hast Du aber nicht eröffnet.
Wenn Du den PIN mittels Schalter von GND trennst, wird der PIN nicht umgeladen.
Wenn Du im setup definierst, das der PIN als INPUT behandelt wird und Du gleichzeitig die Ladung mittels PULLUP aktivierst, wird das funktionieren.
@Uwefed hat in #3 alles wichtige beschrieben. Neben den fehlenden pinMode() Anweisungen in der setup() Routine, gehe ich mal davon aus, dass Du einen Pulldown Widerstand an dem Pin 3 brauchst (wenn pinMode = INPUT ist), damit dieser zuverlässig auf LOW gezogen wird, wenn der Schalter den Stromkreis öffnet.
Neben der ausgefuchsten Variante die @paulpaulson gepostet hat, hätte ich noch diese zu bieten:
//
// Timerklasse
//
class Timer {
public:
void start() { timeStamp = millis(); }
bool operator()(const unsigned long duration) { return (millis() - timeStamp >= duration) ? true : false; }
private:
unsigned long timeStamp{0};
};
//
// Datenstruktur für Schalter und globale Konstanten/Variablen
//
enum class SwSate : byte { noaction, changed, wait };
struct Switch {
const byte pin;
byte cState;
byte pState;
SwSate state;
};
constexpr byte OUT {4};
constexpr int DEBOUNCE_TIME {50}; // Millisekunden
Timer sTimer; // Timerobjekt für das Entprellen erzeugen.
struct Switch mySwitch{3, LOW, LOW, SwSate::noaction}; // Schalterobjekt
//
// Forward-Deklaration der Funktionen
//
void pulse();
bool switchChanged();
//
// Hauptprogramm
//
void setup() {
pinMode(mySwitch.pin, INPUT);
pinMode(OUT, OUTPUT);
// Verhindert erste Pulsauslösung nach dem Einschalten
// unabhängig von der Schalterstellung
delay(10);
mySwitch.pState = digitalRead(mySwitch.pin);
}
void loop()
{
if (switchChanged()) {pulse();}
}
void pulse() {
digitalWrite(OUT, HIGH); //Setzt den Ausgang auf 1
delay(500); //Verzögerung von 0,5s
digitalWrite(OUT, LOW); //Setzt den Ausgang auf 0
}
bool switchChanged() {
bool isAction {false};
mySwitch.cState = digitalRead(mySwitch.pin);
if (mySwitch.cState != mySwitch.pState) {
if (mySwitch.state != SwSate::wait) { mySwitch.state = SwSate::changed; }
}
switch (mySwitch.state) {
case SwSate::changed:
sTimer.start();
mySwitch.state = SwSate::wait;
break;
case SwSate::wait:
if (sTimer(DEBOUNCE_TIME)) {
mySwitch.pState = mySwitch.cState;
mySwitch.state = SwSate::noaction;
isAction = true;
}
break;
default: break;
}
return isAction;
}
Hintergrund ist, dass die Codes dafür sorgen, dass ein evtl. Prellen des Schalters nicht zu "Signalchaos" führt und der Impuls nur erzeugt wird, wenn der Schaltvorgang wirklich abgeschlossen ist.
Es beugt, je nach Schalter, zumindest davor vor, dass ein kurzes Berühren, Wackeln nicht gleich eine Impuls auslöst. Außerdem gibt es gleich die Möglichkeit, eine Mindest-Einschaltzeit für den Schalter vorzugeben, bevor ein Impuls erzeugt wird.
Also um alle nochmal auf den neuesten Stand zu bringen;
ich habe das Problem gelöst, indem ich pullup Widerstände verwendet hab.
Der Arduino hat ja welche die sich aktivieren lassen.
Der Code sieht nun volgendermaßen aus:
//Eingänge werden definiert:
#define SWITCH_1 3 //Input 1 wird auf Pin D3 gelegt.
//Ausgänge werden definiert:
#define OUT_1 5 //Output 1 wird auf Pin D5 gelegt.
//-------------------------------------------------------------------------------------------------------------------------------------------
boolean switchChanged_1() {
static int oldState_1 = LOW; // LOW oder HIGH, je nach Schalter (NO/NC)
int currentState_1 = digitalRead(SWITCH_1);
if (currentState_1 == oldState_1)
return false;
oldState_1 = currentState_1;
return true;
}
//-------------------------------------------------------------------------------------------------------------------------------------------
void setup()
{
//Eingangspins werden als Input Definiert:
pinMode(SWITCH_1, INPUT);
//Interne Pullup Widerstände für die Inputs werden aktiviert:
digitalWrite(SWITCH_1, HIGH);
}
//-------------------------------------------------------------------------------------------------------------------------------------------
void loop()
//-------------------------------------------------------------------------------------------------------------------------------------------
{
if (switchChanged_1()) //Wenn sich der zustand des Schalters Ändert dann tuhe folgendes
{
digitalWrite(OUT_1, HIGH); //Setzt den Ausgang auf 1
delay(500); //Verzögerung von 0,5s
digitalWrite(OUT_1, LOW); //Setzt den Ausgang auf 0
}
else //Ansonsten tuhe folgendes
{
digitalWrite(OUT_1, LOW); //Setzt Ausgang 1 auf 0
}
}
Es gibt zwar noch Dinge, die man optimieren könnte, z.b. ist der else befehl im if/else Teil nicht notwendig, aber das kommt dann in zukunft beim richtigen Coden noch.
Und aus welchem Grund genau weigerst Du dich noch immer, das erforderliche
pinMode (OUT_1, OUTPUT);
ins void setup() zu setzen? Spätestens wenn Du versuchst, an einem als Ausgang benutzten Pin eine LED anzuschliessen, wirst Du feststellen, dass die Anweisung, den Pin als Ausgang zu definieren, nicht freiwillig soder erforderlich ist.
Oh, danke für den Hinweis. Ich habe nicht nicht geweigert, ich hatte es nur nicht mehr im Kopf, und es wahr bisher auch nicht erforderlich, da das Programm auch so funktioniert hat, zumindest weitestgehend.
Das ich den pinMode Output nicht verwendet habe könnte aber evtl erklären, warum ausgerechnet der D12 Pin als einziger Pin kein outpursignal gibt, denn ich habe das oben gepostete Pogramm vervielfältigt ummöglichst viele Schalter an einen Arduino anschließend zu können.
Denn wenn ich den D12 Pin in meinem "Single" Programm verwende funktioniert er, aber im Großenprogramm nicht.
Ich wusste gar nicht das es einen Befehl für den Pullupwiderstand gibt...
Mein Technicklehrer meinte das sich der Pullupwiderstand nur so aktivieren lässt wie ich es in meinem Programm gemacht habe.
Aber wie ich schonmal geschrieben habe, verbesserungspotenzial gibt es immer, aber bei mir muss das programm einfach nur funktionieren. Das XXL Programm was ich gepostet habe, ist im Prinzip nur das Kleine Programm von oben, nur 9 mal dupliziert.
Das beweist, das Du zu faul warst zu lesen, was man Dir auf den Weg gibt.
Ich bin sonst gerne auch bereit Codeduplikate aufzulösen, aber das lässt mich sprachlos zurück.
Tut mir leid, ich hatte deine Nachricht übersehen, aber das Codeduplikat ist auch nicht zum auflösen gedacht. Bevor das für richlich verwirrung sorgt, werde ich es wieder löschen.
Aber damit ist mein Problem vorerst gelöst, danke für eure Hilfe
Nunja, wenn Ausgänge nicht als solches deklariert sind, mag war das Programm an Sich funktionieren, aber der PIN tut es nicht. Zumindest nicht als Stromtreiber, weil nämlich der Interne Treiber des Pin schlichtweg inaktiv ist. Ob der Pin ohne als Output deklariert zu sein, Strom sinken (aufnehmen) kann, das weiss ich nicht, weil ichs bisher noch nicht ausprobiert habe.