Lesson 8. Communication with USART
In this lesson I show you the simplest way to use USART for communication with other device (for example your PC).
USART configuration
USART peripheral is descibed in section 23 of RM0041 document. There is lot of data to read, but for simple asynchronous communication we don't need read whole chapter. Main features are descibed in sections from 23.3.1 to 23.3.4. To use USART peripheral we must enable clock for it, and for GPIO used by peripheral. It is obvious, but sometimes easy to forget. USART1, which are used in this lesson is connected to APB2 bus, and use GPIOA (by default). Code for enable clock for USART1 and GPIOA :
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN; |
After enabling clock for USART1 peripheral, we can configure it. What we need to do? At this moment we need two things : enable usart transmitter, and sets baudrate. Enabling transmistter is done by setting UE (USART enable) and TE (transmitter enable) bits in CR1 register of USART1 peripheral :
USART1->CR1 = USART_CR1_UE | USART_CR1_TE; |
In RM0041 document there is shown sophisticated way to calculate USART baudrate. There is mantissa and fractional part of divider, but forget about them! Calculating baudrate is easier than shown in reference manual. So how to calculate value of BRR register? Just divide peripheral clock by baudrate! We want configure USART for communication with transmission speed equal to 115200 bits per second. Its done by one line :
USART1->BRR = (SystemCoreClock / 115200); |
What is SystemCoreClock? This is variable sets by SystemInit function, that holds current system frequency. By default, APB2 bus clock is equal to system frequency, we can use it to calculate baudrate.
Sending single character
In this lesson I show simplest way to sending data - using pooling. Before write data to DR register, we check state of TXE (transmitter empty) flag. When this flag is clear, we can't write to DR register. High value of this flag mean that is no data in transmit buffer (previous data just be sent or there is first tranmission) and we can write new data to send. So let's create function dedicated to sending one byte via USART :
void USART_PutChar(uint8_t ch)
{
while(!(USART1->SR & USART_SR_TXE));
USART1->DR = ch;
} |
Sending text
When we can send single character we can write function for sending typical for C language null-terminated strings. Null terminated string is character array, that last element has value zero. Empty string has one element - value zero. So before sending character we must check if character has different value than zero. If this condition is true, we can send first character and increment pointer to prepare next character to send. Repeat this in loop until pointer will be pointed to character value zero.
void USART_PutString(uint8_t * str)
{
while(*str != 0)
{
USART_PutChar(*str);
str++;
}
} |
Now, we are ready to send text by USART :
USART_PutString(text); // argument is pointer variable |
USART_PutString("Some text to send"); // argument is constant string |
Complete source code :
//=============================================================================
// STM32VLDISCOVERY tutorial
// Lesson 8. Communication with USART
// Copyright : Radoslaw Kwiecien
// http://en.radzio.dxp.pl
// e-mail : radek(at)dxp.pl
//=============================================================================
#include "stm32f10x.h"
#include "antilib_gpio.h"
//=============================================================================
// Defines
//=============================================================================
#define USART_RX_GPIO GPIOA
#define USART_RX_PIN 10
#define USART_TX_GPIO GPIOA
#define USART_TX_PIN 9
uint8_t text [] = "STM32VLDISCOVERY tutorial\n\rhttp://en.radzio.dxp.pl/stm32vldiscovery/\n\r\n\r";
//=============================================================================
//
//=============================================================================
void USART_PutChar(uint8_t ch)
{
while(!(USART1->SR & USART_SR_TXE));
USART1->DR = ch;
}
//=============================================================================
//
//=============================================================================
void USART_PutString(uint8_t * str)
{
while(*str != 0)
{
USART_PutChar(*str);
str++;
}
}
//=============================================================================
// main function
//=============================================================================
int main(void)
{
vu32 dly;
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN;
#if (USART_RX_PIN > 7)
USART_RX_GPIO->CRH = (USART_RX_GPIO->CRH & CONFMASKH(USART_RX_PIN)) | GPIOPINCONFH(USART_RX_PIN, GPIOCONF(GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULLUPDOWN));
#else
USART_RX_GPIO->CRL = (USART_RX_GPIO->CRL & CONFMASKL(USART_RX_PIN)) | GPIOPINCONFL(USART_RX_PIN, GPIOCONF(GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULLUPDOWN));
#endif
#if (USART_TX_PIN > 7)
USART_TX_GPIO->CRH = (USART_TX_GPIO->CRH & CONFMASKH(USART_TX_PIN)) | GPIOPINCONFH(USART_TX_PIN, GPIOCONF(GPIO_MODE_OUTPUT2MHz, GPIO_CNF_AFIO_PUSHPULL));
#else
USART_TX_GPIO->CRL = (USART_TX_GPIO->CRL & CONFMASKL(USART_TX_PIN)) | GPIOPINCONFL(USART_TX_PIN, GPIOCONF(GPIO_MODE_OUTPUT2MHz, GPIO_CNF_AFIO_PUSHPULL));
#endif
USART1->CR1 = USART_CR1_UE | USART_CR1_TE;
USART1->BRR = (SystemCoreClock / 115200);
while (1)
{
USART_PutString(text);
for(dly = 0; dly < 1000000; dly++);
}
}
//=============================================================================
// End of file
//============================================================================= |
Effect of this code :
|