Администрация форума не несёт ответственности за достоверность информации и оставляет за собой право редактировать или в особых случаях даже удалять посты без предупреждения. Спасибо за понимание.

Программирование ATMEL в BASCOM.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Программирование ATMEL в BASCOM. » Бытовая и промышленная техника, авто, мото и т.п. » Спидометр, помогите с алгоритмом


Спидометр, помогите с алгоритмом

Сообщений 1 страница 28 из 28

1

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

Как правильней мерить скорость измерением частоты импульсов за одну секунду или измерением периода и пересчетом в скорость?

Написал два алгоритма, прошу строго не судить , я только начинаю АВРки изучать.
Для упрощение пока беру длинну окружности колеса 1 метр, потом пересчитаю

Алгоритм номер 1
Должен работать так

Таймер 1 переполняется каждую секунду, по прерыванию я забираю из счетчика таймера о значение, это частота импульсов, пересчитываю её в скорость.

В протеусе работает странно, к примеру если у меня частота с генератора 1 герц, то нормально считает 3.6 км/ч, если я ставлю дробное значение частоты,  скажем 1.5 гц, то показание всё время меняются. Что это Глюк протеус?

Код:
$regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 40
$swstack = 16
$framesize = 32


Dim S As Single                                             ' Speed
Dim B As Byte                                               '  Помещаем значение из  Timer0

Config Lcdpin = Pin , Db4 = Portc.0 , Db5 = Portc.1 , Db6 = Portc.2 , Db7 = Portc.3 , E = Portc.5 , Rs = Portc.4
Reset Ddrb.1


Config Timer1 = Timer , Prescale = 256                      ' Таймер должен переполнятся 1 раз в секунду
Config Timer0 = Counter , Edge = Falling ' Счетчик импульсов
   Timer1 = 0
   Enable Timer0
      Start Timer0
On Timer1 Speed
Enable Interrupts
Enable Timer1
Timer1 = 3036 ' Таймер должен переполнятся раз в секуду
Cursor Off
Cls
Locate 1 , 1
Lcd "Test Line"
Wait 1
Cls

Do ' основной цикл 


S = B * 36 ' скорость из частоты
S = S / 10
Locate 1 , 1
Lcd S
Loop

Speed:
Stop Timer0 ' Останавливая Таймер
B = Timer0 ' Забираю значение
Timer0 = 0 ' Обнуляю Таймер 
Timer1 = 3036
Start Timer0 
Return

http://s7.uploads.ru/t/r62UE.jpg

0

2

Второй алгоритм, гдея я пытаюсь измерить период импульсов на входе ISP1 и из этого получить скорость.

Код:
$regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 40
$swstack = 16
$framesize = 32


Config Lcdpin = Pin , Db4 = Portc.0 , Db5 = Portc.1 , Db6 = Portc.2 , Db7 = Portc.3 , E = Portc.5 , Rs = Portc.4
Config Timer1 = Timer , Prescale = 256 , Capture Edge = Falling

Dim T As Single
Dim F As Single
Dim V As Single

On Capture1 Captmr
Timer1 = 0
Enable Interrupts
Enable Capture1
 Cursor Off

Do   ' основной цикл

T = Capture1 / 62500 ' измеряю период

F = 1 / T  ' частота из периода

V = F * 36 ' скорость из частоты
V = V / 10

Locate 1 , 1
Lcd V

Waitms 50
Loop

Captmr:
Timer1 = 0
Return
End

Тут то же проблемы, как быть если импульсы не поступают или их период больше одной секунды, в этом случае таймер1 переполниться и
при преходе следующего импульса захватиться неправильное значение?

Как нибудь можно переменные Word использовать? Мне скорость нужна только целые значения.

Подскажите пожалуста!

Отредактировано Evgeny 76 (2013-12-16 18:16:43)

0

3

Делать проверку на значение Capture1 как на максимальное значение (отсутствие импульсов), так и на минимальное значение (при этом можно уменьшать делитель таймера1) так получим высокую точность на высоких скоростях.

0

4

Может у кого есть готовый алгоритм для сравнения?

0

5

MACTEPok написал(а):

Делать проверку на значение Capture1 как на максимальное значение (отсутствие импульсов), так и на минимальное значение (при этом можно уменьшать делитель таймера1) так получим высокую точность на высоких скоростях.

Сдела по переполнению Timer1 прерывание, где обнуляется Capture1
Получается, что когда нет импульсов таймер переполнится и программа обнулит регистр захвата.

0

6

Блин опять косяк, так как прерывания в прерываниях не работают, то если переполнение возникло при отутсвие ипульсов, то
показание в нуль сбрасываются, а при малой скорости идёт прерывания от капча и до следующего импульса таймер все равно переполняется и начинает считать заново.

0

7

В общем если пределитель 1024 сделать, то и длинные периоды меряет и при отсутствие импульсов обнуляет, правда через 4 секуныды

0

8

Усложняешь сильно ))
Тебе по сути по прерыванию нужно выгребать значение таймера и вычислять значение скорости (мгновенное), усреднять показания за несколько секунд и рисовать скорость, переводить период в частоту для этого не обязательно.
Для пройденного пути будет достаточно просто считать прерывания и умножать на длину окружности колеса.
В помощь исходники можешь взять отсюда http://radiokot.ru/forum/viewtopic.php?f=43&t=87477  , там хорошо разжевано. Превратить тахометр в спидометр для велосипеда проще пареной репы )

Отредактировано Skull (2013-12-16 20:15:53)

0

9

Кстати, необязательно использовать таймер как таймер (им считать периоды).
Можно его использовать просто как генератор прерывания с повышенной частотой (чувствительность, только не сильно её задирать), для отдельного счетчика на Dword переменной. Подобрать нужную скорость чтобы эта переменная никогда не переполнялась. А дальше всё проще, можно вообще поставить ограничитель на максимальное значение и по нему определять бесконечность (колесо не крутится). Считаем только старты (импульсы с датчика), по приходу сигнала просто считывать показания и сбрасывать (так по кругу). Далее поставив параллельно сторонний спидометр, можно посмотреть сколько импульсов насчитывается при какой скорости (закономерность должна быть: чем больше импульсов - тем меньше скорость вращения колеса). Думаю замерив пару показаний, можно знать коэффициент перерасчёта скорости (линейно всё).

0

10

Спасибо, за советы.

Еще вопрос датчик холла с цифровым выходом дребезга не имеет? По идеи там уже гистерезис аппаратно должен быть реализован?

0

11

Skull написал(а):

Усложняешь сильно ))
Тебе по сути по прерыванию нужно выгребать значение таймера и вычислять значение скорости (мгновенное), усреднять показания за несколько секунд и рисовать скорость, переводить период в частоту для этого не обязательно.
Для пройденного пути будет достаточно просто считать прерывания и умножать на длину окружности колеса.
В помощь исходники можешь взять отсюда http://radiokot.ru/forum/viewtopic.php?f=43&t=87477  , там хорошо разжевано. Превратить тахометр в спидометр для велосипеда проще пареной репы )

Отредактировано Skull (Сегодня 17:15:53)

Подпись автора

    из горящей спиртовки не отхлёбывать!

Как в Bascom усреднять показания скажем трех значений одной переменной ?

по идеи (a1*a2*a3)/(a1+a2+a3),  как это сделать для одной переменной, в цикле еще две временных завести?

И еще один вопрос, какая постоянная времени должна быть у спидометра, то есть период измерения?

Отредактировано Evgeny 76 (2013-12-16 23:06:24)

0

12

Evgeny 76 написал(а):

Как в Bascom усреднять показания скажем трех значений одной переменной ?
по идеи (a1*a2*a3)/(a1+a2+a3),  как это сделать для одной переменной, в цикле еще две временных завести?
И еще один вопрос, какая постоянная времени должна быть у спидометра, то есть период измерения?
Отредактировано Evgeny 76 (Вчера 22:06:24)

Неправильно. Тебе нужно среднее арифметическое. Это (A1+A2+An) \ n.
Создаешь переменную типа
dim T(3) as word
do
тут вычисляешь (A1+A2+An) \ n. желательно по флагу, который выставишь в прерывании по завершении третьего вычисления. За скорость работы прерывания можешь не париться, все равно ТАК быстро ты ездить не сможешь, а если сможешь, то раньше сгоришь в атмосфере ))

loop

в прерывании:
int_:
incr tt
{ тут процедура вытягивания из таймера значения}
T(tt)={данное из процедуры}
if tt=3 then tt=0
return

Период измерения возьми на свой вкус ) Чтобы не страдать на малых скоростях поставь 2-4 магнитика на колесо (учти в пересчете скорости) Хотя, сантиметры в минуту тебе не пригодятся ))
Смотри, если взять 26`колесо (559мм) длина его окружности- 3.1415926*0.559 =1.75615 Метра 1 оборот. (перемеряй с шиной, это по ободу)
Если начинать с 1 км\ч, то :
1000\1.75615=569.4273553 оборотов колеса на км
период импульса составит 3600сек\569.4273553=6.32214 сек\оборот. Это и есть твой минимальный период для скорости от 1 км\ч.
Учитывая, что более 4сек померить не можешь, 3 магнита в зубы и считай период )) Или считай переполнения.... тут как фантазия подскажет...

Отредактировано Skull (2013-12-17 02:01:38)

0

13

Ну вот как то так получилось:

Код:
$regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 40
$swstack = 16
$framesize = 32


Config Lcdpin = Pin , Db4 = Portc.0 , Db5 = Portc.1 , Db6 = Portc.2 , Db7 = Portc.3 , E = Portc.5 , Rs = Portc.4
Config Timer1 = Timer , Prescale = 256
Config Pind.2 = Input
Config Int0 = Falling

 On Int0 Count
 On Timer1 Res

 Dim C As Word
 Dim Speed As Long


 Enable Interrupts
 Enable Int0
 Enable Timer1
 Cursor Off
 Cls

Do
 Speed = 225000 / C
 Locate 2 , 1
 Lcd Speed                                                  'Speed
 Waitms 800
 Cls
Loop

Count:
 Stop Timer1
 C = Timer1
 Timer1 = 0
 Start Timer1
Return

Res:
 Stop Timer1
 Timer1 = 0
 C = 0
Return

Теперь коэффициент надо придумать как считать под колесо, пока оно у меня 1 метр :)

Отредактировано Evgeny 76 (2013-12-17 03:43:28)

0

14

То же подумал, пересчитаю под  1024, кварцев нету к сожалению других, верней есть пинборды аля ардуинос 16 мегагерцами уже впаянными.

0

15

Для Atmega8 8МГц делал автомобильный тахометр. Измеряет от 0,5Гц, что соответствует 15 оборотам двигателя в минуту. Переделать в спидометр, думаю, будет несложно. Единственный небольшой недостаток в том, что показывает 0 оборотов лишь через 2 секунды, как двигатель выключили. Выжимка:

Код:
$crystal = 8000000
Config Int0 = Falling
On Int0 Impulse
Config Timer1 = Counter , Prescale = 256 ' При частоте 8МГц, переполнение каждые 2 секунды
On Timer1 Taho_timeout
Dim Taho As Word
Dim Rpm as Single
Main_program:
' тут делаем что-то, в том числе и считаем обороты двигателя:
' Период импульсов с датчика = количество импульсов Timer1 между двумя импульсами с датчика
' 0.000032 - это период Timer1 в секундах:
Rpm = Taho * 0.000032 
' Частота импульсов с датчика:
Rpm = 1 / Rpm
Goto Main_program

Impulse:
Taho = Timer1
Timer1 = 0
Return

Taho_timeout:
   Taho = 0
Return

0

16

Всем привет!
Когда-то, многоуважаемый dmm дал мне отличный совет(вообще их очень много), использовать табличный метод. вместо вычислений.

Таким образом твоя программа будет работать стабильно и быстро.

Суть:
В Exel делаешь таблицу необходимой размерности со значениями таймера.
Например, Для 16 MHZ с предделителем таймера1 1024 и 1 метра длины окружности получится следующее:
Если на один оборот колеса приходится один импульс датчика скорости (что не очень хорошо для малых скоростей)
при скорости 1 км/ч (‪0,277778‬ м/c)  время оборота колеса будет равно t = S / V, где S - пройденный путь (в нашем случае, длина окружности колеса), а V - текущая скорость
t = 1 / 0.277778 = 3,5999971200023039981568014745588 секунд.
Чтобы узнать значение таймера, нужно это время разделить на (1024/16000000) = 56250. Ну чтож, в рамки размерности timer1 вместились.
Рассчитав значение таймера для остальных скоростей (сколько там он едет) с шагом в 1км/ч, получим таблицу:

Speed:

Data 65000                       '0 km/h
Data 56250                       '1 km/h
Data 28124                       '2 km/h
......

В первую, точнее, нулевую строку, добавляем значение, при котором будем считать, что мопед никуда не двигается.

Таким образом, номер строки в таблице будет соответствовать скорости в км/ч

Все, что остается - по ICP или по другому прерыванию, не важно, поднимаешь флаг (переменную), чтобы основная программа поняла, что импульс пришел. В основной программе узнаешь значение таймера1 и перебираешь строки таблицы, увеличивая индекс строки от 0 до максимального значения (максимальная скорость), чтобы выяснить, какому значению в таблице он соответствует ( условием >=) и вывести на дисплей номер строки с припиской km/h

И никаких умножений, делений, сложений. ничего. лишь одна операция сравнения. ну и пара присваиваний
Profit!

Отредактировано demonizer (2013-12-22 19:55:46)

0

17

А чтобы не было при резкой остановке паразитной скорости - по переполнению таймера1 ставишь флаг, например, run = 0
а при срабатывании прерывания run = 255, в зависимости от него либо вычисляешь скорость, либо пишешь 0 km/h

0

18

Совет хороший наверное, но как то табличный метод у меня с чем то более быстро действенным всегда ассоциации вызывал
ну там синус-косинус генерить, где время на вычисления уже не остаётся.

В общем работает спидометр по моему алгоритму.

Пока погода позволяла повозился . Сначала измерил длину окружности колеса с покрышкой
для этого просто тупо мелом на покрышки черту нарисовал, проехал, потом измерил расстояние между следами.
После этого пересчитал всё под длину колеса.

Сравнил показания по GPS, почти совпали , подкорректировал коэффициент под GPS, проверил на ментовском табло
(в Германии такие весят для устрашения водил, просто скоростимеры без камеры), показания совпадают.

0

19

Я вот вопросом задаюсь, а вот LCD двухзначные или отдельные модули большие бывают ?
То есть знакоместо в высоту 3-5 см и как они называются?
Экранчик 16Х2 мелковат. Есть у меня LED индикаторы большие, но на солнце их не видно будет.

И еще при скорости больше 85-90 км/ч появляются расхождение с GPS сапидометром где то на 1-1.5 км/ч
хотя не критично, в машине то же не совпадают, там где то на 3 км/ч меньше во всё диапазоне .

Отредактировано Evgeny 76 (2013-12-26 22:20:34)

0

20

Evgeny 76
хочетсся код глянуть

0

21

demonizer написал(а):

Evgeny 76
хочетсся код глянуть

Криво, но пока так, потом хочу с другим кварцем попробовать

Код:
$regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 40
$swstack = 16
$framesize = 32


Config Lcdpin = Pin , Db4 = Portb.2 , Db5 = Portb.3 , Db6 = Portb.4 , Db7 = Portb.5 , E = Portb.1 , Rs = Portb.0
Config Timer1 = Timer , Prescale = 1024
Config Pind.2 = Input
Config Int0 = Falling
Config Pind.3 = Input
Config Int1 = Falling
Config Pind.6 = Input
Config Pind.7 = Input

 On Int0 Count
 On Timer1 Res
 On Int1 Menu

 Dim C As Word
 Dim Speed As Single
 Dim Rad1 As Eram Single
 Dim Rad As Single

 Dim Mtime As Byte




 Enable Interrupts
 Enable Int0
 Enable Int1
 Enable Timer1
 Cursor Off

'Rad = Rad1

Rad = 820


Cls
Do

 Speed = 56 / C
 Speed = Speed * Rad

 Locate 1 , 1
 Lcd Speed

                                                   'Speed
 Locate 1 , 3

'Lcd " KM/H"
 Waitms 800
 Cls
Loop

Count:
 Stop Timer1
 C = Timer1
 Timer1 = 0
 Start Timer1
Return

Res:
 Stop Timer1
 Timer1 = 0
 C = 0
Return

Menu:
Cls

Do
Locate 1 , 1
Lcd "Correction mm"

If Pind.6 = 0 Then
Incr Rad
Mtime = 0
End If

If Pind.7 = 0 Then
Decr Rad
Mtime = 0
End If

Locate 2 , 1
Lcd Rad
Incr Mtime
Waitms 200
Loop Until Mtime = 10
Rad1 = Rad
Mtime = 0
Cls


Return

0

22

Потом перепишу, так как мне нужен по сути дела не спидометр, а ограничитель скорости (от полиции которая мерит в случае чего на стендах).

Надо что бы при достижение разрешенного предела в цепь датчика зажигания включался RC фильтр

0

23

В первом же действии делим на НОЛЬ?  :tired:

Evgeny 76 написал(а):

Speed = 56 / C

0

24

в арифметике низя а в аврке Speed = 56 / C при C=0 получается 0, алгоритм работает.

Сейчас тоже это в коде заметил.

Вот код

Код:
$regfile = "m8def.dat"
$Crystal=16000000
$hwstack=40
$swstack=16
$framesize = 32
Config Lcdpin = Pin , Db4 = Portb.2 , Db5 = Portb.3 , Db6 = Portb.4 , Db7 = Portb.5 , E = Portb.1 , Rs = Portb.0       'LCD PINs
Dim A As Word
Dim B As Word
Dim C As Word
 Cls
A = 100
B = 0

C = A / B

Locate 1 , 1

Lcd C
      End

ноль получается

Может это и не правильно, я упустил из внимания, но работает кондёры не взрываются и микруха не горит  :D

http://s6.uploads.ru/b0CkI.jpg

0

25

В документации к баскому сказано, что деление на ноль вызовет ошибку. Также сказано, что никаких сообщений на данный момент не предусмотрено, поэтому, нужно следить за этим самостоятельно и не допускать нуля в делителе.

http://www.mikrocontroller.net/attachment/48113/divzerosafety.jpg

0

26

Добавил кусок кода:

Код:
If C = 0 Then
   Speed = 0
  Goto Outspeed
  Else
 Speed = 56 / C
  End If

Outspeed:

 Locate 1 , 1
 Lcd Speed

Ни чего не поменялось.

В чём интересно опастность деления на ноль в МК?

0

27

В неопределенности.

0

28

А как по мне нет никакой опасности. Мк выдает конкретный ответ при делении на 0. Всегда.

Расчет скорости я бы организовал следующим способом:

запускаем timer 0
Ловим импульс на init1
do
сюда можно переместить расчет скорости.
loop

подпрограмма нулевого таймера:
в подпрограмме нулевого таймера увеличиваем переменную. Если переменная больше какогото значения то останавливаем таймер 0 и присваиваем скорости значение равное 0.

подпрограмма init1:
останавливаем таймер 0
считаем скорость исходя из длинны импульса S= P/(переменная + timer0/256)*k `где Р - периметр колеса, k - коэффициент, рассчитанный по геометрическим формулам и с учетом кварца
присваиваем переменной и таймеру значение 0
запускаем таймер 0.
а еще можно попробовать предугадать скорость " нынешнее значение скорости + предыдущее значение - нынешнее"

Отредактировано Pasha (2013-12-31 23:33:34)

0


Вы здесь » Программирование ATMEL в BASCOM. » Бытовая и промышленная техника, авто, мото и т.п. » Спидометр, помогите с алгоритмом