|
CodevisionAVR фунция scanf, Как прервать scanf если в порт ничего больше подаваться не будет? |
|
|
|
Aug 23 2011, 03:17
|

Частый гость
 
Группа: Участник
Сообщений: 95
Регистрация: 4-04-11
Из: челябинск
Пользователь №: 64 111

|
Подскажите, пожалуйста! использую функцию scanf("%s",&string); Потом делаю с этой строкой все что нужно. Но бывает проблема, когда в UART приходит символ "ентер", и мне как бы не надо считывать эту строку, и прервать операцию по превышению TIMEOUT, а scanf ждет, пока в порт придет еще что-нибудь. Хочу сделать, чтобы в прерывании TIM0_OVF если TIMEOUT превышен, то scanf каким-то образом переставала считывать строку.
|
|
|
|
|
Aug 23 2011, 04:12
|

Профессионал
    
Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357

|
Цитата(Варяг @ Aug 23 2011, 07:17)  Подскажите, пожалуйста! использую функцию scanf("%s",&string); Потом делаю с этой строкой все что нужно. Но бывает проблема, когда в UART приходит символ "ентер", и мне как бы не надо считывать эту строку, и прервать операцию по превышению TIMEOUT, а scanf ждет, пока в порт придет еще что-нибудь. Хочу сделать, чтобы в прерывании TIM0_OVF если TIMEOUT превышен, то scanf каким-то образом переставала считывать строку. А как вам вообще пришло в голову использовать эту функцию? То, что вы написали, лишь считывает приходящие по UART-у байты в буфер. А что мешает считывать их самому? А этой функцией в контроллерах лучше вообще не пользоваться, как минимум из-за ее громоздкости и медлительности. К тому же все равно она в необходимых случаях вызывает atoi() и подобные - так лучше самому их вызвать, по крайней мере в этому случае все буде под контролем. Во-вторых спецификатором %s не стоит пользоваться из-за опасности записи за пределы буфера. Что произойдет если байтов придет больше чем размер буфера?
|
|
|
|
|
Aug 23 2011, 05:52
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Не про CodeVision-реализацию, а про стандартный scanf со времён K&R: Пожалуйста, кто-нибудь, переполните мне буфер: Код #include <stdio.h>
#define STRINGIFY_(a) #a #define STRINGIFY(a) STRINGIFY_(a)
#define STR_SIZE 4
char str[STR_SIZE+1];
int main() { do { if( !scanf("%" STRINGIFY(STR_SIZE) "s", str) ) break; str[STR_SIZE] = 0; puts(str); } while(str[0] != 'Q'); } Цитата real@REALPC:~/temp$ ./ssc 1234567890qwertyuiop[]asdfghjkl 1234 5678 90qw erty uiop []as dfgh jkl Q Q Жирным выделен ввод с клавиатуры. А то, панимашли, «небезопасен», «переполнение»... p.s. Для тех, кто не так быстро в голове макросы раскручивает: формат там "%4s", просто через макрос для синхронной смены вместе с размером буфера.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Aug 23 2011, 06:54
|

Профессионал
    
Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357

|
Цитата(Варяг @ Aug 23 2011, 10:34)  Ну так а все-таки, будь то getchar or scanf, как сделать, чтобы он не бесконечно пытался считать входящий символ, и переставал считывать после определенного времени? Так где вы все-таки этого начитались? В каком-нибудь учебнике по Си? Вообще-то вы пишите программу для микроконтроллера, поэтому лучше взять учебник по микроконтроллерам. Там найдете что-нибудь типа Код volatile bool StopReading = false; char buff[SIZE]; char *p = buff; while(1) { if((UCSR0A & _BV(RXC0)) != 0) if((*p++ = UDR0) == '\n' || p >= buff+SIZE) break; if(StopReading) break; } Но лучше конечно читать по прерываниям.
Сообщение отредактировал 777777 - Aug 23 2011, 06:55
|
|
|
|
|
Aug 23 2011, 06:56
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Как в CodeVision -- не подскажу. Но обработку таймаутов надо на нижний уровень и садить. В avr-gcc, если бы такое захотелось, я бы в подставляемые мной функции ввода/вывода байта для данного файлового объекта поселил бы обработку таймаутов и возврат признака EOF, который и до scanf-а добежал бы. scanf вернул бы 0 (точнее, меньше полей, чем запрошено).
p.s[0] Согласен с тем, что для мелкого микроконтроллера, без особых на то показаний, лучше отказаться от scanf и читать самостоятельно. scanf жрёт много памяти кода, а его возможности на деле мало кому нужны в таких местах.
p.s[1] Ну а по мнимой небезопасности scanf в строку я уже высказался. Можно, конечно, придумать ситуацию, например, «а у нас scanf в одном месте, а мы передаём туда разные буфера, длина каждый раз разная и в форматную строку не подставить», но в типичном применении проблемы переполнения буфера в scanf нет. Есть проблема незнания его форматов ввода.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Aug 23 2011, 07:30
|

Частый гость
 
Группа: Участник
Сообщений: 95
Регистрация: 4-04-11
Из: челябинск
Пользователь №: 64 111

|
Цитата(777777 @ Aug 23 2011, 10:54)  Так где вы все-таки этого начитались? В каком-нибудь учебнике по Си? Вообще-то вы пишите программу для микроконтроллера, поэтому лучше взять учебник по микроконтроллерам. Там найдете что-нибудь типа Код volatile bool StopReading = false; char buff[SIZE]; char *p = buff; while(1) { if((UCSR0A & _BV(RXC0)) != 0) if((*p++ = UDR0) == '\n' || p >= buff+SIZE) break; if(StopReading) break; } Но лучше конечно читать по прерываниям. Я читаю CodevisionAVR автор Лебедев. Там сказано, что формат %s является строка, завершающаяся нулевым символом. Следовательно, пока я не приму нулевой символ он и будет пытаться его считать. А мне надо это прервать. По поводу буффера, это не проблема, ничего не переполняется. По поводу того, что scanf много жрет кода, так я и половины флэш памяти не могу забить. Да и скорости обработки мне не надо, иначе бы пользовался "*p++ = UDR0". А scanf достаточно наглядная, и мне тупо надо её прервать. Спасибо большое за приведенные примеры!
|
|
|
|
|
Aug 23 2011, 08:25
|

Профессионал
    
Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357

|
Цитата(Варяг @ Aug 23 2011, 11:30)  Я читаю CodevisionAVR автор Лебедев. Там сказано, что формат %s является строка, завершающаяся нулевым символом. Следовательно, пока я не приму нулевой символ он и будет пытаться его считать. А мне надо это прервать. По поводу буффера, это не проблема, ничего не переполняется. По поводу того, что scanf много жрет кода, так я и половины флэш памяти не могу забить. Да и скорости обработки мне не надо, иначе бы пользовался "*p++ = UDR0". А scanf достаточно наглядная, и мне тупо надо её прервать. Спасибо большое за приведенные примеры! Да где ж тут наглядность? Как раз в том и проблема, что программируя микроконтроллер вы при этом не знаете что он делает! Как раз самой наглядной является строка "*p++ = UDR0" и работать с UART-ом через регистры надо как раз для того, чтобы иметь над ним полный контроль и в любой момент делать с ним все что вам нужно. Прочитайте даташит, запрограммируйте его прием по прерываниям и тогда вопрос о том как остановить ввод даже не возникнет.
|
|
|
|
|
Aug 24 2011, 04:43
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(ReAl @ Aug 23 2011, 09:52)  Пожалуйста, кто-нибудь, переполните мне буфер:  ...оторви мне чего-нибудь, укуси меня за... (с) "Несчастный случай". Цитата формат там "%4s" Ну так жешь нужно вспомнить было про возможность задать ограничение на длину строки, а если тупо "%s", то всегда пожалуйста. Цитата(ReAl @ Aug 23 2011, 10:56)  но в типичном применении проблемы переполнения буфера в scanf нет. Есть проблема незнания его форматов ввода. Согласен. Спасибо за hint!
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Aug 24 2011, 07:02
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(demiurg_spb @ Aug 24 2011, 07:43)   ...оторви мне чего-нибудь, укуси меня за... (с) "Несчастный случай". «Та нє»™, тут скорее «поднимите мне веки» :-) Цитата(demiurg_spb @ Aug 24 2011, 07:43)  Ну так жешь нужно вспомнить было про возможность задать ограничение на длину строки, а если тупо "%s", то всегда пожалуйста. Да там по вводу строк ещё и ограничить набдор символов можно кроме ширины. Только без s уже: "%4[0-9]" -- максимум 4 цифры "%4[^0-9]" -- максимум 4 не-цифры И ввод символа %c тоже позволяет задать ширину, тогда внутри такого поля '\n' идёт на правах символа, а не разделителя, как для %sКод #include <stdio.h>
char str[5];
int main() { str[4] = 0;
scanf("%4c", str); printf("[%s]\n", str); scanf("%4c", str); printf("[%s]\n", str); scanf("%4c", str); printf("[%s]\n", str); } Цитата qw r01234567
[qw r] [0123] [4567] Вот потому полновесный scanf такой толстый. Умеет много. Не всегда нужного.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Aug 26 2011, 09:35
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (Варяг @ Aug 26 2011, 11:38)  Так как я не понял, как прервать функцию scanf Читайте ответы внимательнее: QUOTE (ReAl @ Aug 23 2011, 09:56)  Как в CodeVision -- не подскажу. Но обработку таймаутов надо на нижний уровень и садить. В avr-gcc, если бы такое захотелось, я бы в подставляемые мной функции ввода/вывода байта для данного файлового объекта поселил бы обработку таймаутов и возврат признака EOF, который и до scanf-а добежал бы. scanf вернул бы 0 (точнее, меньше полей, чем запрошено). А сбрасывать процессор можно через Watchdog Timer.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|