In pervious two guides we took look at how to use systick timer to blink an led without using delay (here) and how to use interrupt to blink multiple led (here). In this guide, we shall use systick timer to handle multiple periodic tasks. Task 1 will be running each 500 milliseconds. Task 2 will be running each 1000 milliseconds and Task 3 will be running each 1500 milliseconds.
In this guide, we will cover the following:
- What is a periodic task
- Required parts
- Code
- Result
1. What is periodic tasks
A periodic task is the one that repeats after a certain fixed time interval. For example in Automotive, you set the cruise control speed to 100KMPH. The mcu keeps track the speed of the vehicle and desired speed. The rate of obtaining the speed of vehicle called periodic task. The most important feature of periodic tasks is it runs to completion, in another word, it should not include any while (1) loop.
2. Required parts
In this guide, we need only STM32F411RE Nucleo-64 no extra components needed.
3. Code
#include "stm32f4xx.h" // Device header #include "stdint.h" #include "stdio.h" #define rate 1000 uint64_t previous; volatile uint64_t ms,rms, periodic_1,periodic_2,periodic_3; void USART2_Init(void); void UART_Write_String(char *p); uint64_t millis(void); void UART_Write_String(char *p); int main(void) { __disable_irq(); SysTick->LOAD=16000-1; SysTick->VAL=0; SysTick->CTRL=7; //0b00000111; USART2_Init(); //initialize uart2 RCC->AHB1ENR |=RCC_AHB1ENR_GPIOAEN; GPIOA->MODER|= GPIO_MODER_MODER5_0; //PA5 as output __enable_irq(); while(1) { if(millis()-previous>rate) //if current time is elapsed, execute the if condition { GPIOA->ODR^=GPIO_ODR_OD5; previous=millis(); } } } void periodicTask1(void) { periodic_1++; UART_Write_String("periodic Task 1 \r\n"); } void periodicTask2(void) { periodic_2++; UART_Write_String("periodic Task 2 \r\n"); } void periodicTask3(void) { periodic_3++; UART_Write_String("periodic Task 3 \r\n"); } uint64_t millis(void) { __disable_irq(); rms=ms; //store current ms in rms __enable_irq(); return rms; } void SysTick_Handler(void){ ms++; if(ms%500==0){periodicTask1();} if(ms%1000==0){periodicTask2();} if(ms%1500==0){periodicTask3();} } void USART2_Init(void){ RCC->APB1ENR|=RCC_APB1ENR_USART2EN; RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN; GPIOA->AFR[0]=0x0700; GPIOA->MODER|=(1<<5);//set bit5 GPIOA->MODER&=~(1<<4);//reset bit4 USART2->BRR = 0x0681; //9600 @16MHz USART2->CR1 |=0x2008; // enable tx } void USART_write(int ch){ while(!(USART2->SR&0x0080)){ } USART2->DR=(ch); } void UART_Write_String(char *p) { while(*p!='\0') { USART_write(*p); p++; } }
For how initialize systick interrupt, check this guide (here)
For UART initialization, check this guide (here) and how send a string (here)
For periodic tasks, we are check if the ms when divided by 500,1000 and 1500 return only (i.e. 3 not 3.1 ) like this
if(ms%500==0){periodicTask1();} if(ms%1000==0){periodicTask2();} if(ms%1500==0){periodicTask3();}
Result
After compiling and upload the code, open teraterm and set the baudrate to 9600 and you should see this in the terminal
Notice that each two time task 1 is executed, you will get 1 execution for task 2.
Task 3 is executed after three tasks of task1 and 1 task of task2
Add Comment