piątek, 16 października 2015

[3] STM32 Nucleo F411RE - USART

W tym poście przedstawię podłączenie mikrokontrolera do komputera za pomocą UART-a.

Wstęp


UART (ang. Universal Asynchronous and Transmitter) jest to układ pozwalający na asynchroniczną transmisję informacji wykorzystującą port szeregowy. W tym układzie zawarte są dwa konwertery, jeden z nich służy do konwersji danych przesyłanych z komputera (równoległo-szeregowy - ang. parallel to serial), drugi natomiast działa odwrotnie (szeregowo-równoległy ang. serial to parallel). W skład UART-u wchodzi także bufor, który przechowuje dane tymczasowo w momencie wykorzystywania szybkiej transmisji. [1]

Pewną odmianą UART-u jest tzw. USART. Może on pracować w trybie synchronicznym jak i asynchronicznym.

Podłączenie


Mikrokontroler zastosowany na płytce używanej przeze mnie płytce Nucleo pozwala na wykorzystywanie trzech portów transmisji synchronicznej/asynchronicznej, są to USART1, USART2, USART6. Jedynka i szóstka mogą się komunikować z prędkością 12.5 Mbit/s, natomiast USART2 z prędkością do 6.25 bit/s. 

W tabeli 1.1. przedstawiono dokładne informacje odnośnie tych portów. Dane zostały zaczerpnięte z noty katalogowej mikrokontrolera. 

Tab. 1.1. Zestawienie danych UART

Parametry zdefiniowane w zestawieniu:
Modem (RTS/CTS) - jest to mechanizm zdefiniowany w standardzie dla RS232, pozwala on na kontrolę przepływu danych. RTS oznacza Request to Send. Stan niski na tej linii, (Dla RS232 jest to -12V) przerywa wysyłanie danych. Podobnie działa to dla CTS czyli Clear To Send. Sygnał kontrolny jest zawsze wysyłany w kierunku przeciwnym do przesyłanych danych. Linią RTS wysyłane jest żądanie wysłania danych z komputera do modemu. CTS podaje czy odbiornik jest gotowy. 

Boud rate - oznacza ilość bitów jakie przypadają na jednostkę transmisji czyli na sekundę. Natomiast nadpróbkowanie jest to wartość przez jaką dzielony jest sygnał taktujący w celu uzyskania odpowiedniej transmisji.

Wyprowadzenia poszczególnych pinów USART-u wyglądają następująco:
  • USART1 - TX - PA9 - RX - PA10,
  • USART2 - TX - PA2 - RX - PA3,
  • USART3 - TX - PB10 - RX - PB11,
  • USART4 - TX - PA0 - RX - PA1,
  • USART5 - TX - PC12 - RX - PD2,
  • USART6 - TX - PC6 - RX - PC7,
  • USART7 - TX - PE8 - RX - PE7,
  • USART8 - TX - PE1 - RX - PA0,

Program


W programach przedstawię obsługę portu USART 2. Do komunikacji wykorzystałem zewnętrzny konwerter UART na USB.

Podłączenie:


Pin Konwertera                    Pin STM32:

  • GND                          GND    
  • 5V                             5V
  • TXD                          PA10                      
  • RXD                          PA9


W tym programie wykorzystam USART1, którego trzeba odpowiednio zainicjalizować.

void USART_Initialize(void)
{
 //konfiguracja układu USART
 USART_InitTypeDef USART_InitStructure;
 
 //Włączenie zegara dla USART1
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
 
 //Ustawienie prędkości transmisji 9600bps
 USART_InitStructure.USART_BaudRate = 9600;
 //Długosc wysylanego slowa
 USART_InitStructure.USART_WordLength = USART_WordLength_8b;
 //Ustawienie jednego bitu stopu
 USART_InitStructure.USART_StopBits = USART_StopBits_1;
 //Kontrola parzystości wyłączona
 USART_InitStructure.USART_Parity = USART_Parity_No;
 //Wylaczenie kontroli przepływu danych
 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
 //Tryb pracy linii odpowiednio odbior i nadawanie
 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
 
 //Konfiguracja układu
 USART_Init(USART1, &USART_InitStructure);
 //Włączenie USART1
 USART_Cmd(USART1, ENABLE);
}

Do linii TX czyli PA9 będą wysyłane dane z mikrokontrolera. Musi ona pracować w trybie funkcji alternatywnych z ustawionym wejściem typu push-pull.
Linia RX czyli PA10 pracuje w trybie wejścia o wysokiej impedancji. Jej zadaniem jest odbieranie danych przez mikrokontroler.

void GPIO_Initialize(void)
{
  //konfigurowanie portow GPIO
  GPIO_InitTypeDef  GPIO_InitStructure;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
 
  //TX dla pinu PA9
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
 
  //RX dla pinu PA10
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
 
  //Włączenie transmisji na podanych pinach
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
}

Ostatnim wymaganym elementem aby móc przesłać dane na ekran komputera jest funkcja wysyłająca zdefiniowany ciąg znaków.

void USART_wyswietl(volatile char *c)
{
 //Pętla działa do puki będzie jakiś znak do wysłania
 while(*c)
 {
  //Sprawdza czy rejestr danych został opróżniony
  while( !(USART1->SR & 0x00000040) );
  //Prześlij dane, 
  USART_SendData(USART1, *c);
  *c++;
 }
}

W przypadku gdy chcemy wysłać pojedynczy znak czyli char. Wtedy można użyć następującej funkcji:

void SendChar(char c)
{
 //Sprawdza czy bufor nadawczy jest pusty
 while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
 USART_SendData(USART1, c);
}

Natomiast główna funkcja wysyłająca dane znajduje się w bibliotece stm32f4xx_usart.c. I wygląda następująco.

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
{
  //Sprawdź parametry
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  assert_param(IS_USART_DATA(Data)); 
 
  //Prześlij dane
  USARTx->DR = (Data & (uint16_t)0x01FF);
}

Na rysunku 1.2. znajduje się okno programu terminal z przedstawionymi ustawieniami, które muszą być takie same jak te ustawione w programie. W części receive znajduje się ciąg znaków wysłany z mikrokontrolera.

Rys. 1.2. Okno programu terminal

Poniżej wklejam cały zestawiony program.

#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_usart.h"
#include "misc.h"
 
void USART_Initialize(void);
void GPIO_Initialize(void);
void USART_Send(volatile char *s);
 
int main(void)
{
 GPIO_Initialize();
 USART_Initialize();
 USART_Send("Dziala");
 while (1) {}
}
 
void USART_Initialize(void)
{
 //konfiguracja układu USART
 USART_InitTypeDef USART_InitStructure;
 
 //Włączenie zegara dla USART1
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
 
 //Ustawienie prędkości transmisji 9600bps
 USART_InitStructure.USART_BaudRate = 9600;
 //Długosc wysylanego slowa
 USART_InitStructure.USART_WordLength = USART_WordLength_8b;
 //Ustawienie jednego bitu stopu
 USART_InitStructure.USART_StopBits = USART_StopBits_1;
 //Kontrola parzystości wyłączona
 USART_InitStructure.USART_Parity = USART_Parity_No;
 //Wylaczenie kontroli przepływu danych
 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
 //Tryb pracy linii odpowiednio odbior i nadawanie
 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
 
 //Konfiguracja układu
 USART_Init(USART1, &USART_InitStructure);
 //Włączenie USART1
 USART_Cmd(USART1, ENABLE);
}
 
void GPIO_Initialize(void)
{
 //konfigurowanie portow GPIO
 GPIO_InitTypeDef  GPIO_InitStructure;
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
 
 //TX dla pinu PA9
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_Init(GPIOA, &GPIO_InitStructure);
 
 //RX dla pinu PA10
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_Init(GPIOA, &GPIO_InitStructure);
 
 //Włączenie transmisji na podanych pinach
 GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
 GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
}
 
void USART_Send(volatile char *c)
{
 //Pętla działa do puki będzie jakiś znak do wysłania
 while(*c)
 {
  //Sprawdza czy rejestr danych został opróżniony
  while( !(USART1->SR & 0x00000040) );
  //Prześlij dane,
  USART_SendData(USART1, *c);
  *c++;
 }
}

Bibliografia

[1]            www.wikipedia.org - UART