#include #include #include #include #define NB_LED_BAR_GPIO 10 static const int LED_BAR_GPIO[NB_LED_BAR_GPIO] = {28, 27, 26, 22, 21, 20, 19, 18, 17, 16}; typedef int led_state; enum LED_STATE { OFF, ON }; typedef struct led led; struct led { int gpio; led_state state; }; void set_led_state(led *l, int state) { if (l != NULL) { l->state = state; gpio_put(l->gpio, l->state); } } char* state_into_str(led_state state) { switch (state) { case ON: return "ON"; case OFF: return "OFF"; default: return "OFF"; } } void init_led_bar(led leds[]) { for (int i = 0; i < NB_LED_BAR_GPIO; i++, leds++) { *leds = (led) { .gpio = LED_BAR_GPIO[i], .state = OFF }; } } void print_led_bar_state(led leds[]) { for (int i = 0; i < NB_LED_BAR_GPIO; i++, leds++) { char *state = state_into_str(leds->state); char led_state[12]; sprintf(led_state, "%3s (%d)", state, leds->gpio); if (i != NB_LED_BAR_GPIO - 1) { strcat(led_state, " | "); } printf(led_state); } printf("\n"); } /** * Convert an integer into a 10 bits array (corresponding to the number of LED). * * It loops over the less to the most significant bit and for each bit, masks it with * the value to find if the value bit is 0 or 1 and then store it in the bits array. * * Example: * - value = 10 <=> 1010, i = 0 * - left shift one: 1 << i <=> 0001 << 0 = 1 * - mask the value with the shifted one: 1010 & 0001 = 0000 * - find the result by right shifting the masked value by i: 0 >> 0 <=> 0000 >> 0 = 0 * - i++ */ int *int_into_bits(int value) { int *bits = malloc(NB_LED_BAR_GPIO * sizeof(int)); for (int i = 0; i < NB_LED_BAR_GPIO; i++) { int mask = 1 << i; int masked_value = value & mask; // the first led is the rightmost, so we start feeding the bit array by the end bits[NB_LED_BAR_GPIO - 1 - i] = masked_value >> i; } return bits; } void blink_failed(uint gpio, uint32_t delay_ms) { for (;;) { gpio_put(gpio, false); sleep_ms(delay_ms); gpio_put(gpio, true); sleep_ms(delay_ms); } } void set_default_led_state(led_state state) { gpio_put(PICO_DEFAULT_LED_PIN, state == ON); } void run_bit_counter(led leds[], uint nb_bit, uint32_t delay_ms) { // nothing to do with 0 bit, entering in failed mode. if (nb_bit <= 0) { blink_failed(PICO_DEFAULT_LED_PIN, 500); return; } // healthcheck set_default_led_state(ON); // `nb_bit` can't be greater than the number of leds if (nb_bit > NB_LED_BAR_GPIO) { nb_bit = NB_LED_BAR_GPIO; } // compute the maximum value int const max_value = 2 << nb_bit - 1; int current_value = 1; for (;;) { if (current_value == max_value) { current_value = 1; led *p_leds = leds; for (int i = 0; i < NB_LED_BAR_GPIO; i++, p_leds++) { set_led_state(p_leds, OFF); } set_default_led_state(OFF); sleep_ms(delay_ms); set_default_led_state(ON); continue; } led *p_leds = leds; int *bits = int_into_bits(current_value); int *p_bits = bits; for (int i = 0; i < NB_LED_BAR_GPIO; i++, p_leds++, p_bits++) { set_led_state(p_leds, *p_bits ? ON : OFF); } free(bits); print_led_bar_state(leds); current_value++; sleep_ms(delay_ms); } } /* Initialize needed GPIO. */ void init_gpio(void) { #ifdef PICO_DEFAULT_LED_PIN gpio_init(PICO_DEFAULT_LED_PIN); gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); #endif for (int i = 0; i < NB_LED_BAR_GPIO; i++) { gpio_init(LED_BAR_GPIO[i]); gpio_set_dir(LED_BAR_GPIO[i], GPIO_OUT); } } /** * Bit counter program with a LED bar. * * Increment a value, convert it in bit and display the value * on the LED bar (1: led on, 0 led OFF) until it reaches max value. * * BA-SIC. But it's fun to see the result. * * When the max value is reached, the program restarts. * * You can customize the incrementation speed and the number of bit to display * (max = number of led on the bar available) by changing the `run_bit_counter` * arguments. * * Ex: display only 4 bits (4 leds) with increment speed of 50 ms: * run_bit_counter(leds, 4, 50); */ int main() { stdio_init_all(); init_gpio(); led leds[NB_LED_BAR_GPIO] = {}; init_led_bar(leds); print_led_bar_state(leds); run_bit_counter(leds, 11, 50); }