// 4B - USART1 příjem řetězců s přerušením #include "stm32f0xx.h" #include "stm32f0xx_ll_bus.h" #include "stm32f0xx_ll_gpio.h" #include "stm32f0xx_ll_rcc.h" #include "stm32f0xx_ll_usart.h" #include "stdio.h" // kvůli fci snprintf() #include "string.h" #define MAX_STRLEN 32 // maximální počet znaků v přijímaném řetězci void init_clock(void); void init_usart1(void); void usart1_putchar(uint8_t data); void usart1_puts(char *Buffer); LL_RCC_ClocksTypeDef clocks; char command[MAX_STRLEN]; // přijatý řetězec (zpráva) char answer[MAX_STRLEN]; // řetězec pro zpracování odpovědi uint8_t num_commands=0; // informuje o příchodu nové zprávy uint32_t test=0; // něco zajímavého ve zprávě :) uint8_t scanned=0; // pomocná proměnná int main(void){ init_clock(); // 48MHz z HSE init_usart1(); while (1){ // pokud přišla nová zpráva if(num_commands){ scanned=sscanf(command,"c = %lu",&test); // pokus se ji přečíst if(scanned==0){usart1_puts("Error\n\r");} // pokud to nešlo else{ // pokud je v pořádku, připrav odpověď... snprintf(answer,MAX_STRLEN,"c = %lu, 2*c = %lu \n\r",test,test*2); usart1_puts(answer); // ...a pošli ji } num_commands=0; // dokončili jsme zpracování zprávy } } } void USART1_IRQHandler(void){ static char received_string[MAX_STRLEN]; // zde se bude ukládat přijímaná zpráva static uint16_t cnt = 0; // počítadlo přijatých znaků char t; // pokud je zdrojem přerušení přijatý znak if(LL_USART_IsActiveFlag_RXNE(USART1)){ t = LL_USART_ReceiveData8(USART1); // přečti přijatý znak (a maže vlajku RXNE - zdroj přerušení) // pokud příchozí znak není konec řádku a ještě máme místo v přijímací paměti if((t!='\r') && (t!='\n') && (cnt < (MAX_STRLEN-1))){ received_string[cnt] = t; // ulož příchozí znak do dočasného pole cnt++; // inkrementuj počítadlo znaků } else{ // jinak je to konec příchozí zprávy strncpy (command,received_string, cnt); // zkopíruj příkaz do pole command command[cnt]= '\0'; // přiřaď na konec řetězce ukončovací znak cnt = 0; // vynuluj počítadlo znaků num_commands++; // oznam hlavní smyčce že má zprávu ke zpracování } } } void usart1_puts(char *Buffer){ while(*Buffer){ // než narazíš na konec řetězce (znak /0) while(!LL_USART_IsActiveFlag_TXE(USART1)){}; // čekej než bude volno v Tx Bufferu LL_USART_TransmitData8(USART1,*Buffer++); // předej znak k odeslání } } void init_usart1(void){ LL_USART_InitTypeDef usart; LL_GPIO_InitTypeDef gp; // PA9 jako TX, PA10 jako RX LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA); // clock pro GPIOA LL_GPIO_StructInit(&gp); gp.Pin = LL_GPIO_PIN_9 | LL_GPIO_PIN_10; gp.Mode = LL_GPIO_MODE_ALTERNATE; gp.Speed = LL_GPIO_SPEED_HIGH; gp.Alternate = LL_GPIO_AF_1; gp.Pull = LL_GPIO_PULL_NO; LL_GPIO_Init(GPIOA,&gp); // konfigurace USART LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_USART1); // clock pro USART1 z APB1 // USART1 si může vybírat z vícero zdrojů clocku (aby mohl běžet v režimu spánku) LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK1); // clock z APB1 // konfigurace USARTu usart.BaudRate = 9600; // 9600 bd/s usart.DataWidth = LL_USART_DATAWIDTH_8B; usart.HardwareFlowControl = LL_USART_HWCONTROL_NONE; usart.OverSampling = LL_USART_OVERSAMPLING_16; // pokud není nouze o rychlost raději 16x usart.Parity = LL_USART_PARITY_NONE; usart.StopBits = LL_USART_STOPBITS_1; usart.TransferDirection = LL_USART_DIRECTION_TX_RX; // vysíláme i přijímáme LL_USART_Init(USART1,&usart); // můžete hlídat návratovou hodnotu ... LL_USART_Enable(USART1); // konfigurace přerušení NVIC_SetPriority(USART1_IRQn,2); // nízká priorita (vysoké číslo) NVIC_EnableIRQ(USART1_IRQn); // povolit přerušení od USART1 // v USART1 povolit přerušení od RXNE (Receive buffer not empty) LL_USART_EnableIT_RXNE(USART1); } // 48MHz z externího 8MHz signálu void init_clock(void){ // nastartovat HSE v režimu Bypass LL_RCC_HSE_EnableBypass(); LL_RCC_HSE_Enable(); while(!LL_RCC_HSE_IsReady()){}; // PLL z HSE/2, x12 = 48MHz LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE_DIV_2,LL_RCC_PLL_MUL_12); LL_RCC_PLL_Enable(); // spouštíme PLL while(!LL_RCC_PLL_IsReady()){}; // vyber PLL jako zdroj pro SYSCLK LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); // aktualizuj proměnnou SystemCoreClock SystemCoreClockUpdate(); }