У меня i.MX6 на специальной плате с разъемом для вентилятора. К сожалению, однако, линия обратной связи тахометра присоединена к выводу GPIO. Есть ли способ точно прочитать скорость вращения вентилятора? Некоторое быстрое прибегание к гуглу не выявило каких-либо счетчиков краев или чего-либо встроенного в i.MX6, которое я мог бы использовать.
Я попытался написать приложение для проверки концепции, которое подсчитывало количество прерываний, но оно ужасно неточно, и я ожидаю, что оно будет меньше, если нагрузка на процессор будет. Я вижу вентилятор, работающий на постоянной скорости, который возвращает значения от 1500 об / мин до 8k об / мин, когда фактическое значение равно 4k.
#include "os/threading/semaphore.h"
#include "os/threading/thread.h"
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <limits>
#include <poll.h>
#include <sstream>
#include <string>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
long timer_end(struct timespec start_time);
void select_gpio_number(const std::string &gpio_number);
void set_gpio_direction(const std::string &gpio_number, const std::string &direction);
void set_edge(const std::string &gpio_number);
static long period_ns = 0;
void select_gpio_number(const std::string &gpio_number)
{
std::ofstream gpio_export("/sys/class/gpio/export");
gpio_export << gpio_number;
gpio_export.flush();
}
void set_gpio_direction(const std::string &gpio_number, const std::string &direction)
{
std::ofstream gpio_direction("/sys/class/gpio/gpio" + gpio_number + "/direction");
gpio_direction << direction;
gpio_direction.flush();
}
void set_edge(const std::string &gpio_number)
{
std::ofstream gpio_edge("/sys/class/gpio/gpio" + gpio_number + "/edge");
gpio_edge << "both";
gpio_edge.flush();
}
long timer_end(struct timespec start_time)
{
struct timespec end_time;
clock_gettime(CLOCK_MONOTONIC, &end_time);
long diffInNanos = end_time.tv_nsec - start_time.tv_nsec;
return diffInNanos;
}
int main(int, char *[], char *[])
{
int num_samples = 0;
std::string input_number("39"); // GPIO2_IO7 -> (2 - 1) * 32 + 7 = 39
struct timespec start_time;
double frequency = 0.0;
std::ostringstream input_value;
input_value << "/sys/class/gpio/gpio" << input_number << "/value";
select_gpio_number(input_number);
set_gpio_direction(input_number, std::string("in"));
set_edge(input_number);
int tach_value_fd = open(input_value.str().c_str(), O_RDONLY | O_NONBLOCK);
struct pollfd tach_poll_fd;
memset(static_cast<void *>(&tach_poll_fd), 0, sizeof tach_poll_fd);
tach_poll_fd.fd = tach_value_fd;
tach_poll_fd.events = POLLPRI;
char current_tach_value;
while (true)
{
// num_samples = 0;
lseek(tach_value_fd, 0, SEEK_SET);
poll(&tach_poll_fd, 1, -1);
read(tach_value_fd, ¤t_tach_value, sizeof current_tach_value);
if (current_tach_value == '0')
{
// printf("edge detected\n");
if (num_samples >= 1)
{
period_ns = timer_end(start_time);
num_samples = 0;
frequency = 1.0 / ((period_ns + 200000.0) / 1000000000.);
printf("Fan is spinning at: %lf Hz or %ld RPM\n", frequency, static_cast<long>(frequency * 30));
sleep(1);
}
else
{
clock_gettime(CLOCK_MONOTONIC, &start_time);
num_samples++;
}
}
}
return 0;
}
Есть ли что-то вопиюще неправильное в коде (да, я знаю, что функции, вероятно, должны быть stati c и тому подобное) или лучше использовать (идеально встроенный в аппаратное обеспечение)? Или я возвращаюсь к команде электриков и говорю им, чтобы они поменяли контакт?