Commit bf58d042 authored by Oleg Nikulin's avatar Oleg Nikulin

Управление ШИМом по таймеру, улучшено измерение rpm

parent 0e6aa156
...@@ -12,73 +12,47 @@ ...@@ -12,73 +12,47 @@
#define CHECK_TEMP_DELAY 1000 //Задержка перед очередным получением температуры от пк #define CHECK_TEMP_DELAY 1000 //Задержка перед очередным получением температуры от пк
#define GET_TEMP_TIMEOUT 500 //Если в течение этого времени температура не была прислана, считается что пк не отвечает #define GET_TEMP_TIMEOUT 500 //Если в течение этого времени температура не была прислана, считается что пк не отвечает
#define RPM_CHECK_INTERVAL 1000 //Частота подсчета rpm и обнуления tachRevs #define RPM_CHECK_INTERVAL 1000 //Частота подсчета rpm и обнуления tachRevs
#define DEFAULT_TACT 1 //Величина которая устанавливается сразу после загрузки (до подключения к пк) #define DEFAULT_PWM_DUTY_CYCLE 254 //Скважность ШИМ поумолчанию (до подулючения к пк)
#define MAX_PWM_DUTY_CYCLE 254 //Максимальная скважность ШИМ
#define SOUND_PIN 10 #define SOUND_PIN 10
#define LED_PIN 13 #define LED_PIN 13
int pwmPins[3] = {3, 5, 6}; //Номера пинов ШИМа int pwmPins[3] = {3, 5, 6}; //Номера пинов ШИМ
uint16_t pwr_tacts[3] = {1, 5, 10}; //питание будет включаться каждый n-ный такт bool pwmState = 0; //Состояние ШИМ
uint16_t counters[3] = {1, 1, 1}; //счетчики тактов
uint32_t last_power_starts[3] = {}; //времена начала импульсов питания
uint32_t last_power_ends[3] = {}; //времена окончания импульсов питания
uint32_t last_signal_starts[FAN_COUNT] = {}; //времена начала импульсов сигнала
uint32_t last_signal_ends[FAN_COUNT] = {}; //времена окончания окончания питания
int tachPins[FAN_COUNT] = {14, 15, 16, 17, 18, 19}; //Номера пинов для считывания оборотов int tachPins[FAN_COUNT] = {14, 15, 16, 17, 18, 19}; //Номера пинов для считывания оборотов
uint16_t tachRevs[FAN_COUNT] = {}; //Обороты (просто сколько насчитано оборотов, а не rpm) uint16_t tachRevs[FAN_COUNT] = {}; //Обороты (просто сколько насчитано оборотов, а не rpm)
uint16_t tachRpm[FAN_COUNT] = {}; //rpm uint16_t tachRpm[FAN_COUNT] = {}; //rpm
bool tachStates[FAN_COUNT] = {}; //Состояния (оборот считывается только если состояние == 0, и считывается 0) bool tachStates[FAN_COUNT] = {}; //Состояния (оборот считывается только если состояние == 0, и считывается 0)
uint32_t lastRpmCheck = 0;
int prev_pwr_tact_value = 0;
int temp, rpmValue; //целочисленные переменные для расчетов
struct fan{ //Данные о вентиляторе //Это пока не используется:
int tachPin; //Номер пина для считывания оборотов struct fan { //Данные о вентиляторе
bool tachState; //Состояние датчика оборотов int tachPin; //Номер пина тахометра
bool tachState; //Состояние тахометра
bool tachType; //Тип датчика. 0 = униполярный, 1 = биполярный
uint16_t revs; //Количество оборотв (просто, не в минуту) uint16_t revs; //Количество оборотв (просто, не в минуту)
uint16_t rpm; //Обороты в минуту uint16_t rpm; //Обороты в минуту
uint32_t lastSignalStart; //Время начала последнего сигнала тахометра uint32_t lastSignalStart; //Время начала последнего сигнала тахометра
uint32_t lastSignalEnd; //Время окончания последнего сигнала тахометра uint32_t lastSignalEnd; //Время окончания последнего сигнала тахометра
}; };
//fanspec fanspace[3] = {{0, 1}, {1, 2}, {2, 8}}; //Массив переменных нового типа struct controll { //Данные о контроллерах вентилятора
int pwmPin; //Номер пина ШИМ
bool pwmState; //Состояние пина ШИМ
};
char fan = 1; //Переменная, отвечающая за выбор типа датчика вентилятора (1 – униполярный датчик Холла, 2 –биполярный датчик Холла)
uint32_t last_beep_time = 0;
uint32_t last_check_time = 0;
int temp; //Температура, полученная от пк
void rpmcalc() { //Считывание оборотов и подсчет rpm uint32_t last_beep_time = 0;
for (int i = 0; i < FAN_COUNT; i++) { uint32_t last_check_time = 0;
if (digitalRead(tachPins[i]) == 0 && tachStates[i] == 0) { //сигнал тахометра появился uint32_t lastRpmCheck = 0;
last_signal_starts[i] = millis();
tachStates[i] = 1;
}
else if (digitalRead(tachPins[i]) == 1 && tachStates[i] == 1) { //сигнал тахометра пропал
if ((last_power_ends[i] - last_signal_starts[i]) - (last_signal_ends[i] - last_signal_starts[i]) > 2) { //оборот засчитывается только если длина сигнала тахометра меньше длины включения питания. В противном случае это фейковый сигнал
tachRevs[i]++;
}
last_signal_ends[i] = millis();
tachStates[i] = 0;
}
}
if (uint32_t(millis() - lastRpmCheck) >= RPM_CHECK_INTERVAL) { //раз в RPM_CHECK_INTERVAL обновляется значение rpm и обороты обнуляются
for (int i = 0; i < FAN_COUNT; i++) {
tachRpm[i] = (tachRevs[i] * (60000 / uint32_t(millis() - lastRpmCheck))) / 2;
tachRevs[i] = 0;
}
lastRpmCheck = millis();
}
}
void wait_for_connection(bool beep) { //функция, которая мигает светодиодом и пищит (если beep == true) до тех пор, пока не будет установлено соединение с ПК void wait_for_connection(bool beep) { //функция, которая мигает светодиодом и пищит (если beep == true) до тех пор, пока не будет установлено соединение с ПК
...@@ -103,7 +77,6 @@ void wait_for_connection(bool beep) { //функция, которая мига ...@@ -103,7 +77,6 @@ void wait_for_connection(bool beep) { //функция, которая мига
analogWrite(SOUND_PIN, 0); analogWrite(SOUND_PIN, 0);
} }
} }
set_pwm();
} }
digitalWrite(LED_PIN, 0); //гасим светодиод digitalWrite(LED_PIN, 0); //гасим светодиод
analogWrite(SOUND_PIN, 0); //и выключаем пищалку analogWrite(SOUND_PIN, 0); //и выключаем пищалку
...@@ -133,8 +106,7 @@ void tempFromPc()// получаем температуру от пк ...@@ -133,8 +106,7 @@ void tempFromPc()// получаем температуру от пк
if (millis() >= query_time + GET_TEMP_TIMEOUT) { //если слишком долго не отвечает if (millis() >= query_time + GET_TEMP_TIMEOUT) { //если слишком долго не отвечает
//Венитялторы на максимум //Венитялторы на максимум
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
pwr_tacts[i] = 1; OCR2A = 254;
counters[i] = 1;
} }
wait_for_connection(true);//снова ждем подключения wait_for_connection(true);//снова ждем подключения
break; break;
...@@ -150,90 +122,99 @@ void tempFromPc()// получаем температуру от пк ...@@ -150,90 +122,99 @@ void tempFromPc()// получаем температуру от пк
void autocontrol()//Автоконтроль температуры void autocontrol()//Автоконтроль температуры
{ {
tempFromPc();//получаем температуру от пк tempFromPc();//получаем температуру от пк
int pwr_tact_value = 1; int pwmDutyCycle = 0;
if (temp < 20) { //<20 if (temp < 20) { //<20 rpm = 600-630
//rpmValue = 50; pwmDutyCycle = 50;
pwr_tact_value = 10;
} }
else if (temp < 40) { //20-39 else if (temp < 40) { //20-39 rpm = 1080-1110
//rpmValue = 100; pwmDutyCycle = 100;
pwr_tact_value = 7;
} }
else if (temp < 60) { //40-59 else if (temp < 60) { //40-59 rpm = 1380-1410
//rpmValue = 150; pwmDutyCycle = 150;
pwr_tact_value = 4;
} }
else if (temp < 80) { //60-79 else if (temp < 80) { //60-79 rpm = 1620-1650
//rpmValue = 200; pwmDutyCycle = 200;
pwr_tact_value = 2;
} }
else { //>=80 else { //>=80 rpm = 1800-1830
//rpmValue = 255; pwmDutyCycle = MAX_PWM_DUTY_CYCLE;
pwr_tact_value = 1;
} }
if (pwmDutyCycle == 0) {
if (prev_pwr_tact_value != pwr_tact_value) { TIMSK2 &= (0 << OCIE2A); //выкл. вызов прерывания
pwmState = 0;
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
pwr_tacts[i] = pwr_tact_value; digitalWrite(pwmPins[i], 0);
counters[i] = 1;
} }
prev_pwr_tact_value = pwr_tact_value;
} }
else {
OCR2A = pwmDutyCycle; //установка скважности
}
} }
ISR(TIMER2_COMPA_vect) { //Эта функия вызывается при прерывании по таймеру 2
pwmState = !pwmState;
void set_pwm() { for (int i = 0; i < 3; i++) {//управление пинами ШИМ
for (int i = 0; i < 3; i++) { digitalWrite(pwmPins[i], pwmState);
if (counters[i] == pwr_tacts[i]) { }
digitalWrite(pwmPins[i], 1);
last_power_starts[i] = millis(); if (pwmState == 1) { //Если питание включилось, то проверяем состояния тахометров
counters[i] = 0; for (int i = 0; i < FAN_COUNT; i++) {
} //Пины тахометров подтянуты к 5в. Если digitalRead == 0, то считается, что тахометр активен, поэтому tachState[i] == 1
else { if (digitalRead(tachPins[i]) == 0 && tachStates[i] == 0) { //сигнал тахометра появился
digitalWrite(pwmPins[i], 0); tachStates[i] = 1;
last_power_ends[i] = millis(); //digitalWrite(13, 1);
}
else if (digitalRead(tachPins[i]) == 1 && tachStates[i] == 1) { //сигнал тахометра пропал
//digitalWrite(13, 0);
tachStates[i] = 0;
tachRevs[i]++; //засчитывается оборот
}
} }
counters[i]++;
} }
} }
void get8bits(int num, bool *bits_array) {
for (int i = 0; i < 8; i++) {
bits_array[i] = num >> (8 - 1 - i) & 1;
}
}
void setup() { void setup() {
pinMode(LED_PIN, OUTPUT); pinMode(LED_PIN, OUTPUT);
pinMode(SOUND_PIN, OUTPUT); pinMode(SOUND_PIN, OUTPUT);
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
pinMode(pwmPins[i], OUTPUT); pinMode(pwmPins[i], OUTPUT);
pwr_tacts[i] = DEFAULT_TACT;
} }
for (int i = 0; i < FAN_COUNT; i++) { for (int i = 0; i < FAN_COUNT; i++) {
pinMode(tachPins[i], INPUT_PULLUP); //Подтигиваем пины для считывания оборотов pinMode(tachPins[i], INPUT_PULLUP);
} }
Serial.begin(BAUDRATE);
TCCR2A |= (1 << WGM20); //запуск таймера
OCR2A = 1; //скважность
TIMSK2 |= (1 << OCIE2A); //вкл. вызов прерывания
Serial.begin(BAUDRATE);
wait_for_connection(false); //Ждем установленя связи с ПК wait_for_connection(false); //Ждем установленя связи с ПК
} }
void loop() { void loop() {
if (millis() >= last_check_time + CHECK_TEMP_DELAY) { if (uint32_t(millis() - last_check_time) >= CHECK_TEMP_DELAY) {
last_check_time = millis(); last_check_time = millis();
autocontrol(); //Получаем температуру от ПК, устанавливаем соотв. скорость вращения autocontrol(); //Получаем температуру от ПК, устанавливаем соотв. скорость вращения
...@@ -252,6 +233,12 @@ void loop() { ...@@ -252,6 +233,12 @@ void loop() {
} }
} }
rpmcalc(); if (uint32_t(millis() - lastRpmCheck) >= RPM_CHECK_INTERVAL) { //подсчет rpm
set_pwm(); for (int i = 0; i < FAN_COUNT; i++) {
tachRpm[i] = (tachRevs[i] * (60000 / uint32_t(millis() - lastRpmCheck))) / 2;
tachRevs[i] = 0;
}
lastRpmCheck = millis();
}
} }
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