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

Помогите разобраться с таймером

Использую А0 для формирования задержек, а А1 для часов.

Вот так я инициализирую таймер:

  TACCTL0=CCIE;
  TACCTL1=CCIE;
  TACCR1=32767;
  TACTL=TASSEL0+TAIE+MC0;
  //IAR показывает, что TACCTL0=0x418, TACCTL1=0x10

А0 работает так, как от него требуется.

void sleep(unsigned short tacts)
{
  __enable_interrupt();
  TACCR0=tacts;
  __low_power_mode_3();
  TACCR0=0;
}

#pragma vector=TIMERA0_VECTOR
__interrupt void TimerA0_ISR(void)
{
  __low_power_mode_off_on_exit ();
};

А что происходит с А1, я понять не могу: он перестает генерировать прерывания в LPM3. Вроде, все делаю, как написано в исходниках-примерах.

#pragma vector=TIMERA1_VECTOR
__interrupt void TimerA1_ISR(void)
{
  if(TAIV==2)
  {
    (здесь увеличиваем время на секунду)
  }
  P2OUT ^= 0x40; //мигаем светодиодом
}

Помогите разобраться, где здесь ошибка.

Изменено пользователем LCD

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


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

У вас как минимум две ошибки.

Во-первых, вы используете режим таймера CountUp (MC0=1, MC1=0) при котором таймер считает вверх (инкрементируется содержимое счетчика TAR) лишь до значения, установленного в TACCR0. После совпадения TAR и TACCR0 счетчик TAR сбрасывается в нуль. Поэтому в режиме CountUp запись в TACCR1 какого либо значения меньшего, чем записано в TACCR0 не дает никакого эффекта. Потому, что при таких условиях (TACCR1>TACCR0) прерывание от совпадения TAR и TACCR1 никогда не наступит.

Во-вторых, в этом режиме запись в TACCT0 нуля дает останов таймера.

В-третьих, у вас присутствует прерывание от переполнения (установлен бит TAIE в TACTL), которое вы не обрабатываете.

Для функций которые вы желаете реализовать таймер должен работать в режиме Continuous - режим счета с переполнением. Поскольку таймер тактируется от часового кварца 32768Гц, то прерывание дважды за период переполнения может вызываться 1) при совпадении какого-либо из CCR и 2) прерыванием от переполнения. Так получем два прерывания за 65536 тактов или период 1 секунду.

Обработчик прерывания выглядит так

#pragma vector=TIMERA1_VECTOR
__interrupt void TimerA1_ISR(void)
{ unsigned int TAIVstate=TAIV;
  switch(TAIVstate)
  { case 0x02:  //прерывания при совпадении TAR и TACCR1
    case 0x0A:  //прерывания при переполнении TAR
      //вызывается дважды за период переполнения (2 с), т.е. с периодом 1 секунда
      //(здесь увеличиваем время на секунду)
      break;
    default:
      break;
  }
  P2OUT ^= 0x40; //мигаем светодиодом
}

Инициализацию таймера делаем так

TACTL=TASSEL0 | TAIE | TACLR;  //здесь разрешаем первый источник прерываний за период
TACCR1=32767;
TACCTL0=0;
TACCTL1=CCIE; //здесь разрешаем второй источник прерываний
TACCTL2=0;
TACTL|=MC1;

Для реализации функции интервальных отсчетов используем TACCR0 как это у вас и задумано. Только не нужно его сбрасывать. Когда вы запускаете интервальный отсчет, то просто возмите текущее значение TAR, добавьте к нему требуемое значение интервала в периодах частоты часового кварца, запишите получившееся число в TACCR0 и разрешите прерывание от совпадения TAR и TACCR0 установкой бита CCIE в TACCTL0, предварительно очистив флаг CCIFG.

void sleep(unsigned int tacts)
{
  TACCTL0=CM0 | CMIS1 | CAP;
  TACCTL0|=CMIS0;
  TACCR0+=tacts;
  TACCTL0=CCIE;
  __bis_SR_register(__SR_CPU_OFF | __SR_SCG0 | __SR_SCG1 | GIE);
  TACCTL0=0;
}

#pragma vector=TIMERA0_VECTOR
__interrupt void TimerA0_ISR(void)
{
  __bic_SR_register_on_exit(__SR_CPU_OFF | __SR_SCG0 | __SR_SCG1);
};

Обращаю особо внимание на три первые строчки функции sleep. Предполагаю, что для MCLK у вас используется DCO, так? Тогда поскольку частоты MCLK=DCO и ACLK=LFXT (используемая для тактирования таймера A) асинхронные, то впрямую считывать TAR нельзя. Прямое чтение TAR может дать неверное значение. Чтобы этого избежать используем режим захвата, сымитировав перепад уровня для его срабатывания. Вот это и реализовано в первых двух строчках. В третьей строке "захваченное" в регистр TACCR0 текущее значение TAR увеличивается на интервал времени, соответствующий требуемому. Естественно интервал не может превышать периода 2 сек или 65536 тактов таймера или увеличению на 0x10000=0x0000, т.к. регистр 16-и разрядный.

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


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

вот такой вопрос.

нужно что бы каждые 2 секунды было прерывание по таймеру и сброс счетчика n.

делаю так:

 

#pragma vector=TIMERA0_VECTOR

__interrupt void TimerA0_ISR(void)

{

unsigned TAIVcopy=TAIV;

switch(TAIVcopy)

{

case 0x02:break;

case 0x0A:break;

}

n=0; //n - счетчик нажатий

}

 

void main()

 

TACCTL1=CCIE;

TACCR1 = 32767;

TACTL = TASSEL_1 +MC_1 +TACLR+ TAIE;

 

_EINT();

 

while(1)

{

 

while (!(P2IN&0x20));

 

while (P2IN&0x20);

 

n++;

 

out(v); //вывод количества нажатий на экран

 

}

}

 

А в итоге на экране всего лишь общее количество нажатий.в чем запарка?

 

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


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

А в итоге на экране всего лишь общее количество нажатий.в чем запарка?

volatile SomeType n;

скорее всего.

По листингу можно сказать точно.

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


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

в чем запарка?
Во-первых, как уже отметил MrYuran, переменная n должна иметь квалификатор volatile. Во-вторых, немного странно ожидать прерывание в функции, расположенной по адресу вектора TIMERA0_VECTOR, в то время, как разрешены прерывания от событий совпадения TAR и CCR1 и от переполнения TAR. Ведь оба этих источника прерываний используют другой вектор - TIMERA1_VECTOR.

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


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

1. volatile int n;

2. поменял вектор прерывания TIMERA0_VECTOR на TIMERA1_VECTOR;

3. прерываний по совпадению и переполнению счетчика как небыло так и нет;

4. и на экране выводит количество нажатий

5. после void main {...} скобочка есть

Изменено пользователем keks9357

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


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

А часовой кварц у вас вообще генерит? То бишь ACLK присутствует? И таймер запускается?

По крайней мере стоит исправить команды инициализации таймера также, как они приведены у меня в сообщении №2

TACTL = TASSEL_1 | TACLR | TAIE;
TACCR1 = 32767;
TACCTL1 = CCIE;
TACTL |= MC_1;

Обратите внимание, что установка бита TACLR влияет (сбрасывает их) на биты MC (count direction) и ID (clock divider). Поэтому в одной команде одновременно с TACLR их устанавливать не имеет смысла - после выполнения команды биты MC и ID все равно будут сброшены.

TACLR Bit 2 Timer_A clear. Setting this bit resets TAR, the clock divider, and the count direction. The TACLR bit is

automatically reset and is always read as zero

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


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

спасибо всем заработало. :1111493779:

подскажите идейку как сделать спидометр, как на велосипедах.

 

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


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

подскажите идейку как сделать спидометр, как на велосипедах.

Использовать таймер в режиме захвата (capture).

Вообще посмотрите ez430-chronos. Беспроводную связь можете не использовать. Используйте корпус и ЖКИ от него. Там практически все готово для спидометра.

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


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

Использовать таймер в режиме захвата (capture).

Вообще посмотрите ez430-chronos. Беспроводную связь можете не использовать. Используйте корпус и ЖКИ от него. Там практически все готово для спидометра.

 

Я не использовал capture. Определял таймер в режиме UP. По прерыванию порта P1 смотрю TAR, вычисляю, обнуляю, а переполнение счётчика по прерыванию таймера смотрю, как доходит до конца, прибавляю к переменной единичку и т.д.

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


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

Я не использовал capture. Определял таймер в режиме UP. По прерыванию порта P1 смотрю TAR, вычисляю, обнуляю, а переполнение счётчика по прерыванию таймера смотрю, как доходит до конца, прибавляю к переменной единичку и т.д.
В режиме capture таймер выполняет все те же самые функции, что вы описали, но только аппаратно. ;)

 

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


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

какие вычисления делаете? и зачем прибавлять к счетчику переполнений единицу?

Изменено пользователем keks9357

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


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

зачем прибавлять к счетчику переполнений единицу?

Типично - для (программного) расширения разрядности счетчика. Когда аппаратных 16-и бит не хватает для вычисления периода.

 

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


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

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

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

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

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

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

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

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

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

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