Перейти к содержанию
    

Несколько вопросов начинающего

Коллеги, ещё один вопрос :

 

Верно ли я понимаю, что значение, которое возвращает xTaskGetTickCount(); периодически сбрасывается в 0 и начинает расти заново, т.к. переполняется 32х разрядная переменная, которая считает тики , и стало быть, при использовании xTaskGetTickCount(); я должен обрабатывать этот сброс в 0 ?

А все функции операционки которые работают со временем (задержка, взять симофор и т.п. ) , то же обрабатывают сброс счётчика тиков в 0 ?

 

МП

 

Если ваша задержка меньше разрядности счётчика, то 0 обрабатывать не нужно. Но если больше - обязательно (или разбивать на части).

 

Пример: пусть счётчик 16-битный. Начальное значение 2, а задержка - 70000 (0x11170). Если взять просто сумму получим 0x11172, из-за переполнения получим в итоге 0x1172, что даст реальную задержку 4464 вместо 70000. Если промахнуться с разрядностью переменной, с которой будет сравниваться счётчик - можно никогда не выйти из цикла ожидания.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня вот это работает, только если возвращаемая переменная static . А если нет, то функция возвращает 0. Как я понимаю, это потому что существование переменной прекращаеся чуть раньше чем программа вышла из функции, и возвращать оказывается нечего.

 

char do_something(void)
{
       chatic char result;

        //.................
  
       return result;
}

нет, не так работает си/с++. если резалт не статик, то при покидании функции переменная резалт удалится из стека, но её значение не потеряется а нормально вернётся. может у вас в одной задаче резальт считается и равен 0, в другой задаче резалт неравен нулю. в итоге, когда статик, то оба резалта не равны нулю, а одному значению. а когда не статик, то один экземпляр равен нулю. ..... вобщем это гадание на кофейной гуще. что то не так у вас. попробуйте запустить только одну задачу и проверит статик и нестатик - результат должен быть одинаковый, потом 1-ую задачу выкл, и включить вторую - проверить.....

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

нет, не так работает си/с++. если резалт не статик, то при покидании функции переменная резалт удалится из стека, но её значение не потеряется а нормально вернётся. может у вас в одной задаче резальт считается и равен 0, в другой задаче резалт неравен нулю. в итоге, когда статик, то оба резалта не равны нулю, а одному значению. а когда не статик, то один экземпляр равен нулю. ..... вобщем это гадание на кофейной гуще. что то не так у вас. попробуйте запустить только одну задачу и проверит статик и нестатик - результат должен быть одинаковый, потом 1-ую задачу выкл, и включить вторую - проверить.....

 

Я даже без ОС в самом простом линейном коде наблюдаю что функция возвращает только 0 если локальная переменная в ней не static.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я даже без ОС в самом простом линейном коде наблюдаю что функция возвращает только 0 если локальная переменная в ней не static.

http://electronix.ru/forum/index.php?showt...t&p=1259306

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я даже без ОС в самом простом линейном коде наблюдаю что функция возвращает только 0 если локальная переменная в ней не static.

даже не чего подсказат. си/с++ не так работает. отправлять вас читать книжки "Учимся писать на СИ" как-то неприлично. может компилятор кривой, может вы что-то путаете.

 

Как же вообще у вас FreeRTOS работает? например функция создания задач

 

signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions )
{
signed  xReturn;
...
return  xReturn;
}

ни каких статиков. и др функции возвращающие не void без всяких статиков.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня вот это работает, только если возвращаемая переменная static . А если нет, то функция возвращает 0. Как я понимаю, это потому что существование переменной прекращаеся чуть раньше чем программа вышла из функции, и возвращать оказывается нечего.

char do_something(void)
{
       chatic char result;

        //.................
  
       return result;
}

Так не бывает. Тем более с переменной типа char. Она помещается в регистр, поэтому не может прекратить своё существование.

Попробуйте убрать статик и назначить переменной какое-то значение по умолчанию, типа

char do_something(void)
{
       char result = 123;

        //.................
  
       return result;
}

И посмотрите, что получится. Если функция будет возвращать 123, значит вы просто забыли присвоить значение переменной result:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так не бывает. Тем более с переменной типа char. Она помещается в регистр, поэтому не может прекратить своё существование.

 

Спасибо. Моя проблема скорее всего была связана с изменением переменных в прерывании, директива static иногда работала как volatile.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Коллеги, доброго времени суток.

 

Не могу до конца понять как работают программные таймеры.

Что такое "очередь таймера" и в каких случаях она переполняется ?

Вот например, мне нужно, что бы таймер начал считать с 0, а если уже считал то сбросился в 0 и начал с 0.

BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xBlockTime );

Делает именно это или что-то другое ?

Что такое xBlockTime , почему про неё сказано , что "это то время, которое задача будет заблокирована, пока команда не запишется в очередь таймера" ? Таймер можно как-нибудь просто сбросить в 0 не блокируя задачу, в которой это делается ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не могу до конца понять как работают программные таймеры.

Что такое "очередь таймера" и в каких случаях она переполняется ?

Вот например, мне нужно, что бы таймер начал считать с 0, а если уже считал то сбросился в 0 и начал с 0.

 

Полагаю, что термин "очередь таймера" относится не к аппаратному таймеру, как таковому, а к планировщику задач операционной системы разделенного времени. Т.е. в отсутствие операционной системы у таймеров нет никаких очередей.

 

Судя по всему, под очередью понимается та задача/процедура, на которую таймер должен переключиться при выходе из своей процедуры прерывания. Т.е. по сути это чисто программная задача, а не аппаратная. Причем, место следующего возврата должно быть определено еще до запуска таймера, поскольку после того, как произойдет по нему прерывание, будет некогда искать того, кто стоит в очереди первым. В прерывании вообще нельзя долго находиться, а уж тем более выяснять там какие-то вопросы, которые обязаны были быть решены заранее.

 

Изменения в самой очереди, по-видимому, происходят только тогда, когда ставится новая задача или снимается/завершается старая. Т.е. только в этот момент в порядке очередности задач могут произойти какие-то изменения, тогда как задача таймера - чистое переключение.

 

В общем случае каких-то стандартов тут нет, т.к. авторы операционной системы вольны создать планировщик задач исключительно по своему вкусу, в том числе и вводить для его описания свои термины. Говорят, что когда-то номер/адрес следующего задания хранили прямо в самом таймере, используя его старшие разряды, которые обычно не используются. Но с тех пор и таймеры стали другими, и задачи стали сложнее, а потому нынче задачи обычно переключают по таблице, малость смахивающую на таблицу прерываний. Что-то более определенное сказать не могу, т.к. свою операционную системы вы не назвали. Хотя, судя по названию процедуры BaseType_t xTimerReset, у вас FreeRTOS.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Судя по всему, под очередью понимается та задача/процедура, на которую таймер должен переключиться при выходе из своей процедуры прерывания. Т.е. по сути это чисто программная задача, а не аппаратная. Причем, место следующего возврата должно быть определено еще до запуска таймера, поскольку после того, как произойдет по нему прерывание, будет некогда искать того, кто стоит в очереди первым. В прерывании вообще нельзя долго находиться, а уж тем более выяснять там какие-то вопросы, которые обязаны были быть решены заранее.
мимо :laughing:

не нужны ни какие места возврата.

 

Не могу до конца понять как работают программные таймеры.
Открываем журнал КиТ №10 2011, страница 93. Читаем....

 

Что такое "очередь таймера" и в каких случаях она переполняется ?

Очередь команд таймеров

Для совершения операций запуска, оста-

нова, сброса, изменения периода и удале-

ния таймеров во FreeRTOS предоставляется

набор API-функций, которые могут вызы-

ваться из задач и обработчиков прерываний,

а также из функций таймеров. Вызов этих

API-функций не воздействует напрямую

на задачу обслуживания таймеров. Вместо

этого он приводит к записи команды в оче-

редь, которую в дальнейшем мы будем на-

зывать очередью команд таймеров. Задача

обслуживания таймеров считывает команды

из очереди и выполняет их.

....

conf igTIMER_QUEUE_LENGTH. Размер

очереди команд — устанавливает макси-

мальное число невыполненных команд,

которые могут храниться в очереди, пре-

жде чем задача обслуживания таймеров их

выполнит.

 

 

Что такое xBlockTime
смотрим там же...

xBlockTime — определяет время тайм-

аута — максимальное время нахождения

вызывающей xTimerChangePeriod() задачи

в блокированном состоянии, если очередь

команд полностью заполнена и нет воз-

можности поместить в нее команду об из-

менении периода таймера.

У вас очередь 5 команд. вызвали из других задач 5 разных команд. Потом из текущей вызываем xTimerChangePeriod(). Что должно произойти? Функция xTimerChangePeriod должна поместить в очередь таймера новую команду изменения периода, но очередь заполнина. Что делать? Текущая задача переходит в блокированное состояние на время xBlockTime или до тех пор, пока в очереди не появиться свободное место.

 

 

Вот например, мне нужно, что бы таймер начал считать с 0, а если уже считал то сбросился в 0 и начал с 0.

BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xBlockTime );

Делает именно это или что-то другое ?

там же, в ките, всёже на русском и могучем...

Сброс таймера

Сброс таймера осуществляется с помощью

API-функции xTimerReset(). Ее прототип:

portBASE_TYPE xTimerReset( xTimerHandle xTimer, portTickType

xBlockTime );

...

Операция сброса может применяться как

к активному таймеру, так и к находящему-

ся в пассивном состоянии. В случае если

таймер находился в пассивном состоянии,

вызов xTimerReset() будет эквивалентен вы-

зову xTimerStart(), то есть таймер будет за-

пущен. Если таймер уже отсчитывал время

в момент вызова xTimerReset() (то есть на-

ходился в активном состоянии), то вызов

xTimerReset() приведет к тому, что таймер

заново начнет отсчет времени с момента вы-

зова xTimerReset().

 

 

Таймер можно как-нибудь просто сбросить в 0 не блокируя задачу, в которой это делается ?

Скорее нельзя. ..... ээээ.... напрямую нет, или да.... вобщем сброс таймера - это запись команды сброса таймера в очередь таймеров. Если у вас 1 таймер... пара мест вызова API для таймера, в которые вы попадаете раз в год и очередь таймера 100 команд, то с вероятностью близкой к 1.0 ваша задача не будет блокирована вызовом xTimerReset(). Если у вас 100 таймеров, 1000 мест вызова API для таймеров... и/или вы ограниченны в длине очереди команд таймера, то можно сделать какойнить финт... типа: сделать задачу сброса таймера. эта задача будет ждать флага/эвента. Основная задача выставляет флаг/запускает эвент сброса таймера и работает дальше, а задача сброса таймера вызывает xTimerReset(). Если очередь таймера полна, то задача сброса таймера блокируется, а основная задача работает. Задача сброса должна быть приоритетом выше.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Про зачистку памяти.....

 

Ту память, которую занимала прибитая задача, зачистит idle. А ту память которую выделили задаче до создания задачи, нужно руками зачищать.

 

например death.c

void vCreateSuicidalTasks( unsigned portBASE_TYPE uxPriority )
{
unsigned portBASE_TYPE *puxPriority;

        /* Create the Creator tasks - passing in as a parameter the priority at which
        the suicidal tasks should be created. */
        puxPriority = ( unsigned portBASE_TYPE * ) pvPortMalloc( sizeof( unsigned portBASE_TYPE ) );
        *puxPriority = uxPriority;

        xTaskCreate( vCreateTasks, "CREATOR", deathSTACK_SIZE, ( void * ) puxPriority, uxPriority, NULL );

        /* Record the number of tasks that are running now so we know if any of the
        suicidal tasks have failed to be killed. */
        uxTasksRunningAtStart = uxTaskGetNumberOfTasks();
}

Если задача vCreateTasks сама себя удалит, или её удалит кто-то другой, то память, веделенная вызовом pvPortMalloc не освободится. Нужно позаботится об её освобождении. Поэтому в задаче vCreateTasks делается ручная зачистка

 

unsigned portBASE_TYPE uxPriority; //создается новая переменная на стеке
...

        uxPriority = *( unsigned portBASE_TYPE * ) pvParameters; //копируется данные из динамической выделенной памяти pvParameters в uxPriority 
        vPortFree( pvParameters ); //удаляется динамически выделенная память.

 

Помогите пожалуйста разобраться с vPortFree.

Вот допустим, я удаляю задачу.

Что делать дальше ? Нужно передать в vPortFree в качестве параметра хендлер этой задачи, и тогда память, которую занимала задача, освободится ?

А если задача удаляет саму себя, перед этим присваивая значение NULL хэндлеру ?

Можно ли перед этим, прямо внутри задачи, запустить vPortFree ?

И как после этого задача продолжит работать , т.е. выполнит два последних действия

v_Task_Handle=NULL;

vTaskDelete(NULL);

если у задачи уже нет никакой памяти, т.е. в эту память может записаться что угодно ?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Читаю все это и волосы дыбом. Тем более что и работаю с этим. Почему программист должен думать об освобождении памяти? Почему многопоточность не поддерживается средствами языка? Почему до сих пор все сидят на древних языках вроде С и С++ (он недалеко ушел от С, пусть и поддерживает ООП, но все равно с ним обрушить любую систему на ура можно. Есть ли нормальные реализации Явы или С шарп для контроллеров? Иначе это хождение по граблям будет вечным. 15 лет в теме и все одно и тоже. И памяти то уже достаточно для Явы например, и все равно. От слов «указатель» и «приведение типов» тошнит уже в век, когда объемы флеш и озу - ничто, а время на выпуск - все, это анахронизм какой то

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Читаю все это и волосы дыбом. Тем более что и работаю с этим. Почему программист должен думать об освобождении памяти? Почему многопоточность не поддерживается средствами языка? Почему до сих пор все сидят на древних языках вроде С и С++ (он недалеко ушел от С, пусть и поддерживает ООП, но все равно с ним обрушить любую систему на ура можно. Есть ли нормальные реализации Явы или С шарп для контроллеров? Иначе это хождение по граблям будет вечным. 15 лет в теме и все одно и тоже. И памяти то уже достаточно для Явы например, и все равно. От слов «указатель» и «приведение типов» тошнит уже в век, когда объемы флеш и озу - ничто, а время на выпуск - все, это анахронизм какой то

 

Если бы озу было "ничто", то я бы вообще не делал динамическое создание/удаление задач.

Если Вы знаете как надо, то скажите основные ключевые слова.

Есть проц STM32L151 . Выбран как самый малопотребляющий, т.е. ни на что более мощное перейти нельзя.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...