Bluecontroller (BCA8-BTM)
Latest stable Version: Epsilon (tested and proven to work) on GitHub!
Das AVR C-Programm dient zum Senden und Empfangen von Textnachrichten über Bluetooth zwischen einem Mikrocontroller und einem Computer:
Microcontroller <-> UART <-> Bluetooth <-> COM Port <-> PC
Hierfür wurde der Bluecontroller verwendet, sodass sich in unserem konkreten Fall der folgende Ablauf ergibt:
ATmega328p <-> USART0 <-> BTM-222 <-> Bluetooth <-> Bluetooth-Gerät-Am-PC <-> COM Port <-> RS232 Terminal <-> Windows-PC
Contents
Projekt
Institut für Technische Informatik, Universität zu Lübeck:
- Autoren: Fabi Rosenthal, Florian Thaeter, Mai Linh E. Nguyen
- Verantwortliche: Dipl.-Ing. Patrick Weiss, Dipl.-Inf. Alexander Gabrecht
mReS - Modular Rehabilitation System
Das Bluecontroller-Projekt ist am Institut für Technische Informatik der Universität zu Lübeck im Rahmen des mReS-Projekts entstanden:
mReS ist ein modular RehabilitationsSystem zum Training der Handfunktion nach Schlaganfall. Die Modularität erlaubt ein breites Spektrum an Trainings- und Fortschrittsbewertungsmöglichkeiten bei gleichzeitiger Reduzierung der Komplexität und Kosten. Dadurch sollen die Systeme auch in kleineren Kliniken mit begrenzten finanziellen Mitteln und in der Heimrehabilitation eingesetzt werden können. Der therapeutische Ansatz beruht auf einer adaptiven, visuellen Rückmeldung hinsichtlich der motorischen Leistungen des Patienten, der auf neurowissenschaftlich bekannten Wirkmechanismen einer sogenannten verzerrten Rückmeldung basiert. (mReS)
mReS-R ist dabei ein Module zum Training von Rotationsbewegungen. Im Rahmen des Bluecontroller-Projekts soll dieses Module über Bluetooth angesteuert werden. Hierfür müssen Motorbefehle über UART an den Bluecontroller gesendet werden, damit der enthaltende Mikrocontroller diese verarbeiten kann.
Verwendete Hard- und Software
Hardware
- Bluecontroller BCA8-BTM-328P-BOOT (Pinbelegung, Befehle, Kaufen)
- Mikrocontroller ATmega328P (Datenblatt)
- Bluetooth-Modul BTM-222 (Datenblatt, Kaufen)
- Programmer STK500 (Datenblatt)
Software (unter Windows 7)
Bluecontroller
Weitere Hilfe: Bluecontroller, BTM-222 Bluetooth-Funkmodul
Modi Command Mode und Communication mode
Das Bluetooth Modul unterscheidet zwischen den beiden Modi Command Mode und Communication mode. Im Command Mode können Einstellungen am Modul vorgenommen werden, indem man die entsprechenden AT-Befehle sendet, während im Communication Mode alle Daten an den Bluetooth Kommunikationspartner weitergesendet werden.
Wechsel zwischen den Modi
Nach einem Reset befindet sich das Modul standardmäßig im Command Mode.
Wechsel vom Command Mode in Communication Mode:
- Geschieht automatisch, wenn erfolgreich eine Bluetooth Verbindung aufgebaut wurde
Wechsel vom Communication Mode in Command Mode:
- Verbindung zum Kommunikationspartner abrechen
- (oder) Escape-Sequenz senden, welche jedoch standardmäßig deaktiviert ist und erst über die Einstellung ATX1 aktiviert werden muss
Abfrage des Modus
Das Programm sollte wissen, in welchem der Modi sich das Modul aktuell befindet, da im Command mode alle Strings als Befehl interpretiert werden. Will man also eigentlich gerade Daten senden, kann dies zu ungeahnten Fehler führen. Aktiviert man die ATQ0 Option aktivieren, sende das Modul die Resul codes[1] zurück:
- OK
- CONNECT
- DISCONNECT
- ERROR
Um nun zu überprüfen, ob man sich gerade im Command Mode befindet, kann man zum Beispiel das AT Kommando schicken. Wird dies mit OK beantwortet, befindet man sich im Command Mode.
Atmel Studio
Das Atmel Studio 6 haben wir zum Programmieren und Kompilieren verwendet. Die ältere Version (Studio 4) haben wir nur dazu genutzt, dass mit Studio 6 erstellte hex-File auf den Mikrocontroller zu überspielen, da das Studio 6 nicht kompatibel mit dem verwendeten Programmer STK500 ist. In den Fuses oder sonst irgendwo, müssen generell keine extra Einstellungen vorgenommen werden.
Unter Programming Mode and Target Settings sollte die ISP Frequency auf 115.2kHz eingestellt sein.
In den Fuses muss gegenfalls noch unter SUT_CKSEL das internen 8 MHz Oszilloskop eingestellt sein.
AVR-GCC Code
Den vollständigen Code als Atmel Studio 6 Projekt findest du auf GitHub unter Bluecontroller_BCA8_BTM.
Verbindungen testen
Zum Testen (schaltet die eine LED aus bzw. an)
/*
* test.c
*
* Program: AVR Studio 4
* Author: Fabi
*
* Dieses Programm dient nur zum Testen, ob ein Programm erfolgreich
* auf den Bluecontroller (BCA8-BTM) überspielt werden kann.
*
* Es schaltet lediglich eine der beiden LED's aus bzw. an ('an' ist
* hierbei auskommentiert).
*/
#include <avr/io.h>
void main(void)
{
DDRB |= (1<<DDB6);
PORTB = (0<<PB6);
/* PORTB |= (1<<PB6); */
while (1) {
//
}
}
UART
Ausführliche Hilfe: AVR-GCC - UART
Einstellung | Wert |
---|---|
CPU clock | 8MHz |
Baud rate | 19200bps |
Data bit | 8 |
Stop bit | 1 |
Parity | none |
Flow control | none (oder H/W) |
uart.h
/**
* @file uart.h
* @author Florian Thaeter, Fabi Rosenthal
* @version Epsilon
* @date 25.03.2013
*
* @section LICENSE
* Licence: CC BY 3.0 (http://creativecommons.org/licenses/by/3.0/)
*
* @section DESCRIPTION
* Code: http://github.com/Xennis/Bluecontroller_BCA8_BTM
*
* Documentation: http://wiki.xennis.de/artikel/Bluecontroller
*/
#ifndef UART_H_
#define UART_H_
/* Define */
#define MCU atmega328p
/** FOSC / Clock Speed (ATmega328P) */
#define F_CPU 8000000UL
/** Baud rate (Bluecontroller) */
#define BAUD 19200
/** MYUBRR = 25 */
#define MYUBRR F_CPU/16/BAUD-1
/* Include */
#include <avr/io.h>
#include <avr/interrupt.h> // Used for sei(), cli() and ISR()
/* Register names USART0 */
#define UBRRH UBRR0H
#define UBRRL UBRR0L
#define UCSRA UCSR0A
#define UCSRB UCSR0B
#define UCSRC UCSR0C
#define UDR UDR0
#define UDRE UDRE0
#define UPE UPE0
#define DOR DOR0
#define FE FE0
#define RXC RXC0
#define TXB8 TXB80
/* Method */
void uart_init(unsigned int ubrr);
void uart_putc(unsigned char data);
#endif /* UART_H_ */
uart.c
/**
* @file uart.c
* @author Florian Thaeter, Fabi Rosenthal
* @version Epsilon
* @date 25.03.2013
*
* @section LICENSE
* Licence: CC BY 3.0 (http://creativecommons.org/licenses/by/3.0/)
*
* @section DESCRIPTION
* Code: http://github.com/Xennis/Bluecontroller_BCA8_BTM
*
* Documentation: http://wiki.xennis.de/artikel/Bluecontroller
*/
#include "uart.h"
/**
* UART Initialization
*
* USART Initialization (datasheet page 178)
*/
void uart_init( unsigned int ubrr )
{
/* Set baud rate */
UBRRH = (unsigned char)(ubrr>>8);
UBRRL = (unsigned char)ubrr;
/* Set double speed */
UCSRA = (0<<U2X0);
/* Enable receiver, transmitter and UART RX Complete Interrupt (activate global interrupt flag necessary) */
UCSRB |= (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
/* Set frame format: 8data, 1stop bit */
UCSRC |= (1<<UCSZ01)|(1<<UCSZ00);
/* Dummy read to clear UDR */
UDR;
}
/**
* Send char
*
* Sending Frames with 5 to 8 Data Bit (datasheet page 179)
*/
void uart_putc( unsigned char data )
{
/* Wait for empty transmit buffer */
while ( !( UCSRA & (1<<UDRE) ) );
/* Put data into buffer, sends the data */
UDR = data;
}
Bluecontroller
bluecontroller.h
/**
* @file bluecontroller.h
* @author Fabi Rosenthal
* @version Epsilon
* @date 25.03.2013
*
* @section LICENSE
* Licence: CC BY 3.0 (http://creativecommons.org/licenses/by/3.0/)
*
* @section DESCRIPTION
* Code: http://github.com/Xennis/Bluecontroller_BCA8_BTM
*
* Documentation: http://wiki.xennis.de/artikel/Bluecontroller
*/
#ifndef BLUECONTROLLER_H_
#define BLUECONTROLLER_H_
/* Include */
#include "uart.h" // Defines F_CPU => important to include before <util/delay.h>
#include <inttypes.h>
#include <avr/io.h>
#include <util/delay.h>
/* Define (BC=Bluecontroller) */
/** PIN 19 (PB6): LED */
#define BC_PIN_LED PINB6
/** PIN 20 (PB7): BT-Reset */
#define BC_PIN_RESET PINB7
#define BC_RESET_PORT PORTB
#define BC_RESET_PIN PINB
#define BC_RESET_DDR DDRB
/** Delay (in ms) after send a char */
#define BC_PUTC_DELAY 10
/** Activate bt_debug method */
#define BC_DEBUG
/* Method */
void bt_init(void);
void bt_setut(void);
void bt_reset(void);
void bt_turn_off(void);
void bt_turn_on(void);
void bt_escape_sequence(void);
void bt_putc(char c);
void bt_puts(char* s);
void bt_send_cmd(char* s);
//uint8_t bt_check_turn_off(void);
void bt_debug(char* s);
void bt_led_on(uint8_t i);
#endif /* BLUECONTROLLER_H_ */
bluecontroller.c (verwendet Methoden von Michael Dreher[3])
/**
* @file bluecontroller.c
* @author Fabi Rosenthal, Michael Dreher (see note)
* @version Epsilon
* @date 25.03.2013
*
* @section LICENSE
* Licence: CC BY 3.0 (http://creativecommons.org/licenses/by/3.0/)
*
* @section DESCRIPTION
* Code: http://github.com/Xennis/Bluecontroller_BCA8_BTM
*
* Documentation: http://wiki.xennis.de/artikel/Bluecontroller
*
* Note:
* This file uses methods, which are Copyright (c) by Michael Dreher
* Source: http://code.google.com/r/michaeldreher42-bluecontroller/source/browse/bluecontroller/examples/Setup_BlueController/Setup_BlueController.pde
*
* This sketch only works, when __no__ Bluetooth connection is established or when the escape sequence is __not__ disabled
*
* Additionally this is a demo of new bootloader functions:
* soft_reset() (works with optiboot and other bootloaders which clear the wdt and MCUSR)
* enter_bootloader() (works only with BlueController optiboot bootloader and magic-word mechanism)
*/
#include "bluecontroller.h"
/**
* Initialization
*
* Initialize Bluecontroller
*/
void bt_init(void)
{
/* UART and timer */
uart_init(MYUBRR);
sei();
_delay_ms(100);
bt_debug("init");
}
/**
* Setup
*
* Setup Bluetooth module
*/
void bt_setut(void)
{
/* Terminate the current Bluetooth connection. */
bt_reset();
/* these setting make the connection as transparent as possible */
bt_send_cmd("\rAT"); // make sure the module is not in sleep mode
bt_send_cmd("ATE0"); // disable echo
bt_send_cmd("ATQ1"); // disable result code
bt_send_cmd("ATC1"); // enable flow control: without this, avrdude under Windows will hang
bt_send_cmd("ATR1"); // device is slave
bt_send_cmd("ATN=Bluecontroller"); // set new name
bt_send_cmd("ATP=1234"); // set PIN
bt_send_cmd("ATD0"); // accept connections from any bt device
bt_send_cmd("ATX0"); // disable escape character (default)
//bt_send_cmd("ATS1"); // enable power down of rs-232 driver (default)
bt_send_cmd("ATO"); // reconnect to peer
/* Allow module to save setting in flash */
_delay_ms(1000);
/* Activate new settings */
bt_reset();
bt_debug("reset");
}
/**
* Reset the Bluetooth module
*
* This terminates the current Bluetooth connection.
*/
void bt_reset(void)
{
bt_turn_off();
bt_turn_on();
}
/**
* Turn off Bluetooth module
*
* Turns off Bluetooth module
*/
void bt_turn_off(void)
{
BC_RESET_DDR |= (1<<BC_PIN_RESET);
BC_RESET_PORT &= ~(1<<BC_PIN_RESET);
_delay_ms(50);
}
/**
* Turn on Bluetooth module
*
* Turns on the Bluetooth module
*/
void bt_turn_on(void)
{
BC_RESET_PORT |= (1<<BC_PIN_RESET);
BC_RESET_DDR &= ~(1<<BC_PIN_RESET);
/* Wait until the module is up and running */
_delay_ms(6000);
}
/**
* Send escape sequence
*
* Sends escape sequence (+++)
*/
void bt_escape_sequence(void)
{
_delay_ms(1200);
bt_puts("+++");
_delay_ms(1200);
}
/**
* Send a character
*
* Sends a character
*
* @param c character
*/
void bt_putc(char c)
{
uart_putc(c);
/* Slow down communication for BTM-222 */
_delay_ms(BC_PUTC_DELAY);
}
/**
* Send a string
*
* Sends a string (char*)
*
* @param s string
*/
void bt_puts(char* s)
{
/* While *s != '\0' so unequally "string-end characters" (terminator) */
while(*s) {
bt_putc(*s);
s++;
}
}
/**
* Send a command
*
* Sends a Bluecontroller command (needed for setup)
*
* @param s string
*/
void bt_send_cmd(char* s)
{
bt_puts(s);
/* Carriage return at end (ASCII 13) */
bt_putc('\r');
}
/**
* Debug method
*
* Send a string, if debug is on.
*
* @param s string
*/
void bt_debug(char* s)
{
#ifdef BC_DEBUG
bt_puts("BC_");
bt_puts(s);
#endif
}
/*
* Wait and check, if no command to keep it on
*
* @return 1 wenn aktiv, 0 wenn nicht aktiv
*/
/*uint8_t bt_check_turn_off( void )
{
uint8_t i;
uint8_t bt=0;
DDRB |= (1<<DDB7);
PORTB |= (1<<PORTB7);
for (i = 30; i> 1; i--) {
_delay_ms(1000);
if ( !(PIND & (1<<PIND2)) ) {
bt=1;
i=1;
_delay_ms(250);
}
}
// if(bt==0) { ... off
return bt;
}*/
/**
* Turn LED on or off
*
* Turns LED on (i==1) / off (i!=1).
*
* @param i If i==1 turn LED on, else off
*/
void bt_led_on(uint8_t i)
{
BC_RESET_DDR |= (1<<BC_PIN_LED);
if(i == 1) {
BC_RESET_PORT = (1 << BC_PIN_LED);
} else {
BC_RESET_PORT = (0 << BC_PIN_LED);
}
}
Commands
Die beiden Command (CMD) Dateien dienen zum Empfangen und Verarbeiten von Befehlen in Form von Strings.
Befehle | Beschreibung |
---|---|
wusel | Antwort xyz, dien als Handshake |
ledOn | Schalte die LED auf dem Board an |
ledOff | Schalte die LED auf dem Board aus |
* | Bei jedem nicht bekannten Befehl, wird dieser (nur im Debug-Modus) zurückgeschickt |
cmd.h
/**
* @file cmd.h
* @author Florian Thaeter, Fabi Rosenthal
* @version Epsilon
* @date 25.03.2013
*
* @section LICENSE
* Licence: CC BY 3.0 (http://creativecommons.org/licenses/by/3.0/)
*
* @section DESCRIPTION
* Code: http://github.com/Xennis/Bluecontroller_BCA8_BTM
*
* Documentation: http://wiki.xennis.de/artikel/Bluecontroller
*/
#ifndef CMD_H_
#define CMD_H_
/* Include */
#include "bluecontroller.h"
#include <string.h> // Used for strcmp()
/* Define */
#define UART_MAXSTRLEN 10
/* Method */
void checkCmd(void);
#endif /* CMD_H_ */
cmd.c
/**
* @file cmd.c
* @author Fabi Rosenthal, Florian Thaeter
* @version Epsilon
* @date 25.03.2013
*
* @section LICENSE
* Licence: CC BY 3.0 (http://creativecommons.org/licenses/by/3.0/)
*
* @section DESCRIPTION
* Code: http://github.com/Xennis/Bluecontroller_BCA8_BTM
*
* Documentation: http://wiki.xennis.de/artikel/Bluecontroller
*/
#include "cmd.h"
/* Global Variables */
volatile char uart_string[UART_MAXSTRLEN + 1] = ""; //used to store incoming commands
volatile uint8_t uart_str_complete = 0; //1 means complete received
volatile uint8_t uart_str_count = 0;
/**
* Check commands
*
* This method checks if received command is a valid command and react to it.
* Furthermore it resets the commandBuffer.
*/
void checkCmd()
{
while (uart_str_complete!=1); //wait for complete command
char* uart_string_val = (char *) uart_string;
if(strcmp(uart_string_val, "wusel") == 0) {
bt_puts("xyz");
}
else if(strcmp(uart_string_val, "ledOn") == 0) {
bt_puts("abc");
bt_led_on(1);
}
else if(strcmp(uart_string_val, "ledOff") == 0) {
bt_puts("123");
bt_led_on(0);
}
else {
// send invalid command back
bt_debug(uart_string_val);
}
uart_str_complete = 0; // reset command
sei(); // TODO: test
}
/**
* Interrupt USART_RX_vect
*
* This interrupt is fired if new data is available in USART receive buffer.
*
* Source: http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_UART
*/
ISR( USART_RX_vect )
{
unsigned char nextChar;
/* Read data from buffer */
nextChar = UDR;
//readCmd(nextChar);
if( uart_str_complete == 0 ) { // only if uart_string is currently not in use
if( nextChar != '\n' &&
nextChar != '\r' &&
uart_str_count < UART_MAXSTRLEN ) {
uart_string[uart_str_count] = nextChar;
uart_str_count++;
}
else {
uart_string[uart_str_count] = '\0';
uart_str_count = 0;
uart_str_complete = 1;
cli(); // TODO: TESTEN
}
}
}
Main
Epsilon.c
/**
* @file Epsilon.c
* @author Fabi Rosenthal, Florian Thaeter
* @version Epsilon
* @date 25.03.2013
*
* @section LICENSE
* Licence: CC BY 3.0 (http://creativecommons.org/licenses/by/3.0/)
*
* @section DESCRIPTION
* Code: http://github.com/Xennis/Bluecontroller_BCA8_BTM
*
* Documentation: http://wiki.xennis.de/artikel/Bluecontroller
*
* Program: Atmel Studio 6
*/
#include "cmd.h"
/**
* Main
*
* Initializes Bluecontroller and checks the commands.
*/
void main(void)
{
bt_init();
/* Write data persistent EEPROM/Flash => only necessary one time */
//bt_setut();
while(1) {
checkCmd();
}
}
Kommunikation zwischen Bluecontroller und PC
Windows
Verbindung mit Bluetooth-Modul (BTM-222) herstellen
Ausführliche Hilfe: Connecting BTM-222 (Windows XP, Linux und Android)
- (Windows 7) Rechtsklick auf das Bluetooth Symbol in der unteren rechten Liste > Gerät hinzufügen > den Bluecontroller auswählen > Weiter > Kopplungscode des Geräts eingeben > 1234 als Code eintippen > Weiter
Wenn du nun erneut einen Rechtsklick auf das Bluetooth Symbol machst und Bluetooth-Netzwerkgeräte anzeigen auswählst, sollte dort nun der Bluecontroller aufgelistet werden.
COM-Nummer herausfinden
- Rechtsklick auf Bluetooth Symbol in der unteren rechen Liste > Einstellungen öffnen > COM-Anschlüsse
Dies sollte etwa wie folgt aussehen:
Der gesuchte COM-Anschluss ist der mit der Richtung Ausgehend des Bluecontrollers (der in unserem Fall blub heißt), d.h. COM5.
Terminal
Mithilfe des RS232 Terminal (siehe oben) kannst du Text bzw. Bytes senden und empfangen.
Neben den benötigten Einstellungen ist auch schon das Ergebnis zu sehen. Der Mikrocontroller sendet regelmäßig ein Was. Schickt man ein x, antwortet er mit einem hallo und einem x dahinter.
Linux (KDE)
Unter Linux kann zum Beispiel das KDE Programm BlueDevil verwendet werden.
- Installiere BlueDevil
atp-get install bluedevil
- Starte das Programm und koppel den PC mit dem Bluecontroller (Kopplungscode ist standardmäßig 1234)
- Verwende das Terminal um den Bluecontroller an einem bestimmten Port einzuhängen (in dem Beispiel ist dieses rfcomm0)
rfcomm bind 0 MAC-ADRESSE -BLUECONTROLLER
Anwendungen
Qt (Raspberry Pi)
- Kommunikation mit dem Bluecontroller über ein Qt Terminal: siehe Qt - Serial port
- Kommunikation zwischen einem Raspberry Pi und einem Bluecontroller: siehe Raspberry Pi - Bluetooth-Kommunikation mit Microcontroller und Code Qt2Bluecontroller
Fehler und Tipps
Kommunikation via UART funktioniert nicht
Problem
Mithilfe des UART-Terminals werden keine Strings empfangen beziehungsweise der Bluecontroller reagiert nicht auf versendete Strings.
Lösung
Versorge den Bluecontroller mit Strom an den dafür vorgesehenen Pins und stelle sich, dass der Programmer nicht angeschlossen ist. Denn ist dieser zusätzlich oder ausschließlich angeschlossen, können keine Nachrichten gesendet oder empfangen werden.
Bluecontroller kann nicht mit Programm geflasht werden
Problem
Beim Überspielen der hex-Datei auf den Bluecontroller erscheint eine (ISP) Fehlermeldung und das Programm kann nicht erfolgreich überspielt werden.
Lösung
Der Grund hierfür sein, dass eine aktive Bluetooth-Verbindung besteht. Halte während des gesamten Überspielens den Reset-Knopf auf dem Bluecontroller gedrückt.
Einstellungen (bt_setup) werden nicht übernommen
Um die Einstelungen des Bluetooth Modus zuändern, d.h. die AT-Befehle zu senden, darf keine Bluetooth-Verbindung bestehen. Wir sind dabei wie folgt vorgegangen
- [Bluetooth Adapter am Computer deaktivieren (um sicherzugehen)]
- Stromversorgung entfernen und Programmer an den Bluecontroller anstecken
- Programm überspielen und warten bis die Bluetooth Status LED schnell blinkt
- Programmer wieder abstecken und kurz warten
- Stattdessen wieder die Stromversorgung schlißenan und warte kurz
- [Bluetooth Adapter am PC aktivieren]
Nun sollten die neuen Einstellungen, wie etwa der Name, übernommen wurden sein und dementsprechend (im Falle des Namens) am PC angezeigt werden.