Commit bf58d042 authored by Oleg Nikulin's avatar Oleg Nikulin

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

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