Бортовой компьютер на мото

Модератор: boogyman

Ответить
Аватара пользователя
Techno_magic
Новичок
Сообщения: 7
Зарегистрирован: 15 фев 2017, 23:36

Бортовой компьютер на мото

#1

Сообщение Techno_magic »

Всем привет!
В общем купил мото, и решил сделать на него в дополнение к приборке типа "бортовой комп". По начальной задумке я хотел тупо выводить номер передачи на 7ми сегментник по 1 проводу.

Как работает? Очень просто, в КПП есть вал который поворачивается на определенный угол, соответствующий своей передаче, проградуировав и разметив углы, сделал не хитрую плату с резисторными делителями. В итоге когда переключается передача - переключается резисторный делитель и напряжение выходное соответственно тоже меняется.
Здесь мне на помощь пришло АЦП и гора условий в коде (самый первый мой шаг в изучении СИ и AVR). Проблем особо не возникло, все работало как часы.
Но мне этого МАЛО! Учитывая что контроллер Atmega169 и у него ого-го-го ног и ресурсов, значит можно еще что-то впинать.

Следующим шагом были часы, нашел коды готовых, поизучал, поизучал асинхронный таймер, понял что это не очень сложно и можно в любой момент код готовых часов воткнуть к себе и временно забил.
Во время изучения часов я решил что не плохо было бы еще показывать напряжение бортовой сети, остаток топлива (емкостный датчик), температуру воздуха и температуру двигателя.
Что касается емкостного датчика, решил временно отложить т.к. бОльшая часть схемы там будет на аналоговых компонентах, а возможности разработать и собрать схему пока нет((
Поэтому взялся вплотную за термометры и вольтметр.

Как я хочу это реализовать:

В контроллере есть куча ног куда можно переключать АЦП. На каждую ногу по своему аналоговому датчику (да, датчики температуры будут аналоговым не цифровым, никаких I2C). Всего будет задействовано 4 входа. Вход под КПП, 2 входа термометры и 1 вход под вольтметр.
Переключение должно происходить по нажатию на кнопку.
Для кнопки завел свою переменную, которая считает нажатия и с помощью switch case ставит в соответствие количеству нажатий кнопки вывод откуда цифровать значение. Вот здесь то я и столкнулся с проблемой.


Думаю стоит перейти к коду. по ходу буду пытаться объяснить )
Самое начало я пожалуй пропущу, где объявлены всякие переменные и циклы в которых крутится прога по прервыниям


Это важный кусок прерывания. Суть такая- запустили преобразование, АЦП оцифровал, поднял флаг, ушел в прерывание, в прерывании записал свое значение в переменную temp, и записал 1 в переменную FLAG. Переменная FLAG понадобится дальше, она служит для отслеживания завершилось ли преобразование АЦП.

Код: Выделить всё


// прерывание по окончанию преобразования АЦП
ISR (ADC_vect)
{
     temp=ADC;
     FLAG=1;
}

На данном этапе вопросов тоже особо нет
Настроил порты под сегменты
Запустил таймер
Настроил АЦП (надеюсь правильно настроил)
В начальный момент АЦП должно ыбть заглушено а потом в основном коде запустаться по необходимости.

Должно так работать- запустили АЦП оно оцифровало, записало в temp, сбросилось на 0 и ждет следующего запуска. Но работает явно не так :(

Код: Выделить всё


// Главная функция
int main (void) 
{ 
DDRB = 0xFF; // выходы на ОА
PORTB = 0x00; // ноль на выходе
DDRD = 0xFF; // выходы на сегменты
PORTD = 0x00; // ноль на выходе




// настройка таймера

TCCR2A |= (1 << CS21); //| (1<<CS20); // делитель  
TIMSK2 |= (1 << TOIE2); // разрешение прерывания по таймеру

// настройка АЦП



   ADCSRA |= (1 << ADEN) // разрешение АЦП
           |(0 << ADSC) // Запуск преобразования
           |(0 << ADATE) // непрерывный режим работы 
           |(1 << ADPS2)|(1 << ADPS1) // Ïделитель на 64 (частота АЦП 125kHz)
           |(1 << ADIE); // разрешение прерываний от АЦП

sei(); //глобально разрешены прерывания

Тут идет опрос кнопки, вроде бы все коректно работает т.к. делал код, чтоб на дисплей выводилось кол-во нажатий на кнопку, все выводит, работает. После 3 нажатий на 0 сбрасывает select. Переменная select собственно и накапливает в себе нажатия кнопки.

Прошу заметить что порт А я нигде не конфигурировал на вход, но как ни странно кнопка работает, может кто объяснить такой прикол?

Код: Выделить всё

while(1)
{ 

if ((PINA & 0x1) == 0) // если нажата кнопка на PA0.
  {
  _delay_ms (50);
  
           // устранение дребезга
     if ((PINA & 0x1) == 0) // опять проверяем нажатие

	  {
           while ((PINA & 0x1) == 0) //ждем пока кнопку не отпустят
                        {}
	        select++;// переменная выбора откуда цифровать АЦП
      }
                   
   }

if (select>2) select = 0; //сброс на 0 при переполнении

Едем дальше, вот тут начинается самый хардкор, который н*%:" не работает как надо

Здесь как раз и пригодилась та перемененная FLAG в прерывании АЦП. Пока АЦП не оцифровал и не записал 1 в переменную FLAG код дальше не идет т.к. если пойдет дальше то там начнется реальная дичь, прям во время цифрования может произойти переключение выводов оцифровки (изначально так и было и вся моя система выдавала полный несуразный бред вплоть до отдельно зажигающихся сегментов)

После завершения цифрования, и после того как FLAG=1 идем дальше. Тут switch case стоит для выбора с какой ноги брать сигнал для оцифровки согласно значению переменной select.

Именно этот фрагмент меня сильнее всего напрягает, ОНО НЕ ПЕРЕКЛЮЧАЕТ выводы для цифровки при нажатии на кнопку, я не знаю как и что тут надо сделать, чтобы он переключал. При проверке в железе, МК цифрует все с ADC3 и на нажатие кнопки не реагирует (точнее реагирует, но не переключает вывод для оцифровки). Мне с самого начала конструкция кода очень подозрительной казалась, но увы моих знаний не хватает чтобы заставить мультиплексор переключать.

На этом куске кода прошу помощи, как что и куда сделать.

Код: Выделить всё


while (FLAG == 0) //ждем завершения оцифровки
 {}


//выбираем с какого вывода цифровать
   switch (select)
  {   
  case 0:
  ADMUX |= (0 << REFS1)|(1 << REFS0)|(1 << MUX0);  //ADC1
  ADCSRA |= (1 << ADSC); // запуск цифрования
  break;  // выход
  case 1:
  ADMUX |= (0 << REFS1)|(1 << REFS0)|(1 << MUX1);  //ADC2
  ADCSRA |= (1 << ADSC);
  break; 
  case 2:
  ADMUX |= (0 << REFS1)|(1 << REFS0)|(1 << MUX0)|(1<<MUX1);  //ADC3 
  ADCSRA |= (1 << ADSC);
  break; 
  };


_delay_ms (50);

Дальше идет более менее рабочий кусок кода. Здесь опять же согласно переменной select выбирается способ обработки данных (переменной temp). В первом случае (case 0) я уже посчитал и сразу написал формулу для расчета напряжения бортовой сети с помощью заведомого известного делителя. (DP1 - это переменная для вывода точки, она не работает т.к. на авось написал и в подпрограмме вывода на дисплей не используется, только тут висит и на ни что не влияет)

Теперь вернусь к кнопке, выше сказал что мультиплексирование не работает, но кнопка работает. Доказательство работы кнопки дает как раз этот кусок кода.При нажатии кнопки меняется способ обработки значений с АЦП. Сначала выводит 19.96В (типа значение вольтметра но без делителя, поэтому тут все норм, как надо, по расчетам должно быть 20.00В), при нажатии на кнопку выводит 1023, еще раз жму опять 1023, еще жму (select сбрасывается на 0) опять вольтметр. При этом оцифровка идет постоянно с ADC3

Код: Выделить всё


switch (select)
  {   
  case 0:
  VOLT=(temp/204.8)*400; // вольтметр
  DP1=10; //точка
  display=VOLT; // запись в переменную дисплея значения напряжения.
  break; 
  case 1:
  display=temp; // будет термометр
  break; 
  case 2:
  display=temp; // будет термометр
  break;  
  };

_delay_ms (50);

while (FLAG == 0) //ждем завершения оцифровки
 {}

FLAG = 0; сбрасываем переменную FLAG для последующего отслеживания выхода с прерывания АЦП

И завершающий кусок кода, который тоже живет своей жизнью. Т.к. начальная и основная задача ставилась - выводить номер передачи, то НЕЗАВИСИМО от select должен постоянно опрашиваться ADC0 чтобы вывести номер передачи на отдельный индикатор. Как вы, надеюсь, догадываетесь, мультиплексирования тоже не происходит, цифрует с ADC3, при этом обидно, что даже при цифровании с ADC3 он не выводит номер передач на индикатор, рисует там "тире" которое соответствует тому, что значение АЦП вне диапазонов делителей (на практике - типа момент переключения передач, когда первая уже выключена, а вторая еще не включена)

Код: Выделить всё


ADMUX |= (0 << REFS1)|(1 << REFS0)| (0 << MUX0)| (0 << MUX1); // опорник 5В ADC0

ADCSRA |= (1 << ADSC);

_delay_ms (50); // задержка чтоб дать АЦП оцифровать и потом взять от туда temp

if ((temp<176) & (temp>196))
    {GEAR=1;}
	
	{if ((temp<126) & (temp>146))
    	{GEAR=11;} // Н в массиве
         
        {if ((temp>317) & (temp<337))
		     {GEAR=2;}
			 
			 {if ((temp>453) & (temp<473))
			     {GEAR=3;}
				  
				  {if ((temp>792) & (temp<812))
				     {GEAR=4;}
                     
					 {if ((temp>920) & (temp>940))
					    {GEAR=5;}
						 
						{GEAR=12;}    // тире в массиве
                      }
                   }
               }
           }
	 }

		_delay_ms (50);
}
}


В общем ХЭЛП, с этим мерзким мультиплексированием, как мне грамотно переключать входы для оцифровки?



Немного про мой "конструктор", софт и программатор.

Плата с контроллером содержит необходимый минимум: кварц на 8МГЦ с обвязкой, фильтры по питанию, выбор опорника (перемычкой выбирается напряжение питания) В комплекете еще 7мисегментный индикатор на 4 цифры, пара кнопок и переменный резистор. Платы делал фоторезистом.
P1100932.JPG
P1100934.JPG
Программатор USB на FTDI микросхеме. Не мой, подарили много лет назад))
P1100936.JPG
Софт, в котором пишу код - AVR Studio 4
Шью через SinaProg
Techno_magic
Аватара пользователя
Techno_magic
Новичок
Сообщения: 7
Зарегистрирован: 15 фев 2017, 23:36

Re: Бортовой компьютер на мото

#2

Сообщение Techno_magic »

Чуть не забыл, вот весь код, рассчитываю на вашу помощь :)
gearDetectorV2.rar
(28.06 КБ) 379 скачиваний
Techno_magic
Аватара пользователя
AntonChip
Администратор
Сообщения: 265
Зарегистрирован: 24 дек 2011, 22:11
Откуда: Киров
Контактная информация:

Re: Бортовой компьютер на мото

#3

Сообщение AntonChip »

подобные выражения

Код: Выделить всё

 ADMUX |= (0 << REFS1)|(1 << REFS0)|(1 << MUX0);
поменяйте на

Код: Выделить всё

 ADMUX = (0 << REFS1)|(1 << REFS0)|(1 << MUX0);
, уберите знак "|"
Аватара пользователя
Techno_magic
Новичок
Сообщения: 7
Зарегистрирован: 15 фев 2017, 23:36

Re: Бортовой компьютер на мото

#4

Сообщение Techno_magic »

Крутяк, похоже прокатило, работает)) Щас ток домой с универа пришел, сразу зашил, переключается по нажатию кнопки. Но похоже с ADC0 не цифрует... сейчас покопаюсь может где накосячил
Techno_magic
Аватара пользователя
Techno_magic
Новичок
Сообщения: 7
Зарегистрирован: 15 фев 2017, 23:36

Re: Бортовой компьютер на мото

#5

Сообщение Techno_magic »

Такой вопрос- такая форма записи коректна?

if ((A>B) & (A<C))
{i++;}
Techno_magic
Аватара пользователя
AntonChip
Администратор
Сообщения: 265
Зарегистрирован: 24 дек 2011, 22:11
Откуда: Киров
Контактная информация:

Re: Бортовой компьютер на мото

#6

Сообщение AntonChip »

Код: Выделить всё

if ((A>B) && (A<C))
{i++;}
Аватара пользователя
Techno_magic
Новичок
Сообщения: 7
Зарегистрирован: 15 фев 2017, 23:36

Re: Бортовой компьютер на мото

#7

Сообщение Techno_magic »

Спасибо) заработало)
Techno_magic
Аватара пользователя
Techno_magic
Новичок
Сообщения: 7
Зарегистрирован: 15 фев 2017, 23:36

Re: Бортовой компьютер на мото

#8

Сообщение Techno_magic »

Как выставлять приоритеты прерывания? Т.е. например если сработало 2 прерывания (сначала одно, и сразу другое), то другому задать приоритет выше первого?
Это нужно для часов. Половина кода работает на прерываниях и если завести часы на асинхронном таймере и по прерыванию складывать секунды, то очень легко потерять будет прерывание если так совпадет и точность будет не айс(
Techno_magic
Аватара пользователя
AntonChip
Администратор
Сообщения: 265
Зарегистрирован: 24 дек 2011, 22:11
Откуда: Киров
Контактная информация:

Re: Бортовой компьютер на мото

#9

Сообщение AntonChip »

ранг прерываний установлен аппаратно, поменять нельзя, если только манипулировать командами разрешения и запрета прерываний
Аватара пользователя
Techno_magic
Новичок
Сообщения: 7
Зарегистрирован: 15 фев 2017, 23:36

Re: Бортовой компьютер на мото

#10

Сообщение Techno_magic »

Есть первый результат) Сырой правда вариант но работает. Прошивка скорее всего меняться больше не будет существенно. Нужно коэффициенты к термодатчикам подобрать.
Также здесь появился режим энергосбережения - отключается дисплей и через полевики отключаются все резисторные делители от питания, работает только одна мега.
Ну есть небольшой баг с 25 часами) На видео это вроде в самом конце почти не влезло. Если настраивать время кнопками то можно успеть натыкать 25 часов, но это чисто визуальный баг, при последующем прерывании обнуляется до 00 00 часов.
Также стоит часовой кварц и часы работают от него.

phpBB [youtube]



Есть небольшой вопрос, как подключать левые библиотеки в АВР Студио 4? Чет прошвырнулся по папкам программы ниге не нашел *.h файлов :o . Хочу с ЖК дисплеем поиграть, нашел от него библиотеки а подключить не могу
Techno_magic
Ответить