|
Модераторы: PILOT, ManiaK, Mazzi |
|
supercelt |
|
||||||
Опытный Профиль Группа: Участник Сообщений: 658 Регистрация: 25.8.2005 Репутация: нет Всего: 1 |
Привет!. Помогите пожалуйста. Для вас это наверное расплюнуть, а у меня непонятки. Пишу код в Keil под stm32. Есть модуль, от которого по usart приходит строка вот такого вида:
Цель: выделить всё что между кавычек. Я так поразмыслил это можно делать 2 способами. Первый: Это кусок кода в файле mod.c где и крутится всё что касается модуля.
Здесь стандартно по прерыванию приёма я сбрасываю флаг, устанавливаю флаг, что я готов записать принятый байт и быстро ухожу. В самом прерывании я не стал записывать в переменную содержание регистра DR ибо сами знаете делать что-то в прерывании не комильфо. значит флаг flag_receive установился и далее в цикле while файла main.c: if(flag_receive){ Get(); flag_receive = 0; } Далее вызываем Get и всё складируется в buffer. Далее с помощью регулярки выдернуть всё что между кавычек. Вариант 2
То есть вытягиваем нужную строку непосредственно в процессе приёма байтов посимвольно. В коде могут быть ошибки, так как хотел показать идею. А теперь главные вопросы Если сначала набивать массив строкой, а потом разбирать регуляркой, как написать эту самую регулярку, что бы между кавычек вытащить? И второй вопрос, что будет работать быстрее и эффективнее 1 или 2 вариант? |
||||||
|
|||||||
Romikgy |
|
|||
Любитель-программер Профиль Группа: Участник Клуба Сообщений: 7326 Регистрация: 11.5.2005 Где: Porto Franco Odes sa Репутация: 3 Всего: 146 |
кто такую чушь сказал? особенно у стм32??? все и складывают в прерывании в отдельный буфер
на стм с его скоростями .... оба хорошо работать будут.. но, имхо , сначала все сгрузить в буфер а после поискать то что нужно .... и регулярки здесь не нужны.... вполне хватит поиска символов по строке... после выделить подстроку. -------------------- Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. |
|||
|
||||
Курсант |
|
|||
Опытный Профиль Группа: Участник Сообщений: 338 Регистрация: 21.2.2009 Где: Балашиха или Воро неж Репутация: нет Всего: 4 |
Регвыр на МК применять, ИМХО, слишком круто, хотя для кругозора можно повозиться.
Не соглашусь с тем, что нужно заполнять буфер. Можно использовать конечный автомат для управления распознаванием символов. Состояний у конечного автомата будет 11: 1. Ожидание \r (начальное состояние). После прихода \r переходим в состояние 2. 2. Ожидание \n (после прихода \n переходим в состояние 2, иначе в состояние 1) 3. Ожидание + (в случае прихода \r переходим в состояние 2, иначе в состояние 1) 4. Ожидание C (после C переходим в состояние 5, после \r - в состояние 2, иначе в состояние 1) 5. Ожидание M 6. Ожидание G 7. Ожидание R 8. Ожидание : 9. Ожидание <пробела> 10. Ожидание " 11. Ввод значения (можно проверять символы на принадлежность к цифрам и сразу преобразовывать в int). После прихода " возвращаем полученное значение функции-абоненту и переходим в состояние 1. Если приходит не цифра, и не ", сбрасываем накопленное значение и переходим в состояние 1.) |
|||
|
||||
baldman88 |
|
|||
Бывалый Профиль Группа: Участник Сообщений: 210 Регистрация: 18.1.2009 Репутация: 1 Всего: 7 |
Все не так просто. В данном случае выгоднее сделать циклический буфер и уже парсить данные, полученные из него.
|
|||
|
||||
Курсант |
|
||||
Опытный Профиль Группа: Участник Сообщений: 338 Регистрация: 21.2.2009 Где: Балашиха или Воро неж Репутация: нет Всего: 4 |
Много подводных камней. Во-первых, нужно своевременно опустошать буфер (или считывать его), хотя это не проблема. Проблема в том, что парсить данные нужно по мере готовности, т.е. после прихода закрывающей кавычки. Слишком много условностей. Конечный автомат, ИМХО, простое и надёжное решение, приспособленное к формату входных данных. Я не скажу, что это более простое решение. С точки зрения кода оно менее очевидное. Но оно быстрее и надёжнее. По сути, Вы делаете функцию парсинга, принимающую один единственный символ:
Это сообщение отредактировал(а) Курсант - 11.1.2017, 00:36 |
||||
|
|||||
baldman88 |
|
|||
Бывалый Профиль Группа: Участник Сообщений: 210 Регистрация: 18.1.2009 Репутация: 1 Всего: 7 |
Я, наверное, параноик (видимо, работая с военными это нормальное состояние), но гарантии, что придет именно кавычка, нет. Тогда может возникнуть ситуация, что в качестве закрывающей будет воспринята открывающая из следующего сообщения (вероятность крайне низка, но такое может случиться!). Нужно предусмотреть сброс автомата в начальное состояние. Именно поэтому целесообразнее иметь буфер (и проверять его после прихода нового символа). И вот здесь использование конечного автомата очень даже оправдано (получили символ, прошлись по буферу -- если все в порядке, то выделили нужное значение, и при новом вызове автомат всегда находится в начальном состоянии). Пы.Сы.: ТС, скорее всего, неправильно поставил слеши -- они должны идти перед r и n. Да и первая строка, по идее, должна идти уже после пятой. |
|||
|
||||
Курсант |
|
||||
Опытный Профиль Группа: Участник Сообщений: 338 Регистрация: 21.2.2009 Где: Балашиха или Воро неж Репутация: нет Всего: 4 |
Как только в режиме чтения строки придёт любой символ из \r или \n, автомат сбросится и буфер обнулится. Ну, должен обнулиться, по крайней мере, возможно я забыл его обунлить, т.к. код иллюстративный, а не точный. Я, кстати, как раз хотел эту саму закрывающую кавычку Вам в качестве аргумента предложить. Т.е. Вам придётся парсить всю строку при каждом пришедшем символе. Более того, у нас один коллега реализовывал обмен по COM-порту как раз с помощью буфера и парсинга строк. Работает, вроде, но бывает что команды игнорирует, приходится повторно отправлять с компа. |
||||
|
|||||
supercelt |
|
|||
Опытный Профиль Группа: Участник Сообщений: 658 Регистрация: 25.8.2005 Репутация: нет Всего: 1 |
В продолжении вопроса. Выделить из кавычек это я поторопился. Надо сначала ещё кучу всего сделать. Там условия такие, что строка может придти когда угодно, какая угодно. Я не знаю ее размер. Таким образом я решил что по мере поступления символов, а прерывании по usart1 я буду просто набивать буфер. А потом, когда он набьётся - разбирать строку. И вот проблема. Раз я не знаю размер строки, то когда она полностью придёт неизвестно. Проверять по символу \r\n не вариант, так как эти символы приходят вначале сообщения и в середине. Короче я думал думал и вот что придумал. Алгоритм такой:
После того, как сработало первое прерывание по приёму usart1, я запускаю таймер. Настраиваю его на прерывание по переполнению. Далее приходит второй символ, таймер сбрасываю, он не успевает переполнится. И так далее. И вот пришёл последний символ. прерывание сработало последний раз и сбросило таймер. Он продолжает тикать. А раз символов то больше нет, он благополучно вваливается в прерывание по переполнению. В обработчике вектора вырубаю таймер и выставляю флаг что я принял всё-таки строку. Алгоритм простой, но как всегда всё работает почему-то не так как надо. Если из кода, который ниже убрать включение прерывание на таймер, то работает, но таймер соответственно не останавливается. А если включить прерывание, что так и должно быть - ничего не работает. Похоже даже на зависание. И самое интересное. Что бы я не делал, в режиме отладки, на кусок кода обработчика прерывания таймера нельзя поставить точку останова. Везде можно а именно на этот кусок нельзя.
|
|||
|
||||
Курсант |
|
|||
Опытный Профиль Группа: Участник Сообщений: 338 Регистрация: 21.2.2009 Где: Балашиха или Воро неж Репутация: нет Всего: 4 |
Вы не знаете чем набьётся буфер. ИМХО, если Вы не знаете максимальный размер того, что приходит между кавычек, Вы не можете гарантированно распознать строку - это раз. В буфер может набиться и две команды, и три, и две с половиной, что тогда? Две выполните, третью выкинете? А потом в следующем прерывании получите закрывающую кавычку от третьей команды и распознаете её как открывающую кавычку, и "съедите" кракозяблы.
Говорите точно, что за строки. Если они как-то описываются, то можно говорить об алгоритме. Если данные на входе не поддаются никакому описанию, то и обработке они не поддаются... Разве только через самообучающуюся нейросеть |
|||
|
||||
supercelt |
|
|||
Опытный Профиль Группа: Участник Сообщений: 658 Регистрация: 25.8.2005 Репутация: нет Всего: 1 |
Понимаете, разбор строки это как оказалось уже 2 шаг. Я застрял на первом. Неважно что пришло, и сколько размером набился буфер. Мне надо просто отследить когда в usart перестали поступать данные с момента начала. Прикрути таймер, но эта штука не особо то и работает. |
|||
|
||||
baldman88 |
|
||||
Бывалый Профиль Группа: Участник Сообщений: 210 Регистрация: 18.1.2009 Репутация: 1 Всего: 7 |
Вам шашечки или ехать? Для начала попробуйте конкретизировать задачу. Что, конкретно, не получилось с таймером? И как он может помочь в изначальном вопросе? |
||||
|
|||||
supercelt |
|
|||
Опытный Профиль Группа: Участник Сообщений: 658 Регистрация: 25.8.2005 Репутация: нет Всего: 1 |
Что с таймером. Вобщем в отладчике ставлю точки остановки на прерывании у таймера и юсарта. Запускаю. И самый первый раз останавливаемся на метке таймера. При том что таймер выключен. По сути получается якобы алгоритм отработал, выключил таймер TIM12->CR1 &= ~TIM_CR1_CEN; Но по задумке, повторю ещё раз: -Срабатывает первое прерывание по принятому байту юсарта
-Набиваем буфер -Если это первое прерывание, то запускаем таймер, если не первое, то обнуляем таймер. -Далее принимаются байты, счётчик сбрасывается, таймер не успевает переполняться. -Затем данные кончились, таймер никто не обнулил, он продолжает считать и досчитывает до топа и переполняется. -Вваливаемся в вектор по переполнению. Выключаем таймер, ставим флаг что набили буфер. А в отладчике. Первое куда мы приходим это вектор таймера. А должно быть - юсарт. И ещё одна странность. По отладчику видно, что приём одного байта занимает примерно 80 тиков таймера. Для наглядности я ставил ARR = 0xFFFF. Завязывал на полную. НО если я поставлю например 20000 тиков, то кол-во тиков между прерываниями приёма юсарта будет уже не 80, а допустим 2000. По идее ARR же никак не должно влиять на количество тиков между прерываниями, ведь до конца все-равно не досчитываем. |
|||
|
||||
baldman88 |
|
|||
Бывалый Профиль Группа: Участник Сообщений: 210 Регистрация: 18.1.2009 Репутация: 1 Всего: 7 |
Я бы не стал на 100% доверять эмулятору. Особенно если уже до этого были проблемы и неточности с его работой.
Насколько я понял, то сообщения от устройства у Вас приходят не очень часто, и Вы хотите использовать таймер именно для определения того, что сообщение уже пришло? Не самый удачный алгоритм. Скорее -- совсем неудачный (если заранее известен формат сообщений от устройства). |
|||
|
||||
supercelt |
|
|||
Опытный Профиль Группа: Участник Сообщений: 658 Регистрация: 25.8.2005 Репутация: нет Всего: 1 |
А если неизвестен? то кроме таймера есть ещё шустрые варианты?
|
|||
|
||||
Курсант |
|
|||
Опытный Профиль Группа: Участник Сообщений: 338 Регистрация: 21.2.2009 Где: Балашиха или Воро неж Репутация: нет Всего: 4 |
Ещё вариант - запустить счётчик реального времени. И при получении байта запоминать метку времени. Кроме того, периодически эту метку времени просматривать. Если интервал от этой метки времени до текущего момент времени превысил максимальную паузу между символами - отправляем накопленную строку на парсинг.
|
|||
|
||||
Правила форума "Микроконтроллеры (MCU) и микропроцессоры (MPU)" | |
|
На данный раздел помимо Правил форума распространяются текже следующие правила:
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, PILOT, ManiaK, UniBomb, Mazzi. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Микроконтроллеры (MCU) и микропроцессоры (MPU) | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |