Commit bbe21432 authored by Oleg Nikulin's avatar Oleg Nikulin

Удален старый файл прошивки за ненадобностью

parent d2480059
#include <Wire.h>
#define FAN_COUNT 6 //Количество вентиляторов
#define BAUDRATE 19200 //Скорость serial порта
#define CHECK_TEMP_DELAY 1000 //Интервал получения температуры от пк (мс)
#define GET_TEMP_TIMEOUT 1000 //Если в течение этого времени температура не была прислана, считается что пк не отвечает (мс)
#define RPM_CHECK_INTERVAL 200 //Интервал подсчета rpm и обнуления tachRevs (мс)
#define RPM_VALUES_COUNT 5 //Количество значений RPM, которые записываются и усредняются (скользящее среднее)
#define MIN_PWM_DUTY_CYCLE 20 //Минимальная скважность ШИМ
#define MAX_PWM_DUTY_CYCLE 254 //Максимальная скважность ШИМ
#define DEFAULT_PWM_DUTY_CYCLE 254 //Скважность ШИМ по умолчанию (до подулючения к пк)
#define BEEP_INTERVAL 1000 //Интервал пищания во время потери связи или перегрева (мс)
#define BEEP_STRENGTH 100 //Уровень ШИМ для пищалки. (При 255 не работает, нужно чтобы был именно ШИМ)
#define BLINK_INTERVAL 200 //Интервал мигания светодиода во время ожидания ответа от пк (мс)
#define SOUND_PIN 10 //Номер пина пищалки
#define LED_PIN 13 //Номер пина светодиода
int pwmPins[3] = {3, 5, 6}; //Номера пинов ШИМ
volatile bool pwmState = 0; //Состояние ШИМ
volatile bool pwm_on = 1; // ==1, если ШИМ включен
int tachPins[FAN_COUNT] = {14, 15, 16, 17, 18, 19}; //Номера пинов для считывания оборотов
volatile uint16_t tachRevs[FAN_COUNT] = {}; //Обороты (просто сколько насчитано оборотов, а не rpm)
uint16_t tachRpm[FAN_COUNT][RPM_VALUES_COUNT] = {}; //rpm
volatile bool tachStates[FAN_COUNT] = {}; //Состояния (оборот считывается только если состояние == 0, и считывается 0)
/*
struct fan { //Данные о вентиляторе
int tachPin; //Номер пина тахометра
bool tachState; //Состояние тахометра
bool tachType; //Тип датчика. 0 = униполярный, 1 = биполярный
uint16_t revs; //Количество оборотв (просто, не в минуту)
uint16_t rpm; //Обороты в минуту
uint32_t lastSignalStart; //Время начала последнего сигнала тахометра
uint32_t lastSignalEnd; //Время окончания последнего сигнала тахометра
};
struct control { //Данные о контроллерах вентилятора
int pwmPin; //Номер пина ШИМ
bool pwmState; //Состояние пина ШИМ
};
*/
int temp; //Температура, полученная от пк
int target_temp = 37;
uint32_t last_beep_time = 0;
uint32_t last_check_time = 0;
uint32_t lastRpmCheck = 0;
uint32_t lastRevTime = 0;
float p = 0;
float i = 0;
float d = 0;
float k_p = 40;
float k_i = 0.005;
float k_d = 0;
float i_max = 210;
void wait_for_connection(bool beep) { //функция, которая мигает светодиодом и пищит (если beep == true) до тех пор, пока не будет установлено соединение с ПК
Serial.println("start_transmission");
digitalWrite(LED_PIN, 1);
unsigned long last_blink_time = millis();
while (Serial.available() == 0) {//ждем ответа
if (millis() >= last_blink_time + BLINK_INTERVAL * 2) {
digitalWrite(LED_PIN, 1);
last_blink_time = millis();
}
else if (millis() >= last_blink_time + BLINK_INTERVAL) {
digitalWrite(LED_PIN, 0);
}
if (beep) {
if (millis() >= last_beep_time + BEEP_INTERVAL * 2) {
analogWrite(SOUND_PIN, BEEP_STRENGTH);
last_beep_time = millis();
}
else if (millis() >= last_beep_time + BEEP_INTERVAL) {
analogWrite(SOUND_PIN, 0);
}
}
}
digitalWrite(LED_PIN, 0); //гасим светодиод
analogWrite(SOUND_PIN, 0); //и выключаем пищалку
while (Serial.available()) {// очистка буфера
Serial.readString();
}
}
void tempFromPc()// получаем температуру от пк
{
String rpm_string = "send_rpm_";
for (int fan = 0; fan < FAN_COUNT; fan++) {
uint32_t avg_rpm = 0;
for (int val = 0; val < RPM_VALUES_COUNT; val++) {
avg_rpm += tachRpm[fan][val];
}
avg_rpm /= RPM_VALUES_COUNT;
rpm_string += String(avg_rpm);
if (fan < 5) {
rpm_string += "_";
}
}
Serial.println("req_temperature_" + rpm_string + "_debug_" + String(OCR2B)); //запрос к пк
unsigned long query_time = millis();
while (Serial.available() == 0) { //ждем пока ответит
if (millis() >= query_time + GET_TEMP_TIMEOUT) { //если слишком долго не отвечает
//Венитялторы на максимум
for (int i = 0; i < 3; i++) {
OCR2B = 254;
}
wait_for_connection(true);//снова ждем подключения
break;
}
}
String response = Serial.readStringUntil('\n');
temp = response.substring(12).toInt();
}
void autocontrol()//Автоконтроль температуры
{
tempFromPc();//получаем температуру от пк
/*
if (temp < 20) { //<20 rpm = 600-630
target_rpm = 650;
//pwmDutyCycle = 50;
}
else if (temp < 40) { //20-39 rpm = 1080-1110
target_rpm = 1000;
//pwmDutyCycle = 100;
}
else if (temp < 60) { //40-59 rpm = 1380-1410
target_rpm = 1250;
//pwmDutyCycle = 150;
}
else if (temp < 80) { //60-79 rpm = 1620-1650
target_rpm = 1500;
//pwmDutyCycle = 200;
}
else { //>=80 rpm = 1800-1830
target_rpm = 1700;
//pwmDutyCycle = 254;
}
*/
}
void rpm_control() {
for (int fan = 0; fan < FAN_COUNT; fan++) {
for (int val = 0; val < RPM_VALUES_COUNT - 1; val++) {
tachRpm[fan][val] = tachRpm[fan][val + 1];
}
tachRpm[fan][RPM_VALUES_COUNT - 1] = (tachRevs[fan] * (60000 / uint32_t(millis() - lastRpmCheck))) / 2;
tachRevs[fan] = 0;
}
float pwmDutyCycle = 0;
uint8_t byte_pwmDutyCycle = 0;
d = (temp - target_temp - p) / float(millis() - lastRpmCheck);
p = temp - target_temp;
i = i + p * (millis() - lastRpmCheck);
if (fabs(i * k_i) >= i_max){
i = i_max / k_i;
}
pwmDutyCycle = round(p * k_p + i * k_i + d * k_d);
if (pwmDutyCycle <= MIN_PWM_DUTY_CYCLE) {
byte_pwmDutyCycle = MIN_PWM_DUTY_CYCLE;
}
else if (pwmDutyCycle >= MAX_PWM_DUTY_CYCLE) {
byte_pwmDutyCycle = MAX_PWM_DUTY_CYCLE;
}
else {
byte_pwmDutyCycle = pwmDutyCycle;
}
if (byte_pwmDutyCycle == 0) {
if (pwm_on == 1) {
pwm_on = 0; //выкл ШИМ
for (int i = 0; i < 3; i++) {//выкл пины ШИМ
digitalWrite(pwmPins[i], 0);
}
}
}
else {
if (pwm_on == 0) {
pwm_on = 1; //вкл ШИМ
}
OCR2B = byte_pwmDutyCycle; //установка скважности
}
//Почему-то иногда может заглючить: скважность стоит 254, pwm_on равно 1, но вентилятор не крутится (но пищит). Похоже каким-то образом меняется pwmState, когда не надо
//Serial.println("debug_" + String(byte_pwmDutyCycle));
lastRpmCheck = millis();
}
ISR(TIMER2_COMPA_vect) { //Функция, вызываемая при прерывании A
for (int i = 0; i < 3; i++) { //Вкл. питание
digitalWrite(pwmPins[i], 1);
}
//Проверка тахометров
for (int i = 0; i < FAN_COUNT; i++) {
if (digitalRead(tachPins[i]) == 0 && tachStates[i] == 0) { //сигнал тахометра появился
tachStates[i] = 1;
//digitalWrite(13, 1);
}
else if (digitalRead(tachPins[i]) == 1 && tachStates[i] == 1) { //сигнал тахометра пропал
//digitalWrite(13, 0);
tachStates[i] = 0;
tachRevs[i]++; //засчитывается оборот
}
}
}
ISR(TIMER2_COMPB_vect) { //Функция, вызываемая при прерывании B
for (int i = 0; i < 3; i++) { //Выкл. питание
digitalWrite(pwmPins[i], 0);
}
}
void setup() {
pinMode(LED_PIN, OUTPUT);
pinMode(SOUND_PIN, OUTPUT);
for (int i = 0; i < 3; i++) {
pinMode(pwmPins[i], OUTPUT);
}
for (int i = 0; i < FAN_COUNT; i++) {
pinMode(tachPins[i], INPUT_PULLUP);
}
//запуск таймера в режиме fast pwm
TCCR2A |= (1 << WGM21);
TCCR2A |= (1 << WGM20);
TIMSK2 |= (1 << OCIE2A); //вкл. вызов прерывания по сравнению A
TIMSK2 |= (1 << OCIE2B); //вкл. вызов прерывания по сравнению B
OCR2B = DEFAULT_PWM_DUTY_CYCLE; //Прерывание B происходит, когда значение таймера совпадает с этим. (По сути это скважность ШИМ)
Serial.begin(BAUDRATE);
wait_for_connection(false); //Ждем установленя связи с ПК
}
void loop() {
if (uint32_t(millis() - last_check_time) >= CHECK_TEMP_DELAY) {
last_check_time = millis();
autocontrol(); //Получаем температуру от ПК, устанавливаем соотв. скорость вращения
if (temp >= 80) { //Если перегрев, включается пищалка
if (millis() >= last_beep_time + BEEP_INTERVAL * 2) {
analogWrite(SOUND_PIN, BEEP_STRENGTH);
last_beep_time = millis();
}
else if (millis() >= last_beep_time + BEEP_INTERVAL) {
analogWrite(SOUND_PIN, 0);
}
}
else {
analogWrite(SOUND_PIN, 0); //Чтобы постоянно не пищал, если температура станет < 80 в то время, как пищалка включена
}
}
if (uint32_t(millis() - lastRpmCheck) >= RPM_CHECK_INTERVAL) {
rpm_control();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment