Мини компьютер на мотоцикл Урал
- Войдите на сайт для отправки комментариев
Чт, 16/05/2013 - 20:08
Делаю микрокомпьютер для урала на дисплее 3310 (Индикатор заряда и напряжения аккумулятора,температура, тахометр цифровой и графическая шкала к нему, индикаторы поворотов и света.)
Сталкнулся с проблемой тахометра. Перечитал много о цифровых тахометрах, но так и разобраться не могу до конца. Кароче не работает, помогите сделать. Сигнал буду брать на прямую с прерывателя (один переход с HIGH на LOW = 1 оборот)
Делал по аналогии с http://cxem.net/arduino/arduino66.php
#include <PCD8544.h>
//для индикатора питания
int AKB = 12;
static const byte sensorPin = 0;
static const byte ledPin = 13;
//для тахометра
volatile float time = 0;
volatile float time_last = 0;
volatile int rpm_array[5] = {0,0,0,0,0};
// Размеры ЖК-дисплея (в пикселях) ...
static const byte LCD_WIDTH = 84;
static const byte LCD_HEIGHT = 48;
// рисунок аккумулятора без зарядки
static const byte AKB_WIDTH = 10;
static const byte AKB_HEIGHT = 1;
static const byte AKB_nocharge[] = { 0x7C, 0x46, 0x46, 0x44, 0x44, 0x44, 0x46, 0x46, 0x7C, 0x00};
// рисунок аккумулятора с зарядкой
static const byte AKB_charge[] = { 0x7C, 0x7E, 0x7E, 0x7C, 0x7C, 0x7C, 0x7E, 0x7E, 0x7C, 0x00};
static PCD8544 lcd;
// функция прерывания
void chopper_interrupt()
{
time = (micros() - time_last);
time_last = micros();
}
void setup() {
Serial.begin(9600);
lcd.begin(LCD_WIDTH, LCD_HEIGHT);
//Цифровой Pin 2 Установить как прерывание
attachInterrupt(0, chopper_interrupt, FALLING);
pinMode(ledPin, OUTPUT);
pinMode(AKB, INPUT);
}
void loop() {
static byte xChart = LCD_WIDTH;
digitalWrite(ledPin, HIGH);
//=============(Индикатор питания)==================
// Считать напряжение
float volt = (5 * analogRead(sensorPin) / 1023 / 0.714); // 0.714 переводной коэф делителя напряжения
// Нарисуйте аккумулятор
lcd.setCursor(0, 0);
if ( digitalRead(AKB) == 0 )
{
lcd.drawBitmap(AKB_nocharge, AKB_WIDTH, AKB_HEIGHT);
}
else
{
lcd.drawBitmap(AKB_charge, AKB_WIDTH, AKB_HEIGHT);
}
// показать напряжение аккумулятора
lcd.setCursor(10, 0);
lcd.print(volt, 1);
lcd.print("B");
//=================================================
//===============(Тахометр)========================
lcd.setCursor(37, 0);
lcd.print("RPM:");
int rpm = 0;
//delay(400);
//Цеферблат оборотов
lcd.setCursor(61, 0);
lcd.print(rpm);
////lcd.setCursor(4, 1);
////lcd.print(time);
//Обновление RPM
if(time > 0)
{
//Усреднение(сглаживание)
rpm_array[0] = rpm_array[1];
rpm_array[1] = rpm_array[2];
rpm_array[2] = rpm_array[3];
rpm_array[3] = rpm_array[4];
rpm_array[4] = 60*(1000000/(time*1));
//Среднее значение по 5 замерам
rpm = (rpm_array[0] + rpm_array[1] + rpm_array[2] + rpm_array[3] + rpm_array[4]) / 5;
}
digitalWrite(ledPin, LOW);
delay(500);
}
А зажигание у вас электронное или контактное?
контактное
Тогда вы должны знать о таком явлении как дребезг котактов. И рекомендую все-таки поставить опторазвязку иначе можно сжеч дуину.
http://hardlock.org.ua/viewtopic.php?f=9&t=16 я вот так буду делать, через транзистор, только не с катушки наверное буду брать, а с самого прерывателя.
maksim, вы можете мне подсказать по поводу кода? почему не рабаотает. уже 2 день бьюсь...
естественно я сейчас пробуду не на прерыватете а на кнопке простой. и получается так что сейчес RPM показывает 0, и ещё, я же бал код вот этот
#include <LiquidCrystal.h> LiquidCrystal lcd(3, 5, 9, 10, 11, 12); volatile float time = 0; volatile float time_last = 0; volatile int rpm_array[5] = {0,0,0,0,0}; void setup() { //Digital Pin 2 Set As An Interrupt attachInterrupt(0, fan_interrupt, FALLING); // set up the LCD's number of columns and rows: lcd.begin(16, 2); // Print a message to the LCD. lcd.print("Current RPM:"); } void loop() { int rpm = 0; while(1){ //Slow Down The LCD Display Updates delay(400); //Clear The Bottom Row lcd.setCursor(0, 1); lcd.print(" "); //Update The Rpm Count lcd.setCursor(0, 1); lcd.print(rpm); ////lcd.setCursor(4, 1); ////lcd.print(time); //Update The RPM if(time > 0) { //5 Sample Moving Average To Smooth Out The Data rpm_array[0] = rpm_array[1]; rpm_array[1] = rpm_array[2]; rpm_array[2] = rpm_array[3]; rpm_array[3] = rpm_array[4]; rpm_array[4] = 60*(1000000/(time*7)); //Last 5 Average RPM Counts Eqauls.... rpm = (rpm_array[0] + rpm_array[1] + rpm_array[2] + rpm_array[3] + rpm_array[4]) / 5; } } } void fan_interrupt() { time = (micros() - time_last); time_last = micros(); }и убал while(1), так как получется так что зацикливалась ардунка на нем(тахометре) и как кие-то бешаные цифры показывала в RPM, в том числе и отрицательные
Доброго времени суток !
Я бы тахометр делал через таймер1.
Настройте таймер 1 в нормальный режим (как это сделать написано в datasheet на Ваш контроллер) частота тактирования таймера задается в зависимости от длинны импульса получаемого на вход (извените не знаю частоты вращения двигателя Урала) Об/Мин_мин / 60 получаем = Об/Сек_мин ; 1 / Об/Сек_мин = Длину одного оборота в секундах. После чего подбираем частоту деления таймера так, что бы в "Длину одного оборота в секундах" вошло 50000 - 60000 тактов. Далее настраиваем маску прерываний от таймера на два прерывания TIMSK = 33 (32(прерывание от ICR) и 1(прерывание от переполнения)) и настраиваем два вектора. Вектор от ICR считывает егистр ICR1 и обнуляет TCNT1. Второе прерывание выставляет флаг двигатель остановлен. Число из ICR быдет длинной входного импульса в тактах, чем меньше тактов - тем выше скорость вращения, зная опорную частоту можно перещитать длинну импульса в секундах, а соответственно и количество оборотов в минуту.
Вы рекомендуете человеку разобраться как настраивать и работать с таймером/счетчиком через регистры, который не знает о дребезге контактов и который не может адаптировать под свой дисплей найденную через поиск по сайту программку тахометра (их с пяток здесь есть). Конечно ваше решение получится красивым, но не для новичка.
Это все равно что третьекласснику посоветовать изучить интеграллы, а затем воспользоваться ими для вычисления плошади прямоугольника. Поэтому вот более простое решение:
#include <LiquidCrystal.h> LiquidCrystal lcd(3, 5, 9, 10, 11, 12); volatile uint32_t time = 0; void setup() { attachInterrupt(0, fan_interrupt, FALLING); lcd.begin(16, 2); lcd.print("Current RPM:"); } void loop() { static uint32_t millis_prev; if(millis()-millis_prev >= 1000) { detachInterrupt(0); lcd.setCursor(0, 1); lcd.print(" "); lcd.setCursor(0, 1); lcd.print(time); time = 0; attachInterrupt(0, fan_interrupt, FALLING); millis_prev = millis(); } } void fan_interrupt() { time++; }данный пример будет показывать колличество срабатываний за одну секунду, расчет и частоту обновлений думаю сами сделаете. Еще раз повторюсь, если вы будите проверять этот пример на кнопке или подключите к прерывателю (не важно) и значения будут завышенными, то читайте что такое дребезг и как с ним бороться.
как вы и говорили. дребезг дал свое... возможно ли избавиться от бребезга програмно в этом случае?
Конечно можно
void fan_interrupt() { static uint32_t millis_prev; if(millis()-10 > millis_prev) time++; millis_prev = millis(); }число 10 это промежуток времени в милисекундах в течении которого последующие срабатывания будут игнорироваться.
Так же может применяться такая конструкция
void fan_interrupt() { static uint32_t millis_prev; if(millis()-10 > millis_prev) { time++; millis_prev = millis(); } }Подскажите пожалуйсто вот ещё в чем. Как сделать мигание индикатора поворота не прерывая основной программы.
#include <PCD8544.h> //для индикаторов int LEFT = 1; int RIGHT = 2; int pa = 1500; // Размеры ЖК-дисплея (в пикселях) ... static const byte LCD_WIDTH = 84; static const byte LCD_HEIGHT = 48; // рисунок левого поворота static const byte LEFT_WIDTH = 7; static const byte LEFT_HEIGHT = 2; static const byte LEFT_H[] = {0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0x02, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF,}; static const byte LEFT_L[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}; static PCD8544 lcd; // программа для левого поворота void left_prog() { lcd.setCursor(1, 14); lcd.drawBitmap(LEFT_H, LEFT_WIDTH, LEFT_HEIGHT); delay(pa); lcd.drawBitmap(LEFT_L, LEFT_WIDTH, LEFT_HEIGHT); delay(pa); } void setup() { lcd.begin(LCD_WIDTH, LCD_HEIGHT); } void loop() { static byte xChart = LCD_WIDTH; digitalWrite(ledPin, HIGH); // индикатор левого поворота if ( analogRead(LEFT) == 0 ) { lcd.setCursor(1, 14); lcd.drawBitmap(LEFT_L, LEFT_WIDTH, LEFT_HEIGHT); } else { left_prog(); } digitalWrite(ledPin, LOW); delay(500); }получается так что не мигает он на экране... просто хочу сделать так, чтобы прерывание поворотов осуществлялось именно через ардуино т.к. мотоцикл 6 вольтовый и нету нормального реле поворотов.