Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed DS18B20 TextLCD
main.cpp
- Committer:
- KamilCuk
- Date:
- 2020-02-13
- Revision:
- 0:55c37ea095b0
- Child:
- 1:f8a4796e766e
File content as of revision 0:55c37ea095b0:
#include "mbed.h"
#include "TextLCD.h"
#include <atomic_flag.h>
#include <string>
#include <cstdio>
#include <cassert>
#include <cstdarg>
#include <DS1820.h>
#include <DebounceIn.h>
#include <limits>
#include <flash.h>
#include <cassert>
static DigitalOut led_on_board(PC_13);
/* str --------------------------------------------- */
void str_remove(char *str, const char *reject) {
while (1) {
const size_t s = strcspn(str, reject);
str += s;
if (str[0] == '\0') {
break;
}
memmove(str, str + 1, strlen(str + 1) + 1);
}
}
void str_pad_suffix(char *str, size_t len, char c) {
if (strlen(str) < len) {
memset(str + strlen(str), c, len - strlen(str));
}
str[len] = '\0';
}
char *str_filename(const char *file) {
return (char*)(strrchr(file, '/') ? strrchr(file, '/') + 1 : file);
}
/* lcd ------------------------------------------------- */
static TextLCD& lcd() {
static TextLCD lcd(PB_15, PA_10, PB_3, PB_4, PB_5, PB_6, TextLCD::LCD16x2); // rs, e, d4-d7
// static TextLCD lcd(PA_0, PA_1, PA_2, PA_3, PA_4, PA_5, TextLCD::LCD16x2); // rs, e, d4-d7
return lcd;
}
void lcd_cls() {
lcd().cls();
}
void lcd_vprintln(const char *fmt, va_list va) {
char buf[20] = {0};
const size_t len = vsnprintf(buf, sizeof(buf), fmt, va);
str_remove(buf, "\r\n");
str_pad_suffix(buf, 16, ' ');
lcd().printf(buf);
}
__attribute__((__format__(__printf__, 1, 2)))
void lcd_println(const char *fmt, ...) {
va_list va;
va_start(va, fmt);
lcd_vprintln(fmt, va);
va_end(va);
}
extern "C" {
void d(const char *fmt, ...) {
va_list va;
va_start(va, fmt);
lcd_vprintln(fmt, va);
va_end(va);
wait(1);
}
}
/* system --------------------------------------------- */
extern "C" void abort() {
for (int i = 0; i < 20 * 5; ++i) {
led_on_board = !led_on_board;
wait(0.05);
}
NVIC_SystemReset();
}
extern "C" void __assert_func(const char *file, int line, const char *func, const char *failedexpr) {
lcd_println("ASSERT %d", line);
lcd_println("%s", str_filename(file));
abort();
}
/* ds18b20 --------------------------------------------- */
/**
* @return
* 0 - no errors ('temp' contains the temperature measured)
* 1 - sensor not present ('temp' is not updated)
* 2 - CRC error ('temp' is not updated)
*/
static int ds18b20_temp(float& temperature_f_C) {
static DS1820 probe('B', PB_1);
static Timer t;
static bool running = false;
// start the conversion if not running
if (running == false) {
running = true;
probe.startConversion();
t.start();
}
// wait for conversion end
const unsigned ms = t.read_ms();
const unsigned conversion_time_ms = 800;
if (ms < conversion_time_ms) {
wait((conversion_time_ms - ms) / 1000.0);
}
// read temperature from buffer
temperature_f_C = -1000;
const uint8_t err = probe.read(temperature_f_C);
// restart new conversion
probe.startConversion();
t.reset();
return err;
}
/* output -------------------------------------------- */
static DigitalOut output(PC_14);
/* state --------------------------------------------- */
struct state {
volatile int high; // in Celcius
volatile int low; // in Celcius
volatile bool inverted;
state() : high(30), low(20) {}
struct data {
static const int data_version = 0x11;
int version;
int high;
int low;
bool inverted : 1;
bool current : 1;
data() : version(data_version) {}
data(const state& s, const DigitalOut& o) :
version(data_version),
high(s.high),
low(s.low),
inverted(s.inverted),
current(output)
{}
void put(state& s, DigitalOut& o) {
s.high = high;
s.low = low;
s.inverted = inverted;
o = current;
}
};
static bool _low_high_valid(int high, int low) {
return -99 < high && high < 99 &&
-99 < low && low < 99 &&
low < high &&
low != high;
}
void save() {
const struct data d(*this, output);
flash::write(d);
}
void restore() {
struct data d;
const int e = flash::read(d);
if (e) {
lcd_println("New flash %d", e);
wait(1);
return;
}
if (!_low_high_valid(d.high, d.low)) {
lcd_println("Invalid flash vals");
lcd_println("%d %d", d.high, d.low);
wait(1);
return;
}
lcd_println("Flash load %d %d", d.high, d.low);
wait(1);
d.put(*this, output);
}
void high_inc() { _inc_it(high, low); }
void high_dec() { _dec_it(high, low); }
void low_inc() { _inc_it(low, high); }
void low_dec() { _dec_it(low, high); }
void invert_invert() {
inverted = !inverted;
save();
}
private:
void _inc_it(volatile int &val, volatile int &other) {
if (val + 1 == other) return;
if (val >= 99) return;
val++;
save();
}
void _dec_it(volatile int &val, volatile int &other) {
if (val - 1 == other) return;
if (val <= -99) return;
val--;
save();
}
};
static state state;
/* buttons -------------------------------------------- */
static DebounceIn button_h_inc(PA_6, PullDown);
static DebounceIn button_h_dec(PA_5, PullDown);
static DebounceIn button_l_inc(PA_4, PullDown);
static DebounceIn button_l_dec(PA_3, PullDown);
static DebounceIn button_inv(PA_2, PullDown);
static DebounceIn button_refresh(PA_1, PullDown);
static void button_h_inc_pressed() { state.high_inc(); }
static void button_h_dec_pressed() { state.high_dec(); }
static void button_l_inc_pressed() { state.low_inc(); }
static void button_l_dec_pressed() { state.low_dec(); }
static void button_inv_pressed() {
output = !output;
state.invert_invert();
}
static void button_init() {
const unsigned debounce_timeout_us = 200 * 1000;
button_h_inc.fall(button_h_inc_pressed, debounce_timeout_us);
button_h_dec.fall(button_h_dec_pressed, debounce_timeout_us);
button_l_inc.fall(button_l_inc_pressed, debounce_timeout_us);
button_l_dec.fall(button_l_dec_pressed, debounce_timeout_us);
button_inv.fall(button_inv_pressed, debounce_timeout_us * 2);
}
static void button_check() {
while(1) {
DebounceIn *arr[6] = {
&button_h_inc,
&button_h_dec,
&button_l_inc,
&button_l_dec,
&button_inv,
&button_refresh
};
lcd_println("%d %d %d %d %d %d\n",
arr[0]->read(),
arr[1]->read(),
arr[2]->read(),
arr[3]->read(),
arr[4]->read(),
arr[5]->read());
lcd_println("");
}
}
/* main --------------------------- */
static void setup() {
// wait for voltage stability
wait(1);
// some info
lcd_cls();
lcd_println("Hello!");
lcd_println("clock=%ld", SystemCoreClock);
wait(1);
lcd_cls();
state.restore();
button_init();
}
static void loop() {
static bool alive;
alive = !alive;
float temperature_f_C = 0;
const int ds18b20_err = ds18b20_temp(temperature_f_C);
lcd_cls();
char temperature_s[8] = "ERROR";
if (ds18b20_err == 0) {
const int temperature_dC = temperature_f_C * 10;
const int temperature_C = temperature_f_C;
if (temperature_C < -100 || temperature_C > 100) {
snprintf(temperature_s, sizeof(temperature_s), "INVAL");
} else {
if (!output ^ state.inverted) {
if (temperature_C > state.high) {
output = 1 ^ state.inverted;
}
} else {
if (temperature_C < state.low) {
output = 0 ^ state.inverted;
}
}
snprintf(temperature_s, sizeof(temperature_s), "%3d.%d'C", temperature_C, temperature_dC % 10);
}
}
led_on_board = output;
lcd_println("%-7s %3s %3s",
temperature_s,
state.inverted ? "INV" : "NOR",
output ? "ON" : "OFF"
);
lcd_println("H=%2d'C L=%2d'C %c%c",
state.high,
state.low,
!alive ? '\xff' : ' ',
alive ? '\xff' : ' '
);
}
int main() {
setup();
while (1) {
loop();
}
return 0;
}