Таймеры/счётчики в AVR

Обсуждаем контроллеры компании Atmel.
Neptyn
Родился
Сообщения: 15
Зарегистрирован: Чт июл 21, 2011 09:58:24

Re: Таймеры/счётчики в AVR

Сообщение Neptyn »

ARV писал(а):у меня дежавю? :shock: уже был впрос про макрос ICR... обработчик прерываний правильно называется ISR - ну читайте же документацию перед писаниной!

Большое спасибо за замечание :))
Я сменил на ISR, но разрешение глобального прерывания всеравно пропадает на несколько тактов позже sei().В чем может быть проблема?
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Таймеры/счётчики в AVR

Сообщение ARV »

во-первых, показанный вами код все равно с ошибкой - после while(1) надо ставить точку с запятой.
во-вторых, лично я не вижу никаких проблем в работе исправленного кода: прерывания вызываются.
что именно вас беспокоит?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Neptyn
Родился
Сообщения: 15
Зарегистрирован: Чт июл 21, 2011 09:58:24

Re: Таймеры/счётчики в AVR

Сообщение Neptyn »

ARV писал(а):во-первых, показанный вами код все равно с ошибкой - после while(1) надо ставить точку с запятой.
во-вторых, лично я не вижу никаких проблем в работе исправленного кода: прерывания вызываются.
что именно вас беспокоит?

Большое, большое спасибо :)) :)) !!
Все заработало!!!!
Аватара пользователя
tantrum
Мучитель микросхем
Сообщения: 447
Зарегистрирован: Сб фев 09, 2013 11:39:13
Откуда: Украина, Марганец

Re: Таймеры/счётчики в AVR

Сообщение tantrum »

Добрый вечер! Помогите, пожалуйста, найти ошибку. Суть программы: на PB5 (ADC0) подается напряжение 0..1.1 В, а на PB0 (OC0A) выходит ШИМ регулируемый. МК: ATTiny13.

Код: Выделить всё

#define F_CPU 9600000
#include <avr/io.h>
int main(void)
{
   DDRB = (0<<PB5);
   DDRB = (1<<PB0);
   ADCSRA |=(1<<ADEN)
   |(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
   ADMUX |= (1<<REFS0)// 1.1V
   |(0<<MUX1)|(0<<MUX0);
   TCCR0A |= (1<<WGM01)|(1<<WGM00)
   |(1<<COM0A1)|(0<<COM0A0) // ШИМ подется на вывод OC0A
   |(0<<CS02)|(0<<CS01)|(1<<CS00);
   TCNT0 = 0x00;
   OCR0A = 0x00;
   while(1)
   {
      unsigned int p;
      ADCSRA |= (1<<ADSC);
      while ((ADCSRA&(1<<ADIF))==0);
      p=(ADCL|ADCH<<8);
      p = p/4;
      OCR0A = p;
   }
}
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

Re: Таймеры/счётчики в AVR

Сообщение Pink-Pank »

Ошибка здесь:

Код: Выделить всё

(0<<CS02)|(0<<CS01)|(1<<CS00);

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

И еще забыли сбрасывать флаг окончания цикла преобразования. Чтобы не заморачиваться с ним, можно отслеживать по ADSC:

Код: Выделить всё

while ((ADCSRA & (1<<ADSC)) != 0);


Еще посоветовал бы уменьшить тактовую частоту и предделитель АЦП побольше поставить. А то молотит, как бешеный.. (Интересно, живой ли еще?)

Код: Выделить всё

DDRB = (0<<PB5);

Не имеет смысла. Аналогична

Код: Выделить всё

DDRB = 0;


Код: Выделить всё

p=(ADCL|ADCH<<8);
p = p/4;

И весь огород с этим связанный...
Не проще сделать выравнивание результата преобразования по левому краю и читать только ADCH?

Спойлер

Код: Выделить всё

#define F_CPU 4800000
#include <avr/io.h>
int main(void)
{
   DDRB = (1<<PB0);
   ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS0);
   ADMUX = (1<<REFS0) | (1<<ADLAR);// 1.1V
   
   TCCR0A = (1<<WGM01) | (1<<WGM00) | (1<<COM0A1); // ШИМ подется на вывод OC0A
   TCCR0B = (1<<CS02) | (1<<CS01) | (1<<CS00);
 
   while(1)
   {
      ADCSRA |= (1<<ADSC);
      while ((ADCSRA & (1<<ADSC)) != 0);

      OCR0A = ADCH;
   }
}


Как вариант, можно запустить преобразование в авто режиме и потом просто копировать ADCH в OCR0A в каждом цикле без всяких проверок:

Код: Выделить всё

while(1)
   {
      OCR0A = ADCH;
   }
Fucking static initialization order fiasco
Аватара пользователя
tantrum
Мучитель микросхем
Сообщения: 447
Зарегистрирован: Сб фев 09, 2013 11:39:13
Откуда: Украина, Марганец

Re: Таймеры/счётчики в AVR

Сообщение tantrum »

Pink-Pank писал(а):Как вариант, можно запустить преобразование в авто режиме и потом просто копировать ADCH в OCR0A в каждом цикле без всяких проверок:

Код: Выделить всё

while(1)
   {
      OCR0A = ADCH;
   }


Спасибо, с этим вы мне очень помогли! :))
Аватара пользователя
B@R5uk
Собутыльник Кота
Сообщения: 2896
Зарегистрирован: Сб ноя 13, 2010 12:53:25
Откуда: приходит весна?

Re: Таймеры/счётчики в AVR

Сообщение B@R5uk »

Подскажите, пожалуйста, есть ли в таймерах режим, позволяющий автоматически считать длительность периода внешнего сигнала в периодах тактовой частоты МК ?
Аватара пользователя
c2n
Сверлит текстолит когтями
Сообщения: 1193
Зарегистрирован: Ср июл 25, 2012 21:40:09
Откуда: Самара
Контактная информация:

Re: Таймеры/счётчики в AVR

Сообщение c2n »

прерывание по внешнему событию вроде должно под задачу подойти. Для более детального обсуждения точнее сформулируйте задачу.
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

Re: Таймеры/счётчики в AVR

Сообщение Pink-Pank »

B@R5uk писал(а):Есть ли в таймерах режим, позволяющий автоматически считать длительность периода внешнего сигнала в периодах тактовой частоты МК ?

Захват.
Fucking static initialization order fiasco
Аватара пользователя
B@R5uk
Собутыльник Кота
Сообщения: 2896
Зарегистрирован: Сб ноя 13, 2010 12:53:25
Откуда: приходит весна?

Re: Таймеры/счётчики в AVR

Сообщение B@R5uk »

Pink-Pank, скажите, пожалуйста, режим захват есть во всех устройствах? Вернее даже, в каких он есть? Так как, например, в ATtiny26 ничего подобного не нашёл, столько не читал спецификацию. Подскажите, пожалуйста, импортное название этого режима, которое гуглить/искать в фичах дейвайсов.
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

Re: Таймеры/счётчики в AVR

Сообщение Pink-Pank »

Вот книга.
Ищите тему про 16-битные таймеры (лучше смотреть в семействе Mega. У Tiny вроде только 8-битные таймеры). Там в описании есть блок захвата. В 8-битных такого блока я что-то не встречал. А в Tiny26 оба таймера 8-битных.
Но даже если такого блока нет - можно извернуться и программно сделать.
Fucking static initialization order fiasco
akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: Таймеры/счётчики в AVR

Сообщение akl »

Pink-Pank писал(а):Вот книга.
Здесь,в сундуке, найти проще.
B@R5uk писал(а): Подскажите, пожалуйста, импортное название этого режима, которое гуглить/искать в фичах дейвайсов.
По забугорному - Capture
Аватара пользователя
B@R5uk
Собутыльник Кота
Сообщения: 2896
Зарегистрирован: Сб ноя 13, 2010 12:53:25
Откуда: приходит весна?

Re: Таймеры/счётчики в AVR

Сообщение B@R5uk »

Всем большое спасибо.
Аватара пользователя
Ljutyj
Первый раз сказал Мяу!
Сообщения: 24
Зарегистрирован: Сб июл 05, 2014 08:27:39
Откуда: Казань

шим и таймер.

Сообщение Ljutyj »

Во общем хочу сделать шим и выключить его по заданном интервалу времени.

К примеру включили устройство, регулируем шим (светодиоды) при помощи двух кнопок.
Перед включением если нужно входим в режим программирования и выбираем время, через которое шим сигнал исчезает (выключаем устройство).

Делаю следующее : программный шим по переполнению (в прерывании) и считаю время так же в прерывании по сравнению (OCR0A=0xFF).
Так как приоритет первого прерывания выше то ничего невыходит.

Подскажите как быть.

Спойлер

Код: Выделить всё

#include <tiny13.h>
#include <delay.h>

#define trig_r PINB.4
#define trig_l PINB.3
#define led PORTB.0

typedef unsigned char byte;// даем псевдоним unsigned char и обзываем byte


eeprom byte eebright,ee_set;// сохраняем уровень яркости, который был до выключения

byte pwm,pwm_b,count,i;

unsigned int us,s;

 void prog (void)
     {
      led=1;
      delay_ms(500);
      led=0;
      delay_ms(500);
     }   


// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{

 
 count++;
     if(count==0)
       {
        pwm_b=pwm;
        led=1;
       }
       
       if(pwm_b==count)led=0; 
         
}

// Timer 0 output compare A interrupt service routine
interrupt [TIM0_COMPA] void timer0_compa_isr(void)
{
 us++;
  if(us>38461)
   {
    s++;
    us=0;
   }


}

// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port B initialization
// Func5=In Func4=In Func3=In Func2=In Func1=In Func0=Out
// State5=P State4=P State3=P State2=P State1=P State0=0
PORTB=0x3E;
DDRB=0x01;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 9600,000 kHz
// Mode: Normal top=0xFF
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x01;
TCNT0=0x00;
OCR0A=0xFF;
OCR0B=0x00;

// External Interrupt(s) initialization
// INT0: Off
// Interrupt on any change on pins PCINT0-5: Off
GIMSK=0x00;
MCUCR=0x00;

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x06;



// Analog Comparator initialization
// Analog Comparator: Off
ACSR=0x80;
ADCSRB=0x00;
DIDR0=0x00;

// ADC initialization
// ADC disabled
ADCSRA=0x00;

#asm("sei")// Global enable interrupts


// if(!trig_r) //Входим в режим пограммирования
//   {
//
//    if(!trig_r)
//     {
//
//      if(!trig_r && ee_set==3)
//       {
//        ee_set=1;
//         
//        for(i=0;i<1;i++)prog();
//       
//       
//       }
//       
//       
//       else
//        {
//         if(!trig_r && ee_set==1)
//          {
//           ee_set=2;
//
//           for(i=0;i<2;i++)prog();
//           
//               
//          }
//         
//         
//         else
//          {
//           ee_set=3;
//           for(i=0;i<3;i++)prog();
//          }
//        } 
//     }
//     
//     while(!trig_r);
//   } 
//   
// 
//   
//   while(pwm<160) // Плавный розжиг
//
//       {
//        delay_ms(30);
//        pwm++;
//        // плавно включаем светодиоды
//       }

while (1)

      {
     
         
         
      }
}
PLATON
Родился
Сообщения: 9
Зарегистрирован: Ср июл 23, 2014 16:23:27

Re: Как поместить прерывание в цикл?

Сообщение PLATON »

Всем доброго! Начинаю изучать программирование МК и вот столкнулся с проблемой!
Прирывание по совпадению никак не хочет работать, вернее не запускается обработка прерывания.
Флаг разрешения прерывания по событию «Совпадение A» таймера/счетчика T1 бит 4 установлен, флаг I регистра SREG тоже, индикация свидетельствущая о прерывании в регистре TIFR есть, но ничего не происходит, не хочет программа выходить из цикла на обработку прерывания помогите пожалуйста!

Вот код: МК atmega16.

Спойлер.def Temp=R16
.def Temp1=R17
.def Temp2=R18

.cseg
.org 0


;Вектора прерываний

jmp Reset
jmp INT_0
jmp INT_1
jmp Timer2_comp
jmp Timer1_COMPA
jmp Timer1_COMPB
jmp Timer1_OVF
jmp Timer0_OVF
jmp SPI_STC
jmp USART_RXC
jmp USART_UDRE
jmp USART_TXC
jmp ADCC
jmp EE_RDY
jmp ANA_COMP
jmp TW1
jmp Timer0_COMP
jmp SPM_RDY


;Reset:
INT_0:
INT_1:
Timer2_comp:
;Timer1_COMPA:
Timer1_COMPB:
Timer1_OVF:
Timer0_OVF:
SPI_STC:
USART_RXC:
USART_UDRE:
USART_TXC:
ADCC:
EE_RDY:
ANA_COMP:
TW1:
Timer0_COMP:
SPM_RDY:

reti


;****************************************************
; ИНИЦИАЛИЗАЦИЯ
;****************************************************
Reset:
ldi Temp,0b11111111 ;настройка портов
out DDRC,Temp

ldi Temp,0b00010000 ;разрешить прерывание компаратора
out TIMSK,Temp

ldi Temp,0b00000011 ;тактовый сигнал = CK/64
out TCCR1B,Temp

ldi Temp,0x4C ;инициализация компаратора
out OCR1AH,Temp
ldi Temp,0x4B
out OCR1AL,Temp

; инициализация стека
LDI Temp4,Low(RAMEND)
OUT SPL,Temp4
LDI Temp4,High(RAMEND)
OUT SPH,Temp4

ldi Temp1,0b00000001 ;инициализация индикатора

ldi Temp,0 ;обнуление таймера
out TCNT1H,Temp
out TCNT1L,Temp

sei ;разрешить прерывания


;****************************************************
; ОСНОВНОЙ ЦИКЛ
;****************************************************
Inf:
jmp Inf ;бесконечный цикл

;****************************************************
; ОБРАБОТЧИК ПРЕРЫВАНИЯ КОМПАРАТОРА
;****************************************************

Timer1_COMPA:
ldi Temp,0 ;обнуление таймера
out TCNT1H,Temp
out TCNT1L,Temp


Shift: cpi Temp1,0b10000000 ;сравнить с крайним знач.
breq Init ;если равно - загрузка нач. знач.

lsl Temp1 ;иначе - сдвиг влево
jmp Output ;перейти на вывод в порт

Init: ldi Temp1,0b00000001 ;загрузить нач. значение
Output: out PortC,Temp1 ;вывод в порт

reti ;выход из обработчика
Последний раз редактировалось Gudd-Head Ср авг 13, 2014 13:50:14, всего редактировалось 2 раза.
Причина: Сюда перенёс
Аватара пользователя
Gudd-Head
Друг Кота
Сообщения: 20092
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

Re: Как поместить прерывание в цикл?

Сообщение Gudd-Head »

PLATON писал(а):Флаг разрешения прерывания по событию «Совпадение A» таймера/счетчика T1 бит 4 установлен, флаг I регистра SREG тоже, индикация свидетельствущая о прерывании в регистре TIFR есть, но ничего не происходит

В Студии гоняете?
PLATON писал(а):Вот код:

Почему не весь код приводите?

Нашёл.
Внимательно посмотрите на свой вектор прерываний и на даташитовский. Снова на свой и на даташитовский :)))
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
PLATON
Родился
Сообщения: 9
Зарегистрирован: Ср июл 23, 2014 16:23:27

Re: Таймеры/счётчики в AVR

Сообщение PLATON »

Всё понял свою ошибку! Спасибо!
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: Таймеры/счётчики в AVR

Сообщение baron_P »

Господа, есть глупый вопрос.
Ковырялся в FastPWM-режиме таймера 1 ATTiny861. В документации такая таблица:
BOTTOM
The counter reaches the BOTTOM when it becomes 0.

Счетчик достигает значения BOTTOM, когда он равен 0.
MAX
The counter reaches its MAXimum value when it becomes 0x3FF (decimal 1023).

Счетчик достигает значения MAXимум, когда он равен 0x3FF (10 битный, очевидно).
TOP
The counter reaches the TOP value (stored in the OCR1C) when it becomes equal to the
highest value in the count sequence. The TOP has a value 0x0FF as default after reset.

Счетчик достигает значения TOP (записанного в OCR1C), когда его значение равно максимальному значению счетной последовательности. Значение TOP по умолчанию после сброса 0x0FF.

Первый и второй пункт понятны. А третий какой-то мутный, я не совсем понял для чего он нужен.
TOP равен, например, 165. Можно сказать, что когда 8-битный счетчик дотикал до 255, он достиг значения TOP (165). Если я укажу в регистре, например, OCR1A значение 82 и включу прямой FastPWM, вывод OC1A будет сбрасывать в ноль при значении счетчика 127. Т.е. регистры сравнения сравниваются с TOP, а не напрямую со значеним счетчика. Это правильно, или я совсем запутался?
We do what we must because we can (c) GLaDOS
GreenDer
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Ср авг 20, 2014 17:15:53

Re: Таймеры/счётчики в AVR

Сообщение GreenDer »

Доброго времени суток всем. Позвольте и мне сунуть свой пятак с вопросом.
Подскажите, пожалуйста, как гарантированно отсчитать время прошедшее со старта контроллера в миллисекундах (в богомерзкой Ардуине за это отвечает функция millis()). Первое что приходит в голову так это запустить таймер и по прерыванию увеличивать переменную. Но таймер(их не так много :( ) жалко да и если понадобится запретить все прерывания подсчет будет неточным. Как быть?
Готовое решение не обязательно, подскажите в какую сторону копать.
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: Таймеры/счётчики в AVR

Сообщение Kavka »

"Счетчик достигает значения TOP, когда его значение равно максимальному значению счетной последовательности."
Это всего лишь определение термина TOP ( [топ], верхняя точка, максимальное значение) в этой спецификации и конкретно для описания таймеров.
Соответственно, в зависимости от режима Таймера/ШИМ "верхушка" может быть как значением в регистре OCR1C, так и жёстко равняться MAX.
Для FastPWM написано "The counter counts from BOTTOM to TOP (defined as OCR1C) then restarts from BOTTOM" Т.е. для этого режима TOP равно значению записанному в OCR1C и счёт будет производиться от 0 до OCR1C. Соответственно, осмысленными значениями OCR1A/B/D будут значения в том же диапазоне.

baron_P писал(а):TOP равен, например, 165. Можно сказать, что когда 8-битный счетчик дотикал до 255
В данном случае, для FastPWM, до 255 он никогда не дотикает, т.к. значение TOP равное 165 вы запишите в OCR1C.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Ответить

Вернуться в «AVR»