Commit 0e6aa156 authored by Oleg Nikulin's avatar Oleg Nikulin

Управление ШИМом вручную, улучшено измерение RPM

parent b8539cd6
//Попробовать работать с таймером.
//Чтобы при его помощи вручную управлять шимом (это позволит точно знать время его включения, при этом иметь шим нормальной частоты)
//И чтобы чтобы через прерывания чекать тахометры.
//Можно еще попробовать реализовать вариант, когда для измерения оборотв на короткое время на питание подается постоянное напряжение вместо шима, и нужно успеть измерить обороты за это время.
#include <Wire.h>
#define BAUDRATE 57600 //Скорость serial порта
#define FAN_COUNT 6 //Количество вентиляторов
#define BAUDRATE 19200 //Скорость serial порта
#define BEEP_INTERVAL 1000 //Частота пищания во время потери связи или перегрева
#define BEEP_STRENGTH 100 //Уровень шима для пищалки. (При 255 не работает)
#define BLINK_INTERVAL 200 //Частота мигания светодиода во время ожидания ответа от пк
#define CHECK_TEMP_DELAY 500 //Задержка перед очередным получением температуры от пк
#define GET_TEMP_TIMEOUT 1000 //таймаут получения температуры от пк
#define ZERO_RPM_TIMEOUT 500 //таймаут обнуления RPM при отсутствии сигналов от вентилятора
#define DEFAULT_RPM_VALUE 255 //Величина которая устанавливается сразу после загрузки (до подключения к пк)
#define CHECK_TEMP_DELAY 1000 //Задержка перед очередным получением температуры от пк
#define GET_TEMP_TIMEOUT 500 //Если в течение этого времени температура не была прислана, считается что пк не отвечает
#define RPM_CHECK_INTERVAL 1000 //Частота подсчета rpm и обнуления tachRevs
#define DEFAULT_TACT 1 //Величина которая устанавливается сразу после загрузки (до подключения к пк)
#define SOUND_PIN 10
#define LED_PIN 13
#define pwmpinA 3 //Выход ШИМ 1
#define pwmpinB 5 //Выход ШИМ 2
#define pwmpinC 6 //Выход ШИМ 3
int tachPins[6] = {14, 15, 16, 17, 18, 19};
int rpms[6] = {};
uint32_t lastSignalTimes[6] = {};
bool rpm_states[6] = {};
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 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; //целочисленные переменные для расчетов
uint32_t lastSignalTime;
typedef struct { // Вводим новый тип переменных для вентиляторов
char fantype;
unsigned int fandiv;
} fanspec;
fanspec fanspace[3] = {{0, 1}, {1, 2}, {2, 8}}; //Массив переменных нового типа
struct fan{ //Данные о вентиляторе
int tachPin; //Номер пина для считывания оборотов
bool tachState; //Состояние датчика оборотов
uint16_t revs; //Количество оборотв (просто, не в минуту)
uint16_t rpm; //Обороты в минуту
uint32_t lastSignalStart; //Время начала последнего сигнала тахометра
uint32_t lastSignalEnd; //Время окончания последнего сигнала тахометра
};
//fanspec fanspace[3] = {{0, 1}, {1, 2}, {2, 8}}; //Массив переменных нового типа
char fan = 1; //Переменная, отвечающая за выбор типа датчика вентилятора (1 – униполярный датчик Холла, 2 –биполярный датчик Холла)
uint32_t last_beep_time = 0;
uint32_t last_check_time = 0;
void rpm_interrupt(){
if(rpm_states[1] == 0){
rpm_states[1] = 1;
}
else{
rpm_states[1] = 0;
return;
}
rpms[1] = 60000000 / (micros() - lastSignalTimes[1]);
lastSignalTimes[1] = micros();
}
void rpmcalc() { //Считывание оборотов
for (int i = 0; i < 6; i ++) {
if (digitalRead(tachPins[i]) == 0) {
if (rpm_states[i] == 0){
rpm_states[i] = 1;
}
else{
rpm_states[i] = 0;
continue;
}
if (millis() - lastSignalTimes[i] != 0) {
rpms[i] = 60000 / (millis() - lastSignalTimes[i]);
}
else {
rpms[i] = 9999;
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]++;
}
lastSignalTimes[i] = millis();
last_signal_ends[i] = millis();
tachStates[i] = 0;
}
else if (millis() >= lastSignalTimes[i] + ZERO_RPM_TIMEOUT) {
rpms[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();
}
}
......@@ -93,7 +103,7 @@ void wait_for_connection(bool beep) { //функция, которая мига
analogWrite(SOUND_PIN, 0);
}
}
set_pwm();
}
digitalWrite(LED_PIN, 0); //гасим светодиод
analogWrite(SOUND_PIN, 0); //и выключаем пищалку
......@@ -109,20 +119,23 @@ void wait_for_connection(bool beep) { //функция, которая мига
void tempFromPc()// получаем температуру от пк
{
String rpm_string = "send_rpm_";
for (int i = 0; i < 6; i++) {
rpm_string += String(rpms[i]);
for (int i = 0; i < FAN_COUNT; i++) {
rpm_string += String(tachRpm[i]);
if (i < 5) {
rpm_string += "_";
}
}
Serial.println("req_temperature_" + rpm_string); //запрос к пк
unsigned long query_time = millis();
while (Serial.available() == 0) { //ждем пока ответит
if (millis() >= query_time + GET_TEMP_TIMEOUT) { //если слишком долго не отвечает
//Венитялторы на максимум
analogWrite(pwmpinA, 255);
analogWrite(pwmpinB, 255);
analogWrite(pwmpinC, 255);
for (int i = 0; i < 3; i++) {
pwr_tacts[i] = 1;
counters[i] = 1;
}
wait_for_connection(true);//снова ждем подключения
break;
}
......@@ -132,47 +145,88 @@ void tempFromPc()// получаем температуру от пк
}
void autocontrol()//Автоконтроль температуры
{
tempFromPc();//получаем температуру от пк
int pwr_tact_value = 1;
if (temp < 20) { //<20
rpmValue = 50;
//rpmValue = 50;
pwr_tact_value = 10;
}
else if (temp < 40) { //20-39
rpmValue = 100;
//rpmValue = 100;
pwr_tact_value = 7;
}
else if (temp < 60) { //40-59
rpmValue = 150;
//rpmValue = 150;
pwr_tact_value = 4;
}
else if (temp < 80) { //60-79
rpmValue = 200;
//rpmValue = 200;
pwr_tact_value = 2;
}
else { //>=80
rpmValue = 255;
//rpmValue = 255;
pwr_tact_value = 1;
}
if (prev_pwr_tact_value != pwr_tact_value) {
for (int i = 0; i < 3; i++) {
pwr_tacts[i] = pwr_tact_value;
counters[i] = 1;
}
prev_pwr_tact_value = pwr_tact_value;
}
}
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();
}
counters[i]++;
}
analogWrite(pwmpinA, rpmValue);//задаем скорость вращения кулера 1
analogWrite(pwmpinB, rpmValue);//задаем скорость вращения кулера 2
analogWrite(pwmpinC, rpmValue);//задаем скорость вращения кулера 3
}
void get8bits(int num, bool *bits_array) {
for (int i = 0; i < 8; i++) {
bits_array[i] = num >> (8 - 1 - i) & 1;
}
}
void setup() {
attachInterrupt(0, rpm_interrupt, FALLING);
pinMode(LED_PIN, OUTPUT);
pinMode(SOUND_PIN, OUTPUT);
for (int i = 0; i < 3; i++) {
pinMode(pwmPins[i], OUTPUT);
pwr_tacts[i] = DEFAULT_TACT;
}
pinMode(pwmpinA, OUTPUT);
pinMode(pwmpinB, OUTPUT);
pinMode(pwmpinC, OUTPUT);
analogWrite(pwmpinA, DEFAULT_RPM_VALUE);
analogWrite(pwmpinB, DEFAULT_RPM_VALUE);
analogWrite(pwmpinC, DEFAULT_RPM_VALUE);
for (int i = 1; i < 6; i++) {
pinMode(tachPins[i], INPUT_PULLUP); // Настраиваем pin на получение прерывания
for (int i = 0; i < FAN_COUNT; i++) {
pinMode(tachPins[i], INPUT_PULLUP); //Подтигиваем пины для считывания оборотов
}
Serial.begin(BAUDRATE);
pinMode(SOUND_PIN, OUTPUT);
wait_for_connection(false); //Ждем установленя связи с ПК
}
......@@ -198,5 +252,6 @@ void loop() {
}
}
//rpmcalc();
rpmcalc();
set_pwm();
}
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