Neues von neuer Seite (mir) :P
Neues von neuer Seite (mir) :P
Hallo alle zusammen,
bin auf diesen Thread gestoßen und wollte auch mal meinen Senf dazu geben:
First of all: danke! Dank dieses Threads und einigen anderen Websites habe ich erfolgreich meinen Arduino auf den Sensorbus aufgeschaltet.
Also: Wozu der ganze Spaß: mir sind die MPX sensoren zu teuer und mit Arduino kann man das ganze auchnoch selber individuell konfigurieren.
Wozu das erneute Aufwärmen des Threads? Es hat sich viel getan was Arduinos etc. angeht, va. bzgl. der Programmieroberfläche und libraries.
Falls Fragen zu dem Thema auftreten oder ihr persönliche Hilfe braucht, gern ne PN oder Mail an mich (simon123_1Äweb*de) [das Ä durch ein @ und den Stren duch einen Punkt ersetzen]
Also, zu meinem Projekt:
Ich brauche: ein Vario, einen Höhenmesser und einen Spannungsmonitor für meinen Antriebslipo.
Hardware:
- Arduinoboard (am besten mit nativem iic, >2 digital pins oder alternativ RX/TX pins vom regulären UART Serial, >1 anolog pin und einem 16bit Timer, damit die, für die Sensoren nötigen libraries problemlos laufen.) Ich empfehle konkret einen Arduino nano (für die Einsteiger unter uns) oder pro mini für die Fortgeschrittenen (3.3V evtl für diese Anwendung die Bessere Wahl). Von ATTiny rate ich ab!!!!
- Kleinere Elektrische Bauteile: Wiederstände im niedrigen kOhm bereich für einen Spannungsteiler (falls Spannungsmessung am Antriebsakku gewünscht); NPN Transistor, 10kOhm und Diode für den "halb-duplex - RX-TX wandler"
Klingt alles kompliziert, ist aber ganz einfach:
Zunächst muss uns eines klar sein: Der Empfänger verwendet für die Sensorschnittstelle einen standart UART-Bus, wie ihn auch der Arduino nativ unterstützt (RX/TX). Als Datenrate(Baudrate) verlangt und nutzt der Empfänger 38,4kBit/s alias 38400Baud. Im Gegensatz zum Arduino, der mit seperaten RX und TX Kabeln arbeitet, fallen beim MPX-Sensorbus beide Leitungen zur RX/TX Leitung zusammen (halb duplex). Wir können aber nicht einfach am Arduino beide Leitungen zusammen klemmen und an den Empfänger anschließen. Der TX-Pin am Arduino steht im Idle (nichts wird gesendet) dauerhaft auf logic 1 was bedeutet, er liegt immer bei 3,3 bzw 5 V. Der RX pin kann dementsprechend keine Daten empfangen.
mit folgender Schaltung von
http://nerdralph.blogspot.de/2014/01/avr-half-duplex-software-uart.html lässt sich das Problem überwinden:
TX/RX ---+--|>|-----+----- Tx
| $ R1
+--------(/^\)--- Rx
NPN E C
(Besseres Bild auf seiner Website, hier nur falls diese mal offline geht)
(Allen code auf der Website können wir für dieses Projekt ignorieren, va. wenn wir Anfänger sind
TX/RX geht zum Senosor Signal des Empfängers und RX und TX zum Arduino (Nicht vergessen Arduino GND und Empfänger - zu verbinden, sonst entseht kein Stromkreis)
Ist alles verkabelt (ein "solderless breadboard" bietet sich an) kann der erste Test gestartet werden:
Ich verwende einen Arduino mit integrierter USB-Schnittstelle (z.b. UNO oder Nano). Achtung: das native UART wird hier bereits durch den USB Anschluss belegt und kann nicht benutz werden für die Kommunikation mit dem Empfänger!
Stattdessen verwende ich die SoftwareSerial library:
Code:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RXpin:Pin 10, TXpin: Pin 11
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(250000);//Serial ist die Verbindung zum PC
Serial.println("hey");//Im Seriellen Monitor der Arduino IDE sollte hey zu lesen sein. (Bautrate am PC auf das maximum der IDE: 250000)
mySerial.setTimeout(5);
mySerial.begin(38400);//mySerial ist die Verbindung zum Empfänger
}
void loop() {
byte b[5];
long l[5];
long t=micros();
while(mySerial.available()>0){mySerial.read();}//wir wollen vor beginn des Tests einen leeren Buffer, wir dumpen seinen Inhalt
while(mySerial.available()<1){t=micros();};//wir warten bis vom Empfänger was ankommt.
long begintime=micros();//wir speichern die Zeit in Mikro Sekunden (nicht millisekunden)
b[0]= mySerial.read();//wir lesen das erste byte, das vom Master ankommt und speichern es
l[0]=t;//wir speichern die Zeit, wann das byte angekommen ist
t=micros();
for(int i=1;i<5;i++){//das selbe wie oben, blos 4 mal hintereinander (schleife)
while(mySerial.available()<1){t=micros();};
l[i]=t;
b[i]= mySerial.read();
t=micros();
}
long endtime=micros();//wir speichen die Zeit, wenn das letzte byte angekommen ist.
for(int i=0;i<5;i++){
Serial.print(b[i],HEX);//wir lassen uns eine Zeile mit den bytes (hexadezimal darstellung) ausgeben, die empfangen wurden
Serial.print(" ");
}
Serial.println();
Serial.print(0);
Serial.print(" ");
for(int i=1;i<5;i++){
Serial.print(l[i]-l[i-1]);//wir lassen uns eine Zeile mit den zeiten ausgeben, die vergangen sind, bevor das jeweilege byte empfangen wurde
Serial.print(" ");
}
Serial.println();
Serial.print(l[4]-l[0]);Serial.print(" ");Serial.println(endtime-begintime);//wir lassen uns 2 mal die dauer ausgeben
delay(2000);//nach 2 Sekunden kommt die nächste Messung
}
Die erste Zeile sind die Anfragen des Masters. Die Adressen, die er anfragt solten von 2 bis f (15) rotieren.
Die zweite Zeile, wieviel zeit jeweils zwischen der vorherigen und dieser Anfrage verstrichen ist. Eigendlich müsste diese Zeit immer ungefär 6ms (=6000micro Sekunden) betragen, bein meinen Tests ergaben sich aber meist Zeiten von etwa 5ms.
Sind weitere Erläuterungen des restlichen Projekts gewünscht?
Hier ist der Code für das Vario (profisorsch)! Wenn Interesse am Projekt besteht (PN bitte) werde ich das ganze gerne noch erläutern.
Für einen Programmierer eine Katastrophe, aber er ist nur zum testen und wird noch optimiert:
Code:
#include <SoftwareSerial.h>
#include <Wire.h>
#include <MS5611.h>
int variobuffer=0;
int variocnt=0;
MS5611 ms5611;
boolean dataavail=false;
int vario=0;
int alt=10;
int voltage=0;
int alert=0;
float prfAlt=0;
float TOALT;
long t;
float lastValue=0;
SoftwareSerial mySerial(10, 11); // RX, TX
void setup() {
analogReference(EXTERNAL);
mySerial.begin(38400);
mySerial.setTimeout(5);
while(!ms5611.begin())
{
delay(500);
}
ms5611.setOversampling(MS5611_ULTRA_HIGH_RES);
prfAlt=ms5611.getAltitude(ms5611.readPressure());
t = micros();
TOALT=ms5611.getAltitude(ms5611.readPressure());
}
void loop() {
if(mySerial.available()>0){
int red=mySerial.read();
if(red==0x5A){
TOALT=prfAlt;
}else if(red==0x03){
delayMicroseconds(1500);
if(mySerial.available()>0){
while(mySerial.available()>0){mySerial.read();}
}else{
if(dataavail){
if(variocnt==5){
vario+=variobuffer;
vario=vario/variocnt;
mySerial.write(0x33);
mySerial.write(lowByte(vario*2+alert));
mySerial.write(highByte(vario*2+alert));
vario=0;
variobuffer=0;
variocnt=0;
}else{
vario+=variobuffer;
variocnt++;
}
}else{
mySerial.write(0x33);
mySerial.write(lowByte(0x8000));
mySerial.write(highByte(0x8000));
}
}
}else if(red==0x04){
delayMicroseconds(1500);
if(mySerial.available()>0){
while(mySerial.available()>0){mySerial.read();}
}else{
if(dataavail){
mySerial.write(0x48);
mySerial.write(lowByte(alt*2+alert));
mySerial.write(highByte(alt*2+alert));
}else{
mySerial.write(0x48);
mySerial.write(lowByte(0x8000));
mySerial.write(highByte(0x8000));
}
}
}else if(red==0x05){
delayMicroseconds(1500);
if(mySerial.available()>0){
while(mySerial.available()>0){mySerial.read();}
}else{
if(dataavail){
mySerial.write(0x51);
mySerial.write(lowByte(voltage*2+alert));
mySerial.write(highByte(voltage*2+alert));
dataavail=false;
}else{
mySerial.write(0x51);
mySerial.write(lowByte(0x8000));
mySerial.write(highByte(0x8000));
}
updatedata();
}
}
}
}
void updatedata(){
voltage=(int)(0.5F+(analogRead(A0)/1024.0F)*66.0F);
long realPressure = ms5611.readPressure();
float absoluteAltitude = ms5611.getAltitude(realPressure);
float vspeed=(1000000*(absoluteAltitude-prfAlt)/(micros()-t));// avg in m/s
t=micros();
prfAlt=absoluteAltitude;
alt=(prfAlt-TOALT)+0.5F;//
if((vspeed<0&&lastValue<0&&vspeed<lastValue*0.3F)||(vspeed>0&&lastValue>0&&vspeed>lastValue*0.3F)){
passVario(vspeed);
}else{
passVario((vspeed+lastValue)/2.0F);
}
lastValue=vspeed;
dataavail=true;
}
void passVario(float value){
if(value>0){
variobuffer=0.5F+value*10;
}else{
variobuffer=value*10-0.5F;
}
}