add bit counter program

This commit is contained in:
rmanach 2025-02-22 15:07:22 +01:00
parent 045a1e20d5
commit ad08d857d1
4 changed files with 232 additions and 3 deletions

View File

@ -29,7 +29,11 @@ ifeq ($(shell test -d $(name) && echo "ok"),)
@false
endif
project: .check-name
project:
ifeq ($(strip $(name)), "")
@echo "error: project name must be set, ex: name=<project_name>"
@false
endif
@./scripts/scaffold_project.bash $(name) $(SDK_VERSION)
format: .check-name

View File

@ -0,0 +1,38 @@
# Generated Cmake Pico project file
cmake_minimum_required(VERSION 3.13)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Pull in Raspberry Pi Pico SDK (must be before project)
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
project(bit_counter C CXX ASM)
# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()
# Add executable. Default name is the project name, version 0.1
add_executable(bit_counter main.c )
pico_set_program_name(bit_counter "bit_counter")
pico_set_program_version(bit_counter "0.1")
# Modify the below lines to enable/disable output over UART/USB
pico_enable_stdio_uart(bit_counter 0)
pico_enable_stdio_usb(bit_counter 1)
# Add the standard library to the build
target_link_libraries(bit_counter
pico_stdlib)
# Add the standard include files to the build
target_include_directories(bit_counter PRIVATE
${CMAKE_CURRENT_LIST_DIR}
)
pico_add_extra_outputs(bit_counter)

187
bit_counter/main.c Normal file
View File

@ -0,0 +1,187 @@
#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);
}

View File

@ -1,4 +1,4 @@
#include <stdio.h>
#include <pico/printf.h>
#include <pico/stdlib.h>
int main()
@ -6,7 +6,7 @@ int main()
stdio_init_all();
while (true) {
printf("<prog_name> is running...\n");
stdio_printf("<prog_name> is running...\n");
sleep_ms(1000);
}
}