1
\$\begingroup\$

In actual I need to measure speed of motor. I have followed a procedure, i.e

  1. use Encoder mode to get pulses from sensor.
  2. count number of these pulses in 1 sec~1000msec using SysTick_Handler(ISR). Means use SysTick_Handler function as a time base to count pulses in 1000msec.

Now, I am bit confused about how to encorporate step no. 2 in codes. Because I have been taught that Systick Handler(ISR) is called every 1 millisecond. And if it is so, while passing through lines of codes inside Handler, will the duration of 1 millisecond sec not get passed. Will the Systick_Handler not get called again before even completely counting for 1 millisecond. Also, how do I make sure that the Systick_Handler counts for only one second and then again starts counting afresh after duration of 1 sec gets over.

This is the Handler function.

void SysTick_Handler(void)
{
  HAL_IncTick();
  HAL_SYSTICK_IRQHandler();
  Encoder_Start();                     //encoder mode start

  counter=Encoder_Read(void);          //reading counter(defined globally and shared by handler and main)

  Encoder_Stop();                      //encoder mode stop

} 

And this is the main

    main.c
    .
    .
    .
    uint32_t Encoder_Read(void)         //reads counts from sensor
    {
        return TIM3->CNT;
    }

    void Encoder_Start(void)            
    {
        HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
    }

    void Encoder_Stop(void)
    {
        HAL_TIM_Encoder_Stop(&htim3, TIM_CHANNEL_ALL);
    }
    main()
{
 .
 .
    while()                                                              
    {
      speed=counter*constant;              //speed, counter is used here

      printf("\n%d",speed);                //print speed using semihosting on eclipse
      PWM code;
      PWM code;
      PWM code;
    }
.
.
}

My original question was this

Development board is STM32F407, OS is Linux(Ubuntu), code is generated using STM32CubeMX.

Any ideas about this?

Or any other alternative, I need to have a time base of 1 sec to measure the number of counts from sensor(LM393 based) and use this time base again and again to measure the speed and display it every second.

\$\endgroup\$
  • \$\begingroup\$ SysTick_Handler() is called every 1ms, not 1s. \$\endgroup\$ – Volodymyr Smotesko Apr 15 '17 at 9:10
  • \$\begingroup\$ @VolodymyrSmotesko Thank you, I have edited this in question. \$\endgroup\$ – abinjacob Apr 15 '17 at 9:19
2
\$\begingroup\$

What you're looking for is probably just a basic scheduler. Example code:

static volatile uint32_t ms_ticks = 0;
static volatile bool tick_1ms_elapsed = false;
static volatile bool tick_1000ms_elapsed = false;

//! The interrupt handler for the SysTick module
void SysTick_Handler(void)
{
    ms_ticks++;

    tick_1ms_elapsed = true;

    if (ms_ticks % 1000 == 0) {
        tick_1000ms_elapsed = true;
    }
}

void main(void) {

    // Setup SysTick Timer for 1ms interrupts
    if (SysTick_Config(sysclk_get_cpu_hz() / 1000)) {
        while (true) {  /* no error must happen here, otherwise this board is dead */ }
    }

    while(true) {

        if (tick_1ms_elapsed) {
            ... Do something every ms
            tick_1ms_elapsed = false; // Reset the flag (signal 'handled')
        }

        if (tick_1000ms_elapsed) {
            ... Do something every second
            if (state == STATE_1) {
                DoTaskOne;
                state = STATE_2;
            }
            else if (state == STATE_2) {
                DoTaskTwo;
                state = STATE_3;
            }
            tick_1000ms_elapsed = false;  // Reset the flag (signal 'handled')
        }
    }
}

What does this do?

  • We initialize the Systick timer to trigger an interrupt every millisecond.
  • Since having long interrupt handlers is a no go, the only thing we do is to handle a flag which tells our main routing (which is handled during normal program flow and not within the interrupt routine) that 1 millisecond has passed
  • Additionally we increment a counter 'ms_ticks' which knows the current 'time' (time as in milliseconds since program start). We can always query that timer to know how much time has passed.

What your next tasks are going to be (at least if I understand you right):

  • Since you want to handle three events which happen after each other each second, you will need to create a state machine which runs inside the 1000ms tick handler.
  • Switch from one state to the next whenever you've completed the task for the current run, then wait until the flag arrives the next time and you will know another second has passed.
\$\endgroup\$
  • \$\begingroup\$ Adding to what you said, I thought something like this if (tick_1ms_elapsed) { count=TIM3->CNT; ..Do something every ms tick_1ms_elapsed = false; } i.e. storing number of counts from sensor \$\endgroup\$ – abinjacob Apr 15 '17 at 10:01
  • \$\begingroup\$ and also this. if (tick_1000ms_elapsed) { HAL_TIM_Encoder_Stop(&htim3, TIM_CHANNEL_ALL);//stop the encoder after 1 second..Do something every second speed=counter*constant; printf("Speed=%d",speed); tick_1000ms_elapsed = false; // Reset the flag (signal 'handled') HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL); //after every second restart the encoder } **Here I removed states**(just because I haven't understood it yet). \$\endgroup\$ – abinjacob Apr 15 '17 at 10:16
  • \$\begingroup\$ I still haven't completely figured out what you're trying to do. If you want to read the revolutions of the motor you can do that by reading the CNT register as you indicated. If you want to stop after one second, you can simply use the code given. Now what happens when you want to restart? Do you account for a potential overflow or underflow of the CNT register? \$\endgroup\$ – Tom L. Apr 15 '17 at 11:56
  • \$\begingroup\$ Objective is only to read the count for 1000ms from CNT register(which is performed in "if (tick_1ms_elapsed) block") and printing the speed ( which is performed in "if (tick_1000ms_elapsed)" block). Here encoder is stopped once "if(tick_1000ms_elapsed)" is entered and timer is started again before exiting the same block. Do it makes any sense? Also I understood everything about what you wrote except the states thing. Also you mentioned that I have three events to be handled. I see events like 1. CNT count, 2. calculating speed 3. printing speed. \$\endgroup\$ – abinjacob Apr 15 '17 at 13:33
  • 1
    \$\begingroup\$ You should avoid the % operator, it's very slow. Use a > comparison and reset the counter. \$\endgroup\$ – user Jan 24 at 16:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.