Hallo,
ich versuche mit einem DC3.6V-6V Mini Wireless Bluetooth Transceiver
Modul rs232 Bluetooth Modul
[http://www.ebay.de/itm/DC3-6V-6V-Mini-Wireless-Bluetooth-Transceiver-Modul-rs232-TTL-/251208178554?pt=Wissenschaftliche_Ger%C3%A4te&hash=item3a7d2c9b7a],
eine serielle Verbindung zwischen einem Atmega8 und einem Android Handy
herzustellen.
Es gelingt mir offenbar, eine Verbindung von meinem Handy zum Bluetooth
aufzubauen. Wenn ich Daten via Bluetoothterminal an das Linvor – Modul
sende, kommen auch Daten (oder zumindest irgendetwas) am Mikrocontroller
an, d.h. Serial.available gibt einen Wert größer 0 zurück. Jedoch kommen
nicht die Daten, die ich gesendet habe an. Ich habe versucht, mit Hilfe
der ctype.h Funktionen herauszufinden, was ankommt aber alle Funktionen
geben ein FALSE zurück. Ich habe insgesamt drei
Android-Bluetooth-Terminals getestet.
Das Bluetooth-Modul antwortet auch nicht auf AT-Commands. Wenn ich z.B.
Serial.println(“AT“) an das Modul sende, kommen keine Daten zurück. Also
Serial.available()=0.
Hier der Code, den ich verwende:
1
#include<ctype.h>
2
#define FALSE 0
3
#define TRUE 1
4
5
charval;// saves incoming data
6
intledPin=9;
7
intalphaNumPin=10;
8
intledDataReadPin=5;// The led which we are going to turn on and off via bluetooth
9
intdataRead;
10
inti;
11
intledCount;
12
13
signedcharcHighLow=1;
14
15
voidsetup(){
16
dataRead=0;
17
pinMode(ledPin,OUTPUT);// use pin 13 as output
18
Serial.begin(9600);// the bluetooth module default rate is 9600
19
digitalWrite(ledDataReadPin,HIGH);// turn the LED off by making the voltage LOW
20
digitalWrite(alphaNumPin,HIGH);// turn the LED off by making the voltage LOW
21
digitalWrite(ledPin,HIGH);
22
Serial.println('AT');
23
24
}
25
26
voidloop(){
27
// only do something if incoming data is available
28
if(Serial.available()>0){
29
val=Serial.read();
30
31
if(isalpha(val)==TRUE){
32
digitalWrite(alphaNumPin,LOW);
33
}
34
elseif(iscntrl(val)==TRUE){
35
digitalWrite(alphaNumPin,LOW);
36
}
37
elseif(isgraph(val)==TRUE){
38
digitalWrite(alphaNumPin,LOW);
39
}
40
elseif(isprint(val)==TRUE){
41
digitalWrite(alphaNumPin,LOW);
42
}
43
elseif(ispunct(val)==TRUE){
44
digitalWrite(alphaNumPin,LOW);
45
}
46
elseif(isspace(val)==TRUE){
47
digitalWrite(alphaNumPin,LOW);
48
}
49
else{
50
digitalWrite(alphaNumPin,LOW);
51
delay(80);
52
digitalWrite(alphaNumPin,HIGH);
53
delay(80);
54
digitalWrite(alphaNumPin,LOW);
55
delay(80);
56
digitalWrite(alphaNumPin,HIGH);
57
}
58
59
if(val=='0'){
60
digitalWrite(ledPin,LOW);
61
}
62
elseif(val=='1')
63
digitalWrite(ledPin,HIGH);
64
}
65
delay(10);
66
}
Meine Vermutung ging dahin, dass möglicherweise eine falsche BAUD-Rate
eingestellt sein könnte. Allerdings ändert auch die Verwendung von
anderen BAUD-Raten nicht viel. Bei 1200 und 2400 kommt nichts mehr am
Controller an. Bei 4800 bis 38400 zeigt sich das gleiche wie oben
beschriebene Verhalten. Bei höheren BAUD-Raten kommen offenbar mehr
Daten an. Jedenfalls wird die Datenverarbeitungsschleife mehrfach
durchlaufen.
Lediglich bei der BAUD-Rate 460800 wurde der if-Block mit der Bedingung
val=“0“ durchlaufen,. Die Ctype-Funktionen haben aber auch hier alle
FALSE zurückgegeben, was in mir Zweifel verusacht hat, ob ich die
Funktionen korrekt verwende. Das Senden von 1 schaltet die LED aber auch
nicht wieder an.
Der Code wurde mit dem Arduino-Compiler erstellt. Ich verwende aber
keinen Arduino, sondern habe den Controller auf einem Breadbord
programmiert. Die Installation dürfte korrekt sein, da es gelingt, von
meinem PC einzelne LEDs gezielt zu kontrollieren.
Das Bluetooth-Modul ist wie folgt angeschlossen. VCC an +5V, Ground an
Ground, TX-Bluetooth an RX-Controller, RX-Bluetooth an TX-Controller.
Die RX-TX-Verknüpfung habe ich überprüft. Das Vertauschen von beiden
führt zu einem sehr hochfrequenten flackern der LED am Bluetoothmodul
und es kommen keine Daten mehr an. Ich habe festgestellt, dass RX und
TX, wenn keine Daten gesendet werden HIGH sind. Ist das korrekt oder
liegt evtl. der Fehler im Setup von RX und TX am Controller?
Um einen Fehler bei der RX-TX –Verschaltung noch weiter auszuschließen,
nochmal etwas Präziser: Wenn ich die Kerbe des Controllers anschaue und
diese oben ist, dann habe ich TX-Bluetooth an den zweiten Pin von links
oben und RX-Bluetooth an den dritten Pin von links oben angeschlossen.
Der Controller arbeitet mit einer Geschwindigkeit von 1000MHz
Abschließend noch der Hinweis, dass ich mich erst seit einigen Wochen
mit Microcontroller-Programmierung befasse und auch die Sprache C noch
fremd für mich ist. Dementsprechend könnten auch Dinge die erfahrenen
Controllerprogrammieren banal escheinen verkehrt sein.
Jede Hilfe ist willkommen. Ich stoße langsam an die Grenze meiner
Kreativität :)
1000Mhz? Das wäre sehr viel für einen AVR.
Wenn du 1000Khz = 1Mhz meinst, dann liegt da auch das Problem. Es kann
nicht aus jeder Taktrate jede Baud Rate generiert werden. Aus einem
Prozessortakt von 1Mhz kann keine Baudrate von 9600kbps generiert
werden. 2Mhz würde gehen. Oder 8Mhz.
Die Schnittstelle empfängt ansonsten nämlich nur Müll.
Habe selber schon mit dem Linvor ein paar Sachen gemacht. Eigentlich
klappt das ganz gut. Beachte, dass das Modul erst seine Antwort auf "AT"
schickt, wenn eine Sekunde lang nichts mehr an das Modul gesendet wird.
Also:
"AT" schreiben
1 Sekunde warten in der nichts gesendet wird
"ATOK" sollte zurück kommen
Gruß
Hallo Sebastian,
natürlich 1MHz. Ich habe eigentlich vorher extra nochmal nachgeschaut.
Irgendwie sind mir die Nullen dann doch noch drangerutscht...
Ich hatte bisher zuviel Respekt, um mich an den Fuses zu vergehen aber
ich habe mich dann heute abend mal drangewagt und den Chip jetzt auf
8MHz eingestellt. Leider ändert sich nur, dass die LEDs jetzt schneller
blinken.
Ist es möglich, dass die Serial-Klasse in irgendeiner Weise auf die
Arduinoboards zugeschnitten ist? Wenn mich morgen niemand davon abhält,
werde ich mal versuchen, den Code im Atmel-Studio lauffähig zu bekommen.
Heute Abend hat es über implizite Deklarationen gemeckert. Du kennst
nicht zufällig ein Tutorial, bei dem ich die Entsprechungen für
digitalWrite und die Serial-Klasse finden kann?
Auf jeden Fall schonmal vielen Dank für deine Hilfe!!
Hi
leider hab ich nicht viel Zeit. Aber auf die schnelle:
1. RX und TX müssen HIGH sein wenn nichts gesendet wird. Das ist normal
und richtig so.
2.Ich glaube nicht das die Serial-Klasse auf Arduino Boards
zugeschnitten ist. Das macht keinen Sinn.
3. Eigentlich dürften dein LEDs nicht schneller blinken wenn du den Takt
änderst, denn der Compiler müsste Automatisch die Delays auch neu
berechnen. Wenn du im Projekt einen andern Prozessortakt einstellst.
(Hast du das gemacht?) Warum blinken da überhaupt LEDs? Sollte doch nur
die eine Blinken wenn du was empfängst, oder?
4. Ich benutz weder Arduino noch Atmel Studio. Also zu dem Bereich kann
ich Dir nicht viel weiter helfen. Aber die entsprechungen zu
digitalWrite und den Serial klassen sollten relativ simpel ausfallen.
Gruß
Hallo,
also ich bin mir ziemlich sicher, dass die schneller geblinkt haben. Die
Delay-Funktion von Arduino hat, als der Chip auf 1MHz getaktet war, auch
nicht mit der tasächlich Zeit übereingestimmt. Ich werde das später
nochmal überprüfen.
Ich habe mir in den letzten Abenden aus verschiedenen Beiträgen
folgenden Code zusammenkopiert, der mindestens so seltsame Ergebnisse
produziert wie vorher der Arduino-Code:
1
#ifndef F_CPU
2
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert
3
(z. B. durch Übergabe als Parameter zum Compiler innerhalb
4
des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die
5
"nachträgliche" Definition hinweist */
6
#warning "F_CPU war noch nicht definiert, wird nun mit 3686400 definiert"
7
#define F_CPU 8000000UL /* Takt 8 Mhz */
8
#endif
9
#include<util/delay.h>
10
11
intmain(void)// <=== (1)
12
{
13
DDRB=0xFF;// PORTB Ausgang <=== (2)
14
DDRC=0xFF;
15
16
UCSRB|=(1<<RXEN);//Empfangen aktivieren
17
UCSRC|=(1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);// 8N1
18
UBRRH=(unsignedchar)(51>>8);
19
UBRRL=51;
20
21
while(1)// <=== (3)
22
{
23
long_delay(500);
24
PORTC|=((1<<PC0)|(1<<PC1)|(1<<PC2)|(1<<PC3));
25
PORTB|=((1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3));
26
long_delay(150);
27
PORTC&=(~(1<<PC0)&~(1<<PC1)&~(1<<PC2)&~(1<<PC3));
28
PORTB&=(~(1<<PB0)&~(1<<PB1)&~(1<<PB2)&~(1<<PB3));
29
30
while(!(UCSRA&(1<<RXC))){//warten bis senden fertig
31
long_delay(300);
32
PORTC|=((1<<PC0)|(1<<PC1)|(1<<PC2)|(1<<PC3));
33
long_delay(300);
34
PORTC&=(~(1<<PC0)&~(1<<PC1)&~(1<<PC2)&~(1<<PC3));
35
long_delay(300);
36
PORTB=UDR;
37
PORTC=(UDR>>4);//Zeichen auf PORTB-LEDs anzeigen
38
long_delay(2000);
39
}
40
//
41
}
42
}
43
44
voidlong_delay(uint16_tms)
45
{
46
for(;ms>0;ms--)_delay_ms(1);
47
}
Ich habe dann auf meinem Breadboard 8 LEDs angebracht. Da der Atmega8
nur an Port B 8 Ein- und Ausgänge hat, die unglücklicherweise teilweise
auch für die Programmierung des Chips notwendig sind, habe ich 4 grüne
für die 4 hohen Bits an Port C und 4 rote für die 4 niedrigen Bits an
Port B angschlossen.
Wenn ich den Chip nun starte, blinken gemäß Intention zuerst 1 mal alle
8 LEDs. Danach wird (nicht gemäß Intention) die Schleife für das
empfangen von Daten durchlaufen. Dort blinken wieder wie gewollt erstmal
alle grünen LEDs. Allerdings bleibt dann das Programm in der Schleife
und wiederholt das Blinken der grünen LEDs.
Erst wenn ich von meinem Handy Daten an den Linvor-BT sende, wird die
Schleife verlassen. Soweit kenne ich das ja schon vom Arduino-Code. Wenn
ich nun ein "a" (&h61 gemäß ASCII-Tabelle) sende, würde ich eigentlich
eine 0110.0001 zurückerwarten. Stattdessen erhalte ich eine 0000.0001.
Ich kann so korrekt bis "z" hochzählen, nur dass nie die hohen 4 Bits
gesetzt werden. Wenn ich nun eine "1" (&h31) sende, würde ich 0011.0001
erwarten, erhalte aber 0000.0001. Bis "9" lässt sich wieder korrekt
hochzählen. Ab "10" aufwärts erhalte ich nur noch 0011.0001.
Man könnte meinen, dass einfach mit den 4 hohen Bits etwas nicht stimmt,
aber wenn ich "A" (&h65) an den Bluetooth sende, würde ich 0110.0101
erwarten und erhalte (man halte sich fest) wieder 0000.0001.
Egal wieviele Zeichen ich sende, ich erhalte nur ein Byte vom Linvor.
Nur bei einer leeren Zeile, kann ich ein weiteres Byte empfangen, aber
die Empfangs-Schleife wird nicht verlassen. Nach dem Empfangen aller
anderen Daten, tritt das Programm nie wieder in die Empfangs-Schleife
ein, egal wieviele Daten man noch sendet. Es blinken in regelmäßigen
Abständen 8 LEDs bis zum jüngsten Gericht oder bis ich meine
Stromrechnung nicht mehr bezahle.
Da tun sich einige Fragen auf:
1) Warum tritt das Programm in die Schleife für das Empfangen von Daten
ein, wenn noch gar keine Daten gesendet wurden?
2) Wenn das Programm schon in diese Schleife eintritt, warum holt es
dann keine Daten heraus, sondern faulenzt in der Schleife rum?
3) Woher kommen die seltsamen Muster, beim Senden der Zeichen?
4) Warum tritt das Programm nach dem einmaligen Empfang nicht wieder in
die Schleife ein?
5) Muss ich mir einen neuen Bluetooth kaufen?
6) Liest überhaupt irgendwer diesen Roman?
Vielen Dank für jede konstruktive Antwort!
Hi Frank
ich bin weiß gott kein C-Guru wie viele andere hier, insofern bitte
meine Hinweise mit Vorsicht genießen. Aber im Rahmen eines Praktikums
hab ich auch gerade mit dem USART zu tun, deshalb denke ich das ich dein
Programm nachvollziehen kann.
Ich denke, dass du dir die while-Schleife nochmal vornehmen solltest,
mit der du die Nachrichten ausliest.
while ( !(UCSRA & (1<<RXC)) ) {
--> wenn in RXC-Flag eine 0 steht, dann gehe durch diese Schleife.
Sprich, er geht solange durch die Schleife, wie das Flag sagt "mein
Puffer ist noch nicht voll"
Ich denke das erklärt auch die seltsamen Muster die du auf deinen LED's
erhälst, du holst ja permanent Daten aus deinem Empfangsregister, auch
wenn es noch nicht voll ist.
Frage an alle, da ich es nicht weiß: Kann es sein, dass das UDP-Register
mit jedem Lesevorgang wieder mit 0 initialisiert wird ? Hier hätte es ja
dann garnichts die Chance ein ganzes Byte zu empfangen, da es ja
permanent halb gefüllt ausgelesen, und dann vielleicht erneut
initialisiert wird ? Würde auch erklären, dass du in deine
while(1)-Schleife nicht mehr rein kommst.
Meine Vermutung wäre jedenfalls, dass das Problem da zu suchen ist. Die
Negation im Schleifenkopf weg zu nehmen dürfte schon helfen.
Mit dem 8Mhz R/C Oszillator kannst Du auch nicht ordentlich seriell
kommunizieren. Du musst einen Quarz verwenden, vorzugsweise einen mit
14,768Mhz.
Welche seriellen Bitraten bei welchen Quarzen gehen, kannst Du dem
Datenblatt des Mikrocontrollers entnehmen. Dazu gibt es extra eine
Tabelle und ein paar Sätze Erklärung dazu.
Beim compilieren des Quelltextes muss die Taktrate bekannt sein, da der
Code dementsprechend angepasst wird. Wenn Du danach die Taktrate
änderst, funktioniert die Initialisierung des seriellen Ports nicht
mehr. Du musst dann neu compilieren.
Wenn Du den Quarz oder den R/C Oszillator änderst, wird warscheinlich
auch der Bootloader des Arduino nicht mehr funktionieren. Du brauchst
dann einen ISP Programmer.
Hallo,
so wie ich das Datenblatt S. 153
[http://www.atmel.com/Images/Atmel-2486-8-bit-AVR-microcontroller-ATmega8_L_datasheet.pdf]
interpetiere, lässt sich der Atmega8 sogar schon ab 1MHz mit 9600 BAUD
betreiben. Mit 8MHz sogar schon mit einer ziemlich niedrigen Fehlerrate.
Korrigiert mich, wenn ich das Datenblatt falsch lese.
Ich habe meinen Code nocheinmal ein wenig modifiziert und um eine gelbe
LED an Port C4 ergänzt:
1
#include<avr/io.h>
2
#ifndef F_CPU
3
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert
4
(z. B. durch Übergabe als Parameter zum Compiler innerhalb
5
des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die
6
"nachträgliche" Definition hinweist */
7
#warning "F_CPU war noch nicht definiert, wird nun mit 3686400 definiert"
8
#define F_CPU 8000000UL /* Takt 8 Mhz */
9
#endif
10
#include<util/delay.h>
11
12
intmain(void)// <=== (1)
13
{
14
DDRB=0xFF;// PORTB Ausgang <=== (2)
15
DDRC=0xFF;
16
17
UCSRB|=(1<<RXEN);//Empfangen aktivieren
18
UCSRC|=(1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);// 8N1
19
UBRRH=(unsignedchar)(51>>8);//9600 BAUD
20
UBRRL=51;//9600 BAUD
21
22
unsignedcharcReceive;
23
24
25
while(1)// <=== (3)
26
{
27
cReceive=0;
28
if(!(UCSRA&(1<<RXC))){//warten bis senden fertig
29
long_delay(300);
30
PORTC|=((1<<PC0)|(1<<PC1)|(1<<PC2)|(1<<PC3));
31
32
long_delay(300);
33
PORTC&=(~(1<<PC0)&~(1<<PC1)&~(1<<PC2)&~(1<<PC3));
34
PORTB&=(~(1<<PB0)&~(1<<PB1)&~(1<<PB2)&~(1<<PB3));
35
long_delay(700);
36
cReceive=UDR;
37
PORTB=cReceive;
38
PORTC=(cReceive>>4);
39
long_delay(2000);
40
}
41
42
PORTC|=(1<<PC4);
43
long_delay(500);
44
PORTC&=~(1<<PC4);
45
long_delay(150);
46
}
47
}
Equinox hatte einen ganz guten Riecher... Das UDR Register wird nach
jedem lesen gelöscht und mit neuen Daten aus dem Puffer versorgt, was zu
meinen seltsamen Daten vom letzten mal geführt hat. Durch das
Zwischenspeichern der Daten werden Sie nun korrekt auf den Ports
dargestellt.
Beim Start des Controllers geht auch bei diesem Code das Programm zuerst
in die Datenempfangsschleife, obwohl noch keine Daten gesendet wurden
aber wie die gelbe LED anzeigt, verlässt es die Schleife nach dem ersten
Durchlauf und tritt beim nächsten mal wieder in sie ein, obwohl immer
noch keine Daten gesendet wurden. Das wird immer weiter fortgesetzt,
solange keine Daten gesendet werden.
Die Schleife wird aber immer noch nicht mehr Durchlaufen, nachdem das
erste Zeichen gesendet wurde. Ich sehe das auch hier grundsätzlich so
wie Equinox, dass ein Problem mit dieser Schleife zu besetehen scheint.
Allerdings kommt der Code hierfür direkt aus dem Datenblatt S. 139.
1
unsignedcharUSART_Receive(void)
2
{
3
/* Wait for data to be received */
4
while(!(UCSRA&(1<<RXC)))
5
;
6
/* Get and return received data from buffer */
7
returnUDR;
8
}
Jedenfalls sollte die Modifikation mE irrelevant sein. Es scheint also
aus irgendeinem Grund im Moment ein Problem mit dem RXC Flag (Receive
Complete) im UCSRA Register zu bestehen, da dieses nicht gesetzt ist,
wenn der Controller gestartet wird und nachdem es einmal gesetzt wurde,
nicht mehr gelöscht wird, wenn neue Daten in den Puffer gelangen. Und
die gelangen in den Puffer. Wenn ich einfach ohne die While Schleife das
UDR Register immerwieder abfrage, erhalte ich, wenn Daten gesendet
werden, häufig korrekte Resultate, wenn auch nicht immer.
@Equinox: Du solltest dein Praktikum weiter machen. Es scheint nicht
schlecht zu sein ;)
Hallo,
ich habs dann doch noch hinbekommen, nachdem das große schwere
Eichenbrett von der Stirn gefallen ist.
Ich habe mich darauf versteift, dass in der While-Schleife Daten
abgerufen werden, obwohl die ja nichts tut außer darauf zu warten, dass
Daten eintreffen.
Falls es noch mehr Bluetooth-Leute mit Brettern vor den Köpfen gibt,
hier der Code, der bei mir funktioniert:
1
#include<avr/io.h>
2
#ifndef F_CPU
3
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert
4
(z. B. durch Übergabe als Parameter zum Compiler innerhalb
5
des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die
6
"nachträgliche" Definition hinweist */
7
#warning "F_CPU war noch nicht definiert, wird nun mit 3686400 definiert"
8
#define F_CPU 8000000UL // Takt 8 MHz
9
#endif
10
#include<util/delay.h>
11
12
// Funktion um die Daten aus dem Lesepuffer des Chips abzurufen
cWord[i]=USART_Receive();// Warteschleife bis Daten empfangen werden
42
if(cWord[i]==33){// Ein "!" (ASCII 33) als einfaches Steuerzeichen signalisiert das Ende der Zeichenfolge
43
for(z=0;z<i;z++){
44
PORTB=cWord[z];// Die vier niedrigen Bits auf den ersten 4 Ausgängen von Port B ausgeben
45
PORTC=(cWord[z]>>4);// Die vier hohen Bits auf den ersten 4 Ausgängen von Port C ausgeben
46
long_delay(2000);
47
}
48
i=0;
49
}else{
50
i++;
51
}
52
53
}
54
}
55
56
// Delay Funktion, um Pausen in den Programmablauf einzubauen
57
voidlong_delay(uint16_tms)
58
{
59
for(;ms>0;ms--)_delay_ms(1);
60
}
Sonst hat noch das erste von mir verwendete Android-Terminal-Programm,
mit dem ich die Daten an den Controller gesendet habe, ein wenig
Probleme bereitet, weil es eigene Steuerzeichen zum Abschluss der
Zeichenfolge gesendet hat. Mit "S2 Bluetooth Terminal3" hats dann
schließlich funktioniert.
Frank G. schrieb:> #warning "F_CPU war noch nicht definiert, wird nun mit 3686400 definiert"> #define F_CPU 8000000UL // Takt 8 MHz
Meinst Du, daß das so sinnvoll ist?
Ich gebe zu, dass ich die Definition des Takts im Code bislang für
sinnvol gehalten habe. Falls es dir nur um die offensichtlich
widersprüchlichen Angaben geht, muss ich zugeben, dass mir das beim
Drüberschauen durch die Lappen gegangen ist. Leider lässt sich das nun
nicht mehr editieren.
Wenn du das aus irgendeinem anderen Grund für Unsinn hältst, wäre es
nett, wenn du erklärst warum. Noch netter wäre es, das zu tun bevor du
Ahnungslose, zu denen ich wie eingangs festgestellt zweifellos zähle,
spekulieren lässt.