STM32duino аппаратные прерывания и таймер
- Войдите на сайт для отправки комментариев
Добрый день. Начну с предыстории: когда то давно всё работало, конечно же, но сейчас всё погорело. Имеется блок парктроников, ранее сигнал принимала плата STM32F407 Discovery, сделано было людьми, у которых не осталось исходников, да и связаться с ними проблема, но нужно всё исправить. В наличии: arduino nano, stm32f103. Ардуину пока откинул, думаю с ней не получится это реализовать, на просторах интернета нашёл код, решил попробовать у себя, но всё выходит не так как хотелось бы.
#define BUFFER_LENGTH 400 volatile uint16_t startImpuls; volatile uint16_t lengthImpuls; volatile uint16_t timerCount=0; byte buffPos = 0; byte Buffer[BUFFER_LENGTH]; byte packet[4]; byte posInPacket=0; byte startBYTE = 15; void setup() { startImpuls=0; lengthImpuls=0; pinMode(PA1, INPUT_PULLDOWN); pinMode(PB6, OUTPUT); digitalWrite(PB6, LOW); for(int i=0; i< BUFFER_LENGTH; i++) Buffer[i]=0; Serial.begin(115200); Timer3.pause(); Timer3.setPrescaleFactor(1800); // 40 кГц Timer3.attachInterrupt(TIMER_UPDATE_INTERRUPT, callback); Timer3.refresh(); // обнулить таймер Timer3.resume(); // запускаем таймер attachInterrupt(PA1, fireUp, RISING); } void callback() { timerCount++; } void loop() { if (lengthImpuls > 0) { uint16_t temp=0; uint16_t li = lengthImpuls; lengthImpuls=0; //--------------------------// // получена приамбула "1 1 1 1" if (li >50 && li <60) { posInPacket =0; } // Расчитываю позицию массиве temp = posInPacket / 8; uint16_t bitPos = posInPacket; // Разворачиваю позицию для метода bitSet(x,n) bitPos = 7 - bitPos; if (bitPos >= 8) { bitPos = posInPacket - (8*temp); } // Получен "0" if (li >4 && li <6) { posInPacket ++; } // Получен "1" else if (li >10 && li <15) { bitSet(packet[temp],bitPos); posInPacket ++; } //digitalWrite(13,LOW); // Отправить пакет "большему брату" if (posInPacket > 15) { detachInterrupt(PA1); // Serial.println("------"); for(int i=0; i<4; i++) { Serial.print(packet[i], BIN); Serial.print(" "); packet[i]=0; } Serial.println(""); posInPacket = 0; attachInterrupt(PA1, fireUp, RISING); } //--------------------------// } } // Функция обработки прерывания на подъем void fireUp() { detachInterrupt(PA1); startImpuls = timerCount; attachInterrupt(PA1, fireDown, FALLING); } // Функция обработки прерывания на подъем void fireDown() { detachInterrupt(PA1); lengthImpuls = timerCount - startImpuls; if (lengthImpuls > 0) { Serial.print("LI:"); Serial.print(lengthImpuls); Serial.print(" TC:"); Serial.print(timerCount); Serial.print(" SI:"); Serial.println(startImpuls); } startImpuls=0; timerCount=0; attachInterrupt(PA1, fireUp, RISING); }
Всё что в loop() ещё не обрабатывалось, судя по отладке lengthImpuls почти всегда 0, бывает редко 1, ещё реже 2.
Сигнал считанный через АЦП:
[url=https://ibb.co/6wT42Bn][img]https://i.ibb.co/SyMK2rs/ADC.png[/img][/url]
Опытным путём ручным снятием удалось понять как сигнал меняется, но вот проблема с использованием сигнала в компьютере, что я делаю не так? Может есть ещё какие пути?
1. МП stmf103 существенно слабее, чем stn32f407, откуда уверенность, что он справится с задачей?
2. код обычно не "ищут", а пишут. В этом случае, как показывает практика, проблем возникает гораздо меньше.
3. Из кода принято удалять все лишнее. Т.е. в публикуемом коде должно быть не более 10-30 строк, которые демонстрируют ошибку. Все, не относящееся к ошибке, должно быть удалено.
4. Вопрос рекомендуется излагать так:
- Что должен делать код.
- Что он на самом деле делает.
- Чем первое отличается от второго.
Вы же забыли даже написать, что должен делать код.
1. О том что слабее - это мне известно, но удавалось это делать и на ардуине, но только УНО(если я не ошибаюсь)
2. Это тоже мне известно, поэтому я код разбирал, пытался понять как устроен, с первой стадией разобрался, но выход не тот, что я ожидал.
3. Учту в следующий раз
4. Сигнал с блока парктроников приходит в бинарном виде(1 и 0). На прикрепленном изображении видно как он приходит с помощью АЦП, т.е.: Первый длинный импульс, далее короткие и чуть побольше импульсы, что обозначают 0 и 1 соответственно. В данном коде реализация с помощью прерывания(ну а другого применения и не придумать, я считаю) считывается сигнал и его длина. Мне нужно знать длину каждого импульса, чтобы знать что пришло в микроконтроллер: стартовый импульс, 0 или 1.
Надеюсь теперь всё понятно объяснил?
4. Сигнал с блока парктроников приходит в бинарном виде(1 и 0). На прикрепленном изображении видно как он приходит с помощью АЦП, т.е.: Первый длинный импульс, далее короткие и чуть побольше импульсы, что обозначают 0 и 1 соответственно. В данном коде реализация с помощью прерывания(ну а другого применения и не придумать, я считаю) считывается сигнал и его длина. Мне нужно знать длину каждого импульса, чтобы знать что пришло в микроконтроллер: стартовый импульс, 0 или 1.
Надеюсь теперь всё понятно объяснил?
Отнюдь.
Вы не ответили ни на один вопрос:
- Что должен делать код.
- Что он на самом деле делает.
- Чем первое отличается от второго.
Поэтому все как было, так и осталось непонятным.
подробно не вникал, но использование Serial в прерывании сразу говорит о том, что писавший код не был мастером своего дела...
Поищите другой пример или, лучше - напишите сами.
Перечитал, понял что коряво написал, попробую ответить по пунктам:
1. Код должен принять сигнал и обработать его, а именно: Когда приходит сигнал 1, должен запустить таймер и читать сигнал дальше, когда приходит 0 закончить таймер, соответственно после этого он должен повторять это снова и снова, а у меня должно быть значение прошедшего времени.
2. Не знаю, так ли это происходит, но у меня всегда значение прошедшего времени равно 0, иногда бывает 1, а очень редко бывает 2, но оно должно ведь быть больше
3. Тем, что я не могу разделить сигналы из-за полученного малого прошедшего промежутка времени
Код сейчас прикреплю
подробно не вникал, но использование Serial в прерывании сразу говорит о том, что писавший код не был мастером своего дела...
Поищите другой пример или, лучше - напишите сами.
Это делал я для отладки, когда разбирался с работой прерываний и отслеживанием, какой сигнал получил.
Код сейчас прикреплю
volatile uint16_t startImpuls;
а с фигали будет выполнятся lengthImpuls > 0 , если void fireUp() и void fireDown() нигде не вызываются ? или я что то не понимаю ?
20 строка, а потом 39.
20 строка, а потом 39.
Они вызываются только при прерываниях
WinKarbik, начните с того, что перенесите все выводы в Сериал в ЛУП из прерывания
МП stmf103 существенно слабее, чем stn32f407, откуда уверенность, что он справится с задачей?
Да не прикалывайтесь...
Там и гавённого СТМ8 хватит... если только по уму делать...
Код должен принять сигнал и обработать его, а именно: Когда приходит сигнал 1, должен запустить таймер и читать сигнал дальше, когда приходит 0 закончить таймер, соответственно после этого он должен повторять это снова и снова, а у меня должно быть значение прошедшего времени.
Бред... всё зависит от приходящего сигнала... насколько он асинхронен к МК... Если МК запущен ДО прихода первого сигнала... то да... надо ловить первую 1... Если же МК запускается в произвольный момент времени... когда сигнал уже присутствует... то нужно отлавливать длинный 0... как маркер начала пакета... Иначе... все ваши данные - коту под хвост...
Тем, что я не могу разделить сигналы из-за полученного малого прошедшего промежутка времени
Патамушта делаете изначально через анал... а нужно через железо... таймером... У вас там времени... ну просто вагон... Учите матчасть... в части таймера... и в частности - PWM Input...
Если МК запущен ДО прихода первого сигнала... то да... надо ловить первую 1... Если же МК запускается в произвольный момент времени... когда сигнал уже присутствует... то нужно отлавливать длинный 0... как маркер начала пакета... Иначе... все ваши данные - коту под хвост...
Это понятно, вполне, но выполняя данные код у меня тикает одно и то же время, у меня постоянно приходит lengthImpuls - 0, иногда промелькивает 1, а очень редко можно увидеть 2(раз в минуту или две, полагаю мк иногда чуть позже срабатывает), так вот и как я пойму что это длинная единица пришла или это тот самый длинный ноль в промежутке, если длина импульса почти неизменна?
выполняя данные код у меня тикает одно и то же время, у меня постоянно приходит lengthImpuls - 0, иногда промелькивает 1, а очень редко можно увидеть 2(раз в минуту или две, полагаю мк иногда чуть позже срабатывает), так вот и как я пойму что это длинная единица пришла или это тот самый длинный ноль в промежутке, если длина импульса почти неизменна?
Откуда же мне знать... что там у вас... и как должно быть ??? Я свой хрустальный шар в аренду сдал... Для начала... нужно логанализатором сделать несколько снимков... посмотреть все длительности... А на вашей картинко... ну совсем нифига не понятно... ни какие импульсы... ни сколько их...
Да и ваш ручной изврат с таймером... мне совсем не понятен... и не интересен... поэтому в код даже и не вникал... ибо это бесмысленно...
Вопрос решён