// 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 "stm32f0xx_ll_utils.h" // konfigurace clocku #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){ LL_UTILS_PLLInitTypeDef pll; LL_UTILS_ClkInitTypeDef clk; pll.Prediv = LL_RCC_PREDIV_DIV_2; // 8MHz / 2 = 4MHz pll.PLLMul = LL_RCC_PLL_MUL_12; // 4MHz * 12 = 48MHz clk.AHBCLKDivider = LL_RCC_SYSCLK_DIV_1; // APB i AHB bez předděličky clk.APB1CLKDivider = LL_RCC_APB1_DIV_1; // voláme konfiguraci clocku LL_PLL_ConfigSystemClock_HSE(8000000,LL_UTILS_HSEBYPASS_ON,&pll,&clk); // aktualizuj proměnnou SystemCoreClock SystemCoreClockUpdate(); }