Working with STM32 and UART part 3: Receive a character in interrupt mode

In the pervious two guides (part 1 & part 2 ) how to send a single character and string using UART. In this guide, we shall discuss how to receive a character from UART using interrupt handler and echo back the sent character and blink the internal led number of times according to the sent number.

UART

In this guide, we will cover the following:

  • Configure UART for full duplex (TX and RX).
  • Code
  • Demo

1. Configure UART for full duplex

In part 1 we discussed how to set the uart to send a single character, we shall use the same initialization sequence.

We started by enabling clock access to USART2 and GPIOA port

RCC->APB1ENR|=RCC_APB1ENR_USART2EN;
RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN;

From part one, we concluded that PA2 is the TX pin and PA3 is the RX pin. Hence, we configure them as alternate function and which alternate function as following:

GPIOA->MODER|=(1<<5);//set bit5
GPIOA->MODER&=~(1<<4);//reset bit4

GPIOA->MODER|=(1<<7);//set bit7
GPIOA->MODER&=~(1<<6);//reset bit6

GPIOA->AFR[0]=0x07700; //ALT7 for UART2 (PA2 and PA3)

Now we need to configure the UART

We starting by setting the baud rate to 9600 as following:

USART2->BRR  = 0x0681;    //9600 @16MHz

then selecting the UART to enable TX, RX and RXNEIE (Receiver interrupt) in Control Register 1 (CR1) and enabling UART module as following:

CR1

Hence, the configuration shall be as following:

USART2->CR1 |= (1<<2)|(1<<3)|(1<<5)|(1<<13);

After than we shall enable the interrupt of USART in NVIC as following

NVIC_EnableIRQ(USART2_IRQn);

Now for the interrupt handler

void USART2_IRQHandler(void){

if(USART2->SR&0x0020) //check if the read data register is not empty
{
c=USART2->DR; //store current data in variable c
}
}

2. Code

#include "stm32f4xx.h"                  // Device header
void delay(int delayms);
void led_play(int value);
void UART2_Init();
void USART2_IRQHandler(void);
void USART2_write(int ch);
char c;
int main ()
{
__disable_irq();
UART2_Init();
GPIOA->MODER|= GPIO_MODER_MODER5_0; //PA5 as output
USART2->CR1|=0x0020;

__enable_irq();

while(1)
{
if(c!=' '){
led_play(c);
USART2_write(c);
USART2_write('\r');
USART2_write('\n');	
c=' ';
}
}

}

void led_play(int value)
{
value %=16; 
	for (;value>0;value--){
	GPIOA->BSRR|=GPIO_BSRR_BS5; //turn on ledd
		delay(100);
		GPIOA->BSRR|=GPIO_BSRR_BR5; //turn off the led		
		delay(100);
	}
}

void delay(int delayms){
SysTick->LOAD=16000-1;
SysTick->VAL=0;
SysTick->CTRL=0x5;
for (int i=0;i<delayms;i++)
{
while(!(SysTick->CTRL &0x10000)){}
		}
	SysTick->CTRL=0;
}

void UART2_Init(){
	RCC->AHB1ENR |=1; //Enable GPIOA clock
	RCC->APB1ENR|=0x20000; //Enable USART clock
	//configure PA3 as alternative function 
	GPIOA->AFR[0]=0x07700; //ALT7 for UART2
	GPIOA->AFR[1]=0x07000;
	GPIOA->MODER|=0x0080;  //enable PA3 as alternate function
	GPIOA->MODER|=0x0020; //enable PA2 as alterate fuction
	USART2->BRR=0x008B; // set baud rate of 115200 for 16MHz
	USART2->CR1|=0x0020;
	USART2->CR1|=0x200C; //enable RX
	NVIC_EnableIRQ(USART2_IRQn);
}

void USART2_IRQHandler(void){

if(USART2->SR&0x0020){
c=USART2->DR;
}
}
void USART2_write(int ch){
	
while(!(USART2->SR&0x0080)){
}
USART2->DR=(ch&0xff);	
}

3. Demo

Demo

Add Comment

Your email address will not be published. Required fields are marked *