application: complete first working firmware version
This commit is contained in:
parent
f5bdc1bbfc
commit
78fff2ed0f
125
application.c
125
application.c
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue