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; volatile uint16_t lengthImpuls; volatile uint16_t timerCount=0; void setup() { startImpuls=0; lengthImpuls=0; pinMode(PA1, INPUT_PULLDOWN); // Контакт сигнала pinMode(PB6, OUTPUT); // Inhibit digitalWrite(PB6, LOW); // Логический 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) { new_LI=lengthImpuls lengthImpuls=0; //Тут кусок моего кода обработки данных } } 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); }volatile uint16_t startImpuls;
volatile uint16_t lengthImpuls; volatile uint16_t timerCount=0; void setup() { startImpuls=0; lengthImpuls=0; pinMode(PA1, INPUT_PULLDOWN); // Контакт сигнала pinMode(PB6, OUTPUT); // Inhibit digitalWrite(PB6, LOW); // Логический 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) { new_LI=lengthImpuls lengthImpuls=0; //Тут кусок моего кода обработки данных } } 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); }а с фигали будет выполнятся 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(раз в минуту или две, полагаю мк иногда чуть позже срабатывает), так вот и как я пойму что это длинная единица пришла или это тот самый длинный ноль в промежутке, если длина импульса почти неизменна?
Откуда же мне знать... что там у вас... и как должно быть ??? Я свой хрустальный шар в аренду сдал... Для начала... нужно логанализатором сделать несколько снимков... посмотреть все длительности... А на вашей картинко... ну совсем нифига не понятно... ни какие импульсы... ни сколько их...
Да и ваш ручной изврат с таймером... мне совсем не понятен... и не интересен... поэтому в код даже и не вникал... ибо это бесмысленно...
Вопрос решён