====== 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; } }