Empfängerprogramm
Abbildung 5-1: 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 Checksummeuint16_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);
}
}