Wstęp
Ustawienie przerwania pozwoli mikrokontrolerowi na przerwanie wykonywanej czynności i wykonanie procedury znajdującej się w funkcji obsługi tego przerwania. Dzięki temu możliwe będzie wyświetlenie przesłanych znaków w trakcie wykonywania innych operacji w układzie.
Program
Na samym początku należy dokonać inicjalizacji układu USART, po tym następuje włączenie zgłaszania przerwania, które nastąpi po odebraniu danych przez interfejs. W tym celu stosuje się komendę USART_ITConfig(USART2, USART_IT_RXNE, ENABLE). Następnie należy skonfigurować obsługę przerwania USART2_IRQn.
Działanie programu polega na tym, że układ będzie zgłaszał przerwanie po każdym odebraniu znaku. W funkcji obsługi przerwania znaki będą dodawane do tablicy.
#include "stm32f10x.h" void GPIOInit(void); void USARTInit(void); void SendCharc(volatile char); uint8_t USART_Getc(USART_TypeDef* USARTx); int8_t USART_Buffer[8][32]; uint16_t usart_buf_in[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint16_t usart_buf_out[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint16_t usart_buf_num[8] = {0, 0, 0, 0, 0, 0, 0, 0}; int main(void) { uint16_t c; GPIOInit(); USARTInit(); while (1) { c = USART_Getc(USART2); if(c) { SendCharc(c); } } } void GPIOInit(void) { GPIO_InitTypeDef GPIOInit; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //PA2 Tx GPIO_StructInit(&GPIOInit); GPIOInit.GPIO_Pin = GPIO_Pin_2; GPIOInit.GPIO_Speed = GPIO_Speed_50MHz; GPIOInit.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIOInit); //PA3 Rx GPIOInit.GPIO_Pin = GPIO_Pin_3; GPIOInit.GPIO_Speed = GPIO_Speed_50MHz; GPIOInit.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIOInit); } void USARTInit(void) { USART_InitTypeDef USARTInit; NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn; RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //Ustawienie prędkości transmisji 9600bps USARTInit.USART_BaudRate = 9600; //Ustawienie dlugosci slowa USARTInit.USART_WordLength = 8; //Ustawienie bitu stopu USARTInit.USART_StopBits = USART_StopBits_1; //Brak kontroli parzystosci USARTInit.USART_Parity = USART_Parity_No; //Kontrola przepływu danych USARTInit.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //Tryb pracy TX i RX USARTInit.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART2, &USARTInit); USART_Cmd(USART2, ENABLE); USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); //Wlaczenie przerwania dla RX //Włącznie obslugi IRQ NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //Ustawienie priorytetu grupowego dla USART1 przypisane jest 0 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00; //Podpriorytet NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStruct); } void SendCharc(volatile char c) { while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); USART_SendData(USART2, c); } void USART_InsertToBuffer(uint8_t usart_num, uint8_t c) { usart_num = 0; //Sprawdza dostepne miejsce w buforze if (usart_buf_num[usart_num] < 32) { if (usart_buf_in[usart_num] > (32 - 1)) { usart_buf_in[usart_num] = 0; } USART_Buffer[usart_num][usart_buf_in[usart_num]] = c; usart_buf_in[usart_num]++; usart_buf_num[usart_num]++; } } uint8_t USART_Getc(USART_TypeDef* USARTx) { uint8_t usart_num = 0; uint8_t c = 0; //Sprawdza czy sa dane w buforze if (usart_buf_num[usart_num] > 0) { if (usart_buf_out[usart_num] > (32 - 1)) { usart_buf_out[usart_num] = 0; } c = USART_Buffer[usart_num][usart_buf_out[usart_num]]; USART_Buffer[usart_num][usart_buf_out[usart_num]] = 0; usart_buf_out[usart_num]++; usart_buf_num[usart_num]--; } return c; } #ifdef USART2 void USART2_IRQHandler(void) { //Sprawdzenie czy wystapilo przerwanie z powodu odebrania danych if (USART_GetITStatus(USART2, USART_IT_RXNE)) { #ifdef USART2_USE_CUSTOM_IRQ //Wywołaj funckje przerwania USART2_ReceiveHandler(USART2->DR); #else //Podaj dane do Buffera USART_InsertToBuffer(0, USART2->DR); #endif } } #endif
Program 2
W przypadku przesłania znaku 1 dioda zostanie zapalona, natomiast gdy zostanie wysłane 0 dioda zostanie zgaszona. Do każdego z tych znaków zostanie wyświetlona odpowiednia wiadomość.
#include "stm32f10x.h" void GPIOInit(void); void USARTInit(void); void SendCharc(volatile char); void USARTSend(volatile char *c); uint8_t USART_Getc(USART_TypeDef* USARTx); int8_t USART_Buffer[8][32]; uint16_t usart_buf_in[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint16_t usart_buf_out[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint16_t usart_buf_num[8] = {0, 0, 0, 0, 0, 0, 0, 0}; int main(void) { uint16_t c; GPIOInit(); USARTInit(); while (1) { c = USART_Getc(USART2); if(c) { switch (c) { case '1': USARTSend("Odebrano 1. Dioda zapalona!\n"); GPIO_SetBits(GPIOA, GPIO_Pin_5); break; case '0': USARTSend("Odebrano 0. Dioda zgaszona!\n"); GPIO_ResetBits(GPIOA, GPIO_Pin_5); break; default: USARTSend("Wybierz 0 lub 1\n"); SendCharc(c); break; } } } } void GPIOInit(void) { GPIO_InitTypeDef GPIOInit; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //PA2 Tx GPIO_StructInit(&GPIOInit); GPIOInit.GPIO_Pin = GPIO_Pin_2; GPIOInit.GPIO_Speed = GPIO_Speed_50MHz; GPIOInit.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIOInit); //PA3 Rx GPIOInit.GPIO_Pin = GPIO_Pin_3; GPIOInit.GPIO_Speed = GPIO_Speed_50MHz; GPIOInit.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIOInit); //Wybranie konfigurowanego pinu GPIOInit.GPIO_Pin = GPIO_Pin_5; //Ustawienie pinu jak wyjście PushPull GPIOInit.GPIO_Mode = GPIO_Mode_Out_PP; //Inicjalizacja linii z podanymi ustawieniami GPIO_Init(GPIOA, &GPIOInit); } void USARTInit(void) { USART_InitTypeDef USARTInit; NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn; RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //Ustawienie prędkości transmisji 9600bps USARTInit.USART_BaudRate = 9600; //Ustawienie dlugosci slowa USARTInit.USART_WordLength = 8; //Ustawienie bitu stopu USARTInit.USART_StopBits = USART_StopBits_1; //Brak kontroli parzystosci USARTInit.USART_Parity = USART_Parity_No; //Kontrola przepływu danych USARTInit.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //Tryb pracy TX i RX USARTInit.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART2, &USARTInit); USART_Cmd(USART2, ENABLE); USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); //Wlaczenie przerwania dla RX //Włącznie obslugi IRQ NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //Ustawienie priorytetu grupowego dla USART1 przypisane jest 0 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00; //Podpriorytet NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStruct); } void SendCharc(volatile char c) { while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); USART_SendData(USART2, c); } void USARTSend(volatile char *c) { //Pętla działa do puki będzie jakiś znak do wysłania while(*c) { //Sprawdza czy rejestr danych został opróżniony while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); //Prześlij dane, USART_SendData(USART2, *c); *c++; } } void USART_InsertToBuffer(uint8_t usart_num, uint8_t c) { usart_num = 0; //Sprawdza dostepne miejsce w buforze if (usart_buf_num[usart_num] < 32) { if (usart_buf_in[usart_num] > (32 - 1)) { usart_buf_in[usart_num] = 0; } USART_Buffer[usart_num][usart_buf_in[usart_num]] = c; usart_buf_in[usart_num]++; usart_buf_num[usart_num]++; } } uint8_t USART_Getc(USART_TypeDef* USARTx) { uint8_t usart_num = 0; uint8_t c = 0; //Sprawdza czy sa dane w buforze if (usart_buf_num[usart_num] > 0) { if (usart_buf_out[usart_num] > (32 - 1)) { usart_buf_out[usart_num] = 0; } c = USART_Buffer[usart_num][usart_buf_out[usart_num]]; USART_Buffer[usart_num][usart_buf_out[usart_num]] = 0; usart_buf_out[usart_num]++; usart_buf_num[usart_num]--; } return c; } #ifdef USART2 void USART2_IRQHandler(void) { //Sprawdzenie czy wystapilo przerwanie z powodu odebrania danych if (USART_GetITStatus(USART2, USART_IT_RXNE)) { #ifdef USART2_USE_CUSTOM_IRQ //Wywołaj funckje przerwania USART2_ReceiveHandler(USART2->DR); #else //Podaj dane do Buffera USART_InsertToBuffer(0, USART2->DR); #endif } } #endif