Sonntag, 19. August 2018

per Drehencoder Tastenradio steuern

Bericht vom

Schon länger wollte ich mit minimalem Aufwand Radiobausteine wie den HEX3653, das Serial Port Baustein Modul oder den BK1068, welche per Mikro-Tasten gesteuert werden, mit einem Drehencoder bedienen können. Da der Encoder grundsätzlich Impulse abgibt, kann er eine einzelne Taste direkt ersetzen. Aber sobald die Drehrichtung des encoders ausgewertet werden muss kommt ein Mikroprozessor ins Spiel.
Mit einem Arduino ist das kein großer Akt. Aber es sollte ein kleiner attiny sein. An dessen Besonderheiten der Pin Change Interrupts bin ich aber gescheitert und bekam keine richtige Entprellung hin und auch keine treffsichere Richtungserkennung.

Diese Probleme konnte ich nun lösen. Ich benutze weitgehend den code von The Wandering Engineer. Der steuert per encoder die Helligkeit einer LED. Ich hab ihn mir so abgeändert daß eine Drehbewegung einen 200ms langen Impuls abgibt, und zwar in Abhängigkeit der Drehrichtung jeweils an einem anderen Ausgangsport.



So sieht mein fertiger code aus:



/*
https://thewanderingengineer.com/2014/08/11/rotary-encoder-on-the-attiny85-part-2/
*/

#include "avr/interrupt.h";

volatile int lastEncoded = 0;
volatile int search_mode = 0;

unsigned long previousMillis = 0; // speichert wie viele Sekunden seit derletzten Änderung vergangen sind
unsigned long interval = 2000;    // Impulslänge

void setup()
{
 pinMode(0, OUTPUT);
 pinMode(1, OUTPUT);

 // set pins 3 and 4 to input

 pinMode(3, INPUT); //Pullup ist im encoder eingebaut
 pinMode(4, INPUT); //Pullup ist im encoder eingebaut

 GIMSK = 0b00100000;       // Enable pin change interrupts
 PCMSK = 0b00011000;       // Enable pin change interrupt for PB3 and PB4
 sei();                    // Turn on interrupts
}

void loop()
{
   if (millis() - previousMillis > interval) {
   digitalWrite(0, HIGH);
   digitalWrite(1, HIGH);
     if (search_mode == 1) {
     digitalWrite(0, LOW);
     search_mode = 0;
     previousMillis = millis();   // aktuelle Zeit abspeichern
     }
     if (search_mode == 2) {
     digitalWrite(1, LOW);
     search_mode = 0;
     previousMillis = millis();   // aktuelle Zeit abspeichern
     }
     }    
}

// This is the ISR that is called on each interrupt
// Taken from http://bildr.org/2012/08/rotary-encoder-arduino/
ISR(PCINT0_vect)
{
 int MSB = digitalRead(3); //MSB = most significant bit
 int LSB = digitalRead(4); //LSB = least significant bit

 int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
 int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

 if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011)
   search_mode = 1;
 if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000)
   search_mode = 2;

 lastEncoded = encoded; //store this value for next time

}

ein paar Erklärungen dazu:

die Impulslänge wird durch die millis() Funktion festgelegt. Dies ist auch gleichzeitig die Entprellzeit. Die erste Einschwingflanke wird ausgewertet und danach wird der encoder 200ms lang in der loop ignoriert. Der Wert "unsigned long interval = 2000;" bedeutet eigentlich 2 Sekunden, vermutlich habe ich aber eine Diskrepanz zwischen dem Takt, den ich mit 1MHz gewählt habe, und den fuses des attiny. Da es sonst keine zeitkritische Funktion gibt macht das keine Probleme.

An den Eingängen werden keine pullups gesetzt, weil der verwendete encoder (KY-040) diese hardwaremässig eingebaut hat. Das gleiche gilt für die Ausgänge. Die Eingänge des Radiobausteins liegen bereits auf high-Potential, und der LOW-Impuls legt diese dann für 200ms auf Masse. Diese Zeit entspricht dem gemütlichen Drücken einer Taste von Hand.

Die Interruptfunktion wertet die Drehrichtung aus und speichert das Ergebnis in der Variablen "search_mode".

In der loop wird ausserhalb der Sperrzeit von 200ms auf diese Variable reagiert, also der entsprechende Ausgangsport gesetzt, und "search_mode" wieder auf 0 gesetzt (1 und 2 sind die beiden Drehrichtungen).

Die Variable "last_encode" könnte als Überrest des ursprünglichen codes ohne Bedeutung sein, das ist mir noch nicht so ganz klar.

So, genug Theorie.

Kommen wir zum Aufbau des Bedienteiles

die kleine Platine trägt den DIL-Sockel für den attiny, die Steckverbindung für das Encoder-Modul und die Steckverbindungen für Spannungsversorgung und Ausgänge.


An dem Encoder wird die Lötleiste rumgedreht, damit er besser an einer Frontplatte befestigt werden kann




hier ist der Grund zu erkennen:


Die Platine für die Lautstärkeregelung ist ein Stück länger als die für die Senderabstimmung, weil sie noch einen Spannungsregler für die 3,3V-Versorgung trägt. Die Speisung des Radio soll später über PowerPack oder USB erfolgen.



Die Verdrahtung der Unterseite:


Der Attiny wird mit Hilfe eines Arduino programmiert:


der komplette Laboraufbau:



hier die Unterschiede zwischen dem Modul für die Sender- und dem für die Lautstärkeeinstellung:



der HEX3653 Baustein (Mickey Mouse Radio):
 

bei einem anderen Baustein müssen dessen Eigenarten der Tasterbeschaltung bei der Programmierung der pullups und des Ausgangimpulses berücksichtigt werden. So hat der BK1068 zum Beispiel Tristate-Eingänge. Die Tasten für vol+ und scan+ schalten den Eingang auf HIGH und vol- und scan- auf LOW.

wer bis hierher durchgehalten hat wird nun noch mit einem Video belohnt. Eine praktische Anwendung für diese Radiosteuerung wird in Bälde folgen

der Verdrahtungsplan:




Ich habe jetzt eine kompaktere Version gebaut, welche nicht mehr das KY-040 Encoder Modul verwendet, sondern den Encoder als Einzelbauteil. Dadurch bin ich flexibler was die Schaltlogik des Pushbutton Switch angeht. Mit einem Jumper kann ich jetzt je nach Anforderung den Switch wahlweise gegen Plus oder gegen Masse schalten lassen. Ich erspare mir also die Manipulation der smd-Pullups und der Verdrahtung im Modul, und auch sowieso den Umbau der Modul-Steckverbindung. Ein weiterer Vorteil ist der Gewinn an mechanischer Stabilität.

Da auch die Pullup-Widerstände für CLK und DT nun nicht mehr existieren muss ich im attiny die Software-Pullups einschalten.

pinMode(3, INPUT_PULLUP); //Aktivieren der software-Pullups
pinMode(4, INPUT_PULLUP); //

Brauche ich für CLK und DT eine andere Logik muss ich das in der Software beim Setzen der Output's anpassen.


Durch die Bauhöhe des gesockelten attiny und wegen der Zugänglichkeit zur Buchsenleiste empfiehlt es sich den Encoder auf die andere Seite der Leiterplatte zu setzen. Eine durchkontaktierte Standard 8x2cm Platine ist ideal, und bietet auch noch Platz falls ein Spannungsregler dazu gesetzt werden soll.

Das timing Problem des attiny ist nun auch behoben. Ich muss lediglich beim ersten Verwenden eines neuen attiny in der Arduino-Software einmalig die fuses setzen ("Bootloader brennen"). Ich benutze einen Takt von 1MHz.

Die Buchsenleiste ist 6-polig eine gängige Variante. Es hat sich angeboten den A1-PIN der attiny als Reserve auf den ansonsten freien PIN der Buchsenleiste zu legen.






1 Kommentar:

  1. Hallo,
    auch wenn dieser Bericht schon alt ist würde mich ein nachbau interessieren.Ich bin schon ein älterer Herr der des Programierens oder umwandelns nicht mehr mächtig ist.Wäre es irgendwie möglich das sie mir den code als Hex file zukommen lassen könnten. ich wäre ihnen sehr dankbar.
    Gruss Horst Klug

    AntwortenLöschen