Empfängerprogramm

Bild: Testaufbau Empfänger


Funktionen:

Das Empfangsprogramm führt folgende Funktionen aus:

  • Einlesen der Codierschalter im Setup (eingestellte Adresse des Empfängers)
  • Eingelangtes Telegramm auf Checksumme und EmpfängerID überprüfen
  • KomponentenID, BefehlsID und gegebenenfalls Wertebytes aus Telegramm extrahieren
  • Schaltbefehle an die Komponenten ausgeben
  • Gegebenenfalls Wertebytes, entweder als PWM-Signal für Drehzahlsteuerung eines E-Motors ausgeben oder als PWM-Signal für die Ansteuerung eines Servo über I2C-Schnittstelle an Attiny senden


Wie im Testaufbau ersichtlich, werden die beiden Servos nicht über den Arduino Uno angesteuert, sondern über einen Attiny45 Controller, der über I2C-Schnittstelle mit dem Uno verbunden ist. Der Grund, warum ich die Servos nicht direkt mit dem Uno steuere liegt daran, dass sich beim Uno die VirtualWire- Library  wahrscheinlich wegen Timerprobleme nicht mit der Servo-Library verträgt und auch nicht mit Servoansteuerungen mit Timer1 oder Timer2 (wie hier gezeigt: Servosteuerung) funktioniert.

Hier geht's zum Programm Servoansteuerung Attiny


Verwendete Libraries:

Neben den Standard-Library Wire verwende ich folgende Library:

  • VirtualWire: Steuert die drahtlose Übertragung eines Telegramms z.B. über eine Funkübertragungsstrecke (den Link zur Library findet iher hier: Fremd-Libraries)


Sonstiges:

Codierschalter:

Mittels zwei Codierschalter kann die Empfängeradresse hardwaremäßig eingestellt werden, wobei sich mit zwei Schalter vier mögliche Adressen ergeben: 00, 01, 10 und 11. Die Schalterstellungen werden im Setup-Teil des Programms eingelesen, bei einer Änderung der Adresse ist also ein Neuanlauf des Empfängerprogramms erforderlich.

Debug-Modus:

Wie auch beim Senderprogramm kann mit der Anweisung "#define debug 1" im Deklarationsteil des Programms das Empfängerprogramm in den "Debug-Modus" geschaltet werden. Dabei werden verschiedene Daten, wie Inhalte von Zwischen- und Sendebuffer zur Kontrolle am Seriellen Monitor (Übertragungsrate auf 115200 Baud stellen) ausgegeben. Wenn die Anzeige am Seriellen Monitor nicht mehr benötigt wird, dann den Debug-Modus mit "#define debug 0" unbedingt ausschalten, da die serielle Ausgabe das Programm unnötig bremst.

Funk-Fernsteuerung_Empfaenger202.ino Version 1.1

//Testprogramm Funk-Fernsteuerung Empfänger
//Funk-Fernsteuerung_Empfaenger202.ino
//Code fuer Arduino
//Author Retian
//Version 1.1


#include <Wire.h>
#include <VirtualWire.h>


//0 ... kein Debug-Modus Ausgabe am Seriellen Monitor
//1 ... Debug-Modus Ausgabe am Seriellen Monitor
#define debug 0


#define rxPin 2 //TX-Pin
#define rxledPin 4 //LED1-Pin
#define led1Pin 7 //LED2-Pin
#define led2Pin 10 //LED3-Pin
#define s0Pin 5 //Codierschalter S0
#define s1Pin 6 //Codierschalter S1
#define motor1Pin 3 //Motor1-Pin
#define motor1RichtungsPin 12 //Motor1 Drehrichtungs-Pin
#define motor2Pin 11 //Motor2-Pin
#define motor2RichtungsPin 13 //Motor2 Drehrichtungs-Pin

#define attiny1I2CAdd 0x07 //I2C-Adresse des ersten Attiny45
#define attiny2I2CAdd 0x08 //I2C-Adresse des zweiten Attiny45 //Derzeit noch nicht vorhanden


//Definition des Sende-Telegramms
//Die Bytes des Sende-Telegramms stehen im Byte-Array "empfangsBuffer" zu Verfuegung
//"empfangsBuffer" muss im loop deklariert werden -> lt. VirtualWire)
const byte telegrammLaenge = 4; //Telegrammlaenge in Bytes
//Byte0: IDByte
//Byte1: PWM-Impulszeit High-Byte
//Byte2: PWM-Impulszeit Low-Byte
//Byte3: CheckSumme


//Index-Nummern des Sendetelegrammms im "empfangsBuffer"
#define indexIDByte 0
#define indexHighByte 1
#define indexLowByte 2
#define indexCheckSumByte (telegrammLaenge - 1)
//Ueber diese Bytes soll die Checksumme ermittelt werden
#define indexCheckSumByteAnf 0
#define indexCheckSumByteEnd (telegrammLaenge - 2)


//Zusammensetzung des ID-Bytes
//Bit7-6: EmpfaengerID
//Bit5-2: KomponentenID
//Bit1-0: BefehlsID
byte empfaengerID;
byte komponentenID;
byte befehlsID;

int pwmTime; //Gesendete PWM-Zeit
byte checkSum = 0; //Errechnete Checksumme

uint16_t anzChecksumFehler = 0; //Anzahl Checksummenfehler

byte empfID; //Mit Tippschalter eingestellte ID des Empfaengers


//Definition vom maximal 16 Komponenten (0 bis 15)
#define LED1 1
#define LED2 2
#define Servo1 12
#define Servo2 13
#define Motor1 14
#define Motor2 15


void setup() {
  if (debug) Serial.begin(115200);
  pinMode(rxledPin, OUTPUT);
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  pinMode(s0Pin, INPUT);
  pinMode(s1Pin, INPUT);
  pinMode(motor1Pin, OUTPUT);
  pinMode(motor1RichtungsPin, INPUT);
  digitalWrite(rxledPin, 0);
  digitalWrite(led1Pin, LOW);
  digitalWrite(led2Pin, LOW);

  //EmpfaengerID von Tippschalter einlesen
  byte s1;
  byte s0;
  s1 = !digitalRead(s1Pin);
  s0 = !digitalRead(s0Pin);
  empfID = (s1 << 1) | s0;
  if (debug)
  {
    Serial.print("S1 S0: ");
    Serial.print(s1);
    Serial.print(" ");
    Serial.println(s0);
    Serial.print("EmpfaengerID: ");
    Serial.println(empfID);
  }

  //Initialisierung von Wire
  Wire.begin();
  Wire.setClock(400000L); //Frequenz auf 400 kHz setzen

  //Initialisierung von VirtualWire
  vw_set_rx_pin(rxPin); //Setze RX-Pin
  vw_setup(8000); //Übertragungsrate 8000 Bits/Sekunde
  vw_rx_start();
  if (debug) Serial.println("Warte auf Befehle ...");
}


void loop() {
  byte empfangsBuffer[telegrammLaenge];
  byte buflen = telegrammLaenge;

  for (byte i = 0; i < telegrammLaenge; i++) empfangsBuffer[i] = '\0'; //Loesche Empfangsbuffer
  vw_wait_rx(); //Warte auf Telegramm
  vw_get_message(empfangsBuffer, &buflen); //Telegramm erhalten
  //Bei jedem empfangenem Telegramm blinkt die LED für 0,05 ms auf
  digitalWrite(rxledPin, 1);
  delayMicroseconds(50);
  digitalWrite(rxledPin, 0);

  //Ermittlung der Checksumme
  checkSum = 0;
  for (byte i = indexCheckSumByteAnf; i <= indexCheckSumByteEnd; i++)
  {
    CheckByte(empfangsBuffer[i], i);
  }
  if (debug)
  {
    Serial.println();
    Serial.print("Checksumme ermittelt: ");
    Serial.println(checkSum);
    Serial.print("Checksumme gesendet : ");
    Serial.println(empfangsBuffer[indexCheckSumByte]);
  }

  //Pruefen ob gesendete Checksumme mit berechneter Checksumme uebereinstimmt
  if (checkSum == empfangsBuffer[indexCheckSumByte])
  {
    if (debug)
    {
      Serial.print("Empfangsbuffer: ");
      for (byte i = 0; i < telegrammLaenge; i++)
      {
        Serial.print(empfangsBuffer[i]);
        Serial.print(" ");
      }
      Serial.println();
    }
    // ID-Byte in empfaengerID, komponentenID und befehlsID zerlegen
    empfaengerID = empfangsBuffer[indexIDByte] >> 6;
    komponentenID = (empfangsBuffer[indexIDByte] & B00111100) >> 2;
    befehlsID = (empfangsBuffer[indexIDByte] & B00000011);

    if (debug)
    {
      Serial.print("EmpfaengerID: ");
      Serial.println(empfaengerID, BIN);
      Serial.print("KomponentenID: ");
      Serial.println(komponentenID, BIN);
      Serial.print("BefehlsID: ");
      Serial.println(befehlsID, BIN);
    }

    //Wenn gesendete EmpfaengerID gleich der eingestellten ID ist,
    //dann Abfrage welche Komponente
    if (empfaengerID == empfID)
    {
      //Wenn KomponentenID = LED1
      if (komponentenID == LED1)
      {
        if (befehlsID == 1) digitalWrite(led1Pin, HIGH); //BefehlsID = Ein
        else if (befehlsID == 0) digitalWrite(led1Pin, LOW); //BefehlsID = Aus
        else if (befehlsID == 2) digitalWrite(led1Pin, !digitalRead(led1Pin)); //BefehlsID = Toogle
      }

      //Wenn KomponentenID = LED2
      if (komponentenID == LED2)
      {
        if (befehlsID == 1) digitalWrite(led2Pin, HIGH); //BefehlsID = Ein
        else if (befehlsID == 0) digitalWrite(led2Pin, LOW); //BefehlsID = Aus
        else if (befehlsID == 2) digitalWrite(led2Pin, !digitalRead(led2Pin)); //BefehlsID = Toogle
      }


      //Wenn KomponentenID = Servo1
      if (komponentenID == Servo1)
      {
        if (befehlsID == B11)
        {
          if (debug)
          {
            pwmTime = (empfangsBuffer[indexHighByte] << 8) | empfangsBuffer[indexLowByte];
            Serial.print("pwmTime: ");
            Serial.println(pwmTime);
          }

          //pwmTime an Attiny45 senden
          Wire.beginTransmission(attiny1I2CAdd);
          Wire.write(1); //Servo1 des Attiny1
          Wire.write(empfangsBuffer[indexHighByte]);
          Wire.write(empfangsBuffer[indexLowByte]);
          Wire.endTransmission();
        }
      }


      //Wenn KomponentenID = Servo2
      if (komponentenID == Servo2)
      {
        if (befehlsID == B11)
        {
          if (debug)
          {
            pwmTime = (empfangsBuffer[indexHighByte] << 8) | empfangsBuffer[indexLowByte];
            Serial.print("pwmTime: ");
            Serial.println(pwmTime);
          }

          //pwmTime an Attiny45 senden
          Wire.beginTransmission(attiny1I2CAdd);
          Wire.write(2); //Servo2 des Attiny1
          Wire.write(empfangsBuffer[indexHighByte]);
          Wire.write(empfangsBuffer[indexLowByte]);
          Wire.endTransmission();
        }
      }


      //Wenn KomponentenID = Motor1
      if (komponentenID == Motor1)
      {
        if (befehlsID == 0)digitalWrite(motor1RichtungsPin, 0); //Drehrichtg. vorwaerts
        else if (befehlsID == 1)digitalWrite(motor1RichtungsPin, 1); //Drehrichtg. rueckwärts
        else if (befehlsID == B11)
        {
          if (debug)
          {
            pwmTime = (empfangsBuffer[indexHighByte] << 8) | empfangsBuffer[indexLowByte];
            Serial.print("pwmTime: ");
            Serial.println(pwmTime);
          }
          analogWrite(motor1Pin, empfangsBuffer[indexLowByte]); //pwmTime ausgeben
        }
      }


      //Wenn KomponentenID = Motor2
      if (komponentenID == Motor2)
      {
        if (befehlsID == 0)digitalWrite(motor2RichtungsPin, 0); //Drehrichtg. vorwaerts
        else if (befehlsID == 1)digitalWrite(motor2RichtungsPin, 1); //Drehrichtg. rueckwärts
        else if (befehlsID == B11)
        {
          if (debug)
          {
            pwmTime = (empfangsBuffer[indexHighByte] << 8) | empfangsBuffer[indexLowByte];
            Serial.print("pwmTime: ");
            Serial.println(pwmTime);
          }
          analogWrite(motor2Pin, empfangsBuffer[indexLowByte]); //pwmTime ausgeben
        }
      }

      //Platz für weitere Komponenten

    }

  }
  else
  {
    anzChecksumFehler++;
    Serial.print("Checksumme Fehler ");
    Serial.println(anzChecksumFehler);
  }
}


//Checksummenbildung
void CheckByte(byte buf, byte i)
{
  for (int j = 0; j < 8; j++)
  {
    if (bitRead(buf, j) == 1) checkSum += (i + j + 1);
  }
}