{"id":1597,"date":"2023-02-26T05:30:14","date_gmt":"2023-02-26T05:30:14","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=1597"},"modified":"2023-02-26T05:30:17","modified_gmt":"2023-02-26T05:30:17","slug":"revised-measuring-the-rotation-speed-using-stm32-and-timer-in-encoder-mode","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=1597","title":{"rendered":"[Revised ] Measuring The Rotation Speed Using STM32 and Timer in Encoder Mode"},"content":{"rendered":"\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"483\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/What-Does-RPM-Mean-in-Carss-1024x483.jpg\" alt=\"\" class=\"wp-image-980\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/What-Does-RPM-Mean-in-Carss-1024x483.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/What-Does-RPM-Mean-in-Carss-300x142.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/What-Does-RPM-Mean-in-Carss-768x362.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/What-Does-RPM-Mean-in-Carss-1150x542.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/What-Does-RPM-Mean-in-Carss-750x354.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/What-Does-RPM-Mean-in-Carss-400x189.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/What-Does-RPM-Mean-in-Carss-250x118.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/What-Does-RPM-Mean-in-Carss.jpg 1166w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<p>In the previous guide (<a rel=\"noreferrer noopener\" href=\"https:\/\/blog.embeddedexpert.io\/?p=430\" target=\"_blank\">here<\/a>), we saw how to configure timer to work in encoder mode. In this guide, we shall take it step further and measure the rotational speed in RPM (Revolutions per Minutes).<\/p>\n\n\n\n<p>In this guide, we shall cover the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>How to measure RPM.<\/li><li>Proposed experiment.<\/li><li>Firmware development.<\/li><li>Code.<\/li><li>Demo.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">1. How to Measure RPM:<\/h2>\n\n\n\n<p>Since the encoder is used to measure the RPM, a timer which will overflow each 1 sec to determine the RPM.<\/p>\n\n\n\n<p>Here is a graphic representation:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"667\" height=\"1024\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/Screenshot-2023-02-26-at-8.03.05-AM-667x1024.png\" alt=\"\" class=\"wp-image-1598\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/Screenshot-2023-02-26-at-8.03.05-AM-667x1024.png 667w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/Screenshot-2023-02-26-at-8.03.05-AM-196x300.png 196w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/Screenshot-2023-02-26-at-8.03.05-AM-768x1179.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/Screenshot-2023-02-26-at-8.03.05-AM-1001x1536.png 1001w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/Screenshot-2023-02-26-at-8.03.05-AM-750x1151.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/Screenshot-2023-02-26-at-8.03.05-AM-400x614.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/Screenshot-2023-02-26-at-8.03.05-AM-250x384.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/Screenshot-2023-02-26-at-8.03.05-AM.png 1014w\" sizes=\"(max-width: 667px) 100vw, 667px\" \/><\/figure>\n\n\n\n<p>Since the measurements occur each 1 second, we can find RPM as following:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1014\" height=\"208\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/Screenshot-2023-02-26-at-8.12.53-AM.png\" alt=\"\" class=\"wp-image-1600\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/Screenshot-2023-02-26-at-8.12.53-AM.png 1014w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/Screenshot-2023-02-26-at-8.12.53-AM-300x62.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/Screenshot-2023-02-26-at-8.12.53-AM-768x158.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/Screenshot-2023-02-26-at-8.12.53-AM-750x154.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/Screenshot-2023-02-26-at-8.12.53-AM-400x82.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/Screenshot-2023-02-26-at-8.12.53-AM-250x51.png 250w\" sizes=\"(max-width: 1014px) 100vw, 1014px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">2. Proposed Experiment:<\/h2>\n\n\n\n<p>In order to test the code, a crude is conducted which includes the following components:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Stepper Motor NEMA17 (42HD2037)<\/li><li>Industrial Rotary encoder (LPD3806-360BM-G5-24C)<\/li><li>Coupling (6mm-6mm)<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"966\" height=\"300\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/Screen-Shot-2022-05-31-at-11.47.42-AM.png\" alt=\"\" class=\"wp-image-992\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/Screen-Shot-2022-05-31-at-11.47.42-AM.png 966w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/Screen-Shot-2022-05-31-at-11.47.42-AM-300x93.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/Screen-Shot-2022-05-31-at-11.47.42-AM-768x239.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/Screen-Shot-2022-05-31-at-11.47.42-AM-750x233.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/Screen-Shot-2022-05-31-at-11.47.42-AM-400x124.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/Screen-Shot-2022-05-31-at-11.47.42-AM-250x78.png 250w\" sizes=\"(max-width: 966px) 100vw, 966px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/IMG_8488-1024x768.jpg\" alt=\"\" class=\"wp-image-993\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/IMG_8488-1024x768.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/IMG_8488-300x225.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/IMG_8488-768x576.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/IMG_8488-1536x1152.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/IMG_8488-2048x1536.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/IMG_8488-1150x863.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/IMG_8488-750x563.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/IMG_8488-400x300.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/05\/IMG_8488-250x188.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Firmware development:<\/h2>\n\n\n\n<p>Since timer3 is used to determine the encoder counts, we shall use tim5 to generate interrupt each 1 second and timer2 to control the stepper motor.<\/p>\n\n\n\n<p>Since the timer in encoder is already discussed, we shall implement it here differently, we shall use timer3 and pins PB4 and PB5 as inputs for the timer.<\/p>\n\n\n\n<p>First, within rpm_encoder header, declare the following enums:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">typedef enum\n{\nno_new_rpm=0,\nnew_rpm=1\n}rpm_data;\n\ntypedef enum\n{\nClockWise=0,\nCounterClockWise=1\n}rpm_dir;<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Also, declare the following function:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void Encoder_init(uint16_t max_count);\nfloat get_rpm();\nuint8_t new_rpm_available();\nuint8_t get_direction();\n\n<\/pre><\/div>\n\n\n\n<p>Hence, the entire header file as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\n#ifndef RPM_ENCODER_H_\n#define RPM_ENCODER_H_\n\n\ntypedef enum\n{\nno_new_rpm=0,\nnew_rpm=1\n}rpm_data;\n\ntypedef enum\n{\nClockWise=0,\nCounterClockWise=1\n}rpm_dir;\n\nvoid Encoder_init(uint16_t max_count);\nfloat get_rpm();\nuint8_t new_rpm_available();\nuint8_t get_direction();\n\n\n\n\n#endif \/* RPM_ENCODER_H_ *\/\n<\/pre><\/div>\n\n\n\n<p>Hence the initializing the encoder mode as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void Encoder_init(uint16_t max_count)\n\t{\n\tRCC-&gt;APB1ENR|=RCC_APB1ENR_TIM3EN;\n\tRCC-&gt;AHB1ENR|=RCC_AHB1ENR_GPIOBEN;\n\tencoder_counts=max_count;\n\t\/*GPIO B configuration for timer mode *\/\n\tGPIOB-&gt;MODER|=GPIO_MODER_MODE4_1|GPIO_MODER_MODE5_1;\n\tGPIOB-&gt;MODER&amp;=~(GPIO_MODER_MODE4_0|GPIO_MODER_MODE5_0);\n\tGPIOB-&gt;AFR[0]|=(AF02&lt;&lt;16)|(AF02&lt;&lt;20);\n\n\t\/*Timer configuration for encoder mode *\/\n\tTIM3-&gt;ARR = 0xFFFF; \/\/set the max count\n\t\/*Timer in encoder mode*\/\n\tTIM3-&gt;CCMR1 |= (TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0 );\n\tTIM3-&gt;CCER &amp;= ~(TIM_CCER_CC1P | TIM_CCER_CC2P);\n\tTIM3-&gt;SMCR |= TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1;\n\n\t\/*Timer 5 to generate interrupt each 100ms*\/\n\n\tRCC-&gt;APB1ENR|=RCC_APB1ENR_TIM5EN;\n\tTIM5-&gt;PSC=16000-1;\n\tTIM5-&gt;ARR=1000-1;\n\tTIM5-&gt;DIER|=TIM_DIER_UIE;\n\tNVIC_EnableIRQ(TIM5_IRQn);\n\tTIM5-&gt;CR1|=TIM_CR1_CEN;\n\n\t\/*Start the timer *\/\n\tTIM3-&gt;CR1|=TIM_CR1_CEN;\n\n\t}<\/pre><\/div>\n\n\n\n<p>For the interrupt handler of TIM5:<\/p>\n\n\n\n<p>Within the interrupt handler, we shall determine the direction by check DIR bit in CR1 of TIM3, if the value is 0 it means clockwise, if it is 1, it means counter clockwise.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\nvoid TIM5_IRQHandler(void)\n{\n\tTIM5-&gt;SR=0; \/*clear the status register*\/\n\t\/*Determine the direction\n\t * 0-&gt; Clockwise\n\t * 1-&gt;Counter Clockwise\n\t * *\/\n\tif((TIM3-&gt;CR1 &amp; TIM_CR1_DIR)&gt;&gt;TIM_CR1_DIR_Pos==0)\n\t{\n\t\tdirection=ClockWise;\n\t\ttimer_counter=TIM3-&gt;CNT;\n\t\tTIM3-&gt;CNT=0;\n\t}\n\telse\n\t{\n\t\tdirection=CounterClockWise;\n\t\ttimer_counter=0xFFFF-TIM3-&gt;CNT;\n\t\tTIM3-&gt;CNT=0xFFFF;\n\t}\n\n\trpm_new_data=new_rpm;\n}\n\n<\/pre><\/div>\n\n\n\n<p>To check in main application if there is new data, we shall simply check rpm_new_data if it is 1 or not as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\nuint8_t new_rpm_available()\n{\n\tuint8_t return_data;\n\tif(rpm_new_data==new_rpm){return_data=new_rpm;}\n\telse {return_data=no_new_rpm;}\n\treturn return_data;\n\n}<\/pre><\/div>\n\n\n\n<p>To calculate the RPM, we shall use the equation above to determine the RPM as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">float get_rpm()\n{\n\trpm_new_data=no_new_rpm;\n\trpm=(float)(((float)timer_counter)\/(float)encoder_counts)*(float)60.0;\n\treturn rpm;\n}\n<\/pre><\/div>\n\n\n\n<p>Also, we can get the direction as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\nuint8_t get_direction()\n{\n\n\treturn direction;\n}\n\n<\/pre><\/div>\n\n\n\n<p>Hence, the entire revised encoder code as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;stm32f4xx.h&quot;\n#include &quot;stdint.h&quot;\n#include &quot;RPM_Encoder.h&quot;\n#include &quot;delay.h&quot;\nconst int AF02=0x02;\nuint32_t encoder_counts;\nfloat rpm;\nuint32_t timer_counter;\nvolatile uint8_t rpm_new_data,direction;\n\nvoid Encoder_init(uint16_t max_count)\n\t{\n\tRCC-&gt;APB1ENR|=RCC_APB1ENR_TIM3EN;\n\tRCC-&gt;AHB1ENR|=RCC_AHB1ENR_GPIOBEN;\n\tencoder_counts=max_count;\n\t\/*GPIO B configuration for timer mode *\/\n\tGPIOB-&gt;MODER|=GPIO_MODER_MODE4_1|GPIO_MODER_MODE5_1;\n\tGPIOB-&gt;MODER&amp;=~(GPIO_MODER_MODE4_0|GPIO_MODER_MODE5_0);\n\tGPIOB-&gt;AFR[0]|=(AF02&lt;&lt;16)|(AF02&lt;&lt;20);\n\n\t\/*Timer configuration for encoder mode *\/\n\tTIM3-&gt;ARR = 0xFFFF; \/\/set the max count\n\t\/*Timer in encoder mode*\/\n\tTIM3-&gt;CCMR1 |= (TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0 );\n\tTIM3-&gt;CCER &amp;= ~(TIM_CCER_CC1P | TIM_CCER_CC2P);\n\tTIM3-&gt;SMCR |= TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1;\n\n\t\/*Timer 5 to generate interrupt each 100ms*\/\n\n\tRCC-&gt;APB1ENR|=RCC_APB1ENR_TIM5EN;\n\tTIM5-&gt;PSC=16000-1;\n\tTIM5-&gt;ARR=1000-1;\n\tTIM5-&gt;DIER|=TIM_DIER_UIE;\n\tNVIC_EnableIRQ(TIM5_IRQn);\n\tTIM5-&gt;CR1|=TIM_CR1_CEN;\n\n\t\/*Start the timer *\/\n\tTIM3-&gt;CR1|=TIM_CR1_CEN;\n\n\t}\n\nfloat get_rpm()\n{\n\trpm_new_data=no_new_rpm;\n\trpm=(float)(((float)timer_counter)\/(float)encoder_counts)*(float)60.0;\n\treturn rpm;\n}\n\n\n\nuint8_t new_rpm_available()\n{\n\tuint8_t return_data;\n\tif(rpm_new_data==new_rpm){return_data=new_rpm;}\n\telse {return_data=no_new_rpm;}\n\treturn return_data;\n\n}\n\nuint8_t get_direction()\n{\n\n\treturn direction;\n}\n\n\n\n\nvoid TIM5_IRQHandler(void)\n{\n\tTIM5-&gt;SR=0; \/*clear the status register*\/\n\t\/*Determine the direction\n\t * 0-&gt; Clockwise\n\t * 1-&gt;Counter Clockwise\n\t * *\/\n\tif((TIM3-&gt;CR1 &amp; TIM_CR1_DIR)&gt;&gt;TIM_CR1_DIR_Pos==0)\n\t{\n\t\tdirection=ClockWise;\n\t\ttimer_counter=TIM3-&gt;CNT;\n\t\tTIM3-&gt;CNT=0;\n\t}\n\telse\n\t{\n\t\tdirection=CounterClockWise;\n\t\ttimer_counter=0xFFFF-TIM3-&gt;CNT;\n\t\tTIM3-&gt;CNT=0xFFFF;\n\t}\n\n\trpm_new_data=new_rpm;\n}\n\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Within the main.c file:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;stdio.h&quot;\n#include &quot;uart.h&quot;\n#include &quot;delay.h&quot;\n#include &quot;RPM_Encoder.h&quot;\n#include &quot;stepper_motor.h&quot;\n#include &quot;lcd.h&quot;\n#include &quot;i2c.h&quot;\nchar char_lcd[20];\nuint8_t dir=0;\nuint64_t previous_millis;\nint main(void)\n{\n\tSCB-&gt;CPACR |= ((3UL &lt;&lt; 10*2)|(3UL &lt;&lt; 11*2));\n\ti2c_init();\n\tstepper_init(9000);\n\tsystick_init_ms(16000000);\n\tuart2_rxtx_init(115200,16000000);\n\tEncoder_init(1440);\n\tlcd_init();\n\tstepper_motor_setDirection(Stepper_Clockwise);\n\tstepper_motor_start();\n\twhile(1)\n\t{\n\t\tif(new_rpm_available()==new_rpm)\n\t\t{\n\t\t\tsetCursor(0,0);\n\t\t\tlcd_send_string(&quot;Current RPM&quot;);\n\t\t\tsprintf(char_lcd,&quot;%0.2f        &quot;,get_rpm());\n\t\t\tsetCursor(0,1);\n\t\t\tlcd_send_string(char_lcd);\n\t\t\tsetCursor(0,2);\n\t\t\tif(get_direction()==ClockWise)\n\t\t\t{\n\t\t\t\tlcd_send_string(&quot;Clockwise        &quot;);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tlcd_send_string(&quot;Counter clockwise&quot;);\n\t\t\t}\n\t\t}\n\n\t\tif(millis()-previous_millis&gt;5000)\n\t\t{\n\t\t\tprevious_millis=millis();\n\t\t\tdir=!dir;\n\t\t\tstepper_motor_setDirection(dir);\n\n\t\t}\n\n\t}\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Code:<\/h2>\n\n\n\n<p>For stepper motor driver code, check <a href=\"https:\/\/blog.embeddedexpert.io\/?p=594\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=594\" target=\"_blank\" rel=\"noreferrer noopener\">this<\/a> guide.<\/p>\n\n\n\n<p>For the LCD using i2c driver, check <a href=\"https:\/\/blog.embeddedexpert.io\/?p=655\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=655\" target=\"_blank\" rel=\"noreferrer noopener\">this<\/a> guide.<\/p>\n\n\n\n<p>You may download the entire code from here:<\/p>\n\n\n\n<div class=\"wp-block-file\"><a href=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/RPM_Encoder.zip\">RPM_Encoder<\/a><a href=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/02\/RPM_Encoder.zip\" class=\"wp-block-file__button\" download>Download<\/a><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. Demo:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Using encoder to measure RPM in STM32F4\" width=\"1170\" height=\"658\" src=\"https:\/\/www.youtube.com\/embed\/41QDR2jo8t8?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p>Happy coding \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the previous guide (here), we saw how to configure timer to work in encoder mode. In this guide, we shall take it step further and measure the rotational speed in RPM (Revolutions per Minutes). In this guide, we shall cover the following: How to measure RPM. Proposed experiment. Firmware development. Code. Demo. 1. How [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,19,11,7,12],"tags":[],"class_list":["post-1597","post","type-post","status-publish","format-standard","hentry","category-embedded-systems","category-lcd","category-peripheral-drivers","category-state-machine","category-stm32"],"_links":{"self":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/1597"}],"collection":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1597"}],"version-history":[{"count":2,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/1597\/revisions"}],"predecessor-version":[{"id":1602,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/1597\/revisions\/1602"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1597"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1597"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1597"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}