реклама на сайте
подробности

 
 
> Помогите разобраться с таймером, TA работает непредсказуемо
LCD
сообщение Sep 10 2008, 16:31
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 92
Регистрация: 1-06-08
Пользователь №: 37 959



Использую А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 - Sep 10 2008, 17:00
Go to the top of the page
 
+Quote Post
2 страниц V   1 2 >  
Start new topic
Ответов (1 - 23)
rezident
сообщение Sep 10 2008, 18:52
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



У вас как минимум две ошибки.
Во-первых, вы используете режим таймера 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-и разрядный.
Go to the top of the page
 
+Quote Post
LCD
сообщение Sep 11 2008, 11:47
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 92
Регистрация: 1-06-08
Пользователь №: 37 959



Спасибо за подробнейшее разъяснение. Вставил ваш код - все заработало.
Go to the top of the page
 
+Quote Post
keks9357
сообщение Oct 7 2011, 11:04
Сообщение #4


Участник
*

Группа: Участник
Сообщений: 32
Регистрация: 27-04-10
Пользователь №: 56 933



вот такой вопрос.
нужно что бы каждые 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); //вывод количества нажатий на экран

}
}

А в итоге на экране всего лишь общее количество нажатий.в чем запарка?
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Oct 7 2011, 11:58
Сообщение #5


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(keks9357 @ Oct 7 2011, 15:04) *
А в итоге на экране всего лишь общее количество нажатий.в чем запарка?

volatile SomeType n;
скорее всего.
По листингу можно сказать точно.


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
Psych
сообщение Oct 7 2011, 13:14
Сообщение #6


Частый гость
**

Группа: Участник
Сообщений: 88
Регистрация: 5-03-11
Пользователь №: 63 410



А после void main() открывающей скобки { точно нету? biggrin.gif
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 7 2011, 14:28
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(keks9357 @ Oct 7 2011, 16:04) *
в чем запарка?
Во-первых, как уже отметил MrYuran, переменная n должна иметь квалификатор volatile. Во-вторых, немного странно ожидать прерывание в функции, расположенной по адресу вектора TIMERA0_VECTOR, в то время, как разрешены прерывания от событий совпадения TAR и CCR1 и от переполнения TAR. Ведь оба этих источника прерываний используют другой вектор - TIMERA1_VECTOR.
Go to the top of the page
 
+Quote Post
keks9357
сообщение Oct 10 2011, 08:50
Сообщение #8


Участник
*

Группа: Участник
Сообщений: 32
Регистрация: 27-04-10
Пользователь №: 56 933



1. volatile int n;
2. поменял вектор прерывания TIMERA0_VECTOR на TIMERA1_VECTOR;
3. прерываний по совпадению и переполнению счетчика как небыло так и нет;
4. и на экране выводит количество нажатий
5. после void main {...} скобочка есть

Сообщение отредактировал keks9357 - Oct 10 2011, 08:51
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 10 2011, 19:19
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



А часовой кварц у вас вообще генерит? То бишь 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
Go to the top of the page
 
+Quote Post
keks9357
сообщение Oct 12 2011, 04:57
Сообщение #10


Участник
*

Группа: Участник
Сообщений: 32
Регистрация: 27-04-10
Пользователь №: 56 933



спасибо всем заработало. 1111493779.gif
подскажите идейку как сделать спидометр, как на велосипедах.
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 12 2011, 13:06
Сообщение #11


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(keks9357 @ Oct 12 2011, 09:57) *
подскажите идейку как сделать спидометр, как на велосипедах.

Использовать таймер в режиме захвата (capture).
Вообще посмотрите ez430-chronos. Беспроводную связь можете не использовать. Используйте корпус и ЖКИ от него. Там практически все готово для спидометра.
Go to the top of the page
 
+Quote Post
FREEKER
сообщение Oct 18 2011, 07:18
Сообщение #12


Участник
*

Группа: Участник
Сообщений: 25
Регистрация: 24-06-06
Пользователь №: 18 330



Цитата(rezident @ Oct 12 2011, 17:06) *
Использовать таймер в режиме захвата (capture).
Вообще посмотрите ez430-chronos. Беспроводную связь можете не использовать. Используйте корпус и ЖКИ от него. Там практически все готово для спидометра.


Я не использовал capture. Определял таймер в режиме UP. По прерыванию порта P1 смотрю TAR, вычисляю, обнуляю, а переполнение счётчика по прерыванию таймера смотрю, как доходит до конца, прибавляю к переменной единичку и т.д.
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 18 2011, 11:32
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(FREEKER @ Oct 18 2011, 12:18) *
Я не использовал capture. Определял таймер в режиме UP. По прерыванию порта P1 смотрю TAR, вычисляю, обнуляю, а переполнение счётчика по прерыванию таймера смотрю, как доходит до конца, прибавляю к переменной единичку и т.д.
В режиме capture таймер выполняет все те же самые функции, что вы описали, но только аппаратно. wink.gif
Go to the top of the page
 
+Quote Post
keks9357
сообщение Oct 25 2011, 10:03
Сообщение #14


Участник
*

Группа: Участник
Сообщений: 32
Регистрация: 27-04-10
Пользователь №: 56 933



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

Сообщение отредактировал keks9357 - Oct 25 2011, 10:28
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 25 2011, 10:44
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(keks9357 @ Oct 25 2011, 15:03) *
зачем прибавлять к счетчику переполнений единицу?

Типично - для (программного) расширения разрядности счетчика. Когда аппаратных 16-и бит не хватает для вычисления периода.
Go to the top of the page
 
+Quote Post
keks9357
сообщение Oct 27 2011, 05:57
Сообщение #16


Участник
*

Группа: Участник
Сообщений: 32
Регистрация: 27-04-10
Пользователь №: 56 933



Реализовать при 12МГц задержку в 3 секунды возможно? если можно пример laugh.gif
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 27 2011, 21:55
Сообщение #17


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(keks9357 @ Oct 27 2011, 10:57) *
Реализовать при 12МГц задержку в 3 секунды возможно? если можно пример laugh.gif
Да хоть на 300 секунд. wink.gif Примерно так.
CODE
#include <msp430x24x.h>
#include <stdint.h>

#define FREQ_TACLK 12000000UL //TimerA clock frequency
#define LED_OUT (1U<<0) //P1.0 - LED output
#define PULSE_IN (1U<<2) //P1.2 - Pulse Input (CCI1A)
#define DELAY_LEDOUT (FREQ_TACLK*3UL) //Value ticks of TimerA = 3s*12MHz

int main(void)
{ WDTCTL = WDTPW | WDTHOLD;
/* Basic Clock module */
BCSCTL3 = LFXT1S_3;
DCOCTL = CALDCO_12MHZ;
BCSCTL1 = CALBC1_12MHZ | XT2OF;
BCSCTL2 = 0;
/* Port1 input/output */
P1DIR = LED_OUT;
P1SEL = PULSE_IN;
P1OUT = 0;
/* TimerA */
TACTL = TASSEL_2 | TACLR | TAIE;
TACCTL0 = 0;
TACCTL1 = CM_3 | CCIS_0 | SCS | CAP | CCIE;
TACCTL2 = 0;
TACTL |= MC_2;

__enable_interrupt();

for (;;)
{
__bic_SR_register(LPM0_bits);
__no_operation();
}
}

#pragma vector=TIMERA1_VECTOR
#pragma type_attribute=__interrupt
void TIMERA_ISR(void)
{ static uint32_t timeCntr, timeDly;
static uint16_t flag;
uint16_t CCRVal;

switch(TAIV)
{ case 0x02: //TACCR1 vector, capture P1.2
CCRVal=TACCR1;
timeDly=timeCntr + DELAY_LEDOUT + CCRVal;
flag = 1;
TACCTL1 &= ~CCIE;
break;
case 0x04: //TACCR2 vector, compare
P1OUT ^= LED_OUT;
TACCTL2 &= ~CCIE;
TACCTL1 |= CCIE;
break;
case 0x0A: //TAR overflow vector, overflow counter
timeCntr += 1UL<<16;
if (flag != 0)
{ if ((timeDly - timeCntr) < (1UL<<16))
{ CCRVal=(uint16_t)(timeDly - timeCntr);
TACCR2 = CCRVal;
TACCTL2 |= CCIE;
flag = 0;
}
}
break;
default:
break;
}
}

P1.0 - выход, к которому подключен светодиод.
P1.2 - вход управления.
По любому перепаду уровня (1->0 или 0->1) на входе P1.2 через установленное время (в примере - 3 сек) светодиод на выходе P1.0 переключится в противоположное состояние. В это время вход P1.2 нечувствителен к перепадам уровня.
Весь функционал реализован на аппаратуре таймера A.
Используется вход захвата CCI1A (P1.2 для MSP430F24x), перепад на котором вызывает захват (capture) значения TAR и запись его в CCR1. При этом в преывании вычисляется величина временной отметки timeDly, отстоящая от данного события на установленное время задержки (3 сек в отсчетах таймера на частоте 12МГц).
CCR2 используется в режиме сравнения (compare) для более точного задания времени задержки.
Прерывание от переполнения используется для расширения разрядности таймера. По переполнению 32-х разрядный счетчик timeCntr инкрементируется на величину разрядности таймера (65536). При установленном флаге flag текущее значение timeDly сравнивается с временной отметкой timeCntr. Если разница укладывается в разрядность таймера (меньше, чем 65536), то остаток разности заносится в CCR2 и разрешается прерывание при событии совпадения TAR и CCR2.
Далее при наступлении события совпадения TAR и CCR2 в прерывании переключается состояние светодиода на пине P1.0 и вновь активируется вход управления.
Точность установки задержки примерно в 20 тактов, которые можно учесть при ее вычислении.
В этом примере есть один нюанс, влияющий на точность задержки, про который я пока умолчу. Если (тщательно изучая мануал) поймете и правильно сформулируете вопрос, то поясню как эту багу можно обойти. sm.gif
P.S. в железе не проверялось laughing.gif
Go to the top of the page
 
+Quote Post
keks9357
сообщение Oct 28 2011, 04:55
Сообщение #18


Участник
*

Группа: Участник
Сообщений: 32
Регистрация: 27-04-10
Пользователь №: 56 933



excl.gif rezident - гуру excl.gif
Go to the top of the page
 
+Quote Post
Nathan Stark
сообщение Dec 19 2011, 15:22
Сообщение #19





Группа: Новичок
Сообщений: 6
Регистрация: 25-02-11
Пользователь №: 63 244



Скажите, какой минимальный набор команд нужен, чтобы Таймер А считал в инкрементальном режиме до определенного числа?

Исходя из документации делаю так:
TACCR0 = 0x100; //Задаем модуль счета таймера
TACTL = 0x110; //Задаем MC0 = 1, то есть запускаем счетчик в режиме "вверх",
//Задаем TASSEL0 = 1, то есть задаем источник импульсов.

Но в итоге регистр TAR никак не меняется. Кажется я чего-то не понимаю
Go to the top of the page
 
+Quote Post
rezident
сообщение Dec 19 2011, 15:47
Сообщение #20


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Nathan Stark @ Dec 19 2011, 20:22) *
Исходя из документации делаю так:
TACCR0 = 0x100; //Задаем модуль счета таймера
TACTL = 0x110; //Задаем MC0 = 1, то есть запускаем счетчик в режиме "вверх",
//Задаем TASSEL0 = 1, то есть задаем источник импульсов.

Неправильно. Сначала следует проинициализировать регистры таймера (TASSEL и TACCR0) и только потом запускать счет, установив бит MC0 в TACTL. Т.е. минимально три команды. Хотя я предпочитаю все значащие регистры проинициализировать так, чтобы исключить "случайно возникающие" прерывания (от CCR0, CCR1, CCR2), которые программой не предусмотрены.
Код
TACTL = TASSEL0 | TACLR; // ACLK/1 в качестве входного клока, сброс TAR, прерывание от переполнения запрещено
TACCR0 = 0x100 - 1; //без единицы, т.к. состояние 0x0000 тоже считается
TACCTL0 = 0; //режим сравнения, запрет прерывания от CCR0
TACCTL1 = 0; //режим сравнения, запрет прерывания от CCR1
TACCTL2 = 0; //режим сравнения, запрет прерывания от CCR2
TACTL |= MC0; //запуск счета, режим CountUp

Цитата(Nathan Stark @ Dec 19 2011, 20:22) *
Но в итоге регистр TAR никак не меняется. Кажется я чего-то не понимаю
В железе или в симуляторе? В симуляторе IAR периферия не симулируется!
Go to the top of the page
 
+Quote Post
Nathan Stark
сообщение Dec 19 2011, 15:58
Сообщение #21





Группа: Новичок
Сообщений: 6
Регистрация: 25-02-11
Пользователь №: 63 244



Цитата
В железе или в симуляторе? В симуляторе IAR периферия не симулируется!


Оу! А как же тогда проверить работу алгоритма на логику если нет железа?
Go to the top of the page
 
+Quote Post
ILYAUL
сообщение Dec 19 2011, 16:11
Сообщение #22


Профессионал
*****

Группа: Свой
Сообщений: 1 940
Регистрация: 16-12-07
Из: Москва
Пользователь №: 33 339



Цитата(Nathan Stark @ Dec 19 2011, 19:58) *
Оу! А как же тогда проверить работу алгоритма на логику если нет железа?


Спаять макетку и проверять


--------------------
Закон Мерфи:

Чем тщательнее составлен проект, тем больше неразбериха, если что-то пошло не так
Go to the top of the page
 
+Quote Post
Nathan Stark
сообщение Dec 19 2011, 16:15
Сообщение #23





Группа: Новичок
Сообщений: 6
Регистрация: 25-02-11
Пользователь №: 63 244



Ага, понятно) Спасибо за помощь)
Еще такой вопрос, а в прерывания по таймеру программа тоже заходить не будет?
Go to the top of the page
 
+Quote Post
rezident
сообщение Dec 19 2011, 19:42
Сообщение #24


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Nathan Stark @ Dec 19 2011, 21:15) *
Еще такой вопрос, а в прерывания по таймеру программа тоже заходить не будет?
В симуляторе можно "вручную" имитировать вызов прерываний Simulator -> Forced Interrupt или настроить макрос для симуляции вызова Simulator -> Interrupt Setup.
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 3rd August 2025 - 12:53
Рейтинг@Mail.ru


Страница сгенерированна за 0.01617 секунд с 7
ELECTRONIX ©2004-2016