[uquote="AlexS4",url="/forum/viewtopic.php?p=4202327#p4202327"]скорее всего у вашей avr нет никакой нинструкции деления[/uquote]
То,что у мелких контроллеров нет операции деления float для меня очевидно,но вот что нет
целочисленного деления - было для меня новостью. Сам-то я только x86 ассемблер знаю,тот что во времена MS DOS использовался. - немало писал на нем по работе тридцать лет назад. С повышением производительности компов как-то отпала регулярная надобность в ассемблере. Да и компиляторы Си стали делать код нередко даже лучше чем руками напишешь.
Ну и извиняюсь что не уточнил сразу - у меня Atmega328p. Некоторое количество их досталось в виде мелких модулей примерно 2х3см размером,из имущества обанкротившегося кружка детской робототехники. Я срисовал схему с платы,благо она там простейшая,и использую модули в своих поделках,благо шаг отверстий по краям совпадает с шагом отверстий на дырчатых макетках - можно модуль впаять на "ножках" из медной проволоки.
сишный / все равно реализован множеством команд, так что беспокоиться о скорости думаю ненужно ;)
Сейчас допишу письмо,скомпилирую тестовый сишный пример в ассемблер,благо gcc это умеет,и полезу изучать как сделано.
Вот уж действительно неожиданность.
если компилятор умеет операции с 32bit - просто загрузите такие переменные (double unsigned int напр) и умножте как хотели.
Как показал эксперимент, правильно работает вот такая конструкция с 16-разрядными целыми если результат заведомо влезает в 16 разрядов,а мне как раз отсчеты с двух каналов АЦП поделить одно на другое захотелось.
a = (unsigned long)b * 1000 / c
За счет указания явного приведения типа gcc понимает как считать и выдает результат,сдвинутый на три разряда (десятичных) влево,а не 5 вместо 5.533. Есть небольшая тонкость - происходит уменно усечение результата,а не классическое округление. Кстати,округление в математическом справочнике - это две страницы текста,а не то школьное правило которое все знают.
делите нацело получив целую часть, и отдельно получайте остаток от деления (оператор % ) , остаток умножайте на 100 или скажем на 10000 и делите на знаменатель получая сотые или десятитысячные доли.
unsigned int z,p;
z=a/b; p=a%b; p*=1000;p/=b; \\ 1000a/b=1000z+p
Вот за эту безусловно красивую идею - Спасибо! И без влезания в ассемблер,на чистом Си,и точность сохраняется и без плавающих чисел. Вот что значит профи в программировании - я,самоучка, до такого бы не додумался.
[uquote="ARV"]самое важное - не надо делать все эти 32-битные умножения-деления в обработчике прерываний, и тогда на их быстродействие будет наплевать.[/uquote]
Понятно что не в прерывании. Программы для Меги я обычно делаю по такой схеме:
Код: Выделить всё
ISR() /*прерывание вызываемое по таймеру*/
{
/*опрос датчика*/
/*команда исполнительному механизму,например запись в регистр таймера,формирующего шим*/
}
main()
{
while(TRUE)
{
/*расчет нового значения команды исполнительному механизму*/
sleep_mode();
/*другая полезная деятельность*/
}
}
Сама идея придумана во времена MS DOS 3.30 чтобы обеспечивать там работу фоновых процессов.
Связь между основным телом программы и обработчиком прерывания - через глобальные переменные.
Как оказалось, вызов прерывания побочным эффектом имеет выход из функции sleep_mode(),в результате контроллер прокручивает один цикл и снова усыпает до следующего прерывания. А не молотит вхолостую поедая электричество как было бы без sleep_mode()
Тем более что и смысла нет гонять расчетный цикл пока не получены новые значения с датчика.
А если прерываний несколько разных - то программа вообще становится похожа на пьесу для механического пианино:)
Выполняется только то что нужно и когда нужно - без всякого кручения холостых циклов с опросами чего-нибудь.
Благо что в Атмеге всегда можно получить прерывание от чего угодно,даже просто от дергания её за ногу.
В одной самоделке я к такой ноге подключил четыре кнопки через диодное "или". Разумеется, еще и каждую кнопку на свой отдельный пин. В результате не надо крутить постоянно цикл опроса кнопок. Любая кнопка сама сообщит когда будет нажата,и можно её обрабатывать.
Понятно что в профессиональных схемах должен быть специфический контроллер клавиатуры типа например pcf8574 - да где же я его в деревне возьму? Потому и заменил конструкцией из rc-цепочек для подавления дребезга и диодного "или".
кстати, просто для справки: во всем известной ардуине практически ВСЕ библиотеки используют float
У ардуино там специфическая "среда" для программирования и не менее специфический язык.
Еще и загрузка в контроллер через специальный бутлоадер вместо привычного программатора.
Всё это изучать надо,а мне в силу пожилого возраста уже несколько лень. Как-то за четверть века привык пользоваться обычным текстовым редактором и компилятором gcc. С gcc познакомился еще под ДОСом в 90х после того как достали кглюки компилатора MS C 5.10. Потом debian c 96 года и по сей день. С 05 года и Атмелы по той же технологии программирую. Привычка - сильная штука. Так что я думаю что доживу свой век без изучения ардуино. Тем более что уже полтора десятка лет как по компьютерной теме не работаю - чисто радиолюбитель,причем еще и сельский давно уже:)
А что касается float - добавится возня с контролем преобразовани типов. Потому как результат работы АЦП - это int, в регистр таймера ШИМ тоже пищется int. Иметь "посредине" long - еще приемлимо,а вот float совсем уже неудобно.