Compare commits
10 Commits
a03d0705f5
...
3320788caf
| Author | SHA1 | Date | |
|---|---|---|---|
| 3320788caf | |||
| d45581b5b8 | |||
| 334ce3fafb | |||
| ce6bc8a8a9 | |||
| eea8c015c0 | |||
| 481bf3aa70 | |||
| 8d94bd87a2 | |||
| 7133f54617 | |||
| f1262d099b | |||
| 295c5b1ccf |
56
Makefile
56
Makefile
@@ -10,10 +10,9 @@
|
|||||||
|
|
||||||
VERBOSE := false
|
VERBOSE := false
|
||||||
ARCH := m1284
|
ARCH := m1284
|
||||||
#FREQ := 18432000UL
|
|
||||||
FREQ := 8000000UL
|
|
||||||
MCU := atmega1284p
|
MCU := atmega1284p
|
||||||
ASP := usbasp
|
FREQ := 18432000UL
|
||||||
|
ISP := usbasp
|
||||||
CC := avr-gcc
|
CC := avr-gcc
|
||||||
LD := $(CC)
|
LD := $(CC)
|
||||||
OBJCOPY := avr-objcopy
|
OBJCOPY := avr-objcopy
|
||||||
@@ -23,6 +22,11 @@ MKDIR := mkdir -p
|
|||||||
RMR := rm -rf
|
RMR := rm -rf
|
||||||
GIT := git
|
GIT := git
|
||||||
|
|
||||||
|
LFUSE := 0xF7
|
||||||
|
HFUSE := 0x97
|
||||||
|
EFUSE := 0xFF
|
||||||
|
LOCK := 0xFF
|
||||||
|
|
||||||
SRCDIR := src
|
SRCDIR := src
|
||||||
BINDIR := bin
|
BINDIR := bin
|
||||||
TMPDIR := $(BINDIR)/build
|
TMPDIR := $(BINDIR)/build
|
||||||
@@ -47,7 +51,7 @@ OBJECTS := $(FILES:%.c=$(TMPDIR)/%.o)
|
|||||||
DEPENDS := $(FILES:%.c=$(TMPDIR)/%.d)
|
DEPENDS := $(FILES:%.c=$(TMPDIR)/%.d)
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# AUXILIARY TARGETS (AND FUSE SETTINGS)
|
# AUXILIARY TARGETS
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
@@ -57,18 +61,33 @@ all: flash
|
|||||||
flash: $(TARGET)
|
flash: $(TARGET)
|
||||||
$(E) "[AVD] Flashing..."
|
$(E) "[AVD] Flashing..."
|
||||||
$(Q) $(AVD) -l $(LOGFILE) \
|
$(Q) $(AVD) -l $(LOGFILE) \
|
||||||
-c $(ASP) -p $(ARCH) \
|
-c $(ISP) -p $(ARCH) \
|
||||||
-U lfuse:w:0xC2:m \
|
-U lfuse:w:$(LFUSE):m \
|
||||||
-U hfuse:w:0x97:m \
|
-U hfuse:w:$(HFUSE):m \
|
||||||
-U efuse:w:0xFF:m \
|
-U efuse:w:$(EFUSE):m \
|
||||||
-U lock:w:0xFF:m \
|
-U lock:w:$(LOCK):m \
|
||||||
-U flash:w:$<
|
-U flash:w:$<
|
||||||
|
|
||||||
.PHONY: run
|
.PHONY: check
|
||||||
run: $(TARGET)
|
check: # Will be added at later stage
|
||||||
|
$(E) "[CHK] Not implemented."
|
||||||
|
$(Q) true
|
||||||
|
|
||||||
|
.PHONY: simulate
|
||||||
|
simulate: $(TARGET)
|
||||||
$(E) "[SIM] $<"
|
$(E) "[SIM] $<"
|
||||||
$(Q) $(SIM) -m $(MCU) -f $(FREQ) $<
|
$(Q) $(SIM) -m $(MCU) -f $(FREQ) $<
|
||||||
|
|
||||||
|
.PHONY: listen
|
||||||
|
listen: opt/tools/serial-listen
|
||||||
|
$(E) "[RUN] $<"
|
||||||
|
$(Q) ./$<
|
||||||
|
|
||||||
|
.PHONY: webgui
|
||||||
|
webgui: opt/webgui/Makefile
|
||||||
|
$(E) "[MAK] $<"
|
||||||
|
$(Q) $(MAKE) -sC $(<D)
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
$(E) "[REM] $(TARGET)"
|
$(E) "[REM] $(TARGET)"
|
||||||
@@ -85,21 +104,6 @@ distclean: clean
|
|||||||
$(E) "[REM] $(BINDIR)"
|
$(E) "[REM] $(BINDIR)"
|
||||||
$(Q) $(RMR) $(BINDIR)
|
$(Q) $(RMR) $(BINDIR)
|
||||||
|
|
||||||
.PHONY: check
|
|
||||||
check:
|
|
||||||
$(E) "[CHK] Not implemented."
|
|
||||||
$(Q) true
|
|
||||||
|
|
||||||
.PHONY: listen
|
|
||||||
listen: opt/tools/serial-listen
|
|
||||||
$(E) "[RUN] $<"
|
|
||||||
$(Q) ./$<
|
|
||||||
|
|
||||||
.PHONY: webgui
|
|
||||||
webgui: opt/webgui/Makefile
|
|
||||||
$(E) "[MAK] $<"
|
|
||||||
$(Q) $(MAKE) -sC $(<D)
|
|
||||||
|
|
||||||
$(TMPDIRS):
|
$(TMPDIRS):
|
||||||
$(E) "[DIR] $@"
|
$(E) "[DIR] $@"
|
||||||
$(Q) $(MKDIR) $@
|
$(Q) $(MKDIR) $@
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
### v0.75-alpha2
|
### v0.75-alpha2
|
||||||
- Use internal oscillator without CKDIV8.
|
|
||||||
- Increase available memory to 4096 bytes.
|
- Increase available memory to 4096 bytes.
|
||||||
|
- Use external 18.432 MHz crystal oscillator.
|
||||||
|
- Consolidate unfinished tasks and update documentation.
|
||||||
|
- Add papers describing PID controller implementation.
|
||||||
|
- Move fuse Makefile variables to general settings.
|
||||||
- Change ARCH and MCU settings to match chip signature.
|
- Change ARCH and MCU settings to match chip signature.
|
||||||
- Update module 'pwm' to run on atmega1284p hardware.
|
- Update module 'pwm' to run on atmega1284p hardware.
|
||||||
- Update module 'usart' to run on atmega1284p hardware.
|
- Update module 'uart' to run on atmega1284p hardware.
|
||||||
- Update module 'watchdog' to run on atmega1284p hardware.
|
- Update module 'watchdog' to run on atmega1284p hardware.
|
||||||
- Update module 'memory' to run on atmega1284p hardware.
|
- Update module 'memory' to run on atmega1284p hardware.
|
||||||
- Update Makefile settings for new chip architecture.
|
- Update Makefile settings for new chip architecture.
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
## License
|
||||||
|
|
||||||
All Rights Reserved
|
All Rights Reserved
|
||||||
|
|
||||||
Copyright (c) 2024 Madcow Software
|
Copyright (c) 2024 Madcow Software
|
||||||
|
|||||||
17
docs/PINOUT.md
Normal file
17
docs/PINOUT.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
## Pinout Reference
|
||||||
|
|
||||||
|
The table below is a cross-reference for all active pins on
|
||||||
|
the microcontroller and their respective purpose:
|
||||||
|
|
||||||
|
| Pin | Name | Function |
|
||||||
|
| ---- | ----- | ------------------------- |
|
||||||
|
| PB0 | MOS01 | MOSFET Peltier enable |
|
||||||
|
| PB1 | MOS02 | MOSFET Heating enable |
|
||||||
|
| PB2 | MOS03 | MOSFET Lights enable |
|
||||||
|
| PC0 | TWSCL | I2C Primary data bus SCL |
|
||||||
|
| PC1 | TWSDA | I2C Primary data bus SDA |
|
||||||
|
| PD0 | UADRX | UART Debug interface RX |
|
||||||
|
| PD1 | UADTX | UART Debug interface TX |
|
||||||
|
| PD4 | FAN01 | PWM Fan peltier hot side |
|
||||||
|
| PD5 | FAN02 | PWM Fan peltier cold side |
|
||||||
|
| PD7 | FAN03 | PWM Fan heating element |
|
||||||
@@ -31,21 +31,24 @@ Makefile for all build settings and make sure they are
|
|||||||
correct for your current environment.
|
correct for your current environment.
|
||||||
|
|
||||||
To remove build-related auxiliary files you may use one
|
To remove build-related auxiliary files you may use one
|
||||||
of these commands:
|
of these commands, with varying levels of cleanliness:
|
||||||
|
|
||||||
make clean
|
make clean
|
||||||
make distclean
|
make distclean
|
||||||
|
|
||||||
Isolated unit tests allow you to verify all testable
|
Isolated unit tests allow you to verify all source modules
|
||||||
components are behaving as expected. Please note that most
|
are behaving as expected. Please note that most tests will
|
||||||
tests will be added later down the road, when the project
|
be added later down the road, when the project has reached
|
||||||
has reached a more mature state.
|
a more mature state. There is also support for running the
|
||||||
|
binaries on simulated hardware if you have
|
||||||
|
[simavr](https://github.com/buserror/simavr) installed.
|
||||||
|
|
||||||
make check
|
make check
|
||||||
|
make simulate
|
||||||
|
|
||||||
You can listen on the serial debug interface by running
|
You can listen on the serial debug interface by executing
|
||||||
the command below. This will also initialize all optional
|
the command below. Optional submodules will be initialized
|
||||||
submodules on first invocation.
|
on first invocation since they contain the necessary tools.
|
||||||
|
|
||||||
make listen
|
make listen
|
||||||
|
|
||||||
|
|||||||
22
docs/TODO.md
Normal file
22
docs/TODO.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
## Current Tasks
|
||||||
|
|
||||||
|
- Implement state machine for actual drying operation.
|
||||||
|
- Rewrite code documentation with proper structure.
|
||||||
|
- Check sensor measurements, conversion results and timer output frequencies.
|
||||||
|
- Implement custom bootloader to facilitate software updates over serial port.
|
||||||
|
- Make sure the initialization sequence can recover from as many technical
|
||||||
|
problems as possible.
|
||||||
|
- Implement I2C timeout or failing components may cause watchdog reset loop.
|
||||||
|
- Detect brown-out and external resets during the initialization sequence.
|
||||||
|
- Write isolated unit tests either with mocks or running in simulation.
|
||||||
|
- Write simulated I2C components for more realistic testing with simavr.
|
||||||
|
- MOSFET module needlessly specific? Rewrite as generic digital output?
|
||||||
|
- Handle more parser commands like UPDATE, START and STOP.
|
||||||
|
- Implement parser timeout for large input. Otherwise an UART RX buffer overflow
|
||||||
|
will swallow the line terminator leading to the next command not getting parsed
|
||||||
|
correctly. Also check for possible edge cases when the UART and parser buffers
|
||||||
|
have different sizes.
|
||||||
|
- Force system reset in Error() function?
|
||||||
|
- Test efficiency for I2C via interrupts and ADS1115 continous mode.
|
||||||
|
- Write cross-platform configuration header for different microchips?
|
||||||
|
- Refactoring and optimization after all v1.0 features are finalized.
|
||||||
BIN
docs/external/PIDC-01.pdf
vendored
Normal file
BIN
docs/external/PIDC-01.pdf
vendored
Normal file
Binary file not shown.
BIN
docs/external/PIDC-02.pdf
vendored
Normal file
BIN
docs/external/PIDC-02.pdf
vendored
Normal file
Binary file not shown.
BIN
docs/external/PIDC-03.pdf
vendored
Normal file
BIN
docs/external/PIDC-03.pdf
vendored
Normal file
Binary file not shown.
Submodule opt/tools updated: ebe9e06e50...16fb890c1e
@@ -14,12 +14,6 @@
|
|||||||
#define TW_MR_SLA_NACK 0x48 // SLA+R transmitted, NACK received
|
#define TW_MR_SLA_NACK 0x48 // SLA+R transmitted, NACK received
|
||||||
#define TW_MR_DATA_ACK 0x50 // Data received, ACK returned
|
#define TW_MR_DATA_ACK 0x50 // Data received, ACK returned
|
||||||
|
|
||||||
// TODO: Error handling and recovery besides watchdog timer.
|
|
||||||
// TODO: Add more documentation from the atmel data sheet.
|
|
||||||
// TODO: ADS1115 continuous mode instead of single-shot?
|
|
||||||
// TODO: Implement TWI_vect ISR? This may not actually be
|
|
||||||
// much better than the blocking approach.
|
|
||||||
|
|
||||||
static void I2C_AHT20_Reset(void);
|
static void I2C_AHT20_Reset(void);
|
||||||
static bool I2C_AHT20_IsCalibrated(void);
|
static bool I2C_AHT20_IsCalibrated(void);
|
||||||
static void I2C_AHT20_Calibrate(void);
|
static void I2C_AHT20_Calibrate(void);
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "bus/pwm.h"
|
#include "bus/pwm.h"
|
||||||
|
|
||||||
// TODO: Add documentation for timer3: TCCR3A, TCCR3B, etc.
|
|
||||||
|
|
||||||
int PWM_Init(void)
|
int PWM_Init(void)
|
||||||
{
|
{
|
||||||
// PD4: PWM NF-12 Fan Peltier Hot Side
|
// PD4: PWM NF-12 Fan Peltier Hot Side
|
||||||
@@ -102,15 +100,8 @@ void PWM_SetValue(int port, int value)
|
|||||||
if (port != FAN01 && port != FAN02 && port != FAN03)
|
if (port != FAN01 && port != FAN02 && port != FAN03)
|
||||||
return; // Invalid port
|
return; // Invalid port
|
||||||
|
|
||||||
// Workaround: Missing third 16-bit timer output
|
|
||||||
n = CLAMP(value, 100, 0) * PWM_CYCLE_TOP / 100.0f;
|
n = CLAMP(value, 100, 0) * PWM_CYCLE_TOP / 100.0f;
|
||||||
|
|
||||||
Info("Setting duty cycle for %s to %d/%d...",
|
|
||||||
(port == FAN01) ? "FAN01" :
|
|
||||||
(port == FAN02) ? "FAN02" :
|
|
||||||
(port == FAN03) ? "FAN03" :
|
|
||||||
"UNKNOWN", n, PWM_CYCLE_TOP);
|
|
||||||
|
|
||||||
switch (port) {
|
switch (port) {
|
||||||
case PD4: OCR1B = n; break;
|
case PD4: OCR1B = n; break;
|
||||||
case PD5: OCR1A = n; break;
|
case PD5: OCR1A = n; break;
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "bus/usart.h"
|
#include "bus/uart.h"
|
||||||
|
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
#include <avr/interrupt.h>
|
#include <avr/interrupt.h>
|
||||||
|
|
||||||
#define USART_BAUDRATE 9600
|
#define UART_BAUDRATE 9600
|
||||||
#define USART_RXBUF_SIZE 128
|
#define UART_RXBUF_SIZE 128
|
||||||
#define USART_TXBUF_SIZE 128
|
#define UART_TXBUF_SIZE 128
|
||||||
|
|
||||||
#define USART_RXBUF_MASK (USART_RXBUF_SIZE - 1)
|
#define UART_RXBUF_MASK (UART_RXBUF_SIZE - 1)
|
||||||
#define USART_TXBUF_MASK (USART_TXBUF_SIZE - 1)
|
#define UART_TXBUF_MASK (UART_TXBUF_SIZE - 1)
|
||||||
#define USART_BAUD_PRESCALE ((((F_CPU / 16) + \
|
#define UART_BAUD_PRESCALE ((((F_CPU / 16) + \
|
||||||
(USART_BAUDRATE / 2)) / (USART_BAUDRATE)) - 1)
|
(UART_BAUDRATE / 2)) / (UART_BAUDRATE)) - 1)
|
||||||
|
|
||||||
static volatile char rxbuf[USART_RXBUF_SIZE]; // RX ring buffer
|
static volatile char rxbuf[UART_RXBUF_SIZE]; // RX ring buffer
|
||||||
static volatile char txbuf[USART_TXBUF_SIZE]; // TX ring buffer
|
static volatile char txbuf[UART_TXBUF_SIZE]; // TX ring buffer
|
||||||
static volatile short rxhead, txhead; // Current write position
|
static volatile short rxhead, txhead; // Current write position
|
||||||
static volatile short rxtail, txtail; // Current read position
|
static volatile short rxtail, txtail; // Current read position
|
||||||
|
|
||||||
int USART_Init(void)
|
int UART_Init(void)
|
||||||
{
|
{
|
||||||
rxhead = 0;
|
rxhead = 0;
|
||||||
rxtail = 0;
|
rxtail = 0;
|
||||||
@@ -28,29 +28,29 @@ int USART_Init(void)
|
|||||||
UCSR0B = BIT(RXCIE0); // Handle RXC interrupts
|
UCSR0B = BIT(RXCIE0); // Handle RXC interrupts
|
||||||
UCSR0B |= BIT(RXEN0) | BIT(TXEN0); // Enable RX and TX circuitry
|
UCSR0B |= BIT(RXEN0) | BIT(TXEN0); // Enable RX and TX circuitry
|
||||||
UCSR0C = BIT(UCSZ01) | BIT(UCSZ00); // 8-bit data, 1-bit stop, no parity
|
UCSR0C = BIT(UCSZ01) | BIT(UCSZ00); // 8-bit data, 1-bit stop, no parity
|
||||||
UBRR0H = (USART_BAUD_PRESCALE >> 8); // Set baud rate upper byte
|
UBRR0H = (UART_BAUD_PRESCALE >> 8); // Set baud rate upper byte
|
||||||
UBRR0L = USART_BAUD_PRESCALE; // Set baud rate lower byte
|
UBRR0L = UART_BAUD_PRESCALE; // Set baud rate lower byte
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char USART_Getc(void)
|
char UART_Getc(void)
|
||||||
{
|
{
|
||||||
if (rxhead == rxtail) {
|
if (rxhead == rxtail) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rxtail = (rxtail + 1) & USART_RXBUF_MASK;
|
rxtail = (rxtail + 1) & UART_RXBUF_MASK;
|
||||||
|
|
||||||
return rxbuf[rxtail];
|
return rxbuf[rxtail];
|
||||||
}
|
}
|
||||||
|
|
||||||
void USART_Putc(char ch)
|
void UART_Putc(char ch)
|
||||||
{
|
{
|
||||||
short head;
|
short head;
|
||||||
|
|
||||||
// Wrap around if end of buffer reached
|
// Wrap around if end of buffer reached
|
||||||
head = (txhead + 1) & USART_TXBUF_MASK;
|
head = (txhead + 1) & UART_TXBUF_MASK;
|
||||||
while (head == txtail); // Wait for space
|
while (head == txtail); // Wait for space
|
||||||
|
|
||||||
txbuf[head] = ch;
|
txbuf[head] = ch;
|
||||||
@@ -69,7 +69,7 @@ ISR(USART0_RX_vect)
|
|||||||
data = UDR0; // Next byte ready
|
data = UDR0; // Next byte ready
|
||||||
|
|
||||||
// Wrap around if end of buffer reached
|
// Wrap around if end of buffer reached
|
||||||
head = (rxhead + 1) & USART_RXBUF_MASK;
|
head = (rxhead + 1) & UART_RXBUF_MASK;
|
||||||
|
|
||||||
// Free space in RX buffer?
|
// Free space in RX buffer?
|
||||||
// Otherwise discard overflow
|
// Otherwise discard overflow
|
||||||
@@ -87,7 +87,7 @@ ISR(USART0_UDRE_vect)
|
|||||||
// Anything in TX buffer?
|
// Anything in TX buffer?
|
||||||
if (txhead != txtail) {
|
if (txhead != txtail) {
|
||||||
// Write next byte to data register
|
// Write next byte to data register
|
||||||
tail = (txtail + 1) & USART_TXBUF_MASK;
|
tail = (txtail + 1) & UART_TXBUF_MASK;
|
||||||
UDR0 = txbuf[tail];
|
UDR0 = txbuf[tail];
|
||||||
txtail = tail;
|
txtail = tail;
|
||||||
} else {
|
} else {
|
||||||
8
src/bus/uart.h
Normal file
8
src/bus/uart.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef MAD_CORE_BUS_UART_H
|
||||||
|
#define MAD_CORE_BUS_UART_H
|
||||||
|
|
||||||
|
int UART_Init(void);
|
||||||
|
void UART_Putc(char ch);
|
||||||
|
char UART_Getc(void);
|
||||||
|
|
||||||
|
#endif // MAD_CORE_BUS_UART_H
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#ifndef MAD_CORE_BUS_USART_H
|
|
||||||
#define MAD_CORE_BUS_USART_H
|
|
||||||
|
|
||||||
int USART_Init(void);
|
|
||||||
void USART_Putc(char ch);
|
|
||||||
char USART_Getc(void);
|
|
||||||
|
|
||||||
#endif // MAD_CORE_BUS_USART_H
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "bus/usart.h"
|
#include "bus/uart.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ void Error(const char *fmt, ...)
|
|||||||
static void Puts(const char *str)
|
static void Puts(const char *str)
|
||||||
{
|
{
|
||||||
while (*str != '\0') {
|
while (*str != '\0') {
|
||||||
USART_Putc(*str++);
|
UART_Putc(*str++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,6 @@
|
|||||||
|
|
||||||
#define CMD_MAX_LEN 128
|
#define CMD_MAX_LEN 128
|
||||||
|
|
||||||
// TODO: Write documentation.
|
|
||||||
// TODO: Reset command buffer on timeout.
|
|
||||||
// TODO: Test with different RXBUF sizes.
|
|
||||||
// TODO: Add commands update, start and stop.
|
|
||||||
|
|
||||||
static char cmdbuf[CMD_MAX_LEN + 1];
|
static char cmdbuf[CMD_MAX_LEN + 1];
|
||||||
static char *tail = cmdbuf + CMD_MAX_LEN;
|
static char *tail = cmdbuf + CMD_MAX_LEN;
|
||||||
static char *head = cmdbuf;
|
static char *head = cmdbuf;
|
||||||
|
|||||||
75
src/main.c
75
src/main.c
@@ -1,21 +1,23 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "bus/usart.h"
|
#include "bus/uart.h"
|
||||||
#include "bus/mosfet.h"
|
#include "bus/mosfet.h"
|
||||||
#include "bus/pwm.h"
|
#include "bus/pwm.h"
|
||||||
#include "bus/i2c.h"
|
#include "bus/i2c.h"
|
||||||
|
|
||||||
#include <avr/interrupt.h>
|
#include <avr/interrupt.h>
|
||||||
|
|
||||||
// TODO: Facilitate software updates over serial port.
|
#define DEADBAND 2.0f
|
||||||
// TODO: Check parser and circular buffer for edge cases.
|
#define HYSTERESIS_C 0.5f
|
||||||
// TODO: Implement command parser timeout for large input.
|
#define HYSTERESIS_H 0.5f
|
||||||
// TODO: Config header for chip specifics like EEPROM size.
|
|
||||||
// TODO: Check thermistor conversion results /w thermometer.
|
// https://en.wikipedia.org/wiki/Bang%E2%80%93bang_control
|
||||||
// TODO: Implement primary state machine for update loop.
|
// https://support.75f.io/hc/en-us/articles/360044956794-Deadband-and-Hysteresis
|
||||||
// TODO: Use 18.432MHz quarz crystal, burn required fuses.
|
// https://www.elotech.de/fileadmin/user_upload/PID-Regelungsgrundlagen.pdf
|
||||||
// TODO: Implement optional CRC8 sensor measurement check.
|
// https://thomasfermi.github.io/Algorithms-for-Automated-Driving/Control/PID.html
|
||||||
// TODO: Proper error handling and recovery (after testing).
|
// https://www.ni.com/en/shop/labview/pid-theory-explained.html
|
||||||
// TODO: Check why the MCUCSR EXTRF reset flag is set.
|
// https://en.wikipedia.org/wiki/Proportional%E2%80%93integral%E2%80%93derivative_controller
|
||||||
|
// https://ctms.engin.umich.edu/CTMS/index.php?example=Introduction§ion=ControlPID
|
||||||
|
// https://www.youtube.com/watch?v=wkfEZmsQqiA&list=PLn8PRpmsu08pQBgjxYFXSsODEF3Jqmm-y
|
||||||
|
|
||||||
enum state_e
|
enum state_e
|
||||||
{
|
{
|
||||||
@@ -52,7 +54,7 @@ static int Init(void)
|
|||||||
// IRQs, so we need to initialize it as soon as
|
// IRQs, so we need to initialize it as soon as
|
||||||
// possible and make sure to enable interrupts.
|
// possible and make sure to enable interrupts.
|
||||||
|
|
||||||
USART_Init();
|
UART_Init();
|
||||||
sei();
|
sei();
|
||||||
|
|
||||||
Info("Initializing...");
|
Info("Initializing...");
|
||||||
@@ -132,9 +134,11 @@ static void Update(void)
|
|||||||
{
|
{
|
||||||
char ch;
|
char ch;
|
||||||
cmd_t cmd;
|
cmd_t cmd;
|
||||||
|
float terr;
|
||||||
|
float derr;
|
||||||
|
|
||||||
// Parse serial commands
|
// Parse serial commands
|
||||||
while ((ch = USART_Getc()) >= 0) {
|
while ((ch = UART_Getc()) >= 0) {
|
||||||
if (!CMD_Parse(ch, &cmd)) {
|
if (!CMD_Parse(ch, &cmd)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -148,15 +152,53 @@ static void Update(void)
|
|||||||
// Get latest sensor values
|
// Get latest sensor values
|
||||||
FetchSensorValues();
|
FetchSensorValues();
|
||||||
|
|
||||||
// Handle state
|
// Two-step (bang-bang) controller testing
|
||||||
|
|
||||||
|
// TODO: Sanity check setpoint!
|
||||||
|
// TODO: Check thermistor for overheating!
|
||||||
|
// TODO: Implement control stages based on hysteresis
|
||||||
|
// TODO: PID control for fan pulse-width modulation?
|
||||||
|
|
||||||
|
// The dead band represents the lower and upper limits
|
||||||
|
// of the error between which the controller doesn’t
|
||||||
|
// react.
|
||||||
|
|
||||||
|
state = S_IDLE;
|
||||||
|
terr = temp - temp_target;
|
||||||
|
derr = dewp - dewp_target;
|
||||||
|
|
||||||
|
if (terr < -DEADBAND / 2) {
|
||||||
|
state = S_HEAT_UP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (terr > DEADBAND / 2) {
|
||||||
|
state = S_COOL_DOWN;
|
||||||
|
}
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case S_IDLE:
|
case S_IDLE:
|
||||||
|
MOS_Disable(MOS01);
|
||||||
|
MOS_Disable(MOS02);
|
||||||
|
PWM_SetValue(FAN01, 20);
|
||||||
|
PWM_SetValue(FAN02, 20);
|
||||||
|
PWM_SetValue(FAN03, 20);
|
||||||
break;
|
break;
|
||||||
case S_HEAT_UP:
|
case S_HEAT_UP:
|
||||||
|
MOS_Enable(MOS02);
|
||||||
|
MOS_Disable(MOS01);
|
||||||
|
PWM_SetValue(FAN01, 20);
|
||||||
|
PWM_SetValue(FAN02, 60);
|
||||||
|
PWM_SetValue(FAN03, 60);
|
||||||
break;
|
break;
|
||||||
case S_COOL_DOWN:
|
case S_COOL_DOWN:
|
||||||
|
MOS_Enable(MOS01);
|
||||||
|
MOS_Disable(MOS02);
|
||||||
|
PWM_SetValue(FAN01, 60);
|
||||||
|
PWM_SetValue(FAN02, 60);
|
||||||
|
PWM_SetValue(FAN03, 60);
|
||||||
break;
|
break;
|
||||||
case S_DEHUMIDIFY:
|
case S_DEHUMIDIFY:
|
||||||
|
UNUSED(derr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,6 +266,11 @@ static void FetchSensorValues(void)
|
|||||||
Info("T3=%.2fC, TD3=%.2fC, RH3=%.2f%%, NT3=%.2fC", t[2], td[2], rh[2], t[5]);
|
Info("T3=%.2fC, TD3=%.2fC, RH3=%.2f%%, NT3=%.2fC", t[2], td[2], rh[2], t[5]);
|
||||||
Info("T_AVG=%.2fC, TD_AVG=%.2fC, RH_AVG=%.2f%%", temp, dewp, rhum);
|
Info("T_AVG=%.2fC, TD_AVG=%.2fC, RH_AVG=%.2f%%", temp, dewp, rhum);
|
||||||
Info("T_TAR=%.2fC, TD_TAR=%.2fC", temp_target, dewp_target);
|
Info("T_TAR=%.2fC, TD_TAR=%.2fC", temp_target, dewp_target);
|
||||||
|
Info("STATE=%s", (state == S_IDLE) ? "S_IDLE" :
|
||||||
|
(state == S_HEAT_UP) ? "S_HEAT_UP" :
|
||||||
|
(state == S_COOL_DOWN) ? "S_COOL_DOWN" :
|
||||||
|
(state == S_DEHUMIDIFY) ? "S_DEHUMIDIFY" :
|
||||||
|
"UNKNOWN");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
|
|||||||
Reference in New Issue
Block a user