Za niewielkie pieniądze można kupić moduł bluetooth HC-05. Dzięki niemu STM32F4Discovery otrzyma możliwość komunikacji ze światem zewnętrznym poprzez port szeregowy i to bezprzewodowo. Dobrze jest zakupić moduł przylutowany do adaptera PCB, dzięki niemu łatwo go podłączymy. Ja posiadam moduł HC-05 taki jak poniżej.
STM32F4Discovery posiada następujące porty COM:
COM1: (rx, tx, cts, rts)=(PA10, PA9 , PA11 , PA12)
COM2: (rx, tx, cts, rts)=(PA3 , PA2 , PD3 , PA1)
COM3: (rx, tx, cts, rts)=(PD9 , PD8 , PD11 , PD12)
COM4: (rx, tx, cts, rts)=(PC11, PC10, GPIO_NONE, GPIO_NONE)
COM5: (rx, tx, cts, rts)=(PD2 , PC12, GPIO_NONE, GPIO_NONE)
COM6: (rx, tx, cts, rts)=(PC7 , PC6 , GPIO_NONE, GPIO_NONE)
Moduł możemy podłączyć do dowolnego portu COM, ale nie sprawdzałem wszystkich. Ja podłączyłem do portu COM2. Minimum co musimy podpiąć, oprócz zasilania, to piny RXD i TXD. Łączymy je na krzyż do wyjść TX i RX. Schemat podłączenia wygląda tak:
HC-05 GND -> STM32F4Discovery GND
HC-05 VCC -> STM32F4Discovery VCC (+5V)
HC-05 RXD -> STM32F4Discovery PA2
HC-05 TXD -> STM32F4Discovery PA3
Dodatkowo można podłączyć wejście WAKEUP (przeważnie podpisane KEY) i wyjście STATE. Ustawienie stanu wysokiego na WAKEUP (KEY) powoduje przejście modułu w tryb komend AT. Umożliwia to konfigurację i sterowanie modułu. Na przykład zmianę nazwy sieciowej, ustawienia innych parametrów transmisji, wykrycie innych modułów itp. Natomiast na wyjściu STATE jest ustawiany stan wysoki w przypadku sparowania modułu. Ja tych dwóch pinów nie podłączałem. Aha. Domyślnie HC-05 działa jako slave z następującymi parametrami: prędkość 9600, brak parzystości, 8 bitów danych, 1 bit stopu, hasło parowania 1234. No oczywiście do poprawnego komunikowania się z modułem niezbędne jest sparowanie z innym urządzeniem bluetooth. Ja do testu sparowałem moduł z PeCetem.
Ok. Prosty test. Wysyłamy bez przerwy tekst kontrolny i wyświetlamy informację jeśli coś odbierzemy. Pozwoli to zorientować się czy moduł działa.
public class Program { public static void Main() { using (var serial = new SerialPort("COM2")) { serial.Open(); serial.DataReceived += (s, e) => { Debug.Print("Data received"); while (serial.BytesToRead > 0) serial.ReadByte(); }; byte[] buffer = Encoding.UTF8.GetBytes("Ping from STM32F4Discovery\r\n"); for (;;) { serial.Write(buffer, 0, buffer.Length); Thread.Sleep(3000); } } } }
Teraz wystarczy tylko odpalić jakiś program terminalowy (np. realterm) i zobaczyć co się będzie działo. Można też zbudować taki prosty program do wysyłania i odbierania danych i odpalić na komputerze (u mnie sparowany port to COM18).
class Program { static void Main() { using (var serial = new SerialPort("COM18")) { serial.Open(); serial.DataReceived += (s, e) => Console.WriteLine(serial.ReadLine()); byte[] buffer = Encoding.ASCII.GetBytes("Ping from PC\r\n"); while (!Console.KeyAvailable) { serial.Write(buffer, 0, buffer.Length); Thread.Sleep(3000); } } } }
Dobra. Bardziej zaawansowany program. Zdalne włączanie i wyłączanie kolorowych diod na płytce. Wysłanie znaków r, g, b, o spowoduje odpowiednio zapalanie i gaszenie skojarzonych diod. Najpierw kot w .NETMF.
Definiujemy komendy i w tablicy kojarzymy je z odpowiednimi diodami. Dodatkowo w głównej pętli programu wysyłamy tekst testowy (co w poprzednim programie) do klienta:
Definiujemy komendy i w tablicy kojarzymy je z odpowiednimi diodami. Dodatkowo w głównej pętli programu wysyłamy tekst testowy (co w poprzednim programie) do klienta:
public enum Command { Unknown, Red, Green, Blue, Orange } private static readonly Hashtable Led = new Hashtable(); public static void Main() { Led.Add(Command.Red, new OutputPort(Stm32F4Discovery.LedPins.Red, false)); Led.Add(Command.Green, new OutputPort(Stm32F4Discovery.LedPins.Green, false)); Led.Add(Command.Blue, new OutputPort(Stm32F4Discovery.LedPins.Blue, false)); Led.Add(Command.Orange, new OutputPort(Stm32F4Discovery.LedPins.Orange, false)); using (var serial = new SerialPort("COM2")) { serial.Open(); serial.DataReceived += DataReceived; byte[] buffer = Encoding.UTF8.GetBytes("Ping from STM32F4Discovery\r\n"); for (; ; ) { serial.Write(buffer, 0, buffer.Length); Thread.Sleep(10000); } } }
Najważniejsza część programu odbywa się w procedurze DataReceived. Czytamy po kolei wszystkie bajty z bufora portu, konwertujemy na komendy, i zmieniamy stan odpowiedniej diody. Dodatkowo wysyłamy poprzez port aktualny stan diody:
private static void DataReceived(object sender, SerialDataReceivedEventArgs e) { var port = (SerialPort) sender; while (port.BytesToRead > 0) { int b = port.ReadByte(); if (b == -1) continue; Command command = ToCommand(b); if (command == Command.Unknown) { Debug.Print(b.ToString("X2")); continue; } var led = (OutputPort) Led[command]; bool newValue = !led.Read(); led.Write(newValue); string response = (char)b + "=" + (newValue ? "on" : "off") + "\r\n"; byte[] buffer = Encoding.UTF8.GetBytes(response); port.Write(buffer, 0, buffer.Length); } } private static Command ToCommand(int value) { if (value == 'r') return Command.Red; if (value == 'g') return Command.Green; if (value == 'b') return Command.Blue; if (value == 'o') return Command.Orange; return Command.Unknown; }
Teraz kot programu sterującego na PC. Program wyświetla odebrane dane w oknie konsoli, a tekst wpisany i zatwierdzony enterem wysyła:
class Program { static void Main() { using (var port = new SerialPort("COM18")) { port.DataReceived += DataReceived; port.Open(); for(;;) { string send = Console.ReadLine(); if(send.Length == 1 && send[0] == 'q') return; port.Write(send); } } } static void DataReceived(object sender, SerialDataReceivedEventArgs e) { var port = (SerialPort) sender; while (port.BytesToRead > 0) { int b = port.ReadByte(); if (b == -1) continue; bool printable = (b >= ' ' && b <= '~') || b == 0x0d || b == 0x0a; if (printable) Console.Write(Convert.ToChar(b)); else Console.Write(b.ToString("X2")); } } }
Kot programu i klienta: DemoBTHC05, SerialController
Brak komentarzy:
Prześlij komentarz