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