Forum: Compiler & IDEs [Attiny85] 2x Modellbau-Empfängersignal auswerten


von Heiko P. (doomgiver)


Lesenswert?

Hallo,

ich bin neu hier und möchte mich kurz vorstellen. Mein Name ist Heiko, 
ich komme aus der schönen(?) Sprottenstadt Kiel. Elektronik bzw. 
Elektrik verwende ich in meinem Hobby Modellbau, weswegen da auch der 
Schwerpunkt liegt. Hauptsächlich Lichtsteuerungen für Raumschiffe und 
Steuermodule für meine RC-Modelle. Angefangen habe ich da mit der 
Arduino-Umgebung, was auch ganz gut klappte und die Scheu vor den 
"nackten" AVRs nahm (Stichwort Fuses). Irgendwann war mir das aber 
zuviel Gekrücke, vor allem wenn ich einfachere Sachen nur mit Attinys 
machen wollte. Daher erfolgte vor kurzem der Sprung auf die "echte" 
AVR-Umgebung (Atmel Studio 6.2, AVRISP MkII, etc.).

Nun zu meinem Problem: Ich versuche über einen Attiny85 zwei Signale 
eines Empfängers einzulesen und entsprechend weiterzuverarbeiten. Im 
ersten Anlauf will ich nur das empfangene Signal eines Kanals zum testen 
ausgeben, wenn das vernünftig funktioniert geht es weiter.
Kern sind die beiden Timer. Timer0 läuft im CTC-Modus und erhöht alle 
8µs einige Zähler um 1. Timer1 ist nur dafür da, alle 20ms die 
Signalausgabe neu zu starten (habe ich auch nur dank dieses Treads zum 
laufen bekommen: Beitrag "ATtiny25, TimerCounter1, CTC-Mode: Bug?").

Der Signalstart alle 20ms funktioniert auch tadellos, nur das 
auszugebende Signal klappt gar nicht. Wenn kein Empfänger angeschlossen 
ist, soll der Start- bzw. letzte gültige Wert zwischen 1000-2000µs 
ausgegeben werden. Stattdessem wandert das Signal förmlich, beginnend 
bei ca. 3200µs langsam runter auf 2000µs und dann wieder von vorne. Kann 
ich auf meinem Spielzeug-Taschen-Oszi richtig schön beobachten.

Ich bin da jetzt langsam etwas ratlos, kaue schon seit einigen Tagen 
daran herum. Die Suche ergab leider nicht so furchtbar viel (mal mit 
PC-Interrupt, mal ohne, oft nur ein Kanal, etc.), auch wenn das Thema 
"Servosignal" offenbar ganze Seiten füllt.
1
#include <avr/interrupt.h>
2
#include <avr/io.h>
3
4
#define pin_benedini PB0                  // Anschluss für Benedini-Modul
5
#define pin_drehgeber PB1                  // Anschlüss für Poti-Geber vom Empfänger
6
#define pin_taster PB2                    // Anschluss für Tast-Geber vom Empfänger
7
#define pin_led PB4                      // Anschluss für Status-LED
8
9
volatile uint16_t zeit = 0;                  // aktuelle Ausgabedauer für Benedini-Modul
10
volatile uint16_t zeit_empfaenger[2] = {188, 188};      // Signaldauer der empfangenen Empfängersignale
11
uint16_t zeit_ausgabe[2] = {188, 188};            // auszugebende Signaldauer für Benedini und LED
12
uint8_t pin_empfaenger[2] = {pin_taster, pin_drehgeber};  
13
uint8_t pinb_alt = 0;                    // Zustand von PINB vor Änderung von PORTB
14
15
int main(void)
16
{  
17
  DDRB |= ((1 << pin_benedini) | (1 << pin_led));      // Benedini und LEd als Ausgang definieren
18
  
19
  TCCR0A |= (1 << WGM01);                  // CTC-Mode aktiviert
20
  TCCR0B |= (1 << CS00);                  // Prescaler = 1
21
  OCR0A = 63;                        // 8µs
22
  TIMSK |= (1 << OCIE0A);                  // Interrupt aktivieren
23
24
  TCCR1 |= ((1 << CS13) | (1 << CS11) | (1 << CS10) | (1 << PWM1A) | (1 << CTC1));  // Prescaler für Timer1 = 1024; CTC aktiviert
25
  OCR1C = 154;                      // 19840µs Periodendauer = 20ms für Servosignal
26
  TIMSK |= (1 << TOIE1);                  // Interrupt aktivieren
27
28
  sei();                          // globale Interrupts aktivieren
29
  
30
    while(1)
31
    {
32
    for(uint8_t i = 0; i < 2; i++){
33
      if(PINB & (1 << pin_empfaenger[i]) && !(pinb_alt & (1 << pin_empfaenger[i]))){    // steigender Pegel, Zeitmessung wird gestartet
34
        zeit_empfaenger[i] = 0;
35
        pinb_alt |= (1 << pin_empfaenger[i]);
36
      }
37
      
38
      if(!(PINB & (1 << pin_empfaenger[i])) && pinb_alt & (1 << pin_empfaenger[i])){    // fallender Pegel, Zeitmessung wird beendet
39
        if(zeit_empfaenger[i] >= 109 && zeit_empfaenger[i] <= 266){            // Zeitdauer ist gültig, als Ausgangsdauer festlegen
40
          zeit_ausgabe[i] = zeit_empfaenger[i];
41
        }
42
        pinb_alt &= ~(1 << pin_empfaenger[i]);
43
      }
44
        
45
    }
46
    
47
    if(zeit > zeit_ausgabe[0] && PINB & (1 << pin_led)){                  // Wenn Dauer der Ausgabe >= geplante Signallänge, Signal abschalten
48
      cli();
49
      PORTB &= ~((1 << pin_led) | (1 << pin_benedini));
50
      sei();
51
    }
52
    }
53
}
54
55
ISR(TIMER0_COMPA_vect){
56
  zeit++;
57
  zeit_empfaenger[0]++;
58
  zeit_empfaenger[1]++;
59
}
60
61
ISR(TIMER1_OVF_vect){
62
  PORTB |= ((1 << pin_led) | (1 << pin_benedini));                      // Alle 20ms die Signalausgabe neu starten
63
  zeit = 0;
64
}

Heiko

von STK500-Besitzer (Gast)


Lesenswert?

Dein Hauptprogramm hat also 64 Taktzyklen, um das ganze Geraffel in der 
Hauptschleife abzuarbeiten. Dazu kommt dann noch, dass zwischendurch der 
eine odere andere Takt übersehen werden könnte, weil die Interrupts 
abgeschaltet wurden.
Das ist verdammt sportlich.

Du solltest einen Timer durchlaufen lassen und in der Hauptschleife den 
Zustand der Portpins überprüfen. Wenn es eine Flanke gab, speichert man 
den Wert des Timers und berechnet ggf. die Pulslänge.

Die 20ms sind alter Kram, den man nicht unbedingt umsetzen muss.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.