Miesięczne archiwum: Marzec 2010

Arduino Bluetooth na Ubuntu

Arduino Bluetooth – czyli Arduino bez portu USB, a zamiast tego moduł Bluetooth. Rozwiązanie idealne gdy potrzebna jest komunikacja bezprzewodowa z Arduino.

Najpierw – kilka różnic w stosunku do zwykłego Arduino Duemilanove. Arduino BT jest oparte o ATmega168 – czyli mamy do dyspozycji trochę mniej pamięci. Nie ma portu USB, więc musimy zasilać Arduino BT we własnym zakresie. Jeśli już o zasilaniu mowa – Arduino BT jest wrażliwe na polaryzację zasilania, więc uważnie podłączajcie masę i Vcc do płytki. Na dodatek maksymalne napięcie zasilania płytki to tylko 5.5V!. Na osłodę – dzięki konwerterowi DC/DC minimalne napięcie zasilające to tylko 1.2V.

Arduino Bluetooth

Arduino Bluetooth

Ponieważ nie ma portu USB, również programowanie odbywa się przez bluetooth. Krótka instrukcja jak to zrobić – system Ubuntu 9.10.

Nie korzystałem z GUI Ubuntu aby skonfigurować połączenie, możliwe że też zadziała ;)

Najpierw (oczywiście po włączeniu Arduino BT) szukamy dostępnych urządzeń:

$ hcitool scan
Scanning ...
	00:07:80:91:30:09	ARDUINOBT

Oto znaleziony moduł. 00:07:80:91:30:09 – to jest adres MAC urządzenia i oczywiście jest różny dla każdego modułu. Wszędzie gdzie wystąpi teraz ten adres należy zastąpić go właściwym dla Arduino, które wy macie.

Teraz podłączamy się do modułu:

$ sudo hcitool cc 00:07:80:91:30:09
$ sudo hcitool auth 00:07:80:91:30:09

Zapewne poprosi was o PIN – domyślny PIN to 12345.

Potrzebujemy informacji o urządzeniu:

$ sdptool browse 00:07:80:91:30:09
Browsing 00:07:80:91:30:09 ...
Service Name: Bluetooth Serial Port
Service RecHandle: 0x10000
Service Class ID List:
  UUID 128: 00001101-0000-1000-8000-00805f9b34fb
Protocol Descriptor List:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    Channel: 1
Language Base Attr List:
  code_ISO639: 0x656e
  encoding:    0x6a
  base_offset: 0x100

To co jest ważną informacją to RFCOMM i Channel 1. RFCOMM jest to protokół emulacji portu szeregowego w transmisji radiowej.

Teraz można wypisać do /etc/bluetooth/rfcomm.conf:

rfcomm0 {
	bind yes;
	device 00:07:80:91:30:09;
	channel	1;
	comment "Arduino BT";
}

Oczywiście channel ma mieć taką samą wartość jak ten zwrócony przez sdptool. Mając wpisane powyższe w plik konfiguracyjny możemy się podłączyć:

$ sudo rfcomm connect 0
Connected /dev/rfcomm0 to 00:07:80:91:30:09 on channel 1
Press CTRL-C for hangup

Teraz wystarczyć powinno minicom -s ustawić port na /dev/rfcomm0 i powinniśmy być podłączeni do seriala Arduino.

Teoretycznie :) Arduino BT powinno być fabrycznie zaprogramowane z następującym programem (oryginał bez formatowania):

/* BT test 01
* ——————
* Massimo Banzi
*
*/

int LED = 13; // select the pin for the LED
int RESET = 7;

void setup() {
  pinMode(LED,OUTPUT); // declare the LED’s pin as output
  pinMode(RESET,OUTPUT); // declare the LED’s pin as output
  Serial.begin(115200); // connect to the serial port
  digitalWrite(RESET, HIGH);
  delay(10);
  digitalWrite(RESET, LOW);
  delay(2000);
  Serial.println(„SET BT PAGEMODE 3 2000 1”);
  Serial.println(„SET BT NAME ARDUINOBT”);
  Serial.println(„SET BT ROLE 0 f 7d00”);
  Serial.println(„SET CONTROL ECHO 0”);
  Serial.println(„SET BT AUTH * 12345”);
  Serial.println(„SET CONTROL ESCAPE – 00 1”);
  Serial.println(„SET CONTROL BAUD 115200,8n1”); //first release 19200
}

void loop () {
  digitalWrite(LED, HIGH);
  delay(100);
  digitalWrite(LED, LOW);
  Serial.println(„ciao”);
  delay(1000);
}

Powinien – z moich skromnych doświadczeń wynika, że z fabryki przychodzi z klasycznym blink – cyfrowy pin 13 zapala się i gaśnie. Tak też jest w powyższym kodzie, ale powinien jeszcze pisać komunikat „ciao” na serial. Nie udało mi się na ‚świeżym’ Arduino BT uzyskać tego komunikatu na serialu (na /dev/rfcomm0 była cały czas cisza), choć pin 13 faktycznie się przełączał (Arduino BT nie ma na płytce diody podłączonej do 13 więc trzeba samemu podłączyć)

Pozostaje wgrać powyższy kod na płytkę. Najlepiej na stałe powiedzieć Arduino IDE, że chcemy korzystać z BT i do pliku ~/.arduino/preferences.txt dodać:

serial.stopbits=1
serial.databits=8
serial.parity=N
serial.port=/dev/rfcomm0
serial.debug_rate=115200
serial.burn_rate=115200
board=bt

Teraz można bez problemu wgrać powyższy program. Uwaga – nawet jeżeli Arduion IDE pisze że korzysta z /dev/ttyS0 czy USB0 to przy powyższym wpisie do preferences.txt powinno wgrywać przez rfcomm0.

Wgrać bez problemu – jeżeli wie się jak to zrobić. Otóż obecne Arduino wyposażone w USB mają firmware pozwalający wgrać w każdej chwili nowy kod (przez USB jest robiony reset płytki po którym jest wgrywany nowy kod). Wersja firmware na Arduino BT nie wspiera tej wygodnej funkcji więc trzeba ręcznie zresetować moduł (przycisk S1) i w ciągu 1 sekundy nacisnąć ‚Upload’ w IDE.

Po takim zabiegu powyższy programik wgra się bez problemu i od teraz minicom nam będzie pokazywał ciao.

Arduino BT jest dostępne na nettigo.pl – w małych ilościach, możliwe jest sprowadzenie na zamówienie (maksymalny czas oczekiwania – miesiąc)

Przesuwane diody

Ostatnim z elementów Arduino Starter Kitu, który jeszcze nie doczekał się opisu na tym blogu jest niepozorny układ scalony – rejestr przesuwny. Jest układ 74HC595, rejestr przesuwny typu SIPO (Serial-In, Parallel-Out) o 8 wyjściach równoległych.

Rejestr przesuwny (ang. shift register) jest układem posiadającym wejście szeregowe i kilka (zazwyczaj 8) wyjść równoległych. Co to znaczy? Z każdą zmianą zegara na wejściu, stany wyjść są przesuwane o jeden. Czyli stan wyjścia 1 jest przepisywany do wyjścia 2, 2 do 3, itd. Stan wejścia 1 jest ustalany na podstawie stanu wejścia szeregowego.

Do czego można to zastosować w praktyce?

Każde miejsce które potrzebuje wielu wyjść cyfrowych, może być miejscem w którym można rozważyć zastosowanie rejestru przesuwnego. Można powiedzieć, że trzy piny mogą sterować znacznie większa ilością wyjść. Zobaczmy to na najprostszym przykładzie – diody LED.

Dzisiejszy artykuł jest oparty na przewodniku opublikowanym na stronach Arduino.cc, stanowi on źródło ilustracji i tekstu. Ilustracje wykorzystują więcej niż jedną płytkę stykową, ale zdecydowałem się je wykorzystać, aby przyspieszyć powstawanie tego wpisu – zrobienie dobrej ilustracji do tego wpisu we Fritzingu chyba nie jest możliwe (hint – czytelnej ilustracji :) )

Zacznijmy od podłączenia:

Schemat układu z rejestrem przesuwnym - zamontowany na płytce stykowej

Schemat układu z rejestrem przesuwnym – zamontowany na płytce stykowej

Zasilanie jest rozprowadzone przez szyny na płytce stykowej. Na lewej płytce są podłączone diody LED wraz rezystorami. Na prawej jest podłączony sam układ scalony 74HC595. Jego wyprowadzenia:

Wyprowadzenia pinów 74HC595

Wyprowadzenia pinów 74HC595

Na powyższym diagramie przedstawione są wyprowadzenia pinów opisane zgodnie z danymi producenta (ST Microelectronics), którego to układy są w ofercie Nettigo i stanowią część Starter Kitu. Na stronie Arduino jest opis przystosowany dla układów z oznaczeniami zgodnymi z nomenklaturą Philipsa. Co to znaczy? Na szczęście w tym wypadku różnica polega tylko w nazwach sygnałów (np wyjścia w STM – QA do QH, w wersji Philipsa Q0-Q7), położenie i znaczenie pinów jest identyczne. W tym przewodniku będę używał nazewnictwa zgodnego z STM.

Najprostsze podłączenie rejestru przesuwnego do Arduino wygląda następująco:

  • Zasilanie +5V do pinu 16 rejestru
  • Masa do pinu 8 rejestru

Jeżeli nie przeszkadza nam to, że po włączeniu diody mogą się nam zapalić w losowym układzie a chcemy użyć mniej wyjść cyfrowych na Arduino podłączamy:

  • G – pin 13 na rejestrze do masy
  • SCLR – pin 10 na rejestrze do +5V

Minimalny zestaw podłączeń do sterowania rejestrem z Arduino przedstawia się następująco (wszystkie piny na Arduino to wejścia cyfrowe):

  • SI – pin 14 rejestru do pinu 11 na Arduino
  • SCK – pin 11 rejestru do pinu 12 na Arduino
  • RCK – pin 12 rejestru do pinu 8 na Arduino

Między pinem RCK a masą może być potrzebny mały kondensator (1 μF – nie jest częścią Starter Kitu). Z serii eksperymentów które przeprowadziłem wynika, że nie powinien być potrzebny :)

Oto schemat logiczny  całego połączenia:

Schemat logiczny układu

Schemat logiczny układu

Co nam pozostaje? Program:

//**************************************************************//
//  Name    : shiftOutCode, One By One                          //
//  Author  : Carlyn Maw, Tom Igoe                           //
//  Date    : 25 Oct, 2006                                      //
//  Version : 1.0                                               //
//  Notes   : Code for using a 74HC595 Shift Register           //
//          : to count from 0 to 255                            //
//****************************************************************

//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 12;
////Pin connected to DS of 74HC595
int dataPin = 11;

//holder for infromation you're going to pass to shifting function
byte data = 0; 

void setup() {
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

}

void loop() {

  //function that blinks all the LEDs
  //gets passed the number of blinks and the pause time
  blinkAll(1,500); 

 // light each pin one by one using a function A
  for (int j = 0; j < 8; j++) {
    lightShiftPinA(j);
    delay(1000);
  }

  blinkAll(2,500);  

 // light each pin one by one using a function A
  for (int j = 0; j < 8; j++) {
    lightShiftPinB(j);
    delay(1000);
  } 

}

//This function uses bitwise math to move the pins up
void lightShiftPinA(int p) {
  //defines a local variable
  int pin;

  //this is line uses a bitwise operator
  //shifting a bit left using << is the same
  //as multiplying the decimal number by two.
  pin = 1<< p;

  //ground latchPin and hold low for as long as you are transmitting
  digitalWrite(latchPin, LOW);
  //move 'em out
  shiftOut(dataPin, clockPin, MSBFIRST, pin);
  //return the latch pin high to signal chip that it
  //no longer needs to listen for information
  digitalWrite(latchPin, HIGH);

}

//This function uses that fact that each bit in a byte
//is 2 times greater than the one before it to
//shift the bits higher
void lightShiftPinB(int p) {
  //defines a local variable
  int pin;

  //start with the pin = 1 so that if 0 is passed to this
  //function pin 0 will light.
  pin = 1;

  for (int x = 0; x < p; x++) {
    pin = pin * 2;
  }

  //ground latchPin and hold low for as long as you are transmitting
  digitalWrite(latchPin, LOW);
  //move 'em out
  shiftOut(dataPin, clockPin, MSBFIRST, pin);
  //return the latch pin high to signal chip that it
  //no longer needs to listen for information
  digitalWrite(latchPin, HIGH);

}

//blinks the whole register based on the number of times you want to
//blink "n" and the pause between them "d"
//starts with a moment of darkness to make sure the first blink
//has its full visual effect.
void blinkAll(int n, int d) {
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, 0);
  digitalWrite(latchPin, HIGH);
  delay(200);
  for (int x = 0; x < n; x++) {
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, 255);
    digitalWrite(latchPin, HIGH);
    delay(d);
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, 0);
    digitalWrite(latchPin, HIGH);
    delay(d);
  }
}

Kod mignie wszystkimi diodami, potem zapali każdą po kolei diodę, mignie dwa razy wszystkimi i jeszcze raz zapali, korzystając z innej metody.

Najważniejsze wiadomości:

  • shiftOut to funkcja biblioteki Arduino, wysyłająca szeregowo wybrany bajt na wybrane wyjścia
  • ustawiając RCK (na Arduino podłaczony do 8) w stan niski możemy wysyłać dane do rejestru

Temperatura i LCD

W ofercie Nettigo dziś pojawił się zestaw LCD do Arduino – jest to moduł LCD alfanumeryczny, 2×16 z przylutowaną złączką pasującą do płytki prototypowej, oraz potencjometr 10 kΩ, liniowy do regulacji kontrastu.

LCD kit dla Arduino w akcji

LCD kit dla Arduino w akcji

Moduł LCD posiada kontroler zgodny z HD44780, co oznacza, że biblioteka LiquidCrystal będzie go obsługiwała. Jak go podłączyć?

Zacznijmy od kodu:

#include <LiquidCrystal.h>

float temp;
LiquidCrystal lcd (12,11,10,9,8,7);

void setup() {
  analogReference(EXTERNAL);
};

void loop () {
  temp = analogRead(0)*3.3/1024.0;

  temp = temp - 0.5;
  temp = temp / 0.01;
  delay(500);
  lcd.print("Temp: ");
  lcd.print(temp);
  lcd.print("        ");
  lcd.setCursor(0,0);
};

Obsługa LCD w podstawowym zakresie sprowadza się do podłączenia go (o tym za chwilę), zainicjowaniu go:

LiquidCrystal lcd (12,11,10,9,8,7);

Powyższe definiuje zmienną lcd, przez którą będziemy się komunikować z modułem. Tutaj przyjmujemy najprostszą postać czyli podajemy do których pinów Arduino podłączamy kolejno:

  • pin RS modułu
  • pin ENABLE modułu
  • piny danych modułu D4, D5, D6, D7

W tym przykładzie 12 – RS, 11 – ENABLE, 10-7 D4-D7. Poza tym do modułu musimy podłączyć zasilanie oraz sygnał R/W modułu LCD do masy (nie będziemy nic do niego zapisywać). Nawet jak to wszystko podłączymy po uruchomieniu zobaczymy co najwyżej 32 czarne kwadraciki. Musimy jeszcze wyregulować kontrast. Odbywa się to przez podanie napięcia między 0 a 5V na pin Vo modułu. Aby móc regulować to napięcie skorzystamy z potencjometru będącego w zestawie. Całość podłączenia zilustrowana we Fritzingu (za MCP9700 robi symbol tranzystora, ale to dlatego, że nie ma takiego elementu we Fritzingu, obudowa jest taka sam (TO92):

Schemat podłączenia modułu LCD

Schemat podłączenia modułu LCD

Następnie w pętli loop odczytujemy temperaturę z czujnika MCP-9700 (opisanego w tym poście). Mając temperaturę wyświetlamy napis Temp: potem wartość odczytu i wracamy na początek linii.

Jak poprawić odczyt temperatury?

Odczyt temperatury (w postaci napięcia mierzonego przez wejście analogowe 0) podawany przez MCP9700 jest podawany z dokładnością zależną od przetwornika napięcia w Arduino. Jest on 10-cio bitowy i domyślnie mierzy napięcia od 0 do 5V. 10 bitów oznacza to że mamy 1024 kroki w odczycie napięcia. Dlatego napięcie jest mierzone z krokiem 4.88 mV (5/1024).

Czujnik MCP9700 ma czułość 10 mV na stopień, czyli w praktyce znaczy to że mamy dokładność odczytu do pół stopnia (nie mówimy tutaj o jakości czujnika tylko o tym jak Arduino jest w stanie dokładnie odczytać napięcie).

Przetwornik A/D Arduino ma możliwość podania napięcia odniesienia (AREF – skrajne wyprowadzenie w rzędzie, gdzie są wejście/wyjścia cyfrowe), które zastąpi domyślne 5V. Napięcie to może być mniejsze lub większe od 5V.EDIT – niestety, ale pomyliłem się tutaj – z danych przetwornika wynika, że maksymalne napięcie odniesienia to napięcie zasilania – dla Arduino to oznacza 5V – jak koś musi mierzyć większe napięcie to dzielnik napięcia zostaje…

UWAGA!
Potencjalne zagrożenie.
Wg dokumentacji funkcji
analogReference, domyślne ustawienie (czyli gdy nie wywołamy w ogóle analogReference lub gdy zrobimy to z wartością DEFAULT), jest podatne na uszkodzenia gdy podamy napięcie na wejście AREF!

Z danych katalogowych MCP9700 wynika że maksymalne napięcie wyjściowe to 500 mV+ 125*10mV = 1.75V. Najlepiej byłoby zmusić przetwornik do pomiaru napięć w przedziale 0-1.75V, ale wymagało by to dodania dzielnika napięcia abyśmy taką wartość uzyskali. Nie jest to żadna skomplikowana sprawa, ale aby nie komplikować bardziej tego przykładu wykorzystamy prosty sposób na poprawę jakości odczytu, bez dodawania nowych elementów. Wykorzystamy fakt, że Arduino dostarcza nam poza 5V również 3.3V i bez żadnych kłopotów możemy poprawić czułość odczytu napięcia.

Dlatego w setup jest wywołanie analogReference(EXTERNAL) (nie wystarczy podać samego napięcia na AREF) a w loop zmienia się wzór do obliczania temperatury. Po zmianie napięcai odniesienia mamy krok odczytu napięcia 3.2 mV, co oznacza że odczyt pomiaru temperatury jest z dokładnością 0.3°C a nie 0.5°C  jak wcześniej.

UWAGA – to jest tylko dokładność odczytu pomiaru a nie poprawa dokładności pomiaru. Czujnik ma, tak jak miał wcześniej dokładność +-2°C :) ta sztuczka poprawi tylko nasze samopoczucie, że odczyt nie skacze tak bardzo :)

Oczywiście, zmiana AREF dotyczy wszystkich wejść analogowych…