From d32fcbab9bc42dd3f69b0fc3443a5d018a00de12 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Wed, 20 May 2026 22:28:01 +0300 Subject: [PATCH] seems like it's alpha-release --- F3:F303/MLX90640-allsky/Readme.md | 12 ++ F3:F303/MLX90640-allsky/allsky.bin | Bin 39000 -> 41028 bytes F3:F303/MLX90640-allsky/commproto.cpp | 118 ++++++++++----- F3:F303/MLX90640-allsky/hardware.h | 29 +++- F3:F303/MLX90640-allsky/heater.c | 134 ++++++++++++++++++ F3:F303/MLX90640-allsky/heater.h | 26 ++++ .../MLX90640-allsky/ir-allsky.creator.user | 2 +- F3:F303/MLX90640-allsky/ir-allsky.files | 2 + F3:F303/MLX90640-allsky/main.c | 2 + F3:F303/MLX90640-allsky/mlxproc.c | 2 +- 10 files changed, 288 insertions(+), 39 deletions(-) create mode 100644 F3:F303/MLX90640-allsky/heater.c create mode 100644 F3:F303/MLX90640-allsky/heater.h diff --git a/F3:F303/MLX90640-allsky/Readme.md b/F3:F303/MLX90640-allsky/Readme.md index 44789c8..3cb7d9f 100644 --- a/F3:F303/MLX90640-allsky/Readme.md +++ b/F3:F303/MLX90640-allsky/Readme.md @@ -41,3 +41,15 @@ Us - send string 's' to other interface ``` To call this help just print '?', 'h' or 'H' in terminal. + + +### Sensors + +| N | ID | Cardinal direction | +|---|------|--------------------| +| 0 | 0x10 | Zenith | +| 1 | 0x11 | East | +| 2 | 0x12 | South | +| 3 | 0x13 | West | +| 4 | 0x14 | North | +--------------------------------- diff --git a/F3:F303/MLX90640-allsky/allsky.bin b/F3:F303/MLX90640-allsky/allsky.bin index a2076548d05f8d8bacbab1893c6812fd93015246..880dd8674d23a28a34732f79a9e0b3dc94c65c9f 100755 GIT binary patch delta 8807 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 delta 6781 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 diff --git a/F3:F303/MLX90640-allsky/commproto.cpp b/F3:F303/MLX90640-allsky/commproto.cpp index b6d8f5e..32e7326 100644 --- a/F3:F303/MLX90640-allsky/commproto.cpp +++ b/F3:F303/MLX90640-allsky/commproto.cpp @@ -7,6 +7,7 @@ extern "C"{ #include "adc.h" #include "commproto.h" #include "hardware.h" +#include "heater.h" #include "i2c.h" #include "mlxproc.h" #include "strfunc.h" @@ -61,41 +62,50 @@ uint8_t cartoon = 0; // Command list #define COMMAND_TABLE \ - COMMAND(help, "show this help") \ + DELIM("MLX commands") \ + COMMAND(acqtime, "show nth image aquisition time") \ COMMAND(ascii, "draw nth image in ASCII (n=0..4)") \ COMMAND(binary, "get nth image as text array of floats") \ + COMMAND(cartoon, "toggle cartoon mode") \ COMMAND(listids, "list active sensors IDs") \ - COMMAND(tempmap, "show temperature map of nth image") \ - COMMAND(acqtime, "show nth image aquisition time") \ - COMMAND(bmereinit, "reinit BME280") \ - COMMAND(environ, "get environment parameters") \ - COMMAND(state, "get MLX state") \ - COMMAND(reset, "reset MCU") \ - COMMAND(time, "print current Tms") \ - COMMAND(iicaddr, "get/set I2C address (non-shifted)") \ + COMMAND(mlxaddr, "get/set I2C address of sensor n (n=0..4)") \ COMMAND(mlxcont, "continue MLX") \ - COMMAND(iicspeed, "get/set I2C speed (0..4)") \ + COMMAND(mlxdump, "dump parameters for sensor n") \ COMMAND(mlxpause, "pause MLX") \ COMMAND(mlxstop, "stop MLX") \ - COMMAND(adc, "get n'th ADC values") \ + COMMAND(state, "get MLX state") \ + COMMAND(tempmap, "show temperature map of nth image") \ + DELIM("Environment/heaters") \ + COMMAND(autoheater, "get/set automatic heater flag (0/1)") \ + COMMAND(bmereinit, "reinit BME280") \ + COMMAND(clearheater,"clear temperature holding") \ + COMMAND(environ, "get environment parameters") \ COMMAND(ntc, "get n'th NTC temperatures") \ - COMMAND(cartoon, "toggle cartoon mode") \ - COMMAND(mlxdump, "dump MLX parameters for sensor n") \ - COMMAND(mlxaddr, "get/set MLX address of sensor n") \ - COMMAND(readreg, "read I2C register: readreg reg [= nwords]") \ - COMMAND(writedata, "write I2C data: writedata = val1 val2 ...") \ - COMMAND(iicscan, "scan I2C bus") \ + COMMAND(pwm, "get/set PWM for channel n (0..100%), (n=0,1 - heaters)") \ + COMMAND(setheater, "set heater holding temperature, int degC") \ + DELIM("Other commands") \ + COMMAND(adc, "get n'th ADC values") \ + COMMAND(dac, "get/set DAC value (MCU heater)") \ + COMMAND(help, "show this help") \ COMMAND(mcutemp, "get MCU temperature") \ COMMAND(mcuvdd, "get MCU Vdd") \ - COMMAND(dac, "get/set DAC value") \ - COMMAND(pwm, "get/set PWM for channel n (0..100%)") \ - COMMAND(sendstr, "send string to other interface: sendstr = text") - + COMMAND(reset, "reset MCU") \ + COMMAND(sendstr, "send string to other interface: sendstr = text") \ + COMMAND(time, "print current Tms") \ + DELIM("Raw I2C commands (MLX process should be stopped or paused)") \ + COMMAND(hwaddr, "set hardware I2C address (non-shifted) ") \ + COMMAND(iicaddr, "get/set I2C address for raw operations") \ + COMMAND(iicscan, "scan I2C bus") \ + COMMAND(iicspeed, "get/set I2C speed (0..4)") \ + COMMAND(readreg, "read I2C register: readreg reg [= nwords]") \ + COMMAND(writedata, "write I2C data: writedata = val1 val2 ...") // Command prototypes +#define DELIM(text) #define COMMAND(name, desc) static errcodes_t cmd_ ## name(const char*, char*); COMMAND_TABLE #undef COMMAND +#undef DELIM // descrtiptions for `help` typedef struct { @@ -104,9 +114,11 @@ typedef struct { } CmdInfo; static const CmdInfo cmdInfo[] = { +#define DELIM(text) { NULL, text }, #define COMMAND(name, desc) { #name, desc }, COMMAND_TABLE #undef COMMAND +#undef DELIM }; // Text descriptions for error codes @@ -171,11 +183,44 @@ static bool argsvals(char *args, int32_t *parno, int32_t *parval){ /************* List of proto functions for each command *************/ +static errcodes_t cmd_autoheater(const char* cmd, char* args){ + int32_t flag; + if(argsvals(args, NULL, &flag)){ + if(flag == 0) AutoHeater = 0; + else AutoHeater = 1; + } + CMDEQ(); + printu(AutoHeater); N(); + return ERR_AMOUNT; +} + +static errcodes_t cmd_clearheater(const char*, char*){ + clearThold(); + return ERR_OK; +} + +static errcodes_t cmd_setheater(const char* cmd, char* args){ + int32_t Tset; + if(argsvals(args, NULL, &Tset)){ + if(setThold(Tset)) return ERR_OK; + else return ERR_CANTRUN; + } + float T; + CMDEQ(); + if(!getThold(&T)) SEND("none\n"); + else{ + printfl(T, 1); N(); + } + return ERR_AMOUNT; +} + static errcodes_t cmd_help(const char*, char*){ SEND(REPOURL); for(size_t i = 0; i < sizeof(cmdInfo)/sizeof(cmdInfo[0]); ++i){ - SEND(cmdInfo[i].name); - SEND(" - "); + if(cmdInfo[i].name){ + SEND(cmdInfo[i].name); + SEND(" - "); + }else SEND(" "); SEND(cmdInfo[i].desc); SEND("\n"); } @@ -300,17 +345,14 @@ static errcodes_t cmd_state(const char* cmd, char*){ /********** I2C commands **********/ -static errcodes_t cmd_iicaddr(const char* cmd, char* args){ +static errcodes_t cmd_hwaddr(const char*, char* args){ int32_t addr; if(argsvals(args, NULL, &addr)){ if(addr < 0 || addr > 0x7f) return ERR_BADVAL; - I2Caddress = (uint8_t)(addr << 1); mlx_sethwaddr(I2Caddress, addr); - return ERR_AMOUNT; + return ERR_OK; } - // getter - CMDEQ(); printuhex(I2Caddress >> 1); N(); - return ERR_AMOUNT; + return ERR_BADVAL; } static errcodes_t cmd_mlxcont(const char*, char*){ @@ -414,16 +456,20 @@ static errcodes_t cmd_mlxdump(const char*, char* args){ return ERR_AMOUNT; } +static errcodes_t cmd_iicaddr(const char* cmd, char* args){ + int32_t addr = -1; + if(argsvals(args, NULL, &addr)){ + if(addr < 0 || addr > 0x7f) return ERR_BADVAL; + I2Caddress = addr << 1; + } + CMDEQ(); printuhex(I2Caddress>>1); N(); + return ERR_AMOUNT; +} + static errcodes_t cmd_mlxaddr(const char* cmd, char* args){ int32_t sensno = -1; - if(!args || !*args) { // without args: show global address - //CMDEQ(); printuhex(I2Caddress>>1); N(); - //return ERR_AMOUNT; - return ERR_BADPAR; - } const char *setter = splitargs(args, &sensno); if(sensno < 0 || sensno >= N_SENSORS) return ERR_BADPAR; - if(setter){ // setter: set current address uint32_t a; const char *nxt = getnum(setter, &a); @@ -574,9 +620,11 @@ const char *parse_cmd(int (*sendfun)(const char*), char *buf) { uint32_t h = hash(command); errcodes_t ecode = ERR_AMOUNT; switch (h){ +#define DELIM(text) #define COMMAND(name, desc) case hash(#name): ecode = cmd_##name(command, args); break; COMMAND_TABLE #undef COMMAND +#undef DELIM default: SEND("Unknown command, try 'help'\n"); } diff --git a/F3:F303/MLX90640-allsky/hardware.h b/F3:F303/MLX90640-allsky/hardware.h index 3b92191..8172127 100644 --- a/F3:F303/MLX90640-allsky/hardware.h +++ b/F3:F303/MLX90640-allsky/hardware.h @@ -30,29 +30,54 @@ #define SPI_CS_0() pin_clear(GPIOB, 1<<9) // interval of environment measurements, ms -#define ENV_MEAS_PERIOD (10000) +#define ENV_MEAS_PERIOD (10000) + +// heater check period, ms +#define HTR_CHECK_PERIOD (10000) + +// temperature hysteresis (+-hyst from holding value) +#define HOLDT_HYSTERESIS (5.f) +// environment for auto-heater +// maximal humidity +#define HUMIDITY_MAX (90.f) +// delta over dew point +#define TDEW_OVER_DELTA (7.f) +// defrosting temperature (when there's very cold) +#define TEMP_DEFROST (5.f) +// PWM starting value (up to reaching holding T) +#define PWM_START_VAL (100) +// middle value +#define PWM_MID_VAL (50) +// PWM holding value (up to setTemp+Thyst) +#define PWM_HOLD_VAL (10) // External heater PWM: TIM3_CH1 or TIM16_CH1 // Max PWM CCR1 value (->1) #define PWM_CCR_MAX (100) +// amount of heaters +#define HTR_AMOUNT (2) // PWM channels (start from 0 - CH1) +#define PWM_CH_HTR(x) (x) // propto external T (the higher - the brighter) #define PWM_CH_TEXT (2) // propto Tsky - Text (the higher - the brighter) #define PWM_CH_TSKY (3) #define PWM_CH_MAX (3) +// amount of T channels +#define NTC_AMOUNT (4) + typedef struct{ float T; // temperature, degC float Tdew; // dew point, degC float P; // pressure, Pa float H; // humidity, percents float Tsky; // mean Tsky, degC - // TODO: add here values of NTC on ADC channels 1/2 uint32_t Tmeas; // time of measurement } bme280_t; extern volatile uint32_t Tms; +extern uint8_t AutoHeater; void hw_setup(); int bme_init(); diff --git a/F3:F303/MLX90640-allsky/heater.c b/F3:F303/MLX90640-allsky/heater.c new file mode 100644 index 0000000..ce0149c --- /dev/null +++ b/F3:F303/MLX90640-allsky/heater.c @@ -0,0 +1,134 @@ +/* + * This file is part of the ir-allsky project. + * Copyright 2026 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "adc.h" +#include "heater.h" +#include "hardware.h" + +#ifdef EBUG +#include "strfunc.h" +#include "usb_dev.h" +#endif + +// turn on/off automatic cover heater in case of high humidity +uint8_t AutoHeater = 0; +static float setTemp = 0.f; +// try to hold setTemp +static uint8_t holdTemp = 0; +// no NTC found - errflag +static uint8_t noNTCfound = 0; +// last time env/hold was checked +static uint32_t lastTcheck = 0; + +uint8_t getThold(float *T){ + if(T) *T = setTemp; + return holdTemp; +} + +// set Thold in degrC +int setThold(int Th){ + if(Th < -10 || Th > 50) return FALSE; + if(noNTCfound) return FALSE; + setTemp = (float) Th; + holdTemp = 1; + return TRUE; +} + +static void setHeaters(uint8_t PWMval){ + for(uint8_t i = 0; i < HTR_AMOUNT; ++i) + setPWM(i, PWMval); +} + +void clearThold(){ + holdTemp = 0; + setHeaters(0); +} + +// calculate maximal and mean T +// return amount of working NTCs +static int CalcT(float *maxval, float *meanval){ + float max = -100.f, sum = 0.f; + int N; + for(uint8_t i = 0; i < NTC_AMOUNT; ++i){ + float Tcur = getNTCtemp(i); + if(Tcur < -100.f) continue; // bad value: short cirquit or break + ++N; + if(Tcur > max) max = Tcur; + sum += Tcur; + } + if(N == 0) return 0; // oops: nothing found + if(meanval) *meanval = sum / N; + if(maxval) *maxval = max; + return N; +} + +void heater_process(){ + static uint8_t overheating = 0; // if ==1 wait until Tset to run again + if(!AutoHeater && !holdTemp) return; + if(Tms - lastTcheck < HTR_CHECK_PERIOD) return; + float Tmax, Tmean; + if(0 == CalcT(&Tmax, &Tmean)){ // turn off heater and return + setHeaters(0); + DBG("NTC not found!"); + noNTCfound = 1; + return; + } +#ifdef EBUG + USB_sendstr("Tmax="); USB_sendstr(float2str(Tmax, 1)); + USB_sendstr("\nTmean="); USB_sendstr(float2str(Tmean, 1)); + newline(); +#endif + noNTCfound = 0; + lastTcheck = Tms; + if(AutoHeater) do{ // check weather conditions and set/reset holdTemp/setTemp + bme280_t env; + if(!get_environment(&env)) break; // can't set holding temperature when dunno env + if(env.H > HUMIDITY_MAX){ + float Tset = env.T + TDEW_OVER_DELTA + 0.5f; + if(Tset < TEMP_DEFROST) Tset = TEMP_DEFROST; // defrost + setThold((int)Tset); + }else{ // all OK: turn off heaters and clear holding + setHeaters(0); + holdTemp = 0; + } + }while(0); + if(holdTemp){ // try to hold `setTemp` +-5 degC + float Tdiff = Tmean - setTemp; // >0 in case of overheating + uint8_t PWMset = 0; + if(Tdiff < -HOLDT_HYSTERESIS){ + PWMset = PWM_START_VAL; + overheating = 0; + }else if(!overheating){ + if(Tdiff > HOLDT_HYSTERESIS){ + overheating = 1; + }else if(Tdiff > 0){ + PWMset = PWM_HOLD_VAL; + }else PWMset = PWM_MID_VAL; + }else if(Tdiff < 0.f){ // need slight heating + PWMset = PWM_HOLD_VAL; + } + // check max for overheating + if(Tmax - setTemp > HOLDT_HYSTERESIS && PWMset > PWM_HOLD_VAL) PWMset = PWM_HOLD_VAL; +#ifdef EBUG + USB_sendstr("Tdiff="); USB_sendstr(float2str(Tdiff, 1)); + USB_sendstr("\nPWMset="); USB_sendstr(u2str(PWMset)); + newline(); +#endif + setHeaters(PWMset); + } +} diff --git a/F3:F303/MLX90640-allsky/heater.h b/F3:F303/MLX90640-allsky/heater.h new file mode 100644 index 0000000..9eaec71 --- /dev/null +++ b/F3:F303/MLX90640-allsky/heater.h @@ -0,0 +1,26 @@ +/* + * This file is part of the ir-allsky project. + * Copyright 2026 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +void heater_process(); +uint8_t getThold(float *T); +void clearThold(); +int setThold(int Th); diff --git a/F3:F303/MLX90640-allsky/ir-allsky.creator.user b/F3:F303/MLX90640-allsky/ir-allsky.creator.user index c32ec9c..2440c59 100644 --- a/F3:F303/MLX90640-allsky/ir-allsky.creator.user +++ b/F3:F303/MLX90640-allsky/ir-allsky.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/F3:F303/MLX90640-allsky/ir-allsky.files b/F3:F303/MLX90640-allsky/ir-allsky.files index fdf0783..04d62be 100644 --- a/F3:F303/MLX90640-allsky/ir-allsky.files +++ b/F3:F303/MLX90640-allsky/ir-allsky.files @@ -6,6 +6,8 @@ commproto.cpp commproto.h hardware.c hardware.h +heater.c +heater.h i2c.c i2c.h main.c diff --git a/F3:F303/MLX90640-allsky/main.c b/F3:F303/MLX90640-allsky/main.c index d83ae9a..4e6495a 100644 --- a/F3:F303/MLX90640-allsky/main.c +++ b/F3:F303/MLX90640-allsky/main.c @@ -18,6 +18,7 @@ #include "adc.h" #include "hardware.h" +#include "heater.h" #include "i2c.h" #include "mlxproc.h" #include "commproto.h" @@ -103,5 +104,6 @@ int main(void){ if(ans) usart_sendstr(ans); } bme_process(); + heater_process(); } } diff --git a/F3:F303/MLX90640-allsky/mlxproc.c b/F3:F303/MLX90640-allsky/mlxproc.c index 0e62161..7a95092 100644 --- a/F3:F303/MLX90640-allsky/mlxproc.c +++ b/F3:F303/MLX90640-allsky/mlxproc.c @@ -71,7 +71,7 @@ int mlx_setaddr(int n, uint8_t addr){ } uint8_t mlx_getaddr(int n){ if(n < 0 || n >= N_SENSORS) return 0; - return sens_addresses[n]; + return sens_addresses[n] >> 1; } // pause state machine and stop void mlx_pause(){