{"id":4176,"date":"2022-02-23T20:00:00","date_gmt":"2022-02-23T19:00:00","guid":{"rendered":"https:\/\/msalamon.pl\/?p=4176"},"modified":"2025-12-27T15:49:26","modified_gmt":"2025-12-27T14:49:26","slug":"how-to-do-multiple-things-at-once-on-a-microcontroller","status":"publish","type":"post","link":"https:\/\/msalamon.pl\/en\/how-to-do-multiple-things-at-once-on-a-microcontroller\/","title":{"rendered":"How to Do Multiple Things at Once on a Microcontroller?"},"content":{"rendered":"\n<p>You\u2019ve surely more than once on the Internet (and not only there) seen problems from people taking their first steps with microcontroller programming. One of such problems is that <strong>we can\u2019t \u201cdo many things at once\u201d<\/strong>. For example, wait for a measurement while at the same time blinking an LED and reading the state of a button. Frustration grows, and the \u201cexperts\u201d laugh at such people in Facebook groups. What\u2019s going on and how do you deal with it?<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">I can\u2019t do many things at once\u2026<\/h1>\n\n\n\n<p>Among people who are beginners in microcontroller programming, there is a <strong>false impression<\/strong> that everything we write should happen <strong>simultaneously.<\/strong> Let\u2019s look at a PC. At the same time, the processor captures what\u2019s on the keyboard, displays it on the screen, and in the background it\u2019s still chatting with the Internet.<\/p>\n\n\n\n<p>This \u201csimultaneity\u201d is not entirely true. Especially on microcontrollers. <strong>It\u2019s only an illusion.<\/strong> Operations simply execute <strong>so fast<\/strong> that to a human it feels like doing <strong>\u201cmany things at once\u201d.<\/strong><\/p>\n\n\n\n<p>On a PC it\u2019s the same. The operating system, e.g., Windows, performs huge numbers of tasks in the background.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2022\/02\/Procesy-PC.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"500\" height=\"225\" src=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2022\/02\/Procesy-PC.jpg\" alt=\"\" class=\"wp-image-2100\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2022\/02\/Procesy-PC.jpg 500w, https:\/\/msalamon.pl\/wp-content\/uploads\/2022\/02\/Procesy-PC-300x135.jpg 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/a><\/figure>\n\n\n\n<p>Only that\u2019s a PC. It has many cores that take on these tasks. The OS cleverly switches the currently running task and we get the impression that everything is happening at once.<\/p>\n\n\n\n<p>A microcontroller has one tiny core. <strong>It can perform only one operation at a time! <\/strong><\/p>\n\n\n\n<p>Our programs at the beginning don\u2019t have such an operating system and nobody switches tasks for it. Besides, we won\u2019t run Windows or Linux anyway. There are other systems for microcontrollers, and we\u2019ll get to that in a moment.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why do we get blocked?<\/h2>\n\n\n\n<p>We\u2019re getting to the heart of the problem. Why can\u2019t we manage to do many activities at once?<\/p>\n\n\n\n<p>The answer is simple. <strong>We block the microcontroller\u2019s work.<\/strong> How?<\/p>\n\n\n\n<p>There is a function available in most frameworks in which we write software:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>For STM32 it will be <strong>HAL_Delay<\/strong><\/li>\n\n\n\n<li>For AVR <strong>_delay_ms<\/strong><\/li>\n\n\n\n<li>For Arduino <strong>delay<\/strong><\/li>\n<\/ul>\n\n\n\n<p><strong>Its behavior ruins<\/strong> our whole elaborate plan of doing \u201cmany things at once\u201d \u201csimultaneously\u201d.<\/p>\n\n\n\n<p>Why? Well, this function orders our program to <strong>STOP and WAIT.<\/strong> To burn current, as I say \ud83d\ude42<\/p>\n\n\n\n<p>It is a <strong>function that BLOCKS the program\u2019s work.<\/strong> Until the condition is met \u2013 the specified time elapses \u2013 this function does not allow other activities to be performed. Simply put, the processor\u2019s task is to wait and be bored.<\/p>\n\n\n\n<p>And that is a huge problem in writing software. Because it could be waiting, but at the same time doing other things and thus creating the impression of parallel task execution.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How to deal with Delay?<\/h2>\n\n\n\n<p>In short \u2013 <strong>you need to remove this Delay. Forget about it as soon as possible!<\/strong><\/p>\n\n\n\n<p>Well, maybe not entirely\u2026 I sometimes use it too, BUT not in the main loop of the program. Only during hardware initialization. <strong>Once the program is running, I avoid it like the plague.<\/strong><\/p>\n\n\n\n<p>Alright, but removing it will cause us to have no delays. How do you then wait for the next measurement or other cyclic activities?<\/p>\n\n\n\n<p>There are <strong>several techniques<\/strong> for that, with which we actually replace Delay instead of just removing it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Software timer \/ millis<\/h2>\n\n\n\n<p>A software timer is the simplest way to remove Delay. How does it work?<\/p>\n\n\n\n<p>It relies on one hardware timer that counts \u2013 most often \u2013 the <strong>number of milliseconds since the program started.<\/strong> Regardless of what we do, this timer has an <strong>interrupt every 1 ms<\/strong> and the only thing it does is increment a global counter called the <strong>System Tick.<\/strong><\/p>\n\n\n\n<p>To read the passing time, we have special functions.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>In STM32: <strong>HAL_GetTick()<\/strong><\/li>\n\n\n\n<li>In Arduino: <strong>millis()<\/strong><\/li>\n\n\n\n<li>In AVR: There isn\u2019t one. You have to implement it yourself on one of the hardware timers<\/li>\n<\/ul>\n\n\n\n<p>By reading the current Tick value we know what time it is. Reading again, we know how much time has passed.<\/p>\n\n\n\n<p>If we need to wait, for example, 500 milliseconds, then we \u201cwait\u201d until the Tick increases by that time. BUT we don\u2019t wait in a blocking way!<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Store the current time.<\/li>\n\n\n\n<li>With each pass of the loop, check whether the specified time has already passed.\n<ol class=\"wp-block-list\">\n<li>If not \u2013 exit the condition and do something else. (Here is that \u201cparallelism\u201d)<\/li>\n\n\n\n<li>If yes \u2013 enter the condition and perform this cyclic action.<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li>Reload the variable with the current time to wait 500 ms again.<\/li>\n\n\n\n<li>Repeat in a loop.<\/li>\n<\/ol>\n\n\n\n<p>There are several ways to check whether the specified time has elapsed. You can reload the remembered Tick. You can add a constant to the remembered Tick. You can reload\/add before performing the action or after. How we write it depends on what we want to achieve.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. State machine<\/h2>\n\n\n\n<p>This is an interesting way to drive the program flow or part of the program. It allows for truly <strong>convenient control of how the program should behave.<\/strong><\/p>\n\n\n\n<p>A state machine by itself will not eliminate blocking delays. <strong>You need to combine it with a software timer.<\/strong><\/p>\n\n\n\n<p>The point is that some object or piece of code can be in<strong> different states.<\/strong> The best example is a button. A plain microswitch.<\/p>\n\n\n\n<p>We can distinguish 3 basic states for it:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>IDLE<\/strong> \u2013 nobody is doing anything, it simply stands and waits to be pressed.<\/li>\n\n\n\n<li><strong>DEBOUNCE<\/strong> \u2013 a press has been detected, we must wait 20\u201350 ms to confirm the press.<\/li>\n\n\n\n<li><strong>PRESSED<\/strong> \u2013 we waited, the button is still pressed \u2013 we confirm the press and perform the action.<\/li>\n<\/ul>\n\n\n\n<p>We jump between states by <strong>doing different actions<\/strong> for each of them. We define<strong> transition conditions<\/strong> between them.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>IDLE waits for a <strong>press<\/strong>. If it happened \u2013 it jumps to DEBOUNCE.<\/li>\n\n\n\n<li>DEBOUNCE <strong>counts down 20\u201350 ms<\/strong> using the software timer. Once it counts down, it checks whether the press is still present. If yes \u2013 <strong>jumps to PRESSED<\/strong>. If not \u2013 <strong>returns to IDLE<\/strong>.<\/li>\n\n\n\n<li>PRESSED performs a<strong> one-time action.<\/strong> As long as we keep holding the button it does nothing. When we release \u2013 it returns to IDLE.<\/li>\n<\/ul>\n\n\n\n<p>There can be more states. By adding more software timers we can detect:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Long press<\/li>\n\n\n\n<li>Repeatable action every X milliseconds<\/li>\n\n\n\n<li>Button release action<\/li>\n<\/ul>\n\n\n\n<p>There\u2019s a lot to do here, and the state machine makes it easier. How does it work?<\/p>\n\n\n\n<p>You enter the machine and look at the current state. If there\u2019s something to do \u2013 you do it. If not \u2013 you exit the machine and do something else. You come back on the next loop pass.<\/p>\n\n\n\n<p>Simple? Sure \ud83d\ude42 Again, we didn\u2019t use Delay, and we already have something really substantial.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. RTOS \u2013 Real-Time Operating System<\/h2>\n\n\n\n<p>This is already <strong>heavy artillery<\/strong>, but it is also <strong>the most effective.<\/strong> Eventually projects will start to get complicated. Then a software timer and a state machine won\u2019t be enough to properly control the <strong>distribution of CPU time among individual tasks.<\/strong><\/p>\n\n\n\n<p>An RTOS helps, i.e. a <strong>real-time operating system<\/strong> (Real Time Operating System). These are small systems \u2013 not like Windows or Linux \u2013 that provide us with the functions needed to build a multitasking system.<\/p>\n\n\n\n<p>However, I\u2019d like to warn beginners a bit. You\u2019ll often hear advice to just take an RTOS and it will be fine. <strong>Unfortunately, it won\u2019t.<\/strong><\/p>\n\n\n\n<p>RTOSes are <strong>compiled tools.<\/strong> You can\u2019t just turn them on so that they work well. You have to write the application with the system in mind.<\/p>\n\n\n\n<p>All tasks in such a system are like <strong>separate programs.<\/strong> The system <strong>itself allocates CPU time<\/strong> to individual tasks <strong>according to priorities and whether they are ready to run.<\/strong> Between tasks we communicate in a <strong>special way<\/strong> using what such a system offers: queues, semaphores, mutexes, signals.<\/p>\n\n\n\n<p>When writing with an RTOS we must <strong>change the way we think<\/strong> about creating software.<\/p>\n\n\n\n<p><strong>My advice is: try the simple things from points 1 and 2 first.<\/strong> Only after you get comfortable with programming should you try RTOSes.<\/p>\n\n\n\n<p>What\u2019s available? A few examples are FreeRTOS, mbed OS, Azure RTOS, Keil RTX, ThreadX, Zephyr.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Where to learn this?<\/h2>\n\n\n\n<p>I personally teach all of this in the <strong>STM32 Course for Beginners<\/strong> (the course is conducted in Polish).<\/p>\n\n\n\n<p>We start with <strong>software timers and the state machine.<\/strong> We build simple things and learn to use these programming techniques.<\/p>\n\n\n\n<p>After learning additional peripherals we move on to <strong>learning FreeRTOS<\/strong> and building a <strong>real application<\/strong> running under this system.<\/p>\n\n\n\n<p>The course contains about <strong>50 hours of STM32 programming material.<\/strong> In addition to learning the microcontroller peripherals themselves, I share<strong> tons of good practices and useful tricks.<\/strong> A total of <strong>12 modules<\/strong> of huge knowledge.<\/p>\n\n\n\n<p><strong>Registration is currently open for the next<\/strong> \u2013 already the fourth \u2013 edition. <strong>So far, OVER 550 people have joined!<\/strong><\/p>\n\n\n\n<p>Don\u2019t miss the opportunity! Registration is open only until <strong>Friday, 25\/02\/2022 at 22:00.<\/strong><\/p>\n\n\n\n<p>All details together with the<strong> COURSE AGENDA<\/strong> and D<strong>EMO LESSONS<\/strong> can be found at <a href=\"https:\/\/kursstm32.pl\" target=\"_blank\" rel=\"noopener\">https:\/\/kursstm32.pl<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/kursstm32.pl\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"820\" height=\"194\" src=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2021\/02\/Kurs-STM32-roz.jpg\" alt=\"\" class=\"wp-image-1834\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2021\/02\/Kurs-STM32-roz.jpg 820w, https:\/\/msalamon.pl\/wp-content\/uploads\/2021\/02\/Kurs-STM32-roz-300x71.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2021\/02\/Kurs-STM32-roz-768x182.jpg 768w\" sizes=\"auto, (max-width: 820px) 100vw, 820px\" \/><\/a><\/figure>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4176&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;0&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;0&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;0&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;0\\\/5 - (0 votes)&quot;,&quot;size&quot;:&quot;24&quot;,&quot;title&quot;:&quot;How to Do Multiple Things at Once on a Microcontroller?&quot;,&quot;width&quot;:&quot;0&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 0px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 19.2px;\">\n            <span class=\"kksr-muted\"><\/span>\n    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>You\u2019ve surely more than once on the Internet (and not only there) seen problems from people taking their first steps with microcontroller programming. One of such problems is that we can\u2019t \u201cdo many things at once\u201d. For example, wait for a measurement while at the same time blinking an LED [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3717,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[160],"tags":[175,178,176,174,177],"class_list":["post-4176","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-stm32","tag-electronics","tag-kursstm32","tag-programming","tag-stm32","tag-stm32cubemx"],"_links":{"self":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4176","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/comments?post=4176"}],"version-history":[{"count":3,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4176\/revisions"}],"predecessor-version":[{"id":4179,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4176\/revisions\/4179"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media\/3717"}],"wp:attachment":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media?parent=4176"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/categories?post=4176"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/tags?post=4176"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}