Search code examples
carduinostm32microcontrollernucleo

Changing between colors using a microcontroller


I'm fairly new at programming microcontrollers and programming in general. I am currently working on a personal project with a Nucleo Development Board and I'm stuck on what code I need to write next to get the functionality I want.

The idea is to turn on the LED when the switch is on, turn LED off when the switch is off, and, this is where I get stuck, cycle through different colors each time I turn the switch on again.

Currently, I cant get the mode to switch to the next color.

All LEDs are set to TIM3 (red, green, blue).

My switch is set to a pulldown.

This is what I have so far:

  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3); // Red
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2); // Green
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4); // Blue

  int mode = 0;


  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
      // Check to see if the switch is pressed.
      if (HAL_GPIO_ReadPin(Toggle_Switch_GPIO_Port, Toggle_Switch_Pin) == GPIO_PIN_SET) {

          mode++;

          if(mode == 1) {

          // Red
          __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 230); // Red
          __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 0); // Green
          __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 0); // Blue

          } else if (mode == 2) {
          // Red
          __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 0); // Red
          __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 230); // Green
          __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 0); // Blue

          }


      } else {
          __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 0); // Red
          __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 0); // Green
          __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 0); // Blue
      }

  }

Any help or suggestions would be great! Again, I'm very new at this so if I missed vital information that needs to be provided please let me know. Thank you!


Solution

  • You probably don't want the colour to change every single time around your loop (which is probably executing thousands of times per second). I'm going to assume that a button transition from "off" to "on" should just change the colour once.

    I'm also going to assume that you want to cycle between red, green and blue. Since you seem to be using PWM (and three LEDs) then lots more colours are possible, but you've not told us about what you really need.

    So it seems like you want some kind of state machine, to track the state of the button, and also the colour you want to display. Something like this (completely untested psuedo-code):

    // Track the current state of the button
    enum button_state_e {
        BUTTON_NOT_PRESSED,
        BUTTON_JUST_PRESSED,
        BUTTON_PRESSED
    };
    
    static enum button_state_e button_state = BUTTON_NOT_PRESSED;
    
    // The colour to show next - 0 = red, 1 = green, 2 = blue, for example
    static uint8_t button_colour;
    
    while (1)
    {
        bool pressed = (HAL_GPIO_ReadPin(Toggle_Switch_GPIO_Port, Toggle_Switch_Pin) == GPIO_PIN_SET);
    
        switch (button_state)
        {
            case BUTTON_NOT_PRESSED:
                if (pressed)
                    button_state = BUTTON_JUST_PRESSED;
                break;
    
            case BUTTON_JUST_PRESSED:
                if (pressed)
                {
                    button_state = BUTTON_PRESSED;
                    switch_on_leds_for(button_colour);
                    button_colour = (button_colour + 1) % 3;
                }
                else
                    button_state = BUTTON_NOT_PRESSED;
                break;
    
            case BUTTON_PRESSED:
                if (!pressed)
                {
                    button_state = BUTTON_NOT_PRESSED;
                    switch_off_all_leds();
                }
                break;
        }
    
        ms_delay(10); // delay 10 ms to make debounce work
    }
    

    This implements a basic de-bounce to prevent glitches on the button from triggering colour changes unexpectedly. This is why you want a delay in your loop. Increase the length of the delay if you still see bounce.

    Since you only have three colours, you need to wrap your button_colour so that after 2 it goes back to 0, hence the modulo.

    I've elided some functions, but you'd want something like:

    void switch_off_all_leds(void)
    {
        __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 0); // Red
        __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 0); // Green
        __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 0); // Blue
    }
    
    void switch_on_leds_for(int colour)
    {
        __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, colour == 0 ? 230 : 0); // Red
        __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, colour == 1 ? 230 : 0); // Green
        __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, colour == 2 ? 230 : 0); // Blue
    }