Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: CodevisionAVR фунция scanf
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Варяг
Подскажите, пожалуйста! использую функцию scanf("%s",&string); Потом делаю с этой строкой все что нужно. Но бывает проблема, когда в UART приходит символ "ентер", и мне как бы не надо считывать эту строку, и прервать операцию по превышению TIMEOUT, а scanf ждет, пока в порт придет еще что-нибудь. Хочу сделать, чтобы в прерывании TIM0_OVF если TIMEOUT превышен, то scanf каким-то образом переставала считывать строку.
777777
Цитата(Варяг @ Aug 23 2011, 07:17) *
Подскажите, пожалуйста! использую функцию scanf("%s",&string); Потом делаю с этой строкой все что нужно. Но бывает проблема, когда в UART приходит символ "ентер", и мне как бы не надо считывать эту строку, и прервать операцию по превышению TIMEOUT, а scanf ждет, пока в порт придет еще что-нибудь. Хочу сделать, чтобы в прерывании TIM0_OVF если TIMEOUT превышен, то scanf каким-то образом переставала считывать строку.


А как вам вообще пришло в голову использовать эту функцию? То, что вы написали, лишь считывает приходящие по UART-у байты в буфер. А что мешает считывать их самому?

А этой функцией в контроллерах лучше вообще не пользоваться, как минимум из-за ее громоздкости и медлительности. К тому же все равно она в необходимых случаях вызывает atoi() и подобные - так лучше самому их вызвать, по крайней мере в этому случае все буде под контролем. Во-вторых спецификатором %s не стоит пользоваться из-за опасности записи за пределы буфера. Что произойдет если байтов придет больше чем размер буфера?
demiurg_spb
используйте getchar и сами складывайте символы в строку.
scanf - не гарантирует не переполнение буфера приёмника строки и тем самым является не безопасной по сути.
Варяг
Спасибо, буду править.
ReAl
Не про 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", просто через макрос для синхронной смены вместе с размером буфера.
Варяг
Ну так а все-таки, будь то getchar or scanf, как сделать, чтобы он не бесконечно пытался считать входящий символ, и переставал считывать после определенного времени?
777777
Цитата(Варяг @ 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;
    }

Но лучше конечно читать по прерываниям.
ReAl
Как в CodeVision -- не подскажу.
Но обработку таймаутов надо на нижний уровень и садить. В avr-gcc, если бы такое захотелось, я бы в подставляемые мной функции ввода/вывода байта для данного файлового объекта поселил бы обработку таймаутов и возврат признака EOF, который и до scanf-а добежал бы. scanf вернул бы 0 (точнее, меньше полей, чем запрошено).

p.s[0] Согласен с тем, что для мелкого микроконтроллера, без особых на то показаний, лучше отказаться от scanf и читать самостоятельно. scanf жрёт много памяти кода, а его возможности на деле мало кому нужны в таких местах.

p.s[1] Ну а по мнимой небезопасности scanf в строку я уже высказался. Можно, конечно, придумать ситуацию, например, «а у нас scanf в одном месте, а мы передаём туда разные буфера, длина каждый раз разная и в форматную строку не подставить», но в типичном применении проблемы переполнения буфера в scanf нет. Есть проблема незнания его форматов ввода.
Варяг
Цитата(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 достаточно наглядная, и мне тупо надо её прервать. Спасибо большое за приведенные примеры!
GDI
В CodeVision, по крайней мере в те времена когда я в нем начинал, был прекрасный мастер проектов, в котором реализован прекрасный буферизированный ввод символов с УАРТ, вроде даже там есть опция работы по прерываниям (но тут мне память может изменить). Просто поставьте нужные галочки. А еще там есть куча примеров проектов, в том числе и с работой с УАРТом.
777777
Цитата(Варяг @ Aug 23 2011, 11:30) *
Я читаю CodevisionAVR автор Лебедев. Там сказано, что формат %s является строка, завершающаяся нулевым символом. Следовательно, пока я не приму нулевой символ он и будет пытаться его считать. А мне надо это прервать. По поводу буффера, это не проблема, ничего не переполняется. По поводу того, что scanf много жрет кода, так я и половины флэш памяти не могу забить. Да и скорости обработки мне не надо, иначе бы пользовался "*p++ = UDR0". А scanf достаточно наглядная, и мне тупо надо её прервать. Спасибо большое за приведенные примеры!

Да где ж тут наглядность? Как раз в том и проблема, что программируя микроконтроллер вы при этом не знаете что он делает! Как раз самой наглядной является строка "*p++ = UDR0" и работать с UART-ом через регистры надо как раз для того, чтобы иметь над ним полный контроль и в любой момент делать с ним все что вам нужно. Прочитайте даташит, запрограммируйте его прием по прерываниям и тогда вопрос о том как остановить ввод даже не возникнет.
demiurg_spb
Цитата(ReAl @ Aug 23 2011, 09:52) *
Пожалуйста, кто-нибудь, переполните мне буфер:
sm.gif ...оторви мне чего-нибудь, укуси меня за... (с) "Несчастный случай".
Цитата
формат там "%4s"
Ну так жешь нужно вспомнить было про возможность задать ограничение на длину строки, а если тупо "%s", то всегда пожалуйста.

Цитата(ReAl @ Aug 23 2011, 10:56) *
но в типичном применении проблемы переполнения буфера в scanf нет. Есть проблема незнания его форматов ввода.
Согласен. Спасибо за hint!
ReAl
Цитата(demiurg_spb @ Aug 24 2011, 07:43) *
sm.gif ...оторви мне чего-нибудь, укуси меня за... (с) "Несчастный случай".
«Та нє»™, тут скорее «поднимите мне веки» :-)

Цитата(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 такой толстый. Умеет много. Не всегда нужного.
Варяг
Так как я не понял, как прервать функцию scanf, возник вопрос. Есть ли в КОДВИЖНе функция сброса микроконтроллера? хочу его сбрасывать, если в порт так ничего и не приняли.
Сергей Борщ
QUOTE (Варяг @ Aug 26 2011, 11:38) *
Так как я не понял, как прервать функцию scanf

Читайте ответы внимательнее:
QUOTE (ReAl @ Aug 23 2011, 09:56) *
Как в CodeVision -- не подскажу.
Но обработку таймаутов надо на нижний уровень и садить. В avr-gcc, если бы такое захотелось, я бы в подставляемые мной функции ввода/вывода байта для данного файлового объекта поселил бы обработку таймаутов и возврат признака EOF, который и до scanf-а добежал бы. scanf вернул бы 0 (точнее, меньше полей, чем запрошено).


А сбрасывать процессор можно через Watchdog Timer.

777777
Цитата(Варяг @ Aug 26 2011, 12:38) *
Так как я не понял, как прервать функцию scanf, возник вопрос. Есть ли в КОДВИЖНе функция сброса микроконтроллера? хочу его сбрасывать, если в порт так ничего и не приняли.

Фу, как грубо.
Ну а все-таки - читать не scanf-ом, а вручную через регистры не планируете? А когда придется что-то принимать через SPI или I2C - тогда что будете делать?
Варяг
Цитата(777777 @ Aug 26 2011, 14:45) *
Фу, как грубо.
Ну а все-таки - читать не scanf-ом, а вручную через регистры не планируете? А когда придется что-то принимать через SPI или I2C - тогда что будете делать?


Не грубо, а "сурово". sm.gif ну а если серьезно, то я бы и хотел вручную через регистры все сделать. Но читать через scanf это уже стало моей идеей фикс. Когда придется что-то принимать через SPI или I2C тогда буду думать дальше. а пока устраивает. Контроллер пока не зависает, но хочу обезопасить себя автосбросом по тайм-ауту.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.