187 lines
4.6 KiB
C
187 lines
4.6 KiB
C
#include <pico/printf.h>
|
|
#include <pico/stdlib.h>
|
|
#include <pico/malloc.h>
|
|
#include <string.h>
|
|
|
|
#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);
|
|
} |