Страница 11 из 72

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

Добавлено: Пн июн 30, 2014 16:11:36
Neptyn
ARV писал(а):у меня дежавю? :shock: уже был впрос про макрос ICR... обработчик прерываний правильно называется ISR - ну читайте же документацию перед писаниной!
Большое спасибо за замечание :))
Я сменил на ISR, но разрешение глобального прерывания всеравно пропадает на несколько тактов позже sei().В чем может быть проблема?

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

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

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

Добавлено: Пн июн 30, 2014 21:38:10
Neptyn
ARV писал(а):во-первых, показанный вами код все равно с ошибкой - после while(1) надо ставить точку с запятой.
во-вторых, лично я не вижу никаких проблем в работе исправленного кода: прерывания вызываются.
что именно вас беспокоит?
Большое, большое спасибо :)) :)) !!
Все заработало!!!!

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

Добавлено: Ср июл 16, 2014 00:01:19
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;
   }
}

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

Добавлено: Чт июл 17, 2014 09:50:01
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;
   }

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

Добавлено: Чт июл 17, 2014 11:20:30
tantrum
Pink-Pank писал(а):Как вариант, можно запустить преобразование в авто режиме и потом просто копировать ADCH в OCR0A в каждом цикле без всяких проверок:

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

while(1)
   {
      OCR0A = ADCH;
   }
Спасибо, с этим вы мне очень помогли! :))

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

Добавлено: Чт июл 31, 2014 21:01:36
B@R5uk
Подскажите, пожалуйста, есть ли в таймерах режим, позволяющий автоматически считать длительность периода внешнего сигнала в периодах тактовой частоты МК ?

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

Добавлено: Чт июл 31, 2014 21:09:42
c2n
прерывание по внешнему событию вроде должно под задачу подойти. Для более детального обсуждения точнее сформулируйте задачу.

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

Добавлено: Чт июл 31, 2014 22:31:35
Pink-Pank
B@R5uk писал(а):Есть ли в таймерах режим, позволяющий автоматически считать длительность периода внешнего сигнала в периодах тактовой частоты МК ?
Захват.

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

Добавлено: Чт июл 31, 2014 23:54:08
B@R5uk
Pink-Pank, скажите, пожалуйста, режим захват есть во всех устройствах? Вернее даже, в каких он есть? Так как, например, в ATtiny26 ничего подобного не нашёл, столько не читал спецификацию. Подскажите, пожалуйста, импортное название этого режима, которое гуглить/искать в фичах дейвайсов.

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

Добавлено: Пт авг 01, 2014 07:15:26
Pink-Pank
Вот книга.
Ищите тему про 16-битные таймеры (лучше смотреть в семействе Mega. У Tiny вроде только 8-битные таймеры). Там в описании есть блок захвата. В 8-битных такого блока я что-то не встречал. А в Tiny26 оба таймера 8-битных.
Но даже если такого блока нет - можно извернуться и программно сделать.

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

Добавлено: Пт авг 01, 2014 07:30:17
akl
Pink-Pank писал(а):Вот книга.
Здесь,в сундуке, найти проще.
B@R5uk писал(а): Подскажите, пожалуйста, импортное название этого режима, которое гуглить/искать в фичах дейвайсов.
По забугорному - Capture

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

Добавлено: Пт авг 01, 2014 09:18:28
B@R5uk
Всем большое спасибо.

шим и таймер.

Добавлено: Сб авг 09, 2014 16:14:04
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)

      { 
      
         
         
      }
}

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

Добавлено: Ср авг 13, 2014 12:10:33
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 ;выход из обработчика

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

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

Нашёл.
Внимательно посмотрите на свой вектор прерываний и на даташитовский. Снова на свой и на даташитовский :)))

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

Добавлено: Ср авг 13, 2014 14:45:02
PLATON
Всё понял свою ошибку! Спасибо!

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

Добавлено: Ср авг 20, 2014 12:49:45
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, а не напрямую со значеним счетчика. Это правильно, или я совсем запутался?

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

Добавлено: Ср авг 20, 2014 17:35:38
GreenDer
Доброго времени суток всем. Позвольте и мне сунуть свой пятак с вопросом.
Подскажите, пожалуйста, как гарантированно отсчитать время прошедшее со старта контроллера в миллисекундах (в богомерзкой Ардуине за это отвечает функция millis()). Первое что приходит в голову так это запустить таймер и по прерыванию увеличивать переменную. Но таймер(их не так много :( ) жалко да и если понадобится запретить все прерывания подсчет будет неточным. Как быть?
Готовое решение не обязательно, подскажите в какую сторону копать.

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

Добавлено: Ср авг 20, 2014 20:23:16
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.