application: complete first working firmware version

This commit is contained in:
King Kévin 2020-12-16 19:36:15 +01:00
parent f5bdc1bbfc
commit 78fff2ed0f
1 changed files with 92 additions and 33 deletions

View File

@ -55,6 +55,17 @@ static volatile bool second_flag = false; /**< flag set when a second passed */
/** number of seconds since boot */
static uint32_t boot_time = 0;
// current state
static uint32_t yeast_time = 0; /**< when we start heating the yeas */
static uint32_t max_time = 0; /**< when the yeast has grown */
static uint16_t current_height = 0; /**< current height */
static uint8_t container_height = 0; /**< how height the container is */
static uint8_t starter_height = 0; /**< how height the yeast/sour dough starter is */
static uint8_t max_height = 0; /**< the maximum height the yeast reached */
static float heater_temp = NAN; /**< heater temperature */
static float yeast_temp = NAN; /**< yeast/sour dough starter temperature */
static float ir_temp = NAN; /**< yeast/sour dough starter temperature as measured by the IR thermometer */
/** heater control pin
* @note connected to power nMOS gate, pulled up to 5V
*/
@ -67,6 +78,9 @@ static uint32_t boot_time = 0;
/** voltages to convert (channel 17 = internal voltage reference) */
const uint8_t channels[] = {ADC_CHANNEL17, ADC_CHANNEL(THERMISTOR_CHANNEL)};
/** pin to control buzzer (active high, piezo-element with driver circuit) */
#define BUZZER_PIN PB2
/** temperature to heat the yeast to, in °C */
const float yeast_target = 30.0;
@ -122,7 +136,6 @@ static double thermistor_temperature(void)
return thermistor_voltage() * THERMISTOR_SLOPE + THERMISTOR_OFFSET;
}
// menu commands
/** display available commands
@ -322,6 +335,30 @@ static void command_bootloader(void* argument)
dfu_bootloader(); // start DFU bootloader
}
/** show current state, e.g. all current measurements
* @param[in] argument no argument required
*/
static void command_state(void* argument)
{
(void)argument; // we won't use the argument
puts("sourdough starter statistics:\n");
uint32_t height = ((container_height && starter_height) ? (container_height - starter_height) : 0);
printf("initial height: %u mm\n", height);
height = ((container_height && current_height) ? (container_height - current_height) : 0);
printf("current height: %u mm\n", height);
printf("sourdough temperature: %.02f °C\n", yeast_temp);
printf("IR temperature: %.02f °C\n", ir_temp);
printf("heater temperature: %.02f °C\n", heater_temp);
puts("heater: ");
puts(gpio_get(GPIO_PORT(HEATER_PIN), GPIO_PIN(HEATER_PIN)) ? "on\n" : "off\n");
uint32_t time = (yeast_time ? (rtc_to_seconds() - yeast_time) : 0);
printf("current time: %02u:%02u:%02u\n", time / 60 / 24, (time / 60) % 60, time % 60);
height = ((container_height && max_height) ? (container_height - max_height) : 0);
printf("maximum height: %u mm\n", height);
time = (max_time ? (max_time - yeast_time) : 0);
printf("maximum height time: %02u:%02u:%02u\n", time / 60 / 24, (time / 60) % 60, time % 60);
}
/** list of all supported commands */
static const struct menu_command_t menu_commands[] = {
{
@ -365,7 +402,7 @@ static const struct menu_command_t menu_commands[] = {
.command_handler = &command_reset,
},
{
.shortcut = 's',
.shortcut = 'S',
.name = "system",
.command_description = "reboot into system memory",
.argument = MENU_ARGUMENT_NONE,
@ -373,13 +410,21 @@ static const struct menu_command_t menu_commands[] = {
.command_handler = &command_system,
},
{
.shortcut = 'b',
.shortcut = 'B',
.name = "bootloader",
.command_description = "reboot into DFU bootloader",
.argument = MENU_ARGUMENT_NONE,
.argument_description = NULL,
.command_handler = &command_bootloader,
},
{
.shortcut = 's',
.name = "state",
.command_description = "show state",
.argument = MENU_ARGUMENT_NONE,
.argument_description = NULL,
.command_handler = &command_state,
},
};
static void command_help(void* argument)
@ -411,6 +456,22 @@ static void process_command(char* str)
}
}
/** use buzzer to beep
* @param[in] beeps number of times to beep
*/
static void beep(uint8_t beeps)
{
for (uint8_t i = 0; i < beeps; i++) {
gpio_set(GPIO_PORT(BUZZER_PIN), GPIO_PIN(BUZZER_PIN)); // enable buzzer
sleep_ms(100); // buzz to show it is working
gpio_clear(GPIO_PORT(BUZZER_PIN), GPIO_PIN(BUZZER_PIN)); // disable buzzer
if (i + 1U < beeps) {
sleep_ms(100); // buzz to show it is working
}
}
gpio_clear(GPIO_PORT(BUZZER_PIN), GPIO_PIN(BUZZER_PIN)); // ensure buzzer is disabled
}
/** program entry point
* this is the firmware function started by the micro-controller
*/
@ -594,6 +655,14 @@ void main(void)
puts("KO\n");
}
puts("setup buzzer: ");
rcc_periph_clock_enable(GPIO_RCC(BUZZER_PIN)); // enable clock for GPIO port domain
gpio_clear(GPIO_PORT(BUZZER_PIN), GPIO_PIN(BUZZER_PIN)); // disable buzzer
gpio_mode_setup(GPIO_PORT(BUZZER_PIN), GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN(BUZZER_PIN)); // set pin as output
gpio_set_output_options(GPIO_PORT(BUZZER_PIN), GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN(BUZZER_PIN)); // set pin output as push-pull
beep(1); // buzz to show it is working
puts("OK\n");
// setup terminal
terminal_prefix = ""; // set default prefix
terminal_process = &process_command; // set central function to process commands
@ -603,13 +672,7 @@ void main(void)
bool action = false; // if an action has been performed don't go to sleep
button_flag = false; // reset button flag
led_on(); // switch LED to indicate booting completed
uint32_t yeast_time = 0; // when we start heating the yeas
uint32_t max_time = 0; // when the yeast has reached its peak
uint8_t container_height = 0; // how height the container is
uint8_t starter_height = 0; // how height the yeast/sour dough starter is
uint8_t max_height = 0; // the maximum height the yeast reached
float heater_temp = NAN; // heater temperature
float yeast_temp = NAN; // yeast/sour dough starter temperature
uint32_t peak_time = 0; // when the yeast has reached its peak
while (true) { // infinite loop
iwdg_reset(); // kick the dog
if (user_input_available) { // user input is available
@ -639,6 +702,7 @@ void main(void)
printf("%u mm\n", container_height); // display measurement
oled_text_line("with starter", 2); // display next instruction
oled_text_update(); // show instruction
beep(1); // beep to indicate action completed
}
sensor_sr04_distance = 0; // clear measurement
} else if (0 == yeast_time || 0 == starter_height) { // time to start monitoring
@ -658,7 +722,8 @@ void main(void)
max_height = starter_height; // initialize the maximum height
yeast_time = rtc_to_seconds(); // remember when we start monitoring
max_time = yeast_time; // initialize the maximum height time
printf("%u mm\n", container_height); // display measurement
printf("%u mm\n", starter_height); // display measurement
beep(1); // beep to indicate action completed
}
sensor_sr04_distance = 0; // clear measurement
}
@ -677,23 +742,15 @@ void main(void)
heater_temp = sensor_ds18b20_temperature(0); // get temperature
if (85.0 != heater_temp) { // the conversion has not been completed
sensor_ds18b20_convert(0); // start next conversion
printf("heater temperature: %.02f °C\n", heater_temp);
}
}
// show yeast temperature
if (thermsitor_ok) {
yeast_temp = thermistor_temperature(); // get temperature
printf("yeast temperature: %.01f °C\n", yeast_temp);
}
// show IR temperature
if (sensor_mlx90614_ok) {
printf("IR thermometer ambient temperature: %.02f °C\n", sensor_mlx90614_temperature_ambient());
printf("IR thermometer object temperature: %.02f °C\n", sensor_mlx90614_temperature_object());
}
// show heater
if (heater_ok) {
puts("heater: ");
puts(gpio_get(GPIO_PORT(HEATER_PIN), GPIO_PIN(HEATER_PIN)) ? "on\n" : "off\n");
ir_temp = sensor_mlx90614_temperature_object(); // get temperature
}
// update uptime
if (yeast_time) {
@ -708,7 +765,7 @@ void main(void)
}
// heat up yeast
if (yeast_time && !isnan(yeast_temp) && heater_ok && !isnan(heater_temp)) {
if (yeast_temp < yeast_target - 0.5) { // temperature not reached
if (yeast_temp < yeast_target - 0.5 && 0 == peak_time) { // temperature not reached
heater_on(); // keep heating
} else if (yeast_temp > yeast_target + 0.5) { // temperature reached
heater_off(); // stop heating
@ -717,33 +774,35 @@ void main(void)
if (!isnan(heater_temp) && heater_temp > 50.0) { // turn off heater for safety
heater_off(); // stop heating
}
if (oled_text_ok) {
oled_text_update(); // display new (even if not new)
}
}
if (sensor_sr04_distance) { // distance measurement is available
printf("distance: %u mm\n", sensor_sr04_distance); // start measurement
// update how much the start raised
if (container_height && starter_height && max_height && sensor_sr04_distance <= starter_height) {
const float rising = (container_height - sensor_sr04_distance) * 1.0 / (container_height - starter_height); // calculate ratio
if (current_height && container_height && starter_height && max_height && current_height <= starter_height) {
const float rising = (container_height - current_height) * 1.0 / (container_height - starter_height); // calculate ratio
char text[13]; // to store text representation
snprintf(text, sizeof(text), "%.02fx %.01fC", rising, yeast_temp); // display ratio and temperature
oled_text_line(text, 2); // add text to display buffer
if (sensor_sr04_distance < max_height && sensor_sr04_distance + 5U > max_height) { // a new maximum height has been reached (and is credible)
max_height = sensor_sr04_distance; // save new maximum height
if (current_height < max_height && current_height + 5U > max_height) { // a new maximum height has been reached (and is credible)
max_height = current_height; // save new maximum height
max_time = rtc_to_seconds(); // remember the time
}
if (sensor_sr04_distance > max_height + 5) { // the yeast has been falling again
static uint32_t peak_time = 0;
if (current_height > max_height + 5) { // the yeast has been falling again
if (max_time > peak_time) {
heater_off(); // stop heating
peak_time = max_time; // remember the peak yeast time
const float peak_ratio = (container_height - max_height) * 1.0 / (container_height - starter_height); // calculate ratio
const uint16_t peak_period = peak_time - yeast_time; // calculate peak time
snprintf(text, sizeof(text), "%.02fx %um", peak_ratio, peak_period / 60); // display peak ratio and time
oled_text_line(text, 3); // add text to display buffer
beep(2); // beep to indicate the peak has been reached
}
}
}
if (oled_text_ok) {
oled_text_update(); // display new (even if not new)
}
}
if (sensor_sr04_distance) { // distance measurement is available
//printf("height: %u mm\n", sensor_sr04_distance);
current_height = sensor_sr04_distance; // save height
sensor_sr04_distance = 0; // clear flag
}
if (action) { // go to sleep if nothing had to be done, else recheck for activity