Compare commits
10 Commits
6baa7b0bbb
...
07c922a04a
| Author | SHA1 | Date | |
|---|---|---|---|
| 07c922a04a | |||
| 2125e4a2e8 | |||
| 4dc100dc18 | |||
| 3d254c5931 | |||
| be7cceb0b5 | |||
| 9ee81f0024 | |||
| c7af2f2b59 | |||
| b563f08ecb | |||
| 9523dc8a78 | |||
| 3682d10a27 |
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Steins7
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
27
README.md
Normal file
27
README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# FanMonitor
|
||||||
|
Advanced controller for industrial fan
|
||||||
|
|
||||||
|
This repository contains all the files used for the creation of a custom industrial fan controller.
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
__Two spaces__ have to be maintained at the lowest temperature possible (to a certain extent).
|
||||||
|
For that purpose, an __industrial fan__ (controlled by a 220V relay) is used. The fan is __physically moved__ from one space to the other depending on the needs (the air intake is outside).
|
||||||
|
|
||||||
|
The goal is to control the fan automatically with 3 temperature sensors, one in each space and one near the air intake. The 3 current tempratures have to be display for the user to check things if needed. The environnement is also very dusty so the system has to be contained in a closed box.
|
||||||
|
|
||||||
|
## System
|
||||||
|
|
||||||
|
The system is made off three main part :
|
||||||
|
- a generic usb charger for the voltage supply
|
||||||
|
- a main board build aroud a __STM32F103__ microprocessor
|
||||||
|
- a screen based on the __HD44780__ driver
|
||||||
|
|
||||||
|
The box's plans are not depicted here since they are very simple (a few holes, no more, no less).
|
||||||
|
Appart form that, you will find here all the code - created from scratch since I didn't want to use ST's HAL and anyways it's funnier this way - and the 3D models used. All the documentation is also there. You may also find (if I didnt forget to put it there) EasyEDA files for the main board PCB.
|
||||||
|
|
||||||
|
## How to compile
|
||||||
|
|
||||||
|
The code uses the __GNU toolchain__, whith __gcc__ and __gdb__ for AMR. __OpenOCD__ is used for the SWD handling, through a __STLinkv2__. Don't forget to install __arm-none-eabi-newlib__ if you want things to work.
|
||||||
|
|
||||||
|
Finaly, there is a RELEASE tag in the Makefile if you want to optimise and remove debug.
|
||||||
41
cad/adapter/adapter.scad
Normal file
41
cad/adapter/adapter.scad
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
$fn = 100;
|
||||||
|
|
||||||
|
// element dimensions
|
||||||
|
w = 60;
|
||||||
|
d = 30;
|
||||||
|
h = 4;
|
||||||
|
|
||||||
|
// aditionnal parameters
|
||||||
|
e = 5;
|
||||||
|
|
||||||
|
// internal values
|
||||||
|
we = w + e;
|
||||||
|
de = d + e;
|
||||||
|
|
||||||
|
translate([0,0,e/2]);
|
||||||
|
cube([we,de,e/3], true);
|
||||||
|
module tab() {
|
||||||
|
translate([-e/4,0,(e/3+h)/2]) {
|
||||||
|
cube([e/2,2*e,h], true);
|
||||||
|
translate([-1.75*e,-e,h/2])
|
||||||
|
rotate([0,-90,-90])
|
||||||
|
linear_extrude(height = 2*e)
|
||||||
|
polygon([[0,1.2*e],[e/4,1.2*e],[0,2*e],[e/2,2*e]],
|
||||||
|
[[0,1,3,2]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
translate([we/2,-de/2+e,0])
|
||||||
|
tab();
|
||||||
|
|
||||||
|
translate([-we/2,0,0])
|
||||||
|
rotate([0,0,180])
|
||||||
|
tab();
|
||||||
|
|
||||||
|
translate([8,de/2,0])
|
||||||
|
rotate([0,0,90])
|
||||||
|
tab();
|
||||||
|
|
||||||
|
translate([0,-de/2,0])
|
||||||
|
rotate([0,0,-90])
|
||||||
|
tab();
|
||||||
@ -1,4 +1,4 @@
|
|||||||
//$fn = 100;
|
$fn = 100;
|
||||||
|
|
||||||
r = 12;
|
r = 12;
|
||||||
h = 12;
|
h = 12;
|
||||||
@ -25,9 +25,9 @@ difference() {
|
|||||||
cube([3,2*center_r,h], center=true);
|
cube([3,2*center_r,h], center=true);
|
||||||
}
|
}
|
||||||
difference() {
|
difference() {
|
||||||
translate([0,0,0.7])
|
translate([0,0,3])
|
||||||
cylinder(h=h, r=0.8*r, center=true);
|
cylinder(h=h, r=0.8*r, center=true);
|
||||||
translate([0,0,0.7])
|
translate([0,0,3])
|
||||||
cylinder(h=h, r=1.4*center_r, center=true);
|
cylinder(h=h, r=1.4*center_r, center=true);
|
||||||
|
|
||||||
}
|
}
|
||||||
231
cad/main_board/main_board_routing.json
Normal file
231
cad/main_board/main_board_routing.json
Normal file
File diff suppressed because one or more lines are too long
15
cad/main_board/main_board_schematic.json
Normal file
15
cad/main_board/main_board_schematic.json
Normal file
File diff suppressed because one or more lines are too long
BIN
docs/Graphs.ods
BIN
docs/Graphs.ods
Binary file not shown.
65
src/config.h
65
src/config.h
@ -1,6 +1,5 @@
|
|||||||
/****************************************************************************
|
//------------------------------------------------------------------------------
|
||||||
* IRQ Priority
|
/* priorities */
|
||||||
****************************************************************************/
|
|
||||||
#define EXTI0_IRQ_PRIORITY 8
|
#define EXTI0_IRQ_PRIORITY 8
|
||||||
#define EXTI1_IRQ_PRIORITY 8
|
#define EXTI1_IRQ_PRIORITY 8
|
||||||
#define EXTI2_IRQ_PRIORITY 8
|
#define EXTI2_IRQ_PRIORITY 8
|
||||||
@ -28,63 +27,3 @@
|
|||||||
|
|
||||||
#define ADC1_2_IRQ_PRIORITY 5
|
#define ADC1_2_IRQ_PRIORITY 5
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* USART Pin and use configuration
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
//#define USE_USART1
|
|
||||||
//#define USART1_GPIO_PORT
|
|
||||||
//#define USART1_GPIO_PINS
|
|
||||||
|
|
||||||
// USART2: Tx --> PA2, Rx --> PA3
|
|
||||||
//#define USE_USART2
|
|
||||||
//#define USART2_GPIO_PORT _GPIOA
|
|
||||||
//#define USART2_GPIO_PINS PIN_2|PIN_3
|
|
||||||
|
|
||||||
//#define USE_USART6
|
|
||||||
//#define USART6_GPIO_PORT
|
|
||||||
//#define USART6_GPIO_PINS
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* I2C Pin and use configuration
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
// I2C1 : SCL --> PB8, SDA --> PB9
|
|
||||||
//#define USE_I2C1
|
|
||||||
//#define I2C1_GPIO_PORT _GPIOB
|
|
||||||
//#define I2C1_GPIO_PINS PIN_8|PIN_9
|
|
||||||
|
|
||||||
//#define USE_I2C2
|
|
||||||
//#define I2C2_GPIO_PORT
|
|
||||||
//#define I2C2_GPIO_PINS
|
|
||||||
|
|
||||||
//#define USE_I2C3
|
|
||||||
//#define I2C3_GPIO_PORT
|
|
||||||
//#define I2C3_GPIO_PINS
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* SPI pin and use configuration
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
// SPI1 pins : LCD_SCK --> D13 --> PA5 : SPI1_SCK
|
|
||||||
// LCD_MOSI --> D11 --> PA7 : SPI1_MOSI
|
|
||||||
//#define USE_SPI1
|
|
||||||
//#define SPI1_GPIO_PORT _GPIOA
|
|
||||||
//#define SPI1_GPIO_PINS PIN_5|PIN_7
|
|
||||||
|
|
||||||
//#define USE_SPI2
|
|
||||||
//#define SPI2_GPIO_PORT
|
|
||||||
//#define SPI2_GPIO_PINS
|
|
||||||
|
|
||||||
//#define USE_SPI3
|
|
||||||
//#define SPI3_GPIO_PORT
|
|
||||||
//#define SPI3_GPIO_PINS
|
|
||||||
|
|
||||||
//#define USE_SPI4
|
|
||||||
//#define SPI4_GPIO_PORT
|
|
||||||
//#define SPI4_GPIO_PINS
|
|
||||||
|
|
||||||
//#define USE_SPI5
|
|
||||||
//#define SPI5_GPIO_PORT
|
|
||||||
//#define SPI5_GPIO_PINS
|
|
||||||
|
|
||||||
|
|||||||
@ -17,31 +17,26 @@ static OnIO io_cb[16]={
|
|||||||
|
|
||||||
void EXTI0_IRQHandler() {
|
void EXTI0_IRQHandler() {
|
||||||
if (io_cb[0]) (io_cb[0])();
|
if (io_cb[0]) (io_cb[0])();
|
||||||
|
|
||||||
EXTI->PR = 1<<0;
|
EXTI->PR = 1<<0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EXTI1_IRQHandler() {
|
void EXTI1_IRQHandler() {
|
||||||
if (io_cb[1]) (io_cb[1])();
|
if (io_cb[1]) (io_cb[1])();
|
||||||
|
|
||||||
EXTI->PR = 1<<1;
|
EXTI->PR = 1<<1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EXTI2_IRQHandler() {
|
void EXTI2_IRQHandler() {
|
||||||
if (io_cb[2]) (io_cb[2])();
|
if (io_cb[2]) (io_cb[2])();
|
||||||
|
|
||||||
EXTI->PR = 1<<2;
|
EXTI->PR = 1<<2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EXTI3_IRQHandler() {
|
void EXTI3_IRQHandler() {
|
||||||
if (io_cb[3]) (io_cb[3])();
|
if (io_cb[3]) (io_cb[3])();
|
||||||
|
|
||||||
EXTI->PR = 1<<3;
|
EXTI->PR = 1<<3;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EXTI4_IRQHandler() {
|
void EXTI4_IRQHandler() {
|
||||||
if (io_cb[4]) (io_cb[4])();
|
if (io_cb[4]) (io_cb[4])();
|
||||||
|
|
||||||
EXTI->PR = 1<<4;
|
EXTI->PR = 1<<4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,9 +138,9 @@ int io_configure(GPIO_TypeDef *gpio, uint16_t pin, uint16_t pin_cfg, OnIO cb) {
|
|||||||
else if (gpio == GPIOE) port_mask = SYSCFG_EXTI_PE_MASK;
|
else if (gpio == GPIOE) port_mask = SYSCFG_EXTI_PE_MASK;
|
||||||
|
|
||||||
// setup external IRQ lines
|
// setup external IRQ lines
|
||||||
uint16_t afio_mask;
|
uint64_t afio_mask;
|
||||||
for(int i=0; i<4; ++i) {
|
for(int i=0; i<4; ++i) {
|
||||||
afio_mask = ((pin_mask & (0xFFFF << i)) >> i) * port_mask;
|
afio_mask = ((pin_mask & (0xFFFFll << (i*16))) >> (i*16)) * port_mask;
|
||||||
if(afio_mask) AFIO->EXTICR[i] |= afio_mask;
|
if(afio_mask) AFIO->EXTICR[i] |= afio_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +199,6 @@ int io_configure(GPIO_TypeDef *gpio, uint16_t pin, uint16_t pin_cfg, OnIO cb) {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -1; //impossible to get there
|
return -1; //impossible to get there
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -161,6 +161,7 @@ void lcd_print(const char* txt) {
|
|||||||
io_write(GPIOA, LCD_MODE_DATA, PIN_10);
|
io_write(GPIOA, LCD_MODE_DATA, PIN_10);
|
||||||
|
|
||||||
// send the caracters until end of string
|
// send the caracters until end of string
|
||||||
|
// TODO implement '\n'
|
||||||
while(*c != '\0') {
|
while(*c != '\0') {
|
||||||
wait_for_ready();
|
wait_for_ready();
|
||||||
write_byte(*c);
|
write_byte(*c);
|
||||||
|
|||||||
@ -108,19 +108,22 @@ int timer_wait_ms(TIM_TypeDef* tmr, uint16_t ms, OnTick cb) {
|
|||||||
else if (tmr == TIM4) RCC->APB1ENR |= 1<<2;
|
else if (tmr == TIM4) RCC->APB1ENR |= 1<<2;
|
||||||
else return -1; // no such timer
|
else return -1; // no such timer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set period
|
||||||
|
tmr->ARR = 0xFFFFFFFF;
|
||||||
|
|
||||||
} else { //non-blocking
|
} else { //non-blocking
|
||||||
if(timer_config_cb(tmr, &clk, cb)) return -1;
|
if(timer_config_cb(tmr, &clk, cb)) return -1;
|
||||||
|
|
||||||
|
// set period
|
||||||
|
tmr->ARR = ms-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set mode
|
// set mode
|
||||||
tmr->CR1 |= (1<<7); //buffering
|
tmr->CR1 = (1<<7) | (1<<2); //buffering and update settings
|
||||||
tmr->CR1 |= (1<<3); //one pulse mode
|
tmr->CR1 |= (1<<3); //one pulse mode
|
||||||
|
|
||||||
// set period
|
// set prescaler 1ms
|
||||||
tmr->ARR = 0xFFFFFFFF;
|
|
||||||
|
|
||||||
// set prescaler 1us
|
|
||||||
tmr->PSC = 8*(clk/1000)-1; //PSC = clk/f - 1 | don't know why 8 times..
|
tmr->PSC = 8*(clk/1000)-1; //PSC = clk/f - 1 | don't know why 8 times..
|
||||||
|
|
||||||
timer_start(tmr);
|
timer_start(tmr);
|
||||||
@ -149,17 +152,20 @@ int timer_wait_us(TIM_TypeDef* tmr, uint16_t us, OnTick cb) {
|
|||||||
else return -1; // no such timer
|
else return -1; // no such timer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set period
|
||||||
|
tmr->ARR = 0xFFFFFFFF;
|
||||||
|
|
||||||
} else { //non-blocking
|
} else { //non-blocking
|
||||||
if(timer_config_cb(tmr, &clk, cb)) return -1;
|
if(timer_config_cb(tmr, &clk, cb)) return -1;
|
||||||
|
|
||||||
|
// set period
|
||||||
|
tmr->ARR = us-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set mode
|
// set mode
|
||||||
tmr->CR1 |= (1<<7); //buffering
|
tmr->CR1 = (1<<7) | (1<<2); //buffering and update settings
|
||||||
tmr->CR1 |= (1<<3); //one pulse mode
|
tmr->CR1 |= (1<<3); //one pulse mode
|
||||||
|
|
||||||
// set period
|
|
||||||
tmr->ARR = 0xFFFFFFFF;
|
|
||||||
|
|
||||||
// set prescaler 1us
|
// set prescaler 1us
|
||||||
tmr->PSC = 8*(clk/1000000)-1; //PSC = clk/f - 1 | don't know why 8 times..
|
tmr->PSC = 8*(clk/1000000)-1; //PSC = clk/f - 1 | don't know why 8 times..
|
||||||
|
|
||||||
@ -229,8 +235,8 @@ int timer_tick_init(TIM_TypeDef *tmr, uint16_t tick_ms, OnTick cb) {
|
|||||||
tmr->SR &= !1;
|
tmr->SR &= !1;
|
||||||
|
|
||||||
// set mode
|
// set mode
|
||||||
tmr->CR1 = (1<<7); //buffering
|
tmr->CR1 = (1<<7) | (1<<2); //buffering and update settings
|
||||||
tmr->DIER = (1<<0); //Enable interrupts
|
tmr->DIER = (1<<0); //Enable interrupts
|
||||||
|
|
||||||
// set prescaler 1ms
|
// set prescaler 1ms
|
||||||
tmr->PSC = 8*(clk/1000)-1; //PSC = clk/f - 1 | don't know why 8 times...
|
tmr->PSC = 8*(clk/1000)-1; //PSC = clk/f - 1 | don't know why 8 times...
|
||||||
@ -294,9 +300,9 @@ int timer_enc_init(TIM_TypeDef* tmr) {
|
|||||||
tmr->CCMR1 |= 0x9;
|
tmr->CCMR1 |= 0x9;
|
||||||
tmr->CCMR1 |= 0x9 << 8;
|
tmr->CCMR1 |= 0x9 << 8;
|
||||||
|
|
||||||
// enable input channels
|
// enable input channels and invert them //TODO add an otpion for that
|
||||||
tmr->CCER |= 0x1;
|
tmr->CCER |= 0x3;
|
||||||
tmr->CCER |= 0x1 << 4;
|
tmr->CCER |= 0x3 << 4;
|
||||||
|
|
||||||
tmr->CR1 |= 0x1; //enable timer
|
tmr->CR1 |= 0x1; //enable timer
|
||||||
|
|
||||||
|
|||||||
@ -42,6 +42,10 @@ void timer_start(TIM_TypeDef *tmr);
|
|||||||
void timer_stop(TIM_TypeDef *tmr);
|
void timer_stop(TIM_TypeDef *tmr);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
/** timer_enc_init
|
||||||
|
* setup timer to read encoder output and keep track of it's position in the
|
||||||
|
* CNT register whithout using CPU time
|
||||||
|
*/
|
||||||
int timer_enc_init(TIM_TypeDef* tmr);
|
int timer_enc_init(TIM_TypeDef* tmr);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|||||||
153
src/main.c
153
src/main.c
@ -14,100 +14,143 @@ Clock_t sysclks;
|
|||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
/* static variables */
|
/* static variables */;
|
||||||
int val = 0;
|
int val = 0; //debug led
|
||||||
int count = 0;
|
int read_flag = 0;
|
||||||
uint16_t data = 0;
|
int sensor_id = 0;
|
||||||
int16_t voltage = 0;
|
|
||||||
int16_t temp = 0;
|
// low_pass filter
|
||||||
|
#define FILTER_LENGTH 10
|
||||||
|
int16_t temp_filter[3][FILTER_LENGTH] = {};
|
||||||
|
|
||||||
|
// adc channels
|
||||||
|
uint8_t channels[3][2] = {
|
||||||
|
{4, 5},
|
||||||
|
{0, 1},
|
||||||
|
{2, 3}
|
||||||
|
};
|
||||||
|
|
||||||
|
vars_t vars = {
|
||||||
|
{},
|
||||||
|
5,
|
||||||
|
2,
|
||||||
|
{},
|
||||||
|
1,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
/* Timer IRQ */
|
/* Timer IRQ */
|
||||||
static void timeout_cb(void) {
|
static void timeout_cb(void) {
|
||||||
io_write(GPIOC, val, PIN_13);
|
io_write(GPIOC, val, PIN_13);
|
||||||
io_write(GPIOB, val, PIN_12);
|
|
||||||
val = !val;
|
val = !val;
|
||||||
data = adc_read(ADC1, 2);
|
|
||||||
data -= adc_read(ADC1, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void enc_button_cb(void) {
|
// set temp read flag
|
||||||
count = !count;
|
read_flag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t read_temp(uint8_t id) {
|
||||||
|
// get ADC values
|
||||||
|
uint32_t data = 0;
|
||||||
|
data = adc_read(ADC1, channels[id][0]);
|
||||||
|
data -= adc_read(ADC1, channels[id][1]);
|
||||||
|
|
||||||
|
int16_t voltage = ((data*4) << 8)/4095 ;
|
||||||
|
|
||||||
|
return ((voltage - 0x73) << 8)/0x9 + vars.facs[id][0];
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
/* main function */
|
/* main function */
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
|
||||||
|
//initialize variables
|
||||||
|
val = 0; //debug led
|
||||||
|
read_flag = 0;
|
||||||
|
sensor_id = 0;
|
||||||
|
|
||||||
|
// configure clocks (necessary before using timers)
|
||||||
rcc_config_clock(CLOCK_CONFIG_PERFORMANCE, &sysclks);
|
rcc_config_clock(CLOCK_CONFIG_PERFORMANCE, &sysclks);
|
||||||
|
|
||||||
// configure GPIO for LED
|
// configure GPIO for LED
|
||||||
if(io_configure(GPIOC, PIN_13, IO_MODE_OUTPUT | IO_OUT_PUSH_PULL, 0))
|
if(io_configure(GPIOC, PIN_13, IO_MODE_OUTPUT | IO_OUT_PUSH_PULL, 0))
|
||||||
return 0;
|
return -1;
|
||||||
if(io_configure(GPIOB, PIN_12, IO_MODE_OUTPUT | IO_OUT_PUSH_PULL, 0))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
io_write(GPIOC, 1, PIN_13);
|
io_write(GPIOC, 1, PIN_13);
|
||||||
io_write(GPIOB, 1, PIN_12);
|
|
||||||
|
// configure GPIO for relay
|
||||||
|
if(io_configure(GPIOB, PIN_11, IO_MODE_OUTPUT | IO_OUT_PUSH_PULL, 0))
|
||||||
|
return -1;
|
||||||
|
io_write(GPIOB, 1, PIN_11);
|
||||||
|
|
||||||
// configure GPIOS for temperature sensors
|
// configure GPIOS for temperature sensors
|
||||||
if(io_configure(GPIOA, PIN_0 | PIN_1 | PIN_2 | PIN_3 | PIN_4 | PIN_5,
|
if(io_configure(GPIOA, PIN_0 | PIN_1 | PIN_2 | PIN_3 | PIN_4 | PIN_5,
|
||||||
IO_MODE_INPUT | IO_IN_ANALOG, 0)) return 0;
|
IO_MODE_INPUT | IO_IN_ANALOG, 0)) return -1;
|
||||||
if(adc_init(ADC1)) return 0;
|
if(adc_init(ADC1)) return -1;
|
||||||
|
|
||||||
// configure lcd
|
// initilize filter
|
||||||
lcd_init(TIM1, 16, 2);
|
for(int i=0; i<3; ++i) {
|
||||||
lcd_send_cmd(LCD_CUR_HOME);
|
int16_t tmp = read_temp(i);
|
||||||
lcd_print("SILO:1 Te: 18""\xDF""C");
|
for(int j=0; j<FILTER_LENGTH; ++j) {
|
||||||
lcd_set_cursor(0,1);
|
temp_filter[i][j] = tmp;
|
||||||
lcd_print("1: 25""\xDF""C 2: 26""\xDF""C");
|
}
|
||||||
lcd_send_cmd(LCD_DISP_CTRL | LCD_CTRL_DISP_ON | LCD_CTRL_CUR_OFF |
|
}
|
||||||
LCD_CTRL_BLINK_OFF);
|
|
||||||
|
|
||||||
// configure encoder
|
|
||||||
io_configure(GPIOB, PIN_6 | PIN_7, IO_MODE_INPUT | IO_IN_FLOATING, 0);
|
|
||||||
timer_enc_init(TIM4);
|
|
||||||
|
|
||||||
io_configure(GPIOB, PIN_8, IO_MODE_INPUT | IO_IN_PULL_UP |
|
|
||||||
IO_IRQ_EDGE_FALL, enc_button_cb);
|
|
||||||
|
|
||||||
|
// setup ui
|
||||||
|
if(ui_init(TIM4, TIM3, &vars)) return -1;
|
||||||
|
|
||||||
// start timed interruption
|
// start timed interruption
|
||||||
timer_tick_init(TIM2, 1000, timeout_cb);
|
timer_tick_init(TIM2, 1000, timeout_cb);
|
||||||
timer_start(TIM2);
|
timer_start(TIM2);
|
||||||
|
|
||||||
// main loop
|
// main loop
|
||||||
while(1){
|
while(1){
|
||||||
// update T1
|
|
||||||
//data = adc_read(ADC1, 0);
|
|
||||||
//data -= adc_read(ADC1, 1);
|
|
||||||
|
|
||||||
//voltage = ((data*4) << 8)/4095;
|
// process sensor values
|
||||||
//temp = ((voltage - 0x73) << 8)/0x9;
|
if(read_flag) {
|
||||||
|
|
||||||
uint32_t pin = io_read(GPIOB, PIN_8);
|
// clear flag
|
||||||
if(!pin) count = !count;
|
read_flag = 0;
|
||||||
if(count) update_temp(T1, (int16_t)TIM4->CNT/2);
|
|
||||||
|
|
||||||
// update T2
|
// shift filter queue
|
||||||
data = adc_read(ADC1, 2);
|
int32_t sum = 0;
|
||||||
data -= adc_read(ADC1, 3);
|
for(int i=0; i<(FILTER_LENGTH-1); ++i) {
|
||||||
|
temp_filter[sensor_id][i] = temp_filter[sensor_id][i+1];
|
||||||
|
sum += temp_filter[sensor_id][i];
|
||||||
|
}
|
||||||
|
|
||||||
voltage = ((data*4) << 8)/4095;
|
// calculate temp value
|
||||||
temp = ((voltage - 0x73) << 8)/0x9;
|
temp_filter[sensor_id][FILTER_LENGTH-1] = read_temp(sensor_id);
|
||||||
|
|
||||||
update_temp(T2, temp);
|
// apply filter
|
||||||
|
sum += temp_filter[sensor_id][FILTER_LENGTH-1];
|
||||||
|
vars.temps[sensor_id] = (sum/FILTER_LENGTH) >> 8;
|
||||||
|
|
||||||
// update T_ext
|
// print new value
|
||||||
data = adc_read(ADC1, 4);
|
ui_update_temp(sensor_id);
|
||||||
data -= adc_read(ADC1, 5);
|
|
||||||
|
|
||||||
voltage = ((data*4) << 8)/4095;
|
// switch to next sensor
|
||||||
temp = ((voltage - 0x73) << 8)/0x9;
|
sensor_id++;
|
||||||
|
sensor_id = sensor_id%3;
|
||||||
|
|
||||||
update_temp(T_EXT, temp);
|
// set fan state
|
||||||
|
if((vars.temps[vars.silo] - vars.temps[T_EXT]) >=
|
||||||
|
vars.start_treshold) {
|
||||||
|
if(!vars.fan) {
|
||||||
|
io_set(GPIOB, PIN_11);
|
||||||
|
vars.fan = 1;
|
||||||
|
}
|
||||||
|
} else if((vars.temps[vars.silo] - vars.temps[T_EXT]) <=
|
||||||
|
vars.stop_treshold) {
|
||||||
|
if(vars.fan) {
|
||||||
|
io_clear(GPIOB, PIN_11);
|
||||||
|
vars.fan = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// update every 0.2 seconds
|
// update every 0.2 seconds
|
||||||
timer_wait_ms(TIM1, 200, 0);
|
ui_update();
|
||||||
|
//timer_wait_ms(TIM1, 200, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
255
src/ui.c
255
src/ui.c
@ -1,21 +1,267 @@
|
|||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/* control variables */
|
||||||
|
static int state;
|
||||||
|
static volatile int button_update;
|
||||||
|
static int sel, prev_sel;
|
||||||
|
static TIM_TypeDef* enc;
|
||||||
|
static TIM_TypeDef* tim;
|
||||||
|
static vars_t* vars;
|
||||||
|
|
||||||
|
/* data variables */
|
||||||
|
static const char* ui_default[] = {
|
||||||
|
"SILO: Te: ""\xDF""C",
|
||||||
|
"1: ""\xDF""C 2: ""\xDF""C"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char* ui_menu[] = {
|
||||||
|
" 1-Retour",
|
||||||
|
" 2-Silo:",
|
||||||
|
" 3-Start:",
|
||||||
|
" 4-Stop:",
|
||||||
|
// " 5-Calibrer Te",
|
||||||
|
// " 6-Calibrer T1",
|
||||||
|
// " 7-Calibrer T2",
|
||||||
|
// " 8-Test ventil",
|
||||||
|
" 1-Retour"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char* ui_interact[] = {
|
||||||
|
" lue: ""\xDF""C",
|
||||||
|
" reelle: ""\xDF""C"
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/* internal functions */
|
||||||
|
void show_bg(const char** bg) {
|
||||||
|
lcd_send_cmd(LCD_CLEAR);
|
||||||
|
lcd_send_cmd(LCD_CUR_HOME);
|
||||||
|
lcd_print(bg[0]);
|
||||||
|
lcd_set_cursor(0,1);
|
||||||
|
lcd_print(bg[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_entry(uint8_t prev_entry, uint8_t value) {
|
||||||
|
// get vlaue in str form
|
||||||
|
char str[8]; //too long to be sure
|
||||||
|
num2str(str, value, 10);
|
||||||
|
|
||||||
|
// print value in the correct position
|
||||||
|
if(sel == prev_entry) lcd_set_cursor(14, 1);
|
||||||
|
else lcd_set_cursor(14, 0);
|
||||||
|
lcd_print(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void change_value(uint8_t entry, uint8_t* entry_val, int max) {
|
||||||
|
int local_val = *entry_val;
|
||||||
|
lcd_set_cursor(14,0);
|
||||||
|
while(!button_update) {
|
||||||
|
local_val = ((enc->CNT/2)%max) + 1;
|
||||||
|
char str[8];
|
||||||
|
num2str(str, local_val, 10);
|
||||||
|
lcd_print(str);
|
||||||
|
lcd_set_cursor(14,0);
|
||||||
|
timer_wait_ms(TIM1, 200, 0);
|
||||||
|
}
|
||||||
|
*entry_val = local_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void interact(uint8_t entry, uint8_t* entry_val) {
|
||||||
|
while(!button_update) {
|
||||||
|
lcd_set_cursor(10,0);
|
||||||
|
lcd_print(" ");
|
||||||
|
lcd_set_cursor(10,0);
|
||||||
|
|
||||||
|
lcd_set_cursor(10,0);
|
||||||
|
lcd_print(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/* timeout timer cb */
|
||||||
|
static void ui_sleep(void) {
|
||||||
|
state = UI_SLEEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* encoder button gpio cb */
|
||||||
|
static void ui_button_cb(void) {
|
||||||
|
for(int i=0; i<1000000; ++i); //avoid double trigger
|
||||||
|
timer_start(tim);
|
||||||
|
button_update = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/* main functions */
|
||||||
|
int ui_init(TIM_TypeDef* encoder, TIM_TypeDef* timeout, vars_t* vars_p) {
|
||||||
|
// save parameters
|
||||||
|
enc = encoder;
|
||||||
|
tim = timeout;
|
||||||
|
vars = vars_p;
|
||||||
|
|
||||||
|
// configure lcd
|
||||||
|
lcd_init(TIM1, 16, 2);
|
||||||
|
lcd_send_cmd(LCD_CUR_HOME);
|
||||||
|
lcd_print(ui_default[0]);
|
||||||
|
lcd_set_cursor(0, 1);
|
||||||
|
lcd_print(ui_default[1]);
|
||||||
|
lcd_send_cmd(LCD_DISP_CTRL | LCD_CTRL_DISP_ON | LCD_CTRL_CUR_OFF |
|
||||||
|
LCD_CTRL_BLINK_OFF);
|
||||||
|
|
||||||
|
// configure encoder
|
||||||
|
io_configure(GPIOB, PIN_6 | PIN_7, IO_MODE_INPUT | IO_IN_FLOATING, 0);
|
||||||
|
timer_enc_init(enc); //TODO fix weird behaviour around 0
|
||||||
|
|
||||||
|
io_configure(GPIOB, PIN_8, IO_MODE_INPUT | IO_IN_PULL_UP |
|
||||||
|
IO_IRQ_EDGE_FALL, ui_button_cb);
|
||||||
|
|
||||||
|
// setup state variables
|
||||||
|
state = UI_SLEEP;
|
||||||
|
sel = 0;
|
||||||
|
prev_sel = -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_update(void) {
|
||||||
|
// manage button press
|
||||||
|
if(button_update) {
|
||||||
|
button_update = 0;
|
||||||
|
|
||||||
|
switch(state) {
|
||||||
|
//-------------------------
|
||||||
|
case UI_DEFAULT:
|
||||||
|
// reset encoder and previous values
|
||||||
|
timer_start(enc);
|
||||||
|
sel = 0;
|
||||||
|
prev_sel = -1;
|
||||||
|
|
||||||
|
// go to menu screen
|
||||||
|
state = UI_MENU;
|
||||||
|
break;
|
||||||
|
//-------------------------
|
||||||
|
case UI_MENU:
|
||||||
|
// go back to default screen whith return
|
||||||
|
if(sel == UI_RETURN) {
|
||||||
|
show_bg(ui_default);
|
||||||
|
lcd_set_cursor(5,0);
|
||||||
|
char str[4];
|
||||||
|
num2str(str, vars->silo, 10);
|
||||||
|
lcd_print(str);
|
||||||
|
|
||||||
|
state = UI_DEFAULT;
|
||||||
|
for(int i=0; i<3; ++i) ui_update_temp(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise interact with option
|
||||||
|
if(sel == UI_CAL_T_EXT || sel == UI_CAL_T1
|
||||||
|
|| sel == UI_CAL_T2) {
|
||||||
|
show_bg(ui_interact);
|
||||||
|
}
|
||||||
|
lcd_send_cmd(LCD_DISP_CTRL | LCD_CTRL_DISP_ON |
|
||||||
|
LCD_CTRL_CUR_ON | LCD_CTRL_BLINK_OFF);
|
||||||
|
timer_start(enc);
|
||||||
|
state = UI_INTERACT;
|
||||||
|
break;
|
||||||
|
//-------------------------
|
||||||
|
case UI_INTERACT:
|
||||||
|
state = UI_MENU;
|
||||||
|
lcd_send_cmd(LCD_DISP_CTRL | LCD_CTRL_DISP_ON |
|
||||||
|
LCD_CTRL_CUR_OFF | LCD_CTRL_BLINK_OFF);
|
||||||
|
break;
|
||||||
|
//-------------------------
|
||||||
|
case UI_SLEEP:
|
||||||
|
// re-enable screen
|
||||||
|
lcd_send_cmd(LCD_DISP_CTRL | LCD_CTRL_DISP_ON | LCD_CTRL_CUR_OFF
|
||||||
|
| LCD_CTRL_BLINK_OFF);
|
||||||
|
|
||||||
|
|
||||||
|
// re-enable timeout system
|
||||||
|
timer_wait_ms(tim, TIMEOUT_LENGHT, ui_sleep);
|
||||||
|
|
||||||
|
// go back to default screen
|
||||||
|
show_bg(ui_default);
|
||||||
|
lcd_set_cursor(5,0);
|
||||||
|
char str[4];
|
||||||
|
num2str(str, vars->silo, 10);
|
||||||
|
lcd_print(str);
|
||||||
|
|
||||||
|
state = UI_DEFAULT;
|
||||||
|
for(int i=0; i<3; ++i) ui_update_temp(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// manage dynamic draw
|
||||||
|
switch(state) {
|
||||||
|
//---------------------
|
||||||
|
case UI_MENU:
|
||||||
|
// get current encoder value
|
||||||
|
sel = (enc->CNT/2)%(MENU_LENGHT+1);
|
||||||
|
|
||||||
|
// refresh menu if selected item changed
|
||||||
|
if(sel != prev_sel) {
|
||||||
|
prev_sel = sel;
|
||||||
|
timer_start(tim); //refresh timeout timer
|
||||||
|
show_bg(ui_menu + sel);
|
||||||
|
lcd_send_cmd(LCD_CUR_HOME);
|
||||||
|
lcd_print_c(0x7E);
|
||||||
|
|
||||||
|
// show silo value if needed
|
||||||
|
if(sel == UI_RETURN || sel == UI_SILO) {
|
||||||
|
update_entry(UI_RETURN, vars->silo);
|
||||||
|
}
|
||||||
|
// show start value if needed
|
||||||
|
if(sel == UI_SILO || sel == UI_START) {
|
||||||
|
update_entry(UI_SILO, vars->start_treshold);
|
||||||
|
}
|
||||||
|
// show start value if needed
|
||||||
|
if(sel == UI_START || sel == UI_STOP) {
|
||||||
|
update_entry(UI_START, vars->stop_treshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
//---------------------
|
||||||
|
case UI_INTERACT:
|
||||||
|
switch(sel) {
|
||||||
|
case UI_SILO:
|
||||||
|
change_value(UI_SILO, &vars->silo, 2);
|
||||||
|
break;
|
||||||
|
case UI_START:
|
||||||
|
change_value(UI_START, &vars->start_treshold, 9);
|
||||||
|
break;
|
||||||
|
case UI_STOP:
|
||||||
|
change_value(UI_STOP, &vars->stop_treshold, 9);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//---------------------
|
||||||
|
case UI_DEFAULT:
|
||||||
|
break;
|
||||||
|
//--------------------
|
||||||
|
case UI_SLEEP:
|
||||||
|
//TODO implement backlight off
|
||||||
|
lcd_send_cmd(LCD_DISP_CTRL | LCD_CTRL_DISP_OFF | LCD_CTRL_CUR_OFF
|
||||||
|
| LCD_CTRL_BLINK_OFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t temp_pos[][2] = {
|
static uint8_t temp_pos[][2] = {
|
||||||
{11, 0},
|
{11, 0},
|
||||||
{ 2, 1},
|
{ 2, 1},
|
||||||
{11, 1}};
|
{11, 1}};
|
||||||
|
|
||||||
void update_temp(uint8_t id, int16_t t) {
|
void ui_update_temp(uint8_t id) {
|
||||||
|
if(state != UI_DEFAULT) return;
|
||||||
|
|
||||||
if(id > 2) return; //protect from overflow
|
if(id > 2) return; //protect from overflow
|
||||||
uint8_t* pos = temp_pos[id];
|
uint8_t* pos = temp_pos[id];
|
||||||
|
|
||||||
// prepare data
|
// prepare data
|
||||||
char str[16]; //longer, in case of error
|
char str[16]; //longer, in case of error
|
||||||
//t = t >> 8;
|
|
||||||
|
|
||||||
// convert int into str
|
// convert int into str
|
||||||
uint32_t nb = num2str(str, t, 10);
|
uint32_t nb = num2str(str, (vars->temps[id]), 10);
|
||||||
|
|
||||||
// clear previous text
|
// clear previous text
|
||||||
lcd_set_cursor(pos[0],pos[1]);
|
lcd_set_cursor(pos[0],pos[1]);
|
||||||
@ -41,3 +287,4 @@ void update_temp(uint8_t id, int16_t t) {
|
|||||||
// write value
|
// write value
|
||||||
lcd_print(str);
|
lcd_print(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
55
src/ui.h
55
src/ui.h
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
// drivers headers
|
// drivers headers
|
||||||
#include "drivers/lcd.h"
|
#include "drivers/lcd.h"
|
||||||
|
#include "drivers/timer.h"
|
||||||
|
|
||||||
// standard headers
|
// standard headers
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -10,20 +11,66 @@
|
|||||||
// project headers
|
// project headers
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
/** temp
|
//------------------------------------------------------------------------------
|
||||||
* list of all the temperature ids on the sreen
|
|
||||||
|
#define TIMEOUT_LENGHT 20000
|
||||||
|
|
||||||
|
/** vars_t
|
||||||
|
* structure that contains all the variables needed by the ui and used or
|
||||||
|
* created elsewhere
|
||||||
*/
|
*/
|
||||||
|
typedef struct {
|
||||||
|
int16_t temps[3];
|
||||||
|
uint8_t start_treshold;
|
||||||
|
uint8_t stop_treshold;
|
||||||
|
uint8_t facs[3][2];
|
||||||
|
uint8_t silo;
|
||||||
|
uint8_t fan;
|
||||||
|
} vars_t;
|
||||||
|
|
||||||
|
// ui enums, created to improve readability
|
||||||
enum temp {
|
enum temp {
|
||||||
T_EXT = 0,
|
T_EXT = 0,
|
||||||
T1 = 1,
|
T1 = 1,
|
||||||
T2 = 2
|
T2 = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ui_state {
|
||||||
|
UI_DEFAULT,
|
||||||
|
UI_MENU,
|
||||||
|
UI_INTERACT,
|
||||||
|
UI_SLEEP
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ui_menu {
|
||||||
|
UI_RETURN = 0,
|
||||||
|
UI_SILO = 1,
|
||||||
|
UI_START = 2,
|
||||||
|
UI_STOP = 3,
|
||||||
|
UI_CAL_T_EXT = 4,
|
||||||
|
UI_CAL_T1 = 5,
|
||||||
|
UI_CAL_T2 = 6,
|
||||||
|
UI_TEST = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MENU_LENGHT 3
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** ui_init
|
||||||
|
* init ui, using a timer for the encoder and another for the timeout delay
|
||||||
|
*/
|
||||||
|
int ui_init(TIM_TypeDef* encoder, TIM_TypeDef* timeout, vars_t* vars_p);
|
||||||
|
|
||||||
|
/** ui_update
|
||||||
|
* update the graphical elements and manages the button press
|
||||||
|
* should be called quite often for a smooth usage
|
||||||
|
*/
|
||||||
|
void ui_update(void);
|
||||||
|
|
||||||
/** update_temp
|
/** update_temp
|
||||||
* update on the lcd the given value for the corresponding id
|
* update on the lcd the given value for the corresponding id
|
||||||
*/
|
*/
|
||||||
void update_temp(uint8_t id, int16_t t_ext);
|
void ui_update_temp(uint8_t id);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -6,5 +6,7 @@
|
|||||||
|
|
||||||
uint32_t num2str(char *s, int number, uint8_t base);
|
uint32_t num2str(char *s, int number, uint8_t base);
|
||||||
|
|
||||||
|
//void print_num(int number,
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user