Замер скорости
- Войдите на сайт для отправки комментариев
Втр, 04/06/2019 - 13:55
Всем привет! Помогите, пожалуйста с кодом. Делаю стенд, точнее пишу код для этого стенда. Стенд представляет собой колесо с магнитами и датчик Холла. Колесо крутится и программа выдает скорость вращения колеса.
//Speedometr unsigned long previousMillis = 0; unsigned long currentMillis = 0; volatile float millis_temp = 0.0; volatile float frequency = 0.0; //частота импульсов volatile float Time1 = 0.0; volatile float Time2 = 0.0; volatile float speed = 0.00; //скорость int timeout = 1400; // (миллисекунд) максимальное время ожидания unsigned int Magnets = 2; // Количество магнитов на колесе unsigned int Distance = 204; // Расстояние между магнитами void setup() { Serial.begin(9600); pinMode(INT0, INPUT); attachInterrupt(INT0, sp_metr, RISING); //INT0 } void loop() { if((millis() - millis_temp) > timeout) //Задержка до обнуления { frequency=0; } else { frequency = (1000 / Time1); //Частота, Гц } speed = (frequency / Magnets)*(PI * Distance / 1000); // Вычисление скорости вращения Serial.print("millis_temp = "); Serial.print(millis_temp); Serial.print(" Time1 = "); Serial.print(Time1); Serial.print(" Time2 = "); Serial.print(Time2); Serial.print(" frequency = "); Serial.print(frequency); Serial.print(" speed = "); Serial.println(speed); } void sp_metr() //Обработка прерывания { Time2 = millis(); Time1 = Time2 - millis_temp; millis_temp = Time2; }
В результате получается вот что:
millis_temp = 86177.00 Time1 = 160.00 Time2 = 86177.00 frequency = 6.25 speed = 2.00 millis_temp = 86177.00 Time1 = 159.00 Time2 = 86336.00 frequency = 6.25 speed = 2.00 millis_temp = 86336.00 Time1 = 159.00 Time2 = 86336.00 frequency = 6.29 speed = 2.02 millis_temp = 86497.00 Time1 = 161.00 Time2 = 86497.00 frequency = 6.21 speed = 1.99 millis_temp = 86497.00 Time1 = 161.00 Time2 = 86497.00 frequency = 6.21 speed = 1.99 millis_temp = 86656.00 Time1 = 159.00 Time2 = 86656.00 frequency = 6.29 speed = 2.02 millis_temp = 86656.00 Time1 = 0.00 Time2 = 86816.00 frequency = 6.29 speed = 2.02 millis_temp = 86816.00 Time1 = 0.00 Time2 = 86816.00 frequency = inf speed = inf millis_temp = 86975.00 Time1 = 0.00 Time2 = 86975.00 frequency = inf speed = inf millis_temp = 86975.00 Time1 = 0.00 Time2 = 86975.00 frequency = inf speed = inf millis_temp = 87136.00 Time1 = 161.00 Time2 = 87136.00 frequency = 6.21 speed = 1.99 millis_temp = 87136.00 Time1 = 161.00 Time2 = 87136.00 frequency = 6.21 speed = 1.99 millis_temp = 87294.00 Time1 = 158.00 Time2 = 87294.00 frequency = 6.33 speed = 2.03 millis_temp = 87294.00 Time1 = 161.00 Time2 = 87455.00 frequency = 6.33 speed = 2.03
Почему-то метка во времени оказывается больше текущего времени.
метка во времени оказывается больше текущего времени.
Так патентуй машину времени, пока кто-нить не стырил.
А код, можно словами, внятно пояснить что там и зачем делается?
Вот код который я использовал для замера скорости вращения PMSM двигателя стиральной машинки LG
"...Почему-то метка во времени оказывается больше текущего времени."
Происходит прерывание пока делаются расчеты и вывод в сериал.
Замеряется время между прерываниями, но основании этого вычисляется частота вращение и из нее уже скорость.
Да, похоже этот момент я упустила, попробую завтра с запрещением прерываний. Но опять же приходит мысль, что данные которые были в момент прерывания потеряются, потому что был расчет и прерывать было нельзя. Надо что-то вроде буфера, что бы отделить прерывания от расчета. Но тогда данные будут не актуальны. В общем тупик. Как тут быть?
Ох! Тут так просто точно не разобраться..))
Ох! Тут так просто точно не разобраться..))
Читайте про атомарное чтение: https://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html
Не совсем понятно, правда, зачем делать МК и себе плохо, закидывая время выполнения во float...
И ещё деление на ноль, не все согласны, что нельзя, но результат врядли предсказуем. Хотя 0.0 и не совсем ноль, скорее всего. ТС надо определиться с типами, он(а) явно тут забил.
И ещё деление на ноль, не все согласны, что нельзя, но результат врядли предсказуем. Хотя 0.0 и не совсем ноль, скорее всего. ТС надо определиться с типами, он(а) явно тут забил.
О! Не я один заметил, что ТС некоторые текстовые обороты пишет как он, а некоторые как она )))
Да, похоже этот момент я упустила, попробую завтра с запрещением прерываний. Но опять же приходит мысль, что данные которые были в момент прерывания потеряются, потому что был расчет и прерывать было нельзя. Надо что-то вроде буфера, что бы отделить прерывания от расчета. Но тогда данные будут не актуальны. В общем тупик. Как тут быть?
Вам правильное решение уже привели, делать не на миллис, а на таймере...
Да, похоже этот момент я упустила, попробую завтра с запрещением прерываний. Но опять же приходит мысль, что данные которые были в момент прерывания потеряются, потому что был расчет и прерывать было нельзя. Надо что-то вроде буфера, что бы отделить прерывания от расчета. Но тогда данные будут не актуальны. В общем тупик. Как тут быть?
Вообще-то очень странно во время обработки прерывания другие прерывания должны быть автоматически запрещены до окончания обработчика. Возможно проблема с тем что для времени сохраняется во флоат.
А на какой ардуине все это делается?
Что же касается рассчетов - то если время между импульсами померяно правильно, то и рассчет будет правильным. Для улучшения производительности совет тот же - не пользуйся float
Вам правильное решение уже привели, делать не на миллис, а на таймере...
А какая разница? Миллис тоже использует таймер. Такие короткие прерывания с интервалом в более 100 мс на работу millis не влияют. Если точности в 1 одну миллисикунду достаточно, то большого смысла работать напрямую с таймерами нет.
Вообще-то очень странно во время обработки прерывания другие прерывания должны быть автоматически запрещены до окончания обработчика. Возможно проблема с тем что для времени сохраняется во флоат.
А на какой ардуине все это делается?
Что же касается рассчетов - то если время между импульсами померяно правильно, то и рассчет будет правильным. Для улучшения производительности совет тот же - не пользуйся float
Если приоритеты одинаковы - да.
Не важно.
Если что-то сравниваете - позаботьтесь о типизации. Сравнивать float например с целым нулём - некорректно, как и сравнивать целое с нецелым. Девушке можно простить непонимание арифметики, мальчику - нельзя. Как и делить на Time1, которое инициализировано 0.0.
Ну, и что такое infinity тоже желательно знать.
Вообще-то очень странно во время обработки прерывания другие прерывания должны быть автоматически запрещены до окончания обработчика. Возможно проблема с тем что для времени сохраняется во флоат.
А на какой ардуине все это делается?
Что же касается рассчетов - то если время между импульсами померяно правильно, то и рассчет будет правильным. Для улучшения производительности совет тот же - не пользуйся float
Если приоритеты одинаковы - да.
Нет. Начнем с того что у AVR нету прерываний с одинаковым приоритетом. Все разные. При любом прерывании запрещаются все прерывания. Из даташита - When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are disabled.
Важно. У ардуин с не AVR контроллером прерывания обслуживаются по другому (STP32, ESP etc)
Ну, и что такое infinity тоже желательно знать.
Это вообще как относится к тому что я писал?
Всегда надо смотреть на оранжевые сообщения компилятора. Он обычно на неявные приведения типов именно так и реагирует. Это предупреждение (warning). И это повод для беспокойства. Идеально - когда компилятор молчит.
Нет. Начнем с того что у AVR нету прерываний с одинаковым приоритетом. Все разные. При любом прерывании запрещаются все прерывания. Из даташита - When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are disabled.
Но потом прерывание будет выполнено, не так ли? То есть прерывания с одинаковым приоритетом откладывают друг-друга, а прерывания с более высоким приоритетом могут прерывать прерывания с более низким, но потом всё равно будут выполнены?
Форум про Ардуино, а это совсем не Ардуино. Но обычно прерывания устроены так, как я написал выше. Нет дураков делать по-своему.
А последнее - вы не смотрели код, который вам предложили, либо ничего в коде не понимаете.
Нет. Начнем с того что у AVR нету прерываний с одинаковым приоритетом. Все разные. При любом прерывании запрещаются все прерывания. Из даташита - When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are disabled.
Но потом прерывание будет выполнено, не так ли? То есть прерывания с одинаковым приоритетом откладывают друг-друга, а прерывания с более высоким приоритетом могут прерывать прерывания с более низким, но потом всё равно будут выполнены?
Еще раз для тех кто в танке - у AVR нету прерываний с одинаковым приоритетом. Если началась обработка прерывания, то все остальные запрещены. И не важно какой у них приоритет. Пока текущее прерывание не закончится (или внутри него программистом явно не будут разрешены глобальные прерывания) никаие другие прерывания его прервать не смогут. Приориет определят какие прерывания будут обслужены первыми если события произошли одновременно или в то время пока прерывания были запрещены.
Форум про Ардуино, а это совсем не Ардуино. Но обычно прерывания устроены так, как я написал выше. Нет дураков делать по-своему.
Любезный, вы будете удивлены, но даже "родные" платы от Ардуино базируются не только на АВР, а уж какое разнообразие поддерживает среда Ардуино.... В том числи и на STM32 и на ESP и другие.
Я видел много разных исполнений контроллеров прерываний в разных микроконтроллерах, вам и не представить. Неужели все разработчики, по вашему, дураки?
Мне никакого кода не предлагали.
Прерывания в avr могут прервать другое прерывание, если ему руками это разрешить, и приоритет здесь вообще не при делах. После прерывания, через 1 такт будет вызвано стоящее в очереди прерывание с наибольшем приоритетом и так далее, пока очередь прерываний не кончится.
Еще раз для тех кто в танке - у AVR нету прерываний с одинаковым приоритетом. Если началась обработка прерывания, то все остальные запрещены. И не важно какой у них приоритет. Пока текущее прерывание не закончится (или внутри него программистом явно не будут разрешены глобальные прерывания) никаие другие прерывания его прервать не смогут. Приориет определят какие прерывания будут обслужены первыми если события произошли одновременно или в то время пока прерывания были запрещены.
Любезный, вы будете удивлены, но даже "родные" платы от Ардуино базируются не только на АВР, а уж какое разнообразие поддерживает среда Ардуино.... В том числи и на STM32 и на ESP и другие.
Я видел много разных исполнений контроллеров прерываний в разных микроконтроллерах, вам и не представить. Неужели все разработчики, по вашему, дураки?
Да я тут даже и не спорил. Если прерывание возникло во время другого прерывания - оно выполнится по завершении того прерывания, вот и всё. И этот приоритет - полная херня, с моей точки зрения, поскольку возникновение двух аппаратных прерываний одновременно - 1/2 в хренотысячной степени вероятность.
Да что мы друг-другу голову морочим. Я не знаю, может у AVR не так, но у 51-х контроллеров были вложенные прерывания, одно могло прервать другое (правда не знаю, зачем). У 86-х вроде тоже.
Любезный мой, я более 20 лет занимаюсь эмбеддингом профессионально, и Ардуино мне просто нравится.
И расскажите, а лучше напишите статью про контроллеры прерываний в разных микроконтроллерах. Вот это будет интересно. А то нам и не представить.
Прерывания в avr могут прервать другое прерывание, если ему руками это разрешить, и приоритет здесь вообще не при делах. После прерывания, через 1 такт будет вызвано стоящее в очереди прерывание с наибольшем приоритетом и так далее, пока очередь прерываний не кончится.
Ну вот ведь. И во всех контроллерах так, зачем делать по-другому?
Прерывания в avr могут прервать другое прерывание, если ему руками это разрешить, и приоритет здесь вообще не при делах. После прерывания, через 1 такт будет вызвано стоящее в очереди прерывание с наибольшем приоритетом и так далее, пока очередь прерываний не кончится.
Если это ответ на мой пост #18 так я же ровно то же самое и написал.
Если это ответ на мой пост #18 так я же ровно то же самое и написал.
Прочтите себя, и удостоверьтесь что нет. Я полагаю это не потому, что вы не понимали. Просто неправильно выразились.
Прочтите себя, и удостоверьтесь что нет. Я полагаю это не потому, что вы не понимали. Просто неправильно выразились.
Перечитал свое
Перечитал Ника
Принципиальных отличий не нашел. Может поясните вашу точку зрения?
Если началась обработка прерывания, то все остальные запрещены. И не важно какой у них приоритет. Пока текущее прерывание не закончится (или внутри него программистом явно не будут разрешены глобальные прерывания) никаие другие прерывания его прервать не смогут.
Ну вам же ясно указали, что это не так. Прерывание с более высоким приоритетом прервёт ваше прерывание, выполнится, и вернёт управление вашему прерыванию. Это называется "вложенные прерывания". Приоритет выполнения прерываний из даташита здесь ни причём - это филькина дудка. Вы с вытесняющей многозадачностью работали? Почти то же самое.
И этот приоритет - полная херня, с моей точки зрения, поскольку возникновение двух аппаратных прерываний одновременно - 1/2 в хренотысячной степени вероятность.
С точки зрения микроконтроллера "одновременно" это в течении одного такта. Что для всяких Ун и Нан составляет 62 наносекунды для 16МГц и 125 наносекунд для 8МГц. И вероятность что два события произойдут в этот интервал хоть и не очень велика, но намного выше "1/2 в хренотысячной степени" . И это вполне случаемое событие. Плюс если события вызывающие прерывания случились когда прерывания запрещены, а за это время могут произойти много таких событий, то они после разрешения будут обслуживаться в порядке приоритета.
Любезный мой, я более 20 лет занимаюсь эмбеддингом профессионально, и Ардуино мне просто нравится.
Если началась обработка прерывания, то все остальные запрещены. И не важно какой у них приоритет. Пока текущее прерывание не закончится (или внутри него программистом явно не будут разрешены глобальные прерывания) никаие другие прерывания его прервать не смогут.
Ну вам же ясно указали, что это не так. Прерывание с более высоким приоритетом прервёт ваше прерывание, выполнится, и вернёт управление вашему прерыванию. Это называется "вложенные прерывания". Приоритет выполнения прерываний из даташита здесь ни причём - это филькина дудка. Вы с вытесняющей многозадачностью работали? Почти то же самое.
Похоже вы просто читать не умеете. Где там указано про "Прерывание с более высоким приоритетом прервёт ваше прерывание" ? И вообще посмотрите даташит наконец
When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are disabled. The user software can write logic one to the I-bit to enable nested interrupts. All enabled interrupts can then interrupt the current interrupt routine. The I-bit is automatically set when a Return from Interrupt instruction – RETI – is executed. There are basically two types of interrupts. The first type is triggered by an event that sets the Interrupt Flag. For these interrupts, the Program Counter is vectored to the actual Interrupt Vector in order to execute the interrupt handling routine, and hardware clears the corresponding Interrupt Flag. Interrupt Flags can also be cleared by writing a logic one to the flag bit position(s) to be cleared. If an interrupt condition occurs while the corresponding interrupt enable bit is cleared, the Interrupt Flag will be set and remembered until the interrupt is enabled, or the flag is cleared by software. Similarly, if one or more interrupt conditions occur while the Global Interrupt Enable bit is cleared, the corresponding Interrupt Flag(s) will be set and remembered until the Global Interrupt Enable bit is set, and will then be executed by order of priority. The second type of interrupts will trigger as long as the interrupt condition is present. These interrupts do not necessarily have Interrupt Flags. If the interrupt condition disappears before the interrupt is enabled, the interrupt will not be triggered. When the AVR exits from an interrupt, it will always retur
С точки зрения микроконтроллера "одновременно" это в течении одного такта. Что для всяких Ун и Нан составляет 62 наносекунды для 16МГц и 125 наносекунд для 8МГц. И вероятность что два события произойдут в этот интервал хоть и не очень велика, но намного выше "1/2 в хренотысячной степени" . И это вполне случаемое событие. Плюс если события вызывающие прерывания случились когда прерывания запрещены, а за это время могут произойти много таких событий, то они после разрешения будут обслуживаться в порядке приоритета.
А вот АВР это по другому. Что же это вы, дорогой мой, за 20 лет работы профессионально в эмбеддед не развили приывычку читать даташиты?
Всё это мне известно, но на практике пользоваться таблицей приоритетов прерываний не приходилось почему-то. Боюсь, потому что она бесполезна.
Каюсь, даташиты читаю лишь по мере необходимости. Я был неправ, по умолчанию вложенные прерывания запрещены: "The user software can write logic one to the I-bit to enable nested interrupts". Но они есть, и об этом вы не упомянули.
Дело в том, что я никогда не программировал AVR, а вы, видимо, профессионал. И вы не знали про nested interrupts.
Всё это мне известно, но на практике пользоваться таблицей приоритетов прерываний не приходилось почему-то. Боюсь, потому что она бесполезна.
Странно слышать это от человека с "20 летним опытом в эмбеддед"
Я не забыл :
Так что ваши наезды по поводу незнания мной про вложенные прерывания несколько беспочвенны. Это вы просто читать не умеете.
Если честно, не хочу я спорить с вами. Я не пытался вас поймать на невежестве, я просто утверждал, что на ноль делить нельзя, даже если это ноль с плавающей точкой, и намекал, что вы этого факта не заметили. Так слово за слово, ёжикам скоро негде будет зимовать)
Странно слышать это от человека с "20 летним опытом в эмбеддед"
Подскажите, как она может пригодиться? И "эмбеддед" слишком ваше поколение, я тупо разрабатывал микроконтроллерные системы.
Если честно, не хочу я спорить с вами. Я не пытался вас поймать на невежестве, я просто утверждал, что на ноль делить нельзя, даже если это ноль с плавающей точкой, и намекал, что вы этого факта не заметили. Так слово за слово, ёжикам скоро негде будет зимовать)
А я, вообще-то, обсуждал то что происходит в прерывании. А там на ноль ничего и не делится. И основная проблема данного скетча именно в работе прерывания.
А если говорить про остальную часть, то да, написано не очень аккуратно. На ноль всегда стоит проверять перед делением. Но вообще-то при нормальной отработки прерывания ноля там и не должно быть. Хотя это и не отменяет необходимости проверки.
Подскажите, как она может пригодиться? И "эмбеддед" слишком ваше поколение, я тупо разрабатывал микроконтроллерные системы.
1 Как может пригодится зависит от много. Давайте хоть с типом контроллера определимся.
2. Про " я более 20 лет занимаюсь эмбеддингом " это не я писал
3. Интересно, а к какому поколению вы меня относите?
4 Насчет "тупо разрабатывал" это я уже понял.
развели срач на пустом месте в чужой теме, некрасиво
Всем спасибо за ответы.
Arduino NANO.
Получился такой код:
теперь работает, но из-за неидеальности расположения магнитов данные скорости "плавают".
как бы исходное значение отфильтровать? я так понимаю нужно сложить и разделить, а количество раз равно количеству магнитов.
Думаю, что все расчеты нужно делать когда пройдёт таймаут и дождетесь четного импульса == полное количество оборотов.
Снова замерить миллис и делать расчеты.
Атомизация чтения неправильно применена. Обработчик прерывания сам по себе атомарен, а вот loop() - нет. ATOMIC_BLOCK нужен именно там.
Всё, что изменяется в обработчике, должно быть volatile.
Производить расчет в обработчике прерывания?
Производить расчет в обработчике прерывания?
Нет. В обработчике запомнить миллис при получении четного импульса и установить флаг, чтоб в лупе неторопливо все посчитать.
Получится как один магнит ( сейчас их два). А если четыре или семь? С одним магнитом и так все работает. Но нам надо больше.))
Получится как один магнит ( сейчас их два).
Это плохо? На выходе имеете полный оборот, а не часть его.
В обработчике прерывания всё, что делаете с одним магнитом, делайте на каждый четвёртый или седьмой вход и выставляйте байтовый флаг "данные готовы". В лупе этот флаг постоянно проверяете - как только он взведён, производите атомарную работу с переменными, которые в обработчике меняете и сбрасываете флаг. И так будет по кругу мотаться всё.
Если не скорость невелика, то, то обработчик можно изобразить так:
В лупе, если будет приделана кнопка "Пуск/Останов", interruptCount обнулять, чтобы начинать счёт с начала круга.
Садман! А остальные магниты тогда зачем?
я бы делал на таймерах, там они как раз потребуются )))
Откуда ж я знаю... для красоты или уравновешивания может. Я вот не совсем понимаю зачем считать не по полному обороту, если даже не знаешь, с какого сектора начал.
Может Ева знает?
развели срач на пустом месте в чужой теме, некрасиво
Согласен, приношу свои извинения ТС, повёлся на бой с военом.
Ну чего не считать по каждому прохождению магнита, сколько бы там их не было? Количество-то то всяко известно, всегда можно поделить полученную скорость на количество магнитов. Я примерно так считаю скорость тележки, только там не магнит, а энокодер на моторе - выдаёт 45 импульсов на оборот. Проблееы не понял. Поясните.
Ну чего не считать по каждому прохождению магнита, сколько бы там их не было? Количество-то то всяко известно, всегда можно поделить полученную скорость на количество магнитов. Я примерно так считаю скорость тележки, только там не магнит, а энокодер на моторе - выдаёт 45 импульсов на оборот. Проблееы не понял. Поясните.
ТС считает, что расстояние между магнитами, если мерять по и против часовой стрелке, разное. В итоге если считать скорость\частоту по пол-оборота, то она слегка плавает в зависимости от того четный это или нечетный полуоборот.
Т.е. расстояния неодинаковы? А одинаковыми никак нельзя сделать?
Т.е. расстояния неодинаковы? А одинаковыми никак нельзя сделать?
нет, потому что у всех магнитов немного разное поле. его размеры никак не измерить. для этого и нужен фильтр, что бы нивелировать технологическую особенность изготовления.
Ну чего не считать по каждому прохождению магнита, сколько бы там их не было? Количество-то то всяко известно, всегда можно поделить полученную скорость на количество магнитов. Я примерно так считаю скорость тележки, только там не магнит, а энокодер на моторе - выдаёт 45 импульсов на оборот. Проблееы не понял. Поясните.
Да, об этом и идет речь.