MOVED FROM SVN

This commit is contained in:
kirill.labutin 2025-01-09 20:25:44 +03:00
commit 11677dfa2b
32 changed files with 94586 additions and 0 deletions

16
Board/CMakeLists.txt Normal file
View File

@ -0,0 +1,16 @@
cmake_minimum_required(VERSION 3.17)
set(AVR_PROJECT ${CMAKE_CURRENT_SOURCE_DIR}/avr-project.cmake)
if (EXISTS ${AVR_PROJECT})
INCLUDE(${AVR_PROJECT})
else (EXISTS ${AVR_PROJECT})
set("AVR_PROJECT_NAME" "Unconfigured project")
endif (EXISTS ${AVR_PROJECT})
project(${AVR_PROJECT_NAME})
#check avr build tools installed
if (DEFINED ENV{AVR_BUILD_TOOLS})
set(BUILD_TOOLS_ROOT "$ENV{AVR_BUILD_TOOLS}")
else (DEFINED ENV{AVR_BUILD_TOOLS})
message(FATAL_ERROR "Build tools is not installed or ENV{AVR_BUILD_TOOLS} is not defined")
endif (DEFINED ENV{AVR_BUILD_TOOLS})
INCLUDE("${BUILD_TOOLS_ROOT}/scripts/commons.cmake")

1299
Board/PCB/1 - Top.gbr Normal file

File diff suppressed because it is too large Load Diff

BIN
Board/PCB/pcb.dip Normal file

Binary file not shown.

BIN
Board/PCB/regulator.dch Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

2
Board/PINS.txt Normal file
View File

@ -0,0 +1,2 @@
input = ADC6
output = PC0

18
Board/avr-project.cmake Normal file
View File

@ -0,0 +1,18 @@
set(AVR_EX_FUSE 0xFF)
set(AVR_H_FUSE 0xD7)
set(AVR_L_FUSE 0xE2)
set(AVR_MCU atmega48)
set(AVR_PROGRAMMER usbasp)
set(AVR_PROJECT_NAME cooler-controller)
set(AVR_UPLOADTOOL_PORT usb)
set(AVR_UPLOADTOOL_BITRATE 9600)
set(MCU_FREQ 8000000)
#additional compiler parameters
#set(EXTRA_FLAGS "-Wl,-u,vfprintf -lprintf_min")
#add_definitions("-Wno-shift-overflow")
#Add defines
#add_definitions("-DNAME=VALUE")
add_definitions("-DUSART_READING")

111
Board/lib/usart/usart.cpp Normal file
View File

@ -0,0 +1,111 @@
#include "usart.h"
#include <string.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <stdlib.h>
#include <math.h>
#ifdef USART_READING
int USART::bufferReadIndex = 0;
int USART::bufferWriteIndex = 0;
int USART::incomingBytes = 0;
uint8_t USART::buffer[USART_BUFFER_SIZE];
ISR(USART_RX_vect){
USART::fillBuffer(UDR0);
}
void USART::reset(){
incomingBytes=0;
bufferWriteIndex = 0;
bufferReadIndex = 0;
}
int USART::available(){
return incomingBytes;
}
void USART::fillBuffer(uint8_t byte){
incomingBytes++;
buffer[bufferWriteIndex] = byte;
bufferWriteIndex++;
if(bufferWriteIndex>=USART_BUFFER_SIZE) bufferWriteIndex=0;
}
uint8_t USART::read(){
while(!available());
uint8_t byte = buffer[bufferReadIndex];
bufferReadIndex++;
if(bufferReadIndex>=USART_BUFFER_SIZE) bufferReadIndex = 0;
incomingBytes--;
return byte;
}
#endif
USART::USART(uint32_t baud_rate) {
uint32_t UBRR_VALUE = ((uint32_t) F_CPU) / 8 / baud_rate - 1;
UBRR0H = (uint8_t) (UBRR_VALUE >> 8);
UBRR0L = (uint8_t) (UBRR_VALUE);
#ifdef USART_READING
UCSR0B = (1<<TXEN0)|(1<<RXEN0)|(1<<RXCIE0);
#else
UCSR0B = (1 << TXEN0);
#endif
UCSR0A |= (1 << U2X0);
UCSR0C = (1 << USBS0) | (1 << UCSZ01) | (1 << UCSZ00);
}
void USART::waitForBufferBeFree() {
while (!(UCSR0A & (1 << UDRE0)));
}
void USART::send(uint8_t b) {
waitForBufferBeFree();
UDR0 = b;
}
void USART::send(void *ptr, size_t count) {
for (size_t i = 0; i < count; i++) send(((uint8_t *) ptr)[i]);
}
void USART::send(char *string) {
send(string, strlen(string));
}
void USART::send_P(const char *string) {
for (size_t i = 0; i < strlen_P(string); i++) send(pgm_read_byte(string + i));
}
void USART::sendFloat(float f, uint8_t p) {
int64_t value = f;
float frac = f-value;
frac*=pow(10, p);
char str[64];
itoa(value, str, 10);
send(str);
value = frac;
if(value > 0){
send('.');
itoa(value, str, 10);
uint8_t d = p - strlen(str);
for(uint8_t i=0;i<d;i++) send('0');
send(str);
}else{
send('.');
send('0');
}
}
void USART::sendInt(int64_t i, int radix) {
char str[64];
itoa(i, str, radix);
send(str);
}

42
Board/lib/usart/usart.h Normal file
View File

@ -0,0 +1,42 @@

#ifndef USART_H_
#define USART_H_
#include <avr/io.h>
#include <avr/pgmspace.h>
#ifndef USART_BUFFER_SIZE
#define USART_BUFFER_SIZE 10
#endif
#ifndef F_CPU
#warning "F_CPU is used to calculate baud rate and should be defined!"
#define F_CPU 1000000UL
#endif
class USART{
public:
USART(uint32_t baud_rate);
void send(uint8_t b);
void send(void*ptr, size_t count);
void send(char * string);
void send_P(const char * string);
void sendFloat(float f, uint8_t p);
void sendInt(int64_t i, int radix);
#ifdef USART_READING
uint8_t read();
static void fillBuffer(uint8_t byte);
int available();
void reset();
#endif
private:
#ifdef USART_READING
static uint8_t buffer[USART_BUFFER_SIZE];
static int bufferReadIndex;
static int bufferWriteIndex;
static int incomingBytes;
#endif
void waitForBufferBeFree();
};
#endif

24
Board/lib/utils/ADC.cpp Normal file
View File

@ -0,0 +1,24 @@
//
// Created by User on 018 18.05.20.
//
#include "ADC.h"
#define ADC_PORT_SELECTION_MASK ((1<<REFS0) | (1<<REFS1) | (1<<ADLAR))
void ADCIO::setup() {
ADCSRA |= (1<<ADEN); //включаем ADC
ADCSRA |= (1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2);//выставляем делитель частоты 128
ADMUX |= (1<<REFS0); //используем внешнее опорное напряжение
}
uint16_t ADCIO::read(ADCPort port) {
ADMUX &= ADC_PORT_SELECTION_MASK;
ADMUX |= port;
uint16_t result = 0;
for(uint8_t i=0;i<ADC_READ_COUNT;i++){
ADCSRA |= (1<<ADSC);//включаем АЦП
while((ADCSRA & (1<<ADSC))); //ждём готовность
result+=(uint16_t)ADCW;
}
return result/ADC_READ_COUNT;
}

27
Board/lib/utils/ADC.h Normal file
View File

@ -0,0 +1,27 @@
//
// Created by User on 018 18.05.20.
//
#ifndef AVR_IOHELP_ADC_H
#define AVR_IOHELP_ADC_H
#include <avr/io.h>
#define ADC_READ_COUNT 5
enum ADCPort{
ADC0 = 0x00,
ADC1 = 0x01,
ADC2 = 0x02,
ADC3 = 0x03,
ADC4 = 0x04,
ADC5 = 0x05,
ADC6 = 0x06,
ADC7 = 0x07
//ADC8_INTERNAL = 0b1000
};
namespace ADCIO{
void setup();
uint16_t read(ADCPort port);
}
#endif //AVR_IOHELP_ADC_H

View File

@ -0,0 +1,43 @@
#include "EEPROM.h"
namespace EEPROM {
void set(uint16_t address, uint8_t data) {
if (get(address) != data) {
/* Wait for completion of previous write */
while (EECR & (1 << EEPE));
/* Set up address and Data Registers */
EEAR = address;
EEDR = data;
/* Write logical one to EEMPE */
EECR |= (1 << EEMPE);
/* Start eeprom write by setting EEPE */
EECR |= (1 << EEPE);
}
}
void set(uint16_t address, void *dataSource, size_t dataSize) {
uint8_t *data = (uint8_t *) dataSource;
for (size_t i = 0; i < dataSize; i++) {
set(address + i, data[i]);
}
}
uint8_t get(uint16_t address) {
/* Wait for completion of previous write */
while (EECR & (1 << EEPE));
/* Set up address register */
EEAR = address;
/* Start eeprom read by writing EERE */
EECR |= (1 << EERE);
/* Return data from Data Register */
return EEDR;
}
void get(uint16_t address, void *dataDest, size_t dataSize) {
uint8_t *data = (uint8_t *) dataDest;
for (size_t i = 0; i < dataSize; i++) {
data[i] = get(address + i);
}
}
}

15
Board/lib/utils/EEPROM.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef AVR_IOHELP_EEPROM_H
#define AVR_IOHELP_EEPROM_H
#include <avr/io.h>
#include <stddef.h>
namespace EEPROM{
void set(uint16_t address, uint8_t data);
void set(uint16_t address, void * dataSource, size_t dataSize);
uint8_t get(uint16_t address);
void get(uint16_t address, void * dataDest, size_t dataSize);
}
#endif //AVR_IOHELP_EEPROM_H

77
Board/lib/utils/TWI.cpp Normal file
View File

@ -0,0 +1,77 @@
#include "TWI.h"
namespace TWI {
BusState startMessage(Address addr) {
TWCR = (1 << TWSTA) | (1 << TWEN) | (1 << TWINT);
wait();
uint8_t status = sendByte(addr);
if (status == 0x18 || status == 0x40) return TWI_OK;
else return status;
}
void close() {
TWCR = (1 << TWSTO) | (1 << TWEN) | (1 << TWINT);
}
BusState sendByte(uint8_t byte) {
TWDR = byte;
TWCR = (1 << TWEN) | (1 << TWINT);
wait();
uint8_t status = (TWSR & 0xF8);
if (status != 0x28 && status != 0x30) return status;
else return TWI_OK;
}
void wait() {
while (!(TWCR & (1 << TWINT)));
}
BusState nack() {
TWCR = (1 << TWEN) | (1 << TWINT);
wait();
uint8_t status = (TWSR & 0xF8);
if (status != 0x50 && status != 0x58) return status;
else return TWI_OK;
}
BusState ack() {
TWCR = (1 << TWEN) | (1 << TWINT) | (1 << TWEA);
wait();
uint8_t status = (TWSR & 0xF8);
if (status != 0x50 && status != 0x58) return status;
else return TWI_OK;
}
uint8_t readByte() {
return TWDR;
}
void init(uint32_t busSpeed) {
// TWSR = ~(1 << TWPS0);
// TWSR = ~(1 << TWPS1);
TWBR = ((F_CPU / busSpeed - 16) / (2 * 4));
/*
// initialize twi prescaler and bit rate
cbi(TWSR, TWPS0);
cbi(TWSR, TWPS1);
TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;*/
/* twi bit rate formula from atmega128 manual pg 204
SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
note: TWBR should be 10 or higher for master mode
It is 72 for a 16mhz Wiring board with 100kHz TWI */
// enable twi module, acks, and twi interrupt
TWCR = _BV(TWEN) | _BV(TWEA); //| _BV(TWIE);
//
}
}

23
Board/lib/utils/TWI.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef TWI_H
#define TWI_H
#include <avr/io.h>
#define TWI_OK 0x00
namespace TWI {
typedef uint8_t BusState;
typedef uint8_t Address;
void init(uint32_t busSpeed);
void close();
BusState startMessage(Address addr);
BusState sendByte(uint8_t byte);
BusState ack();
uint8_t readByte();
BusState nack();
void wait();
}
#endif

32
Board/lib/utils/Timer.cpp Normal file
View File

@ -0,0 +1,32 @@
//
// Created by User on 018 18.05.20.
//
#include "Timer.h"
void Timer1::setup(TimerPrescaler prescaler, uint16_t OCR) {
TCCR1B |= (1 << WGM12); //режим сброса по свпадению
switch (prescaler) {
case PRESCALER_NO:
TCCR1B |= (1 << CS10);
break;
case PRESCALER_8:
TCCR1B |= (1 << CS11);
break;
case PRESCALER_64:
TCCR1B |= (1 << CS10) | (1 << CS10);
break;
case PRESCALER_256:
TCCR1B |= (1 << CS12);
break;
case PRESCALER_1024:
TCCR1B |= (1 << CS12) | (1 << CS10);
break;
}
TIMSK1 |= (1 << OCIE1A); //устанавливаем бит разрешения прерывания 1ого счетчика по совпадению с OCR1A(H и L)
OCR1AH = (OCR & 0xFF00) >> 8;
OCR1AL = (OCR & 0x00FF);
}

23
Board/lib/utils/Timer.h Normal file
View File

@ -0,0 +1,23 @@
//
// Created by User on 018 18.05.20.
//
#ifndef AVR_IOHELP_TIMER_H
#define AVR_IOHELP_TIMER_H
#include <avr/io.h>
#define onTimer1Triggered() ISR(TIMER1_COMPA_vect)
enum TimerPrescaler{
PRESCALER_NO,
PRESCALER_8,
PRESCALER_64,
PRESCALER_256,
PRESCALER_1024
};
namespace Timer1{
void setup(TimerPrescaler prescaler, uint16_t OCR);
}
#endif //AVR_IOHELP_TIMER_H

22
Board/lib/utils/iohelp.h Normal file
View File

@ -0,0 +1,22 @@
//
// Created by kirillius on 20.04.2020.
//
#ifndef AVR_IOHELP_H
#define AVR_IOHELP_H
//Пример: pinmode_input(DDRB, PORTB1);
#define pinmode_input(DDREGISTER, PINNAME) (DDREGISTER &= ~(1<<PINNAME))
#define pinmode_output(DDREGISTER, PINNAME) (DDREGISTER |= (1<<PINNAME))
//Пример: pinstateset(PORTB, PORTB1, true);
#define pinstateset(PORTREGISTER, PINNAME, STATE) do{ if(STATE){ PORTREGISTER |= (1<<PINNAME); }else{ PORTREGISTER &= ~(1<<PINNAME); } }while(0)
//Пример: int state = pinstateget(PINB, PORTB1);
#define pinstateget(PINREGISTER, PINNAME) (PINREGISTER & (1<<PINNAME))
#endif //AVR_IOHELP_H

22
Board/lib/utils/spi.cpp Normal file
View File

@ -0,0 +1,22 @@
//
// Created by kirillius on 25.09.2021.
//
#include "spi.h"
uint8_t SPI::transfer(uint8_t byte){
SPDR = byte;
while(!(SPSR & (1<<SPIF))); //ожидание готовности SPI
return SPDR; //возврат того, что пришло
}
void SPI::send(uint8_t byte){
SPI::transfer(byte);
}
uint8_t SPI::receive(){
return SPI::transfer(0xFF);
}
uint8_t SPI::data() {
return SPDR;
}

19
Board/lib/utils/spi.h Normal file
View File

@ -0,0 +1,19 @@
//
// Created by kirillius on 25.09.2021.
//
#ifndef AVR_IOHELP_SPI_H
#define AVR_IOHELP_SPI_H
#include <avr/io.h>
#define SPI(MOSI, MISO, SCK) do{DDRB = ((DDRB&~(1<<MISO))|(1<<MOSI)|(1<<SCK)); (SPCR |= (1<<SPE)|(1<<MSTR)); SPSR |= (1<<SPI2X);}while(0)
namespace SPI{
uint8_t transfer(uint8_t byte);
void send(uint8_t byte);
uint8_t receive();
uint8_t data();
}
#endif //AVR_IOHELP_SPI_H

58
Board/src/ComMessage.h Normal file
View File

@ -0,0 +1,58 @@
//
// Created by kirillius on 09.04.2022.
//
#ifndef COOLER_CONTROLLER_COMMESSAGE_H
#define COOLER_CONTROLLER_COMMESSAGE_H
#include <avr/io.h>
enum MessageType {
SAVE,
PING,
REBOOT,
READ,
WRITE,
ERROR
};
enum ErrorCodes{
ERR_UNSUPPORTED_OPERATION,
ERR_UNKNOWN_DATA_TYPE,
ERR_UNKNOWN_ACTION_TYPE,
ERR_INVALID_CHECKSUM
};
enum DataType{
NONE,
TEMP,
LEVEL,
START_TEMP,
STOP_TEMP,
MAX_TEMP,
MIN_LEVEL,
MAX_LEVEL
};
struct Message {
public:
MessageType action;
DataType dataType;
uint8_t value;
uint8_t checksum;
void validate() {
checksum = calcChecksum();
}
bool isValid() {
return checksum == calcChecksum();
}
private:
uint8_t calcChecksum() {
return 18 + value + action * 23 + 42 * value+5*dataType;
}
};
#endif //COOLER_CONTROLLER_COMMESSAGE_H

30
Board/src/Configuration.h Normal file
View File

@ -0,0 +1,30 @@
//
// Created by kirillius on 09.04.2022.
//
#ifndef COOLER_CONTROLLER_CONFIGURATION_H
#define COOLER_CONTROLLER_CONFIGURATION_H
#define CONFIG_EEPROM_ADDR 0x42
struct Configuration {
uint8_t startTemp;
uint8_t maxTemp;
uint8_t minLevel;
uint8_t maxLevel;
uint8_t signature;
uint8_t stopTemp;
bool isValid() {
return signature == 0x42;
}
void validate() {
signature = 0x42;
}
void invalidate() {
signature = 0x00;
}
};
#endif //COOLER_CONTROLLER_CONFIGURATION_H

View File

@ -0,0 +1,37 @@
//
// Created by kirillius on 09.04.2022.
//
#include "FanController.h"
#include <utils/iohelp.h>
#include <avr/io.h>
#include <avr/interrupt.h>
FanController::FanController() {
pinmode_output(DDRC, PORTC0);
TCCR0A = 0;
TCCR0B = 0;
TCCR0A |= (1 << WGM01);// Режим CTC (сброс по совпадению)
TCCR0B |= (1 << CS01);// Тактирование от CLK CLK/8
OCR0A = 64;
TIMSK0 |= (1 << OCIE0A);// Прерывание по совпадению
}
uint8_t FanController::PWM, FanController::PWMCounter = 0;
ISR(TIMER0_COMPA_vect) {
if (FanController::PWM == 0) {
PORTC &= ~(1 << PORTC0);
return;
}
if (++FanController::PWMCounter == 0) {
PORTC |= (1 << PORTC0);
return;
}
if (FanController::PWMCounter == FanController::PWM) {
PORTC &= ~(1 << PORTC0);
}
}

20
Board/src/FanController.h Normal file
View File

@ -0,0 +1,20 @@
//
// Created by kirillius on 09.04.2022.
//
#ifndef COOLER_CONTROLLER_FANCONTROLLER_H
#define COOLER_CONTROLLER_FANCONTROLLER_H
#include <stdint.h>
class FanController {
public:
static uint8_t PWM;
static uint8_t PWMCounter;
FanController();
};
#endif //COOLER_CONTROLLER_FANCONTROLLER_H

196
Board/src/NTC.cpp Normal file
View File

@ -0,0 +1,196 @@
/*
* NTC.cpp
*
* Created: Ср 11.12.19 21:51:00
* Author: User
*/
#include <avr/pgmspace.h>
#include "NTC.h"
namespace NTC {
const PROGMEM NTCValue NTCTable[] = {
{-50, 1012},
{-49, 1011},
{-48, 1010},
{-47, 1009},
{-46, 1008},
{-45, 1007},
{-44, 1006},
{-43, 1005},
{-42, 1003},
{-41, 1002},
{-40, 1000},
{-39, 999},
{-38, 997},
{-37, 995},
{-36, 993},
{-35, 991},
{-34, 989},
{-33, 987},
{-32, 984},
{-31, 982},
{-30, 979},
{-29, 976},
{-28, 973},
{-27, 970},
{-26, 967},
{-25, 962},
{-24, 959},
{-23, 956},
{-22, 952},
{-21, 947},
{-20, 942},
{-19, 938},
{-18, 933},
{-17, 928},
{-16, 922},
{-15, 916},
{-14, 910},
{-13, 905},
{-12, 898},
{-11, 891},
{-10, 884},
{-9, 877},
{-8, 870},
{-7, 863},
{-6, 854},
{-5, 845},
{-4, 837},
{-3, 829},
{-2, 820},
{-1, 810},
{0, 799},
{1, 791},
{2, 781},
{3, 771},
{4, 760},
{5, 748},
{6, 739},
{7, 728},
{8, 717},
{9, 705},
{10, 692},
{11, 682},
{12, 671},
{13, 659},
{14, 647},
{15, 633},
{16, 622},
{17, 611},
{18, 599},
{19, 586},
{20, 573},
{21, 562},
{22, 550},
{23, 538},
{24, 525},
{25, 512},
{26, 501},
{27, 490},
{28, 478},
{29, 466},
{30, 453},
{31, 443},
{32, 432},
{33, 421},
{34, 409},
{35, 397},
{36, 387},
{37, 377},
{38, 367},
{39, 356},
{40, 345},
{41, 336},
{42, 327},
{43, 317},
{44, 308},
{45, 298},
{46, 290},
{47, 282},
{48, 273},
{49, 265},
{50, 256},
{51, 249},
{52, 242},
{53, 234},
{54, 227},
{55, 219},
{56, 213},
{57, 207},
{58, 200},
{59, 194},
{60, 187},
{61, 182},
{62, 176},
{63, 171},
{64, 165},
{65, 160},
{66, 155},
{67, 150},
{68, 146},
{69, 141},
{70, 136},
{71, 132},
{72, 128},
{73, 124},
{74, 120},
{75, 116},
{76, 112},
{77, 109},
{78, 106},
{79, 102},
{80, 99},
{81, 96},
{82, 93},
{83, 90},
{84, 87},
{85, 84},
{86, 82},
{87, 80},
{88, 77},
{89, 75},
{90, 72},
{91, 70},
{92, 68},
{93, 66},
{94, 64},
{95, 62},
{96, 60},
{97, 59},
{98, 57},
{99, 55},
{100, 53},
{101, 52},
{102, 50},
{103, 49},
{104, 47},
{105, 46},
{106, 45},
{107, 43},
{108, 42},
{109, 41},
{110, 40},
{111, 39},
{112, 38},
{113, 37},
{114, 36},
{115, 35},
{116, 34},
{117, 33},
{118, 32},
{119, 31},
{120, 30}
};
size_t NTCTableCount = sizeof(NTCTable) / sizeof(NTCValue);
int8_t getTemperature(uint16_t volt) {
for (uint8_t i = 0; i < NTCTableCount; i++) {
NTCValue item;
memcpy_P(&item, &NTCTable[i], sizeof(NTCValue));
if (item.value < volt) return item.temp;
}
return 120;
}
}

17
Board/src/NTC.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef COOLER_CONTROLLER_NTC_H
#define COOLER_CONTROLLER_NTC_H
#include <avr/io.h>
namespace NTC {
struct NTCValue {
int8_t temp;
uint16_t value;
};
int8_t getTemperature(uint16_t volt);
}
#endif //COOLER_CONTROLLER_NTC_H

234
Board/src/ServiceApp.cpp Normal file
View File

@ -0,0 +1,234 @@
//
// Created by kirillius on 09.04.2022.
//
#include <avr/wdt.h>
#include <utils/ADC.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "ServiceApp.h"
#include "NTC.h"
#include <utils/EEPROM.h>
FanController ServiceApp::Fan;
USART ServiceApp::Serial(9600);
ServiceApp::ServiceApp() {
wdt_enable(WDTO_8S);
ADCIO::setup();
readConfig();
FanController::PWM = 255;
level = 0;
temp = 0;
sei();
}
uint8_t ServiceApp::lerp(uint8_t a, uint8_t b, uint8_t t) {
return (uint8_t)((float) a + (float) (b - a) * (float) t / 100.0f);
}
void ServiceApp::update() {
setFanPWM();
communicate();
wdt_reset();
_delay_ms(100);
}
void ServiceApp::readConfig() {
EEPROM::get(CONFIG_EEPROM_ADDR, &Config, sizeof(Configuration));
if (!Config.isValid()) {
//default config
Config.minLevel = 32;
Config.maxLevel = 255;
Config.startTemp = 30;
Config.maxTemp = 40;
Config.stopTemp = 26;
}
}
void ServiceApp::writeConfig() {
Config.validate();
EEPROM::set(CONFIG_EEPROM_ADDR, &Config, sizeof(Configuration));
}
bool ServiceApp::readMessage(Message *dest) {
if (Serial.available() >= 4) {
dest->action = static_cast<MessageType>(Serial.read());
dest->dataType = static_cast<DataType>(Serial.read());
dest->value = Serial.read();
dest->checksum = Serial.read();
return true;
}
return false;
}
void ServiceApp::sendMessage(Message *src) {
src->validate();
Serial.send(src->action);
Serial.send(src->dataType);
Serial.send(src->value);
Serial.send(src->checksum);
}
void ServiceApp::communicate() {
Message message;
if (readMessage(&message)) {
if (message.isValid()) {
switch (message.action) {
case SAVE:
message.dataType = NONE;
message.value = 255;
sendMessage(&message);
writeConfig();
break;
case PING:
sendMessage(&message);
break;
case READ:
switch (message.dataType) {
case TEMP:
message.value = temp;
sendMessage(&message);
break;
case LEVEL:
message.value = level;
sendMessage(&message);
break;
case START_TEMP:
message.value = Config.startTemp;
sendMessage(&message);
break;
case MAX_TEMP:
message.value = Config.maxTemp;
sendMessage(&message);
break;
case MIN_LEVEL:
message.value = Config.minLevel;
sendMessage(&message);
break;
case MAX_LEVEL:
message.value = Config.maxLevel;
sendMessage(&message);
break;
default:
message.action = ERROR;
message.dataType = NONE;
message.value = ERR_UNKNOWN_DATA_TYPE;
sendMessage(&message);
case NONE:
break;
case STOP_TEMP:
message.value = Config.stopTemp;
sendMessage(&message);
break;
}
break;
case WRITE:
switch (message.dataType) {
case STOP_TEMP:
Config.stopTemp = message.value;
sendMessage(&message);
break;
case TEMP:
case LEVEL:
message.action = ERROR;
message.dataType = NONE;
message.value = ERR_UNSUPPORTED_OPERATION;
sendMessage(&message);
break;
case START_TEMP:
Config.startTemp = message.value;
sendMessage(&message);
break;
case MAX_TEMP:
Config.maxTemp = message.value;
sendMessage(&message);
break;
case MIN_LEVEL:
Config.minLevel = message.value;
sendMessage(&message);
break;
case MAX_LEVEL:
Config.maxLevel = message.value;
sendMessage(&message);
break;
default:
message.action = ERROR;
message.dataType = NONE;
message.value = ERR_UNKNOWN_DATA_TYPE;
sendMessage(&message);
}
break;
case REBOOT:
message.dataType = NONE;
message.value = 255;
sendMessage(&message);
wdt_disable();
wdt_enable(WDTO_500MS);
while (true);
break;
default:
message.action = ERROR;
message.dataType = NONE;
message.value = ERR_UNKNOWN_ACTION_TYPE;
sendMessage(&message);
}
} else {
message.action = ERROR;
message.dataType = NONE;
message.value = ERR_INVALID_CHECKSUM;
sendMessage(&message);
}
}
if (comCounter++ == 0) {
message.action = PING;
message.value = 0x42;
message.dataType = NONE;
sendMessage(&message);
}
}
void ServiceApp::setFanPWM() {
temp = NTC::getTemperature(ADCIO::read(ADC6));
uint8_t minTemp = min(Config.startTemp, Config.stopTemp);
if (temp >= Config.maxTemp) { //выставить макс. мощность если темп выше или равна максимальной
level = Config.maxLevel;
} else if (temp <= minTemp) { //вылкючить если температура меньше или равна минимальной из двух (старт или стоп)
level = 0;
FanController::PWM = 0;
return;
} else if (temp >= Config.startTemp) { //мощность вычисляется в зависимости от температуры если темп больше стартовой
uint8_t interpolation = (uint8_t)(100.0f * (float) (temp - Config.startTemp) /
(float) (Config.maxTemp - Config.startTemp));
level = lerp(Config.minLevel, Config.maxLevel, interpolation > 100 ? 100 : interpolation);
}else if(level > 0){
//если темп больше stopTemp но меньше startTemp то задаем минимальную мощность
level = Config.minLevel;
}
if (FanController::PWM == 0 && level > 0) {
//не стартуем с 0 мощности
FanController::PWM = 32;
} else {
if (FanController::PWM > level) {
//slow decrease
if (FanController::PWM - level > 5) {
FanController::PWM -= 1;
} else {
FanController::PWM = level;
}
} else {
FanController::PWM = level;
}
}
}
float ServiceApp::clamp(float a, float min, float max) {
return (a < min ? min : (a > max ? max : a));
}
uint8_t ServiceApp::min(uint8_t a, uint8_t b) {
return a < b ? a : b;
}

48
Board/src/ServiceApp.h Normal file
View File

@ -0,0 +1,48 @@
//
// Created by kirillius on 09.04.2022.
//
#ifndef COOLER_CONTROLLER_SERVICEAPP_H
#define COOLER_CONTROLLER_SERVICEAPP_H
#include <usart/usart.h>
#include "FanController.h"
#include "Configuration.h"
#include "ComMessage.h"
class ServiceApp {
private:
static USART Serial;
static FanController Fan;
Configuration Config;
int8_t temp;
uint8_t level;
uint8_t comCounter;
void readConfig();
void writeConfig();
bool readMessage(Message *dest);
void sendMessage(Message *src);
void communicate();
void setFanPWM();
public:
ServiceApp();
void update();
static uint8_t lerp(uint8_t a, uint8_t b, uint8_t t);
static float clamp(float a, float min, float max);
static uint8_t min(uint8_t a, uint8_t b);
};
#endif //COOLER_CONTROLLER_SERVICEAPP_H

8
Board/src/main.cpp Normal file
View File

@ -0,0 +1,8 @@
#include <avr/wdt.h>
#include "ServiceApp.h"
int main() {
wdt_disable();
ServiceApp app;
do app.update(); while (true);
}

1
Board/svn.modules.json Normal file
View File

@ -0,0 +1 @@
{"modules":[{"path":"lib/utils","uri":"https://svn.kirillius.ru/mcu-avr/avr-iohelp/trunk/lib/utils","revision":"HEAD"},{"path":"lib/usart","uri":"https://svn.kirillius.ru/mcu-avr/avr-usart/trunk/lib/usart","revision":"HEAD"}]}