Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Изменение периода таймера внутри прерывания
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > MSP430
//Nikson
Можно ли изменять регистр периода таймера внутри процедуры обработки прерывания этого самого таймера ? "Тикнул" таймер, изменили период, снова тикнул - опять изменили. Вообще во время работы таймера его период менять можно. А именно в этом месте? Если нельзя, то как по-человеески организовать постоянно меняющиеся временные интервалы?
rezident
Можно, если осторожно smile.gif Все дело в том, что если в режиме счета Count_Up период, задаваемый регистром CCR0, вы установите больше текущего, то все отработает нормально. Но если задаваемый период будет меньше текущего, то таймер сначала досчитает до переполнения 0xFFFF и только затем будет отрабатывать заданный период. Так что в последнем случае, кроме установки CCR0 нужно еще и сбрасывать счетчик таймера (TAR).
Если вы используете таймер для формирования сигнала ШИМ, периодом которого желаете управлять, то можно использовать таймер в режиме Continuous и каждый раз по прерыванию CCR0 простым суммированием невзирая на переполнение добавлять новый период с текущему содержимому CCR0. Кстати, для Timer_B это выглядит еще проще. У него уже предусмотрена двойная буферизация регисторов сравнения CCRx.
Резюмируя: читайте User's Guide, там все написано. Перевод см. тут.
P.S. ну и совсем очевидную вещь добавлю. Учитывайте скорость выполнения программы (частоту сигнала MCLK) и частоту тактирования собственно таймера. Естественно, если они равны, то вы не сможете манипулировать периодами ШИМ величиной в единицы тактов. CPU просто не успеет.
//Nikson
Можно, если осторожно
и
Так что в последнем случае, кроме установки CCR0 нужно еще и сбрасывать счетчик таймера (TAR).

спасибо, надеюсь всё будет теперь работать нормально.

PS Нет, это не ШИМ. Просто надо производить последовательно набор действий через различные промежутки времени. Вот мне и показалось что наиболее просто - выполнили действие, переставили таймер итд.
//Nikson
Кстати, а если промежутки времени, через которые надо выполнять действия, по длительности сопоставимы с тактовым сигналом - может не стоит использовать таймер (пока выставишь период, пока произойдёт вызов итд итп пройдёт намного больше времени), а прямо в основной процедуре писать пошагово действия, разделяя их задержками? И что можно использовать в качестве таких задержек?
rezident
Если периоды выполнения "действий" сопоставимы с периодом системной тактовой частоты, то либо неправильно выбрана тактовая частота, либо сам кристалл. Учитывайте что вызов прерывания и выход из прерывания это как минимум 11 тактов MCLK. Плюс еще действия по сохранению и восстановлению контекста (регистров).
И вообще зачем вам обрабатывать прерывания таймера, если программа линейная и действия прогнозируемые? Опрашивайте и сбрасывайте в основной программе флаги прерываний таймера, это быстрее, чем каждый раз вызывать прерывания только для того, чтобы изменить метку времени.
sensor_ua
Если необходимые времена, например, имеют порядок от единиц до sizeof(int) миллисекунд, а тактовая достаточно высокая, но не переполняет таймер за 1 миллисекунду, то можно применить следующий механизм:
1. Таймер запускаем на автоперезагрузку с периодом 1 мс
2. Заводим переменную типа unsigned (например, int или long), назовем её unsigned long Tms = 0;
3. В обработчике прерывания инкрементируем Tms без всяких проверок
4. В нужном месте программы выполняем функцию delay(N), где N - число миллисекунд
void delay(unsigned int N){
unsigned int StartTime;
unsigned int CurrentTime;
StartTime = (unsigned int)Tms; // начинаем считать от этого времени
do{
CurrentTime = (unsigned int)Tms;
}
while( (CurrentTime-StartTime) < N)
}

Может Вам такое и подойдёт
ek74
Цитата(sensor_ua @ Feb 14 2006, 19:42) *
void delay(unsigned int N){
unsigned int StartTime;
unsigned int CurrentTime;
StartTime = (unsigned int)Tms; // начинаем считать от этого времени
do{
CurrentTime = (unsigned int)Tms;
}
while( (CurrentTime-StartTime) < N)
}


Тогда уж лучше сделать так, поскольку будет тратится меньше процессорного времени
Код
void delay(unsigned int N)
{
  unsigned int StopTime = (unsigned int)Tms+N;
  while ((unsigned int)Tms < StopTime);
}

и не забыть описать Tms как volatile
sensor_ua
Цитата
Тогда уж лучше сделать так, поскольку будет тратится меньше процессорного времени


void delay(unsigned int N)
{
unsigned int StopTime = (unsigned int)Tms+N;
while ((unsigned int)Tms < StopTime);
}


ИМХО, при некоторых условиях работать не будет. Представим, что Tms = 0xFFFFFFFE, N = 5, соответственно StopTime =0xFFFFFFFE+5= 3. Когда Tms переполнится (Tms ==0) выполнится условие ((unsigned int)Tms < StopTime) ==> (0<3), т.е. недосчитаем.

На самом деле StartTime можно узнавать в любом удобном месте, откуда нужно начинать счёт, а проверку на ( (CurrentTime-StartTime) < N) выполнять также - в "нужном" месте - либо как системные дела, либо просто перед обработкой параметра в алгоритме - тогда это будет не пауза, а проверка на "не вышел ли указанный таймаут". Таким образом можно разгружать обработчики прерывания от if(timeout) --timeout;

Цитата
и не забыть описать Tms как volatile


согласен
VAI
у меня тоже тикает таймерное прерывание каждую милисекунду.
Что-бы избежать всех вышеперечисленных ошибок, сделал тики unsigned long
Код
volatile unsigned long tick_ms;        // милисекундные тики, хватит на 49 дней непрерывной работы прибора

void delay( unsigned long del )
{
  for ( del += tick_ms; del > tick_ms; )
  ;
}

Кстати микросекундные задержки (> 10 мкс) можно делать через Compare.
Через Compare у меня работает и 1-wire - общаюсь с DS1821
sensor_ua
Цитата
2. Заводим переменную типа unsigned (например, int или long), назовем её unsigned long Tms = 0;

Ну дык важно только чтобы обслужилось
Цитата
while( (CurrentTime-StartTime) < N)

хотя бы раз за 49 суток, иначе придётся верить, что ничего плохого не произойдёт (не под конец этих 49-и суток начали отсчёт StartTime, например) и всё пучком, но
Цитата
хватит на 49 дней непрерывной работы прибора

- подразумевает необязательность долговременой работы прибора.
А микросекундные можно делать, используя вместо Tms непосредственно показания таймера, но ошибки нужно оценивать при малых интервалах
ek74
Цитата
ИМХО, при некоторых условиях работать не будет. Представим, что Tms = 0xFFFFFFFE, N = 5

Тут Вы правы, такая ошибка может возникнуть. Хотя если требуется долговременная работа прибора, то можно период отсчёта таймер сделать не 1 мс, а например 10 мс. Тогда счётчика хватит на 497 суток и проблемы с переполнением вряд ли возникнут (за такой срок прибор в любом случаи хотя раз да перезапустится)

Хотя всё это сильно зависит от задачи, у меня например период отсчёта таймер 100 мс. Как говорится "А мне больше и не надо" smile.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.