STM32duino аппаратные прерывания и таймер

WinKarbik
Offline
Зарегистрирован: 22.02.2021

Добрый день. Начну с предыстории: когда то давно всё работало, конечно же, но сейчас всё погорело. Имеется блок парктроников, ранее сигнал принимала плата 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]

 

Опытным путём ручным снятием удалось понять как сигнал меняется, но вот проблема с использованием сигнала в компьютере, что я делаю не так? Может есть ещё какие пути?

WinKarbik
Offline
Зарегистрирован: 22.02.2021

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

1. МП stmf103 существенно слабее, чем stn32f407, откуда уверенность, что он справится с задачей?

2. код обычно не "ищут", а пишут. В этом случае, как показывает практика, проблем возникает гораздо меньше.

3. Из кода принято удалять все лишнее. Т.е. в публикуемом коде должно быть не более 10-30 строк, которые демонстрируют ошибку. Все, не относящееся к ошибке, должно быть удалено.

4. Вопрос рекомендуется излагать так:

- Что должен делать код.

- Что он на самом деле делает.

- Чем первое отличается от второго.

Вы же забыли даже написать, что должен делать код.

WinKarbik
Offline
Зарегистрирован: 22.02.2021

1. О том что слабее - это мне известно, но удавалось это делать и на ардуине, но только УНО(если я не ошибаюсь)
2. Это тоже мне известно, поэтому я код разбирал, пытался понять как устроен, с первой стадией разобрался, но выход не тот, что я ожидал.
3. Учту в следующий раз
4. Сигнал с блока парктроников приходит в бинарном виде(1 и 0). На прикрепленном изображении видно как он приходит с помощью АЦП, т.е.: Первый длинный импульс, далее короткие и чуть побольше импульсы, что обозначают 0 и 1 соответственно. В данном коде реализация с помощью прерывания(ну а другого применения и не придумать, я считаю) считывается сигнал и его длина. Мне нужно знать длину каждого импульса, чтобы знать что пришло в микроконтроллер: стартовый импульс, 0 или 1.
Надеюсь теперь всё понятно объяснил?

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

WinKarbik пишет:

4. Сигнал с блока парктроников приходит в бинарном виде(1 и 0). На прикрепленном изображении видно как он приходит с помощью АЦП, т.е.: Первый длинный импульс, далее короткие и чуть побольше импульсы, что обозначают 0 и 1 соответственно. В данном коде реализация с помощью прерывания(ну а другого применения и не придумать, я считаю) считывается сигнал и его длина. Мне нужно знать длину каждого импульса, чтобы знать что пришло в микроконтроллер: стартовый импульс, 0 или 1.
Надеюсь теперь всё понятно объяснил?

Отнюдь.

Вы не ответили ни на один вопрос:

andriano пишет:

- Что должен делать код.

- Что он на самом деле делает.

- Чем первое отличается от второго.

Поэтому все как было, так и осталось непонятным.

b707
Offline
Зарегистрирован: 26.05.2017

подробно не вникал, но использование Serial в прерывании сразу говорит о том, что писавший код не был мастером своего дела...

Поищите другой пример или, лучше - напишите сами.

WinKarbik
Offline
Зарегистрирован: 22.02.2021

Перечитал, понял что коряво написал, попробую ответить по пунктам:
1. Код должен принять сигнал и обработать его, а именно: Когда приходит сигнал 1, должен запустить таймер и читать сигнал дальше, когда приходит 0 закончить таймер, соответственно после этого он должен повторять это снова и снова, а у меня должно быть значение прошедшего времени.
2. Не знаю, так ли это происходит, но у меня всегда значение прошедшего времени равно 0, иногда бывает 1, а очень редко бывает 2, но оно должно ведь быть больше
3. Тем, что я не могу разделить сигналы из-за полученного малого прошедшего промежутка времени

Код сейчас прикреплю

WinKarbik
Offline
Зарегистрирован: 22.02.2021

b707 пишет:

подробно не вникал, но использование Serial в прерывании сразу говорит о том, что писавший код не был мастером своего дела...

Поищите другой пример или, лучше - напишите сами.

Это делал я для отладки, когда разбирался с работой прерываний и отслеживанием, какой сигнал получил.
 

WinKarbik пишет:

Код сейчас прикреплю

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); 
}  

 

mixail844
Offline
Зарегистрирован: 30.04.2012

WinKarbik пишет:

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() нигде не вызываются ? или я что то не понимаю ? 

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

mixail844 пишет:
а с фигали будет выполнятся lengthImpuls > 0 , если  void fireUp() и void fireDown() нигде не вызываются ? или я что то не понимаю ? 

20 строка, а потом 39.

mixail844
Offline
Зарегистрирован: 30.04.2012

xDriver пишет:

mixail844 пишет:
а с фигали будет выполнятся lengthImpuls > 0 , если  void fireUp() и void fireDown() нигде не вызываются ? или я что то не понимаю ? 

20 строка, а потом 39.

 

да заметил потом: 
attachInterrupt(PA1, fireUp, RISING);
WinKarbik
Offline
Зарегистрирован: 22.02.2021

Они вызываются только при прерываниях

b707
Offline
Зарегистрирован: 26.05.2017

WinKarbik, начните с того, что перенесите все выводы в Сериал в ЛУП из прерывания

ssss
Offline
Зарегистрирован: 01.07.2016

andriano пишет:

МП stmf103 существенно слабее, чем stn32f407, откуда уверенность, что он справится с задачей?

Да не прикалывайтесь...

Там и гавённого СТМ8 хватит... если только по уму делать...

ssss
Offline
Зарегистрирован: 01.07.2016

WinKarbik пишет:

Код должен принять сигнал и обработать его, а именно: Когда приходит сигнал 1, должен запустить таймер и читать сигнал дальше, когда приходит 0 закончить таймер, соответственно после этого он должен повторять это снова и снова, а у меня должно быть значение прошедшего времени.

Бред... всё зависит от приходящего сигнала... насколько он асинхронен к МК... Если МК запущен ДО прихода первого сигнала... то да... надо ловить первую 1... Если же МК запускается в произвольный момент времени... когда сигнал уже присутствует... то нужно отлавливать длинный 0... как маркер начала пакета... Иначе... все ваши данные - коту под хвост...

Цитата:

Тем, что я не могу разделить сигналы из-за полученного малого прошедшего промежутка времени

Патамушта делаете изначально через анал... а нужно через железо... таймером... У вас там времени... ну просто вагон... Учите матчасть... в части таймера... и в частности - PWM Input...

WinKarbik
Offline
Зарегистрирован: 22.02.2021

ssss пишет:

Если МК запущен ДО прихода первого сигнала... то да... надо ловить первую 1... Если же МК запускается в произвольный момент времени... когда сигнал уже присутствует... то нужно отлавливать длинный 0... как маркер начала пакета... Иначе... все ваши данные - коту под хвост...


Это понятно, вполне, но выполняя данные код у меня тикает одно и то же время, у меня постоянно приходит lengthImpuls - 0, иногда промелькивает 1, а очень редко можно увидеть 2(раз в минуту или две, полагаю мк иногда чуть позже срабатывает), так вот и как я пойму что это длинная единица пришла или это тот самый длинный ноль в промежутке, если длина импульса почти неизменна?

ssss
Offline
Зарегистрирован: 01.07.2016

WinKarbik пишет:

выполняя данные код у меня тикает одно и то же время, у меня постоянно приходит lengthImpuls - 0, иногда промелькивает 1, а очень редко можно увидеть 2(раз в минуту или две, полагаю мк иногда чуть позже срабатывает), так вот и как я пойму что это длинная единица пришла или это тот самый длинный ноль в промежутке, если длина импульса почти неизменна?

Откуда же мне знать... что там у вас... и как должно быть ??? Я свой хрустальный шар в аренду сдал... Для начала... нужно логанализатором сделать несколько снимков... посмотреть все длительности... А на вашей картинко... ну совсем нифига не понятно... ни какие импульсы... ни сколько их...

Да и ваш ручной изврат с таймером... мне совсем не понятен... и не интересен... поэтому в код даже и не вникал... ибо это бесмысленно...

WinKarbik
Offline
Зарегистрирован: 22.02.2021

Вопрос решён