Jump to content
ELFORUM - Forumul electronistilor

gabitzu2006

Membru Activ
  • Posts

    496
  • Joined

  • Last visited

Profile Fields

  • Location
    Buzău

Recent Profile Visitors

762 profile views

gabitzu2006's Achievements

Proficient

Proficient (10/14)

  • Posting Machine Rare
  • Dedicated
  • First Post
  • Collaborator
  • Conversation Starter

Recent Badges

  1. @vlad2005 era un pdf de la phillips parca, despre Snubber networks. Discutia de acolo era despre snubber pentru triace, dar ceva ceva tot se potriveste si in acest caz. Acolo sunt date niste formule de calcul, deci nu e totul empiric. In alta ordine de idei, am si eu o problema asemanatoare,a sa am dat peste acest topic. Am un modul de comanda cu ESP32 care imi comanda niste relee si un motor DC printr-un driver TA6586 (e un modul selector de intrari audio si control volum - cu potentiometru cu motor; am o postare despre asta, in alta sectiune). Ambele module (cel cu ESP si driver) sunt alimentate din aceeasi sursa de 5V. Problema este ca ESP se reseteaza cand ii dau comanda de Vol up sau Vol down (adica este pornit motorul intr-un sens sau altul). Am pus un cond de 470uF pe alimentarea TA6586 dar se pare ca nu rezolva problema. Voi incerca cu 100nF pe pinul de reset, cum a spus @ratza. Si o alta chestie ciudata: am alimentat ambele module dintr-o sursa step-up chinezeasca, reglata la 5V pe iesire; cand am dat comanda vol up, motorul a functionat pt scurt timp, afisajul sursei s-a stins si a mirosit a ars. Modulul cu ESP prezenta scurt pe alimentare. Un coleg a descoperit ca se strapunsese cond-ul smd de pe intrarea regulatorului AMS1117 de pe placuta ESP. Deci cumva, am avut o supratensiune acolo (probabil caderea de tensiune cauzata de pornirea motorului a facut ca sursa sa mareasca tensiunea de iesire pentru a compensa scaderea tensiunii). In fine, problema principala cred ca e resetarea MCU si voi incerca varianta lui @ratza si revin. In orice caz, in montajul final probabil voi folosi un regulator liniar, dar tot va fi probalema cu resetul.
  2. http://blog.copcea.ro/files/tehnium/revista/9408-09.pdf E aici un articol cu schema. Atat am gasit deocamdata.
  3. am modificat acel wait_loops la 3000 si acum clipirea a disparut (cel puțin ochiometric). /* Muffsy Relay Input Selector * * Control relays using IR and rotary encoder * Control external power to amp using IR and push button * LM3886 * * Last update with functionality changes: 2023-09-27 * * Introduction: * The software works on the concept of "powerState", which determines the behavior of the Input Selector: * * 0: Boot * Read last input channel from NVRAM, selecting the same input as when the input selector was turned off or lost power * The input selector is muted, and mute LED is turned off * Print startup message * powerState is changed to 2 (off) * 2: Power OFF * Turn off all relays * Set power amp to off (SSR = LOW) * The input selector is muted, and mute LED is turned off * Limited functionality, only IR powerbutton and rotary encoder pushbutton is active * All input events, even those not available, will be shown in the serial monitor * * 1: Power ON * Turn on power button LED * Set power amp to on, SSR = HIGH * Activates the input channel read from NVRAM * Will start muted with mute LED turned on * No actions are read until the input selector unmutes after 1500 ms (default) * All functions available, IR Remote and rotary encoder * All input events and actions will be shown in the serial monitor */ /* * Load libraries */ #include <EEPROM.h> // EEPROM Library #include <IRremote.h> // IR Remote Library #include <Versatile_RotaryEncoder.h> // Rotary Encoder Library /* * Startup delay * * When powering on, the input selector is muted to avoid any unwanted pops * Set the delay value in milliseconds (default 1500) * * Change to 0 for no delay */ #define startupDelay 1500 /* * Enable SSR * * If you want to use a Solid State Relay to control mains power to an * amplifier or similar, set this value to 1 * * Default 0 (disabled), as handling mains power is dangerous */ #define enableSSR 1 /* Mute and Power on / off: * * The rotary encoder is also a push button, which registers * either a short or a long press. These are their functions: * * Short press: Power on / off * Long press: Mute * * To reverse this behaviour, change the value below to 1 (default = 0) */ #define encPush 0 /* * Rotary encoder direction. * * If the rotary encoder rotation is the wrong way around, change this value to 1 * Default: 0 */ #define encDirection 0 /* * Rotational encoder rate * * Delay between registering rotational encoder turns, in milliseconds. * If the repeat rate when turning the rotational encoder is too fast, change this timer. * * Note: * Introducing a delay in reading turns of the rotational encoder may skip one or more * of the encoders "clicks". In turn, it prevents you from skipping channels if you turn * the encoder to fast. * * Lower number: Faster repeat rate * Higher number: Slower repeat rate * Default: 0 */ #define rotRate 0 /* * IR rate * * Delay between registering IR commands, in milliseconds. * If the repeat rate when holding down a button on the remote is * to slow or too fast, change this timer. * * Lower number: Faster repeat rate * Higher number: Slower repeat rate * Default: 175 */ #define irRate 250 /* *IR Commands * * The following variables map all the buttons on the remote * control that comes with the Muffsy Input Selector. * * For instructions on how to configure your own remote, see: * https://www.muffsy.com/muffsy-relay-input-selector-4#configureremote * * While connecting your Input Selector to the computer, it will display * any remote commands in the Arduiono IDE's Serial Monitor like this: * * [LM3886]: Received IR code: <IR code of button pushed> * * There are placeholder commands in the function irRemote{} for the buttons * 0 and 5 to 9 that serves as templates for your own IR routines * */ #define zeroButton 10 // Placeholder command in the function irRemote{}, default: 13 #define oneButton 1 // Input 1, default: 12 #define twoButton 2 // Input 2, default: 24 #define threeButton 3 // Input 3, default: 94 #define fourButton 4 // Input 4, default: 8 #define fiveButton 5 // Placeholder command in the function irRemote{}, default: 28 #define sixButton 6 // Placeholder command in the function irRemote{}, default: 90 #define sevenButton 7 // Placeholder command in the function irRemote{}, default: 66 #define eightButton 8 // Placeholder command in the function irRemote{}, default: 82 #define nineButton 9 // Placeholder command in the function irRemote{}, default: 74 #define eqButton 70 // Default value: 70 #define modeButton 68 // Default value: 68 #define muteButton 23 // Mute, default: 71 #define ffButton 17 // "Fast Forward" button: Channel up, default: 21 #define rewButton 18 // "Rewind" button: Channel down, default: 7 #define powerButton 22 // Power on / off, default: 69 #define volupButton 20 // Default value: 25 #define voldownButton 21 // Default value: 22 #define rptButton 64 // Default value: 64 #define tfuButton 67 // Default value: 67 #define playButton 99 // Default value: 9 /********************************************************** * Do not edit below, unless you intend to change the code! **********************************************************/ // Rotary encoder pins #define clk 35 // (A3) #define dt 34 // (A4) #define sw 5 // (A5) // Functions prototyping to be handled on each Encoder Event void handleRotate(int8_t rotation); void handlePressRelease(); void handleLongPress(); // Create a global pointer for the encoder object Versatile_RotaryEncoder *versatile_encoder; // EEPROM size: 1 (relayCount) #define EEPROM_SIZE 1 // Variables, pin definitions // Onboard LED/Power LED #define LED 2 // IR Receiver pin and setup //const byte IR_Recv = 36; #define IR_Recv 36 // Relays #define R1 16 #define R2 12 #define R3 27 #define R4 33 #define R5 32 //Volume Up and down #define vup 13 #define vdwn 14 //Solid State Relay #define SSR 17 // Mute LED #define muteLed 4 // Relay Array volatile int relays[] = {16, 12, 27, 33, 32}; // Relay variables volatile int relayCount; int previousRelay; int relayNumber; int wait_loops; /* * Power/Mute variables * * powerState explained in detail at the beginning of this program: * 0 = Welcome message, getting ready * 1 = Powered on * 2 = Powered off * * mute: * 0: Tell toggleMute() to unmute * 1: Tell toggleMute() to mute * * poweronMute: * 1: mute for the period defined by startupDelay, then unmute, only when powering on (change powerState to 1) * 0: Disable the startupDelay if powerState is unchanged */ int powerState = 0; // Power ready-state int mute = 1; // Mute off/on (0/1) -> The circuit starts out muted, tell toggleMute() to stay muted at first run int poweronMute = 1; // Mute at poweron, with startupDelay void setup() { Serial.begin(115200); // Set serial monitor transfer rate to 115,200 versatile_encoder = new Versatile_RotaryEncoder(clk, dt, sw); // Load to the rotary encoder functions versatile_encoder->setHandleRotate(handleRotate); versatile_encoder->setHandlePressRelease(handlePressRelease); versatile_encoder->setHandleLongPress(handleLongPress); // Modify rotary encoder defualt values (optional) versatile_encoder->setReadIntervalDuration(3); // set 3 ms as long press duration (default is 1 ms) // versatile_encoder->setShortPressDuration(35); // set 35 ms as short press duration (default is 50 ms) // versatile_encoder->setLongPressDuration(550); // set 550 ms as long press duration (default is 1000 ms) // Define INPUT pins, make sure the inputs aren't touch enabled pinMode (sw,INPUT_PULLUP); pinMode (clk,INPUT_PULLDOWN); pinMode (dt,INPUT_PULLDOWN); pinMode (IR_Recv,INPUT_PULLUP); // Define OUTPUT pins // Onboard LED pinMode (LED,OUTPUT); // Mute LED pinMode (muteLed,OUTPUT); // Relays pinMode (R1,OUTPUT); pinMode (R2,OUTPUT); pinMode (R3,OUTPUT); pinMode (R4,OUTPUT); pinMode (R5,OUTPUT); pinMode (SSR,OUTPUT); //volume Up and down pinMode (vup,OUTPUT); pinMode (vdwn,OUTPUT); // Relay variables EEPROM.begin(EEPROM_SIZE); relayCount = EEPROM.read(0); previousRelay = relayCount + 1; // Start out not matching relayCount // Enable IR Receiver IrReceiver.begin(IR_Recv); } bool bRecRepeat = false; /****** * Main loop ******/ void loop() { if (powerState == 0) { // Booting, welcome message powerOn(); } else if (powerState == 1){ // Powered on relayOn(); // Will automatically change input if a function changes the relayCount variable irRemote(); // Allowing all functionality in the irRemote() function rotEncoder(); // Read the rotaryencoder } else { // Powered off irRemote(); // irRemote() function, react to Power on/off only rotEncoder(); // Read the rotaryencoder, react to Power on/off only } } // End Main loop /****** * Functions ******/ /* * Power on amplifier (Welcome/Boot message when first powered on) */ void powerOn() { // Only called if powerState is 0 (Ready-status) Serial.println("\n --- LM3886 ---\n"); Serial.println("The Muffsy Relay Input Selector has woken up!\n"); Serial.print(" ** Reading saved relay state from NVRAM: "); Serial.println(relayCount); digitalWrite(relays[4],LOW); Serial.println("\n ** Mute Relay turned ON"); Serial.println(" ** All input relays are turned OFF"); relayOff(); Serial.println(" ** Solid State Relay is turned OFF\n"); digitalWrite (SSR,LOW); Serial.println(" ** Startup completed - waiting for Power ON\n"); Serial.println(" -------------------------\n"); // Set powerState to 2 (Powered off). This function will not run again. powerState = 2; } // End powerOn() /* * Turn off all relays */ void relayOff() { for (int off = 0; off <= 3; off++) { digitalWrite(relays[off], LOW); } } // End relayOff /* * Turn on or off input relays (mute relay is controlled by toggleMute()) * * relayCount is the actual chosen active relay * previousRelay is the previous chosen active relay * This function is triggered if the two are unequal * The function can be forced to trigger by changing previousRelay: previousRelay = relayCount + 1; */ void relayOn() { // If relayCount has changed: Turn on the selected relay (next, previous, direct) // If previousRelay has changed: Turn on the last selected relay if (relayCount != previousRelay) { auto localRelayCount = relayCount; // local copy, assuming atomic integer /* Rollover 3 or 0, * * There are four input relays, 0 to 3 (Status messages prints them as inputs 1 to 4) * This part makes sure we can't choose relays lower than 0 or higher than 3 */ if (localRelayCount > 3) { localRelayCount = 0; } else if (localRelayCount < 0) { localRelayCount = 3; } // Turn off all relays, then turn on localRelayCount relayOff(); digitalWrite(relays[localRelayCount], HIGH); relayCount = localRelayCount; // Write relayCount to memory EEPROM.write(0,relayCount); EEPROM.commit(); Serial.print("[LM3886]: Written \"relayCount = "); Serial.print(relayCount); Serial.println("\" to save slot 0"); // Reset counters, output relayNumber previousRelay = relayCount; relayNumber = relayCount + 1; Serial.print("[LM3886]: Activated relay #"); Serial.println(relayNumber); Serial.println(); /* * Mute, then unmute if just powered on * relayOn() is called at power on, placing the startupDelay mute here is convenient so we don't have to run a separate function * If the configurable value startupMute is 0, there will be no delay */ if ((poweronMute == 1) && (startupDelay == 0)) { poweronMute = 0; // Set poweronMute to 0, so this mutedelay doesn't occur every time the circuit is muted mute = 0; // toggleMute will unmute toggleMute; } else if (poweronMute == 1) { poweronMute = 0; // Set poweronMute to 0, so this mutedelay doesn't occur every time the circuit is muted Serial.println("[LM3886]: Turning on mute LED"); digitalWrite(muteLed,HIGH); Serial.print("[LM3886]: Milliseconds delay before turning off mute: "); Serial.println(startupDelay); delay(startupDelay); mute = 0; // toggleMute will unmute when called next toggleMute(); } } } // End relayOn() /* * Mute activate/deactivate */ void toggleMute() { // This function will mute if unmuted, and vice versa everytime it's called if (mute == 1) { // Read mute variable. if unmuted, turn on mute Serial.println("[LM3886]: Mute relay turned ON"); digitalWrite(relays[4],LOW); if (powerState == 1){ // If powered on, also turn on mute LED Serial.println("[LM3886]: Turning on mute LED\n"); digitalWrite(muteLed,HIGH); // Set mute to 0, next time toggleMute is called, it will turn OFF mute // mute = 0 now means we're muted mute = 0; // Unmute next time this function is called } // End if powered on } else { // Mute must be 0, turn off mute Serial.println("[LM3886]: Mute relay turned OFF"); digitalWrite(relays[4],HIGH); Serial.println("[LM3886]: Turning off mute LED\n"); digitalWrite(muteLed,LOW); // Turn off mute LED, no matter if it was turned on or off earlier. // Set mute to 1, next time toggleMute is called, it will turn ON mute // mute = 1 now means we're unmuted mute = 1; // Mute next time this function is called } // } // End toggleMute() /* * Power on / off */ void togglePower() { /* * If powerState is 1, turn OFF: All relays OFF, power amp OFF */ if (powerState == 1) { powerState = 2; // Setting powerState to 2 (off) if (mute == 1) { // If unmuted, turn on mute toggleMute(); // mute variable = 1, toggleMute will turn on mute. powerState = 2, mute LED will not turn on } else if (mute == 0) { // If already muted, turn off mute LED Serial.println("[LM3886]: Mute relay stays turned ON"); Serial.println("[LM3886]: Turning off mute LED"); digitalWrite(muteLed,LOW); // Turning off the mute LED } relayOff(); if (enableSSR == 1) { // Only turn off SSR if "enableSSR" is set to 1 digitalWrite (SSR,LOW); // Turning off Solid State Relay Serial.println("[LM3886]: Solid State Relay OFF"); } Serial.println("[LM3886]: Turning off power LED"); Serial.println("[LM3886]: Power OFF\n"); digitalWrite (LED,LOW); // Turning off the power LED poweronMute = 1; // Set poweronMute to 1, this will force a mute with delay on next power on /* * If powerState is 2, turn ON: Last selected relay ON, power amp (Solid State Relay ON) */ } else if (powerState == 2) { // powerState = 1; // Setting powerState to 1 (on) Serial.println("[LM3886]: Turning on power LED"); digitalWrite (LED,HIGH); // Turning on the power lED previousRelay = relayCount + 1; // Trigger relayOn() Serial.println("[LM3886]: Power ON"); if (enableSSR == 1) { // Only enable SSR if "enableSSR" is set to 1 digitalWrite (SSR,HIGH); // Turning on Solid State Relay Serial.println("[LM3886]: Solid State Relay ON\n"); } // We have just powered on // The circuit is muted, manually in powerOn(), toggleMute() has not been involved to set the mute variable // mute = 0; tells toggleMute() that we are muted, and that toggleMute() will unmute the next time it's called // relayOn() will call toggleMute if poweronMute = 1 mute = 0; relayOn(); } } // End togglePower() /* * Read the rotary encoder */ void rotEncoder() { versatile_encoder->ReadEncoder(); } /* * IR Remote */ void irRemote() { // Start irRemote function // Decode the infrared input if (IrReceiver.decode()) { long int decCode = IrReceiver.decodedIRData.command; if (decCode != 0) { Serial.print("[LM3886]: Received IR code: "); Serial.println(decCode); } // Read pushed remote control button and take action // All actions for remote control buttons are defined here switch (decCode) { // Start switch/case case oneButton: // Relay 1 - Input 1 { Serial.println("[LM3886]: Button \"1\""); if (powerState == 1) { relayCount = 0; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case twoButton: // Relay 2 - Input 2 { Serial.println("[LM3886]: Button \"2\""); if (powerState == 1) { relayCount = 1; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case threeButton: // Relay 3 - Input 3 { Serial.println("[LM3886]: Button \"3\""); if (powerState == 1) { relayCount = 2; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case fourButton: // Relay 4 - Input 4 { Serial.println("[LM3886]: Button \"4\""); if (powerState == 1) { relayCount = 3; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case fiveButton: // Button 5 - Info message { Serial.println("[LM3886]: Button \"5\""); if (powerState == 1) { ; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case sixButton: // Button 6 - Info message { Serial.println("[LM3886]: Button \"6\""); if (powerState == 1) { ; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case sevenButton: // Button 7 - Info message { Serial.println("[LM3886]: Button \"7\""); if (powerState == 1) { ; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case eightButton: // Button 8 - Info message { Serial.println("[LM3886]: Button \"8\""); if (powerState == 1) { ; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case nineButton: // Button 9 - Info message { Serial.println("[LM3886]: Button \"9\""); if (powerState == 1) { ; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case zeroButton: // Button 0 - Info message { Serial.println("[LM3886]: Button \"0\""); if (powerState == 1) { ; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case volupButton: // Volume up - Info message { Serial.println("[LM3886]: Button \"vup\""); if (powerState == 1) { digitalWrite (vup, HIGH); wait_loops=3000; // bRecRepeat = true; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case voldownButton: // Volume down - Info message { Serial.println("[LM3886]: Button \"vdwn\""); if (powerState == 1) { digitalWrite (vdwn, HIGH); // bRecRepeat = true; wait_loops=3000; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case muteButton: // Mute { Serial.println("[LM3886]: Button \"Mute\""); if (powerState == 1) { toggleMute(); } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case ffButton: // Channel UP { Serial.println("[LM3886]: Button \"UP\""); if (powerState == 1) { relayCount++; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case rewButton: // Channel DOWN { Serial.println("[LM3886]: Button \"DOWN\""); if (powerState == 1) { relayCount--; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); }; break; } case powerButton: // Power button { Serial.println("[LM3886]: Button \"POWER\""); togglePower(); unsigned long powMillis = millis(); // Always wait a bit longer after powerButton to avoid turning on immediately after power off, regardless of irRate while (millis() - powMillis < 750) { ; } break; } /*default: bRecRepeat = false; { Serial.println("[LM3886]: Going back to waiting for IR remote keypress\n"); } */ }// End switch/case unsigned long irMillis = millis(); while (millis() - irMillis < irRate) { ; } IrReceiver.resume(); // Receives the next value from the button you press } // End of if IrReceiver decode wait_loops=wait_loops-1; if(wait_loops==0) { wait_loops=1; digitalWrite (vup, LOW); digitalWrite (vdwn, LOW); } } // End irRemote() /* * Rotate the rotary encoder * * Change the encDirection value if you want to reverse the direction */ void handleRotate(int8_t rotation) { Serial.print("[LM3886]: Rotational encoder turned "); // encDirection set to 0 if ( ((rotation > 0) && (encDirection == 0)) || ((rotation < 0) && (encDirection == 1)) ) { // Channel down (counter-clockwise) Serial.println("counter-clockwise"); if (powerState == 1) { // Increase relayCount relayCount--; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); // Powered off } } else if ( ((rotation > 0) && (encDirection == 1)) || ((rotation < 0) && (encDirection == 0)) ) { // Channel up (clockwise) Serial.println("clockwise"); if (powerState == 1) { // Increase relayCount relayCount++; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); // Powered off } } // Wait for the amount of milliseconds defined by rotRate until reading the next IR command // This delay uses interrupts, so it won't hold up the rest of the program unsigned long rotMillis = millis(); while (millis() - rotMillis < rotRate) { ; } } // End handleRotate() /* * Press rotary encoder button. * * Will turn on or off the Muffsy Input selector when the button is released, * or mute if you have changed the encPush value and the powerState is 1 (on) */ void handlePressRelease() { if (encPush == 0) { // Power off Serial.println("[LM3886]: Button \"Power\""); togglePower(); } else { // Mute Serial.println("[LM3886]: Button \"Mute\""); if (powerState == 1) { toggleMute(); } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } } } // End handlePressRelease() /* * Long press the rotary encoder button. * * It will mute or unmute, as long as powerState is 1 (on), * or power on/off if you have changed the encPush value */ void handleLongPress() { if (encPush == 1) { // Power off Serial.println("[LM3886]: Button \"Power\""); togglePower(); } else { // Mute Serial.println("[LM3886]: Button \"Mute\""); if (powerState == 1) { toggleMute(); } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } } } // End handleLongPress() // END OF THE PROGRAM
  4. @cloudy îmi pare rău, dar nu știu unde ar trebui să inserez codul tau, imi da eroare la compilare. Poti pune, te rog, tot sketch-ul? ca sigur eu am inserat aiurea ce ai postat tu. Multumesc!
  5. Mi-am dat seama ca trebuie sa testez montajul complet, cu tot cu encoder, desi nu cred ca a suferit modificari codul pe partea de encoder. O altă chestie este un flicker al LED-urilor,atunci cand tin apasat butonul pe telecomanda. Banuiesc ca flicker-ul se poate diminua modificand valoarea wait_loops, nu? Ar trebui micsorata sau marita?
  6. Șiii...câștigător este primul cod din arhiva lui @cristi7521!! Încă nu am testat varianta propusă de @cloudy. Trebuie să înlocuiesc în sketch ce a postat el, îmi va lua ceva timp sa fac asta, ca tare imi e ca uit vreo paranteza ceva sau lipesc aiurea. Dar îl voi incerca si pe acela în curand si anunt aici daca merge sau nu. În orice caz, mulțumesc mult pentru ajutor. Atașez codul funcțional. Îl voi mai testa zilele astea si daca am timp testez și cu integratul de control al motorului potentiometrului de volum, ca a fie treaba treabă. /* Muffsy Relay Input Selector * * Control relays using IR and rotary encoder * Control external power to amp using IR and push button * LM3886 * * Last update with functionality changes: 2023-09-27 * * Introduction: * The software works on the concept of "powerState", which determines the behavior of the Input Selector: * * 0: Boot * Read last input channel from NVRAM, selecting the same input as when the input selector was turned off or lost power * The input selector is muted, and mute LED is turned off * Print startup message * powerState is changed to 2 (off) * 2: Power OFF * Turn off all relays * Set power amp to off (SSR = LOW) * The input selector is muted, and mute LED is turned off * Limited functionality, only IR powerbutton and rotary encoder pushbutton is active * All input events, even those not available, will be shown in the serial monitor * * 1: Power ON * Turn on power button LED * Set power amp to on, SSR = HIGH * Activates the input channel read from NVRAM * Will start muted with mute LED turned on * No actions are read until the input selector unmutes after 1500 ms (default) * All functions available, IR Remote and rotary encoder * All input events and actions will be shown in the serial monitor */ /* * Load libraries */ #include <EEPROM.h> // EEPROM Library #include <IRremote.h> // IR Remote Library #include <Versatile_RotaryEncoder.h> // Rotary Encoder Library /* * Startup delay * * When powering on, the input selector is muted to avoid any unwanted pops * Set the delay value in milliseconds (default 1500) * * Change to 0 for no delay */ #define startupDelay 1500 /* * Enable SSR * * If you want to use a Solid State Relay to control mains power to an * amplifier or similar, set this value to 1 * * Default 0 (disabled), as handling mains power is dangerous */ #define enableSSR 1 /* Mute and Power on / off: * * The rotary encoder is also a push button, which registers * either a short or a long press. These are their functions: * * Short press: Power on / off * Long press: Mute * * To reverse this behaviour, change the value below to 1 (default = 0) */ #define encPush 0 /* * Rotary encoder direction. * * If the rotary encoder rotation is the wrong way around, change this value to 1 * Default: 0 */ #define encDirection 0 /* * Rotational encoder rate * * Delay between registering rotational encoder turns, in milliseconds. * If the repeat rate when turning the rotational encoder is too fast, change this timer. * * Note: * Introducing a delay in reading turns of the rotational encoder may skip one or more * of the encoders "clicks". In turn, it prevents you from skipping channels if you turn * the encoder to fast. * * Lower number: Faster repeat rate * Higher number: Slower repeat rate * Default: 0 */ #define rotRate 0 /* * IR rate * * Delay between registering IR commands, in milliseconds. * If the repeat rate when holding down a button on the remote is * to slow or too fast, change this timer. * * Lower number: Faster repeat rate * Higher number: Slower repeat rate * Default: 175 */ #define irRate 250 /* *IR Commands * * The following variables map all the buttons on the remote * control that comes with the Muffsy Input Selector. * * For instructions on how to configure your own remote, see: * https://www.muffsy.com/muffsy-relay-input-selector-4#configureremote * * While connecting your Input Selector to the computer, it will display * any remote commands in the Arduiono IDE's Serial Monitor like this: * * [LM3886]: Received IR code: <IR code of button pushed> * * There are placeholder commands in the function irRemote{} for the buttons * 0 and 5 to 9 that serves as templates for your own IR routines * */ #define zeroButton 10 // Placeholder command in the function irRemote{}, default: 13 #define oneButton 1 // Input 1, default: 12 #define twoButton 2 // Input 2, default: 24 #define threeButton 3 // Input 3, default: 94 #define fourButton 4 // Input 4, default: 8 #define fiveButton 5 // Placeholder command in the function irRemote{}, default: 28 #define sixButton 6 // Placeholder command in the function irRemote{}, default: 90 #define sevenButton 7 // Placeholder command in the function irRemote{}, default: 66 #define eightButton 8 // Placeholder command in the function irRemote{}, default: 82 #define nineButton 9 // Placeholder command in the function irRemote{}, default: 74 #define eqButton 70 // Default value: 70 #define modeButton 68 // Default value: 68 #define muteButton 23 // Mute, default: 71 #define ffButton 17 // "Fast Forward" button: Channel up, default: 21 #define rewButton 18 // "Rewind" button: Channel down, default: 7 #define powerButton 22 // Power on / off, default: 69 #define volupButton 20 // Default value: 25 #define voldownButton 21 // Default value: 22 #define rptButton 64 // Default value: 64 #define tfuButton 67 // Default value: 67 #define playButton 99 // Default value: 9 /********************************************************** * Do not edit below, unless you intend to change the code! **********************************************************/ // Rotary encoder pins #define clk 35 // (A3) #define dt 34 // (A4) #define sw 5 // (A5) // Functions prototyping to be handled on each Encoder Event void handleRotate(int8_t rotation); void handlePressRelease(); void handleLongPress(); // Create a global pointer for the encoder object Versatile_RotaryEncoder *versatile_encoder; // EEPROM size: 1 (relayCount) #define EEPROM_SIZE 1 // Variables, pin definitions // Onboard LED/Power LED #define LED 2 // IR Receiver pin and setup //const byte IR_Recv = 36; #define IR_Recv 36 // Relays #define R1 16 #define R2 12 #define R3 27 #define R4 33 #define R5 32 //Volume Up and down #define vup 13 #define vdwn 14 //Solid State Relay #define SSR 17 // Mute LED #define muteLed 4 // Relay Array volatile int relays[] = {16, 12, 27, 33, 32}; // Relay variables volatile int relayCount; int previousRelay; int relayNumber; int wait_loops; /* * Power/Mute variables * * powerState explained in detail at the beginning of this program: * 0 = Welcome message, getting ready * 1 = Powered on * 2 = Powered off * * mute: * 0: Tell toggleMute() to unmute * 1: Tell toggleMute() to mute * * poweronMute: * 1: mute for the period defined by startupDelay, then unmute, only when powering on (change powerState to 1) * 0: Disable the startupDelay if powerState is unchanged */ int powerState = 0; // Power ready-state int mute = 1; // Mute off/on (0/1) -> The circuit starts out muted, tell toggleMute() to stay muted at first run int poweronMute = 1; // Mute at poweron, with startupDelay void setup() { Serial.begin(115200); // Set serial monitor transfer rate to 115,200 versatile_encoder = new Versatile_RotaryEncoder(clk, dt, sw); // Load to the rotary encoder functions versatile_encoder->setHandleRotate(handleRotate); versatile_encoder->setHandlePressRelease(handlePressRelease); versatile_encoder->setHandleLongPress(handleLongPress); // Modify rotary encoder defualt values (optional) versatile_encoder->setReadIntervalDuration(3); // set 3 ms as long press duration (default is 1 ms) // versatile_encoder->setShortPressDuration(35); // set 35 ms as short press duration (default is 50 ms) // versatile_encoder->setLongPressDuration(550); // set 550 ms as long press duration (default is 1000 ms) // Define INPUT pins, make sure the inputs aren't touch enabled pinMode (sw,INPUT_PULLUP); pinMode (clk,INPUT_PULLDOWN); pinMode (dt,INPUT_PULLDOWN); pinMode (IR_Recv,INPUT_PULLUP); // Define OUTPUT pins // Onboard LED pinMode (LED,OUTPUT); // Mute LED pinMode (muteLed,OUTPUT); // Relays pinMode (R1,OUTPUT); pinMode (R2,OUTPUT); pinMode (R3,OUTPUT); pinMode (R4,OUTPUT); pinMode (R5,OUTPUT); pinMode (SSR,OUTPUT); //volume Up and down pinMode (vup,OUTPUT); pinMode (vdwn,OUTPUT); // Relay variables EEPROM.begin(EEPROM_SIZE); relayCount = EEPROM.read(0); previousRelay = relayCount + 1; // Start out not matching relayCount // Enable IR Receiver IrReceiver.begin(IR_Recv); } bool bRecRepeat = false; /****** * Main loop ******/ void loop() { if (powerState == 0) { // Booting, welcome message powerOn(); } else if (powerState == 1){ // Powered on relayOn(); // Will automatically change input if a function changes the relayCount variable irRemote(); // Allowing all functionality in the irRemote() function rotEncoder(); // Read the rotaryencoder } else { // Powered off irRemote(); // irRemote() function, react to Power on/off only rotEncoder(); // Read the rotaryencoder, react to Power on/off only } } // End Main loop /****** * Functions ******/ /* * Power on amplifier (Welcome/Boot message when first powered on) */ void powerOn() { // Only called if powerState is 0 (Ready-status) Serial.println("\n --- LM3886 ---\n"); Serial.println("The Muffsy Relay Input Selector has woken up!\n"); Serial.print(" ** Reading saved relay state from NVRAM: "); Serial.println(relayCount); digitalWrite(relays[4],LOW); Serial.println("\n ** Mute Relay turned ON"); Serial.println(" ** All input relays are turned OFF"); relayOff(); Serial.println(" ** Solid State Relay is turned OFF\n"); digitalWrite (SSR,LOW); Serial.println(" ** Startup completed - waiting for Power ON\n"); Serial.println(" -------------------------\n"); // Set powerState to 2 (Powered off). This function will not run again. powerState = 2; } // End powerOn() /* * Turn off all relays */ void relayOff() { for (int off = 0; off <= 3; off++) { digitalWrite(relays[off], LOW); } } // End relayOff /* * Turn on or off input relays (mute relay is controlled by toggleMute()) * * relayCount is the actual chosen active relay * previousRelay is the previous chosen active relay * This function is triggered if the two are unequal * The function can be forced to trigger by changing previousRelay: previousRelay = relayCount + 1; */ void relayOn() { // If relayCount has changed: Turn on the selected relay (next, previous, direct) // If previousRelay has changed: Turn on the last selected relay if (relayCount != previousRelay) { auto localRelayCount = relayCount; // local copy, assuming atomic integer /* Rollover 3 or 0, * * There are four input relays, 0 to 3 (Status messages prints them as inputs 1 to 4) * This part makes sure we can't choose relays lower than 0 or higher than 3 */ if (localRelayCount > 3) { localRelayCount = 0; } else if (localRelayCount < 0) { localRelayCount = 3; } // Turn off all relays, then turn on localRelayCount relayOff(); digitalWrite(relays[localRelayCount], HIGH); relayCount = localRelayCount; // Write relayCount to memory EEPROM.write(0,relayCount); EEPROM.commit(); Serial.print("[LM3886]: Written \"relayCount = "); Serial.print(relayCount); Serial.println("\" to save slot 0"); // Reset counters, output relayNumber previousRelay = relayCount; relayNumber = relayCount + 1; Serial.print("[LM3886]: Activated relay #"); Serial.println(relayNumber); Serial.println(); /* * Mute, then unmute if just powered on * relayOn() is called at power on, placing the startupDelay mute here is convenient so we don't have to run a separate function * If the configurable value startupMute is 0, there will be no delay */ if ((poweronMute == 1) && (startupDelay == 0)) { poweronMute = 0; // Set poweronMute to 0, so this mutedelay doesn't occur every time the circuit is muted mute = 0; // toggleMute will unmute toggleMute; } else if (poweronMute == 1) { poweronMute = 0; // Set poweronMute to 0, so this mutedelay doesn't occur every time the circuit is muted Serial.println("[LM3886]: Turning on mute LED"); digitalWrite(muteLed,HIGH); Serial.print("[LM3886]: Milliseconds delay before turning off mute: "); Serial.println(startupDelay); delay(startupDelay); mute = 0; // toggleMute will unmute when called next toggleMute(); } } } // End relayOn() /* * Mute activate/deactivate */ void toggleMute() { // This function will mute if unmuted, and vice versa everytime it's called if (mute == 1) { // Read mute variable. if unmuted, turn on mute Serial.println("[LM3886]: Mute relay turned ON"); digitalWrite(relays[4],LOW); if (powerState == 1){ // If powered on, also turn on mute LED Serial.println("[LM3886]: Turning on mute LED\n"); digitalWrite(muteLed,HIGH); // Set mute to 0, next time toggleMute is called, it will turn OFF mute // mute = 0 now means we're muted mute = 0; // Unmute next time this function is called } // End if powered on } else { // Mute must be 0, turn off mute Serial.println("[LM3886]: Mute relay turned OFF"); digitalWrite(relays[4],HIGH); Serial.println("[LM3886]: Turning off mute LED\n"); digitalWrite(muteLed,LOW); // Turn off mute LED, no matter if it was turned on or off earlier. // Set mute to 1, next time toggleMute is called, it will turn ON mute // mute = 1 now means we're unmuted mute = 1; // Mute next time this function is called } // } // End toggleMute() /* * Power on / off */ void togglePower() { /* * If powerState is 1, turn OFF: All relays OFF, power amp OFF */ if (powerState == 1) { powerState = 2; // Setting powerState to 2 (off) if (mute == 1) { // If unmuted, turn on mute toggleMute(); // mute variable = 1, toggleMute will turn on mute. powerState = 2, mute LED will not turn on } else if (mute == 0) { // If already muted, turn off mute LED Serial.println("[LM3886]: Mute relay stays turned ON"); Serial.println("[LM3886]: Turning off mute LED"); digitalWrite(muteLed,LOW); // Turning off the mute LED } relayOff(); if (enableSSR == 1) { // Only turn off SSR if "enableSSR" is set to 1 digitalWrite (SSR,LOW); // Turning off Solid State Relay Serial.println("[LM3886]: Solid State Relay OFF"); } Serial.println("[LM3886]: Turning off power LED"); Serial.println("[LM3886]: Power OFF\n"); digitalWrite (LED,LOW); // Turning off the power LED poweronMute = 1; // Set poweronMute to 1, this will force a mute with delay on next power on /* * If powerState is 2, turn ON: Last selected relay ON, power amp (Solid State Relay ON) */ } else if (powerState == 2) { // powerState = 1; // Setting powerState to 1 (on) Serial.println("[LM3886]: Turning on power LED"); digitalWrite (LED,HIGH); // Turning on the power lED previousRelay = relayCount + 1; // Trigger relayOn() Serial.println("[LM3886]: Power ON"); if (enableSSR == 1) { // Only enable SSR if "enableSSR" is set to 1 digitalWrite (SSR,HIGH); // Turning on Solid State Relay Serial.println("[LM3886]: Solid State Relay ON\n"); } // We have just powered on // The circuit is muted, manually in powerOn(), toggleMute() has not been involved to set the mute variable // mute = 0; tells toggleMute() that we are muted, and that toggleMute() will unmute the next time it's called // relayOn() will call toggleMute if poweronMute = 1 mute = 0; relayOn(); } } // End togglePower() /* * Read the rotary encoder */ void rotEncoder() { versatile_encoder->ReadEncoder(); } /* * IR Remote */ void irRemote() { // Start irRemote function // Decode the infrared input if (IrReceiver.decode()) { long int decCode = IrReceiver.decodedIRData.command; if (decCode != 0) { Serial.print("[LM3886]: Received IR code: "); Serial.println(decCode); } // Read pushed remote control button and take action // All actions for remote control buttons are defined here switch (decCode) { // Start switch/case case oneButton: // Relay 1 - Input 1 { Serial.println("[LM3886]: Button \"1\""); if (powerState == 1) { relayCount = 0; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case twoButton: // Relay 2 - Input 2 { Serial.println("[LM3886]: Button \"2\""); if (powerState == 1) { relayCount = 1; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case threeButton: // Relay 3 - Input 3 { Serial.println("[LM3886]: Button \"3\""); if (powerState == 1) { relayCount = 2; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case fourButton: // Relay 4 - Input 4 { Serial.println("[LM3886]: Button \"4\""); if (powerState == 1) { relayCount = 3; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case fiveButton: // Button 5 - Info message { Serial.println("[LM3886]: Button \"5\""); if (powerState == 1) { ; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case sixButton: // Button 6 - Info message { Serial.println("[LM3886]: Button \"6\""); if (powerState == 1) { ; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case sevenButton: // Button 7 - Info message { Serial.println("[LM3886]: Button \"7\""); if (powerState == 1) { ; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case eightButton: // Button 8 - Info message { Serial.println("[LM3886]: Button \"8\""); if (powerState == 1) { ; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case nineButton: // Button 9 - Info message { Serial.println("[LM3886]: Button \"9\""); if (powerState == 1) { ; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case zeroButton: // Button 0 - Info message { Serial.println("[LM3886]: Button \"0\""); if (powerState == 1) { ; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case volupButton: // Volume up - Info message { Serial.println("[LM3886]: Button \"vup\""); if (powerState == 1) { digitalWrite (vup, HIGH); wait_loops=1000; // bRecRepeat = true; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case voldownButton: // Volume down - Info message { Serial.println("[LM3886]: Button \"vdwn\""); if (powerState == 1) { digitalWrite (vdwn, HIGH); // bRecRepeat = true; wait_loops=1000; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case muteButton: // Mute { Serial.println("[LM3886]: Button \"Mute\""); if (powerState == 1) { toggleMute(); } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case ffButton: // Channel UP { Serial.println("[LM3886]: Button \"UP\""); if (powerState == 1) { relayCount++; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } break; } case rewButton: // Channel DOWN { Serial.println("[LM3886]: Button \"DOWN\""); if (powerState == 1) { relayCount--; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); }; break; } case powerButton: // Power button { Serial.println("[LM3886]: Button \"POWER\""); togglePower(); unsigned long powMillis = millis(); // Always wait a bit longer after powerButton to avoid turning on immediately after power off, regardless of irRate while (millis() - powMillis < 750) { ; } break; } /*default: bRecRepeat = false; { Serial.println("[LM3886]: Going back to waiting for IR remote keypress\n"); } */ }// End switch/case unsigned long irMillis = millis(); while (millis() - irMillis < irRate) { ; } IrReceiver.resume(); // Receives the next value from the button you press } // End of if IrReceiver decode wait_loops=wait_loops-1; if(wait_loops==0) { wait_loops=1; digitalWrite (vup, LOW); digitalWrite (vdwn, LOW); } } // End irRemote() /* * Rotate the rotary encoder * * Change the encDirection value if you want to reverse the direction */ void handleRotate(int8_t rotation) { Serial.print("[LM3886]: Rotational encoder turned "); // encDirection set to 0 if ( ((rotation > 0) && (encDirection == 0)) || ((rotation < 0) && (encDirection == 1)) ) { // Channel down (counter-clockwise) Serial.println("counter-clockwise"); if (powerState == 1) { // Increase relayCount relayCount--; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); // Powered off } } else if ( ((rotation > 0) && (encDirection == 1)) || ((rotation < 0) && (encDirection == 0)) ) { // Channel up (clockwise) Serial.println("clockwise"); if (powerState == 1) { // Increase relayCount relayCount++; } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); // Powered off } } // Wait for the amount of milliseconds defined by rotRate until reading the next IR command // This delay uses interrupts, so it won't hold up the rest of the program unsigned long rotMillis = millis(); while (millis() - rotMillis < rotRate) { ; } } // End handleRotate() /* * Press rotary encoder button. * * Will turn on or off the Muffsy Input selector when the button is released, * or mute if you have changed the encPush value and the powerState is 1 (on) */ void handlePressRelease() { if (encPush == 0) { // Power off Serial.println("[LM3886]: Button \"Power\""); togglePower(); } else { // Mute Serial.println("[LM3886]: Button \"Mute\""); if (powerState == 1) { toggleMute(); } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } } } // End handlePressRelease() /* * Long press the rotary encoder button. * * It will mute or unmute, as long as powerState is 1 (on), * or power on/off if you have changed the encPush value */ void handleLongPress() { if (encPush == 1) { // Power off Serial.println("[LM3886]: Button \"Power\""); togglePower(); } else { // Mute Serial.println("[LM3886]: Button \"Mute\""); if (powerState == 1) { toggleMute(); } else { Serial.println("[LM3886]: Powered off, doing nothing...\n"); } } } // End handleLongPress() // END OF THE PROGRAM test_remote.txt
  7. am testat continutul celui de-al doilea fisier de la @cristi7521. partea de schimbat canale functioneaza normal, partea de volum, nu: daca apas vup, led-ul (ca pt testare folosesc led-uri pe pinii pt ctrl volum) de vup ramane aprins chiar si dupa ce a incetat apasarea tastei. La fel se intampla si pt vdwn, totusi cand se stinge un led celalalt se stinge (exista insa un timp cand cele 2 leduri sunt simultan aprinse, ceea ce este rău pentru puntea H ce va fi comandată!). Ledurile pot fi stinse apoi doar cu power off, in rest, ramane unul aprins. Ma pun sa incerc si primul fisier.
  8. da, butoanele de la 0-9 au acele valori. La fel si butoanele power, mute, chanel up si dwn, vol up si dwn. de celelalte nu am nevoie, asa ca nici nu le-am mai verificat. ESP trimite pe serial ce tasta s-a apasat la telecomanda, asa le-am dibuit. Folosesc o telecomanda universala pe care am programat-o sa dea coduri pt daewoo cred, ca nu am nimic daewoo prin casa. Am incercat si alte coduri IR, dar unele erau din 2 secvente, de exemplu pentru tasta 1 imi trimite 22 si 15. Am incercat pana am gasit un cod IR care sa fie din cel mult 2 cifre si sa nu interfereze cu ce am prin casa.
  9. L-am intrebat pe Bing dar nu ma inteleg cu el. Cred ca nu stiu eu sa-l intreb.
  10. Salutare! Sunt si eu interesat de acest subiect, ba chiar de proiectul colegului @Untold pe care-l rog sa incarce sketch-ul final, functional, daca se poate. Multumesc!
  11. E posibil ca Nano sa nu poate gestiona treaba cu ecranul (poate procesor prsa slab, prea puțin RAM, mai ales la o clona). Citisem pe undeva ca sunt probleme la combinatia asta de nano cu ecran (grafic) oled. Incearca cu un ESP32, poate e mai potent. E doar o parere...
  12. de testat, testez eu cand am timp. Numai sa nu patesc cum am patit si in cealalta postare: programatorul s-a lasat pagubas.
  13. multumesc pentru raspuns, dar oare ar fi bine sa modificam codul si sa o luam de la capat cu incercarile? Am mai incercat acum ceva ani sa fac un astfel de selector si cu control volum si am ajuns la concluzia ca mai bine il fac pe acesta. Codul e deja scris, mai e de bibilit puțin la el. Cred ca acel bRecRepeat nu e pus unde trebuie....dar nu ma pricep L.E.: codul nu-mi apartine, e facut de nordicul ala. Eu doar am incercat sa-l adaptez
  14. Am revenit. am compilat sketch-ul, nicio problemă. L-am încărcat și testat: power on si apoi power off, la vreo 2 secunde, în buclă. Nu mai primeste nicio comanda, probabil pentru ca nu mai are timp sa primeasca si comenzi. Nu stiu unde sa modific, probabil e prins in bucla ceva ce nu ar trebui sa fie acolo.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.Terms of Use si Guidelines