czwartek, 29 października 2015

[3b] STM32 Nucelo F411RE - Obsługa wbudowanego USART-u, funckja printf

W tym poście pokaże jak obsłużyć układ USART z konwerterem wbudowanym w płytkę Nucleo

Wstęp


Wbudowany konwerter USART podłączony jest do USART2, który jest podłączony do pinów PA2 oraz PA3.
Układ wbudowany jest w płytkę, dzięki temu po podłączeniu do komputera i odpowiednim zaprogramowaniu można od razu z niego korzystać. Nie ma potrzeby stosowania dodatkowych elementów.

Program 1


Programowanie przebiega w standardowy sposób, przedstawiony we wcześniejszych postach. Dlatego teraz od razu wklejam program. W nim zawarte są komentarze pozwalające na efektywne zrozumienie całego kodu.

#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\r\n");
 while (1) {}
}
 
void USART_Initialize(void)
{
 //konfiguracja układu USART
 USART_InitTypeDef USART_InitStructure;
 
 //Włączenie zegara dla USART2
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, 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(USART2, &USART_InitStructure);
 //Włączenie USART2
 USART_Cmd(USART2, ENABLE);
}
 
void GPIO_Initialize(void)
{
 //konfigurowanie portow GPIO
 GPIO_InitTypeDef  GPIO_InitStructure;
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
 
 //TX dla pinu PA2
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
 GPIO_Init(GPIOA, &GPIO_InitStructure);
 
 //RX dla pinu PA3
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
 GPIO_Init(GPIOA, &GPIO_InitStructure);
 
 //Włączenie transmisji na podanych pinach
 GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART1);
 GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, 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( !(USART2->SR & 0x00000040) );
  //Prześlij dane,
  USART_SendData(USART2, *c);
  *c++;
 }
} 

Program 2


W przypadku kiedy chcemy przesłać informacje inne niż string dobrze jest zintegrować z funkcją printf. Zwiększa ono niestety wielkość programu, pozwala także na łatwiejszą edycję tekstu.

Żeby umożliwić wykorzystywanie funkcji printf należy dołączyć odpowiednie funckje edycji tekstu.

int __io_putchar(int c)
{
 send_char(c);
 return c;
}
 
void send_char(char c)
{
 while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
 USART_SendData(USART2, c);
}

Pozostała część programu pozostaje bez zmian. Natomiast funkcja main() prezentuje się następująco:

int main(void)
{
 int Wartosc1 = 1;
 float Wartosc2 = 54.8725;
 GPIO_Initialize();
 USART_Initialize();
 USART_Send("Dziala\r\n");
 //Przykładowe dane liczbowe
 printf("Calkowita - %d\r\n", Wartosc1);
 printf("Zmiennoprzecinkowa - %.3f\r\n", Wartosc2);
 while (1) {}
}

Wynik działania programu przedstawiłem na rysunku 1.1.


Rys. 1.1. Wynik działania programu