====== 8. USART ======
===== Cíle cvičení =====
- Nastavit komunikační rozhraní USART, aby MCU mohl přijímat a odesílat data po sériové lince do PC
===== Co je třeba si připravit =====
- Pro komunikaci budete potřebovat vhodný sériový terminál na PC, např.
* [[https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html|Putty]] (Win, Linux)
* [[https://www.der-hammer.info/pages/terminal.html | HTerm]] (Win, Linux)
* WCHSerialPort (MacOS)
* Prostředí **SES** má v sobě terminálový emulátor zabudovaný. Zobrazíte ho buď nabídkou z horní lišty ''Tools -> Terminal Emulator -> Terminal Emulator'' nebo klávesovou zkratkou ''CTRL+Alt+M''. Přes nastavení zadejte potřebné parametry. (Win, Linux, MacOS)
* Prostředí **STM32CubeIDE** má v sobě terminál zabudovaný. Zobrazíte ho přes ''Window -> Show View -> Console'', následně je třeba vytvořit rozhraní (konzoli) přes tlačítko přidat rozhraní, vyberte ''Command Shell Console'' a přidejte nové zařízení podle nastavení. [[https://community.st.com/t5/stm32-mcus/how-to-use-the-stm32cubeide-terminal-to-send-and-receive-data/ta-p/49434|Celý návod zde.]] (Win, Linux, MacOS)
===== Podklady pro cvičení =====
{{ :courses:b2m37mam:labs:mam_2024-cviceni_8.pdf |Podklady pro cvičení_stopky - Skalický}}
{{ :courses:b2m37mam:labs:mam_2023-cviceni_9.pdf |Podklady pro cvičení_USART - Skalický}}
{{ :courses:b2m37mam:labs:stm32f401re.pdf | Datasheet STM32F401 }}
{{ :courses:b2m37mam:stm32f401_refmanual.pdf | Referenční manuál STM32F401 }}
{{ :courses:b2m37mam:nucleo_64_pins.pdf | Datasheet Nucleo F401RE}}
[[courses:b2m37mam:tutorials:dev_kits:nucleof401| Podklady pro Nucleo STM32F401]]
===== Projekty =====
{{ :courses:b2m37mam:labs:mam-usart.zip |}}
===== Kódy pro cvičení =====
==== Konfigurace GPIO ====
USART dva GPIO piny, které slouží jako vysílací (Tx) a přijímací (Rx). Kromě standardního nastavení je třeba nastavit mód příslušných GPIO pinů jako ''alternativní funkce''.
* GPIOx MODER: str. 157 referenčního manuálu
* GPIOx AFR: str. 162 referenčního manuálu
void gpio_init (void)
{
setbit(RCC->AHB1ENR, 0); // Enable AHB1 clock
setbit(GPIOA->MODER, 5); // PA2 alternate function,
setbit(GPIOA->MODER, 7); // PA3 alternate function
GPIOA->AFR[0] |= 0x0700; // alternate function, PA2 will be USART2_TX
GPIOA->AFR[0] |= 0x7000; // alternate function, PA3 will be USART2_RX
// see p. 45 of STM32F401xE datasheet
}
==== Inicializace USART ====
/*
* USART2 init
* USART2 is connected to APB1 bus
* USART2 uses PA2 as TX and PA3 as RX
*/
void usart_init (void)
{
setbit(RCC->APB1ENR, 17); // Enable APB1 clock
setbit(USART2->CR1, 13); // Enable USART2
setbit(USART2->CR1, 2); // USART2 - enable receive
setbit(USART2->CR1, 3); // USART2 - enable transmit
USART2->BRR = (104 << 4); // USART2 baudrate, first 4 bits are dedicated to fraction
/*
* STM32F401 default clock is 16MHz HSI
* BRR ~ fclk/(8*(OVER8-2)*baudrate)
* OVER8 reset state is 0
* see p. 514 of STM32F401 reference manual
* baudrate: 9600
*/
}
==== USART - transmit byte ====
void usart_tx (unsigned char ch) {
// wait till transmit register is empty 7th bit of SR
while (!readbit(USART2->SR, 7));
USART2->DR = ch;
}
==== USART - receive byte ====
int usart_rx (unsigned char *x)
{
// read from DR while receive register is not empty - 5th bit of SR
if (getbit(USART2->SR, 5)) {
*x = USART2->DR;
return 1;
}
return 0;
}
==== Hlavní program ====
int main(void)
{
char mess[20];
char a;
int i = 0;
gpio_init();
usart_init();
while (1)
{
if (usart_rx (&a))
{
if (a != '\r' && a != '\n')
mess[i++] = a;
else
{
send_string(mess, i);
i = 0;
}
}
}
}
==== Kruhový buffer ====
// *******************
// main.h
#define bufferSizeMask 0x3F // 63
#define bufferSize 64
enum bufferStatus_e {
BUFFER_WAIT,
BUFFER_SEND,
BUFFER_SENDING
};
typedef struct {
uint8_t buffer[bufferSize];
uint8_t head;
uint8_t tail;
enum bufferStatus_e status;
}circularBuffer_t;
// *******************
// main.c
void copyBuffers(circularBuffer_t *d, circularBuffer_t *s){
while(s->tail != s->head){
d->buffer[d->head++] = s->buffer[s->tail++];
d->head &= bufferSizeMask;
s->tail &= bufferSizeMask;
}
}
void USART2_sendBuffer(circularBuffer_t *b){
while(b->tail != b->head){
while(!(USART2->SR & USART_SR_TXE));
USART2->DR = b->buffer[b->tail++];
b->tail &= bufferSizeMask;
}
}