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

Обсуждаем контроллеры компании Atmel.
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

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

Сообщение COKPOWEHEU »

"Приоритеты" в случае прерываний AVR определяют, какое обработается раньше, если оба возникли, когда прерывания были запрещены. И даже в таком понимании приоритетов, PCINT идут сразу за INTx, то есть, первыми, если INTx неактивны или вызываются редко. Так что никакой необходимости тянуть проводки к INTx нет.
Что за ноги таймера :shock:
Таймер он внутри тикает у него ног нету :facepalm:
"ноги таймера" - выводы, которые могут обрабатываться модулем таймера без участия ядра. Например, OC1A, T0, ICP. При правильной настройке, разумеется.
Будет ли работать данный код на других AVR контроллерах?
У всех контроллеров есть Timer0, он везде восьми разрядный?
Может быть разное количество настроек и, соответственно, разное количество регистров TCCR0A, кроме того, может быть отдельный TIMSK0. Насчет разрядности - да, T0 и T3 всегда 8-разрядные.
Аватара пользователя
alexan9er
Открыл глаза
Сообщения: 54
Зарегистрирован: Пт окт 03, 2014 14:41:16

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

Сообщение alexan9er »

Lihouzov писал(а):Будет ли работать данный код на других AVR контроллерах?

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

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

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

У всех контроллеров есть Timer0, он везде восьми разрядный?
Биты настройки будут отличаться?

Евстифеева скачайте - там описаны все различия на большинство AVR
Fucking static initialization order fiasco
DarkWolf
Встал на лапы
Сообщения: 117
Зарегистрирован: Ср ноя 05, 2014 19:04:31

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

Сообщение DarkWolf »

Добрый день! Появилась такая проблема. Суть программы: при первом включении происходит инициализация таймера. Каждую секунду вывожу на индикатор, после 5 секунды таймер останавливаю. На прерывание повешена кнопка выбора режимов. При нажатии на эту кнопку происходит выбор режима и, суть проблемы, почемуто запускается таймер. В чем может быть проблема?
Привожу код программы:
Спойлер/*******************************************************
This program was created by the
CodeWizardAVR V3.10 Advanced
Automatic Program Generator
© Copyright 1998-2014 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project : Dozimetr
Version : 1.0
Date : 05.11.2014
Author :
Company :
Comments:


Chip type : ATmega324P
Program type : Application
AVR Core Clock frequency: 8,000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 512
*******************************************************/

#include <mega324.h>
#include <delay.h>
// I2C Bus functions
#include <i2c.h>
//#include <Display.h>
// Declare your global variables here

int i = 1;
int counterTime = 0;
int counterPulse = 0;
int countR = 0;
// структура определяе следующие сосотояния:
// sTime - 1 - было прерывание от таймера
// sPulse - 1 - было прерывание от импульса
// sOn - 1 - прибор включен
// sOff - 1 - прибор выключен
// sRejim - 10 - режим 1, 01 - режим 2, 11 - режим 3.
//
struct Flag
{
char sTime;
char sPulse;
char sOn;
char sOff;
char sRejim;
}sFlag;//={0x0,0x0,0x0,0x0,0x01};

// Функция работы с дисплем
void Display(int num)
{
// точка - 0x80
// массив содержит цифры от 0 - 9 в переводе на значения сегментов
char Zahl[10] = {0x3f,0x6,0x5b,0x4f,0x66,0x6d,0x7d,0x27,0x7f,0x6f};
//char Zahl[10] = {0x7e,0x30,0x6d,0x79,0x33,0x5b,0x5f,0x72,0x7f,0x7b};
//char Zahl_4[10] = {0x3f,0x6,0x5b,0x4f,0x66,0x6d,0x7d,0x27,0x7f,0x6f};
int j;
int led_data[2]; // массив количества символов на ЖКИ
int temp = 0;

i2c_start(); // Issue start signal
i2c_write(0x70); // Address SAA 1064
i2c_write(0); // Start
i2c_write(0x27); // config

//a=temp/100 для вывода сотен
//b=temp%100/10 для вывода десятков
//с=temp%100%10 для вывода единиц

temp = num;
j = 0;


while (j <= 1)
{
if (j != 0) temp /= 10;
led_data[j] = Zahl[temp %10];
j++;
}

// led_data[3] = temp/1000 ;
// led_data[2] = temp/100 ;
// led_data[1] = temp%100/10;
// led_data[0] = temp%100%10;

// if (num<1000) led_data[3] = 0x7e;
// if (num<100) led_data[2] = 0x7e;
if (num<10) led_data[1] = 0x3f;

// Add decimal point if required
//led_data[1] |= 0x80;

// Auto increment applies for digit data. Have to send out digits in reverse
// because most significant digit is 1st digit.
// i2c_write(0x01);
for (j=2;j>=1;j--)
{
i2c_write(led_data[j-1]);
}
i2c_stop();
}

// Функция инициализации аналогово компаратора
void InitializeComparator()
{
// Analog Comparator initialization
// AIN0 подключаем к источнику внутреннего опорного напряжения. AIN1 используется как простой выход.
// Analog Comparator: On
// К подключаем AIN0 внутрений источник опорного напряжения ACBG = 1
ACSR = (0<<ACD) | (1<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIC) | (1<<ACIS1) | (0<<ACIS0);
ADCSRB = (1<<ACME); // включаем мультиплексар аналогового компаратора
ADCSRA = (0<<ADEN); // сбрасываем бит ADEN для отключения АЦП
// ADMUX = (0<<MUX2) | (0<<MUX1) | (0<<MUX0); // Выбираем вход АЦП - ADC0
// Digital input buffer on AIN0: Off
// Digital input buffer on AIN1: On
// DIDR1=(1<<AIN0D) | (0<<AIN1D);
}
// Функция инициализации портов
void InitializePort()
{
// Input/Output Ports initialization
// Port A initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRA = 0x00;
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTA = 0x00;

// Port B initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRB = 0x00;
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTB = 0x00;

// Port C initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRC = 0x00;
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTC = 0x00;

// Port D initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRD = 0x00;
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTD = 0x00;
}

void InitTimer()
{
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 7,813 kHz
// Mode: Normal top=0xFFFF
// OC1A output: Disconnected
// OC1B output: Disconnected
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer Period: 8,3886 s
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (1<<WGM12) | (1<<CS12) | (0<<CS11) | (1<<CS10);
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x1E;
OCR1AL=0x85;
OCR1BH=0x00;
OCR1BL=0x00;
TIMSK1=(0<<ICIE1) | (0<<OCIE1B) | (1<<OCIE1A) | (0<<TOIE1);
}

// Прерывание кнопки Режим
interrupt [PC_INT3] void pin_change_isr3(void)
{
// Place your code here
switch (i)
{
case 1:
{
sFlag.sRejim = 1;
Display(1);
i++;
break;
}
case 2:
{
sFlag.sRejim = 2;
Display(2);
i++;
break;
}
case 3:
{
sFlag.sRejim = 3;
Display(3);
i++;
break;
}
default:
{
i = 1;
sFlag.sRejim = 1;
Display(1);
i++;
}
}
}

// Pin change 0-7 interrupt service routine
interrupt [PC_INT0] void pin_change_isr0(void)
{
// Place your code here
counterPulse++;

}

// Timer1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
// Place your code here
counterTime++; // увеличиваем переменную каждую секунду
sFlag.sTime = 1;
if(counterTime == 6)
{
// выключаем таймер
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
sFlag.sTime = 0;
sFlag.sOn = 1;
}
//TCNT0=0; //обнуляем таймер
}

void main(void)
{
// если включились первый раз
if (sFlag.sOn == 0)
{
InitializePort();
InitializeComparator();

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=(1<<CLKPCE);
CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0);
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-15: Off
// Interrupt on any change on pins PCINT16-23: Off
// Interrupt on any change on pins PCINT24-31: Off
EICRA=(0<<ISC21) | (0<<ISC20) | (0<<ISC11) | (0<<ISC10) | (0<<ISC01) | (0<<ISC00);
EIMSK=(0<<INT2) | (0<<INT1) | (0<<INT0);
EIFR=(0<<INTF2) | (0<<INTF1) | (0<<INTF0);
PCMSK0=(1<<PCINT7) | (0<<PCINT6) | (0<<PCINT5) | (0<<PCINT4) | (0<<PCINT3) | (0<<PCINT2) | (0<<PCINT1) | (0<<PCINT0);
PCMSK3=(0<<PCINT31) | (0<<PCINT30) | (0<<PCINT29) | (0<<PCINT28) | (1<<PCINT27) | (0<<PCINT26) | (0<<PCINT25) | (0<<PCINT24);
PCICR=(0<<PCIE3) | (0<<PCIE2) | (0<<PCIE1) | (1<<PCIE0);

EIMSK=(1<<INT2) | (1<<INT1) | (1<<INT0);
EIFR=(1<<INTF2) | (1<<INTF1) | (1<<INTF0);
// Bit-Banged I2C Bus initialization
// I2C Port: PORTC
// I2C SDA bit: 1
// I2C SCL bit: 0
// Bit Rate: 100 kHz
// Note: I2C settings are specified in the
// Project|Configure|C Compiler|Libraries|I2C menu.
InitTimer();
i2c_init();
sFlag.sOn = 1;
sFlag.sRejim = 1;
// Global enable interrupts
#asm("sei")
}
while (1)
{
delay_ms(100);
// Place your code here
// if (PIND.7 == 0)
// {
if (sFlag.sTime == 1)
{
Display(counterTime);
//Сбрасываем флаг времени
//sFlag.sTime = 0x00;
}


// }

}

}
Аватара пользователя
alexan9er
Открыл глаза
Сообщения: 54
Зарегистрирован: Пт окт 03, 2014 14:41:16

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

Сообщение alexan9er »

DarkWolf писал(а): if(counterTime == 6)
{
// выключаем таймер
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
sFlag.sTime = 0;
sFlag.sOn = 1;
}

Что-то я не вижу где вы тут отключаете таймер.
TIMSK1 надо было подкрутить.
DarkWolf
Встал на лапы
Сообщения: 117
Зарегистрирован: Ср ноя 05, 2014 19:04:31

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

Сообщение DarkWolf »

Сделал TIMSK1 &= ~(1<<TOIE1); результат тот же. Проблема скорее всего в переменной sFlag.sOn. Если правильно понял всегда происходит инициализация таймера.
Сделал по другому: объявил переменную в eeprom - eeprom int StatusOn = 0; и через нее провожу инициализацию. Но почему то при объявлении eeprom int StatusOn = 0 0 не записываеться. Отлаживаю в протеусе, может ли быть косяк в протеусе? или всетаки у меня?

Извините за глупые вопросы.. недавно программирую(
Аватара пользователя
alexan9er
Открыл глаза
Сообщения: 54
Зарегистрирован: Пт окт 03, 2014 14:41:16

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

Сообщение alexan9er »

DarkWolf писал(а):Сделал TIMSK1 &= ~(1<<TOIE1); результат тот же. Проблема скорее всего в переменной sFlag.sOn

Попробуйте просто присвоить TIMSK1 = 0;
Не вижу, при чём тут переменная sFlag.sOn - как вы рассуждаете?
DarkWolf
Встал на лапы
Сообщения: 117
Зарегистрирован: Ср ноя 05, 2014 19:04:31

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

Сообщение DarkWolf »

переменная sFlag.sOn отвечает за состояние включения прибора. Если она равна 0 то прибор включается впервые и проходит инициализация его. В конструкции if ( sFlag.sOn = 0) {инициализация}. Затем этой переменной присваиваю 1. Теперь по логике когда выходит из прерывания и заходит в main(), то т.к. sFlag.sOn = 1 инициализация таймера проходить не будет.
DarkWolf
Встал на лапы
Сообщения: 117
Зарегистрирован: Ср ноя 05, 2014 19:04:31

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

Сообщение DarkWolf »

Всем большое спасибо! разобрался. Проблема именно в переменной sOn. Она почему то не держит состояние в 1. Сейчас инициализацию таймера провожу по нажатию на кнопку. Все работает.
Аватара пользователя
alexan9er
Открыл глаза
Сообщения: 54
Зарегистрирован: Пт окт 03, 2014 14:41:16

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

Сообщение alexan9er »

DarkWolf писал(а):Всем большое спасибо! разобрался. Проблема именно в переменной sOn. Она почему то не держит состояние в 1. Сейчас инициализацию таймера провожу по нажатию на кнопку. Все работает

А, понятно, я этот вариант не рассматривал т.к. думал что она "состояние держит" =)
А вы отладчиком не пользуетесь чтоли? Можно было бы легко такое отловить.
alexey6522
Встал на лапы
Сообщения: 149
Зарегистрирован: Чт июл 28, 2011 18:12:28

Таймеры/Счетчики

Сообщение alexey6522 »

Добрый вечер! Можно ли включить два ISR в Atmega128 что бы они не мешали друг другу при срабатывании одного из прерываний, пока обрабатывается одно прерывание другое не останавливалось?

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

void timer_init (void)
{
cli();
TCCR0=(1<<WGM01);
TCCR2=(1<<WGM01);
TIMSK |= (1<<OCIE0)|(1<<OCIE2); // устанавливаем бит разрешения прерывания  счетчика по совпадению
OCR0 = 0b11111111; // определяем число сравнения
OCR2 = 0b11111111; // определяем число сравнения
TCCR0|=(1<<CS01); //запуск таймера с предделителем
TCCR2|=(1<<CS01); //запуск таймера с предделителем
sei();
}

ISR(TIMER2_COMP_vect)
{
//пока выполняется этот код, ISR(TIMER0_COMP_vect) отдыхает :-(
}

ISR(TIMER0_COMP_vect)
{
//пока выполняется этот код, ISR(TIMER2_COMP_vect) отдыхает :-(
}
Аватара пользователя
pyzhman
Друг Кота
Сообщения: 7016
Зарегистрирован: Вс июл 12, 2009 19:15:29
Откуда: Ижевск
Контактная информация:

Re: Таймеры/Счетчики

Сообщение pyzhman »

alexey6522 писал(а): пока обрабатывается одно прерывание другое не останавливалось

Два микроконтроллера. Или вы не ясно изложили задачу.
Docendo discimus
alexey6522
Встал на лапы
Сообщения: 149
Зарегистрирован: Чт июл 28, 2011 18:12:28

Re: Таймеры/Счетчики

Сообщение alexey6522 »

Нет один МК Atmega128. Мне нужно что бы две разные задачи в одном МК обрабатывались независимо друг от друга, как две программы на компе которые не мешают работе одна - другой.
Раньше я справлялся с данной задачей разбивая паузу на миллисекунды и делал обработку нажатия кнопок, теперь задача усложнилась и как-то надо выходить из тупика.

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

 
//Пауза
void PAUSE(void)
{
     for (unsigned int u=0; u<10; u++)
     {
     _delay_ms(100);   
         //...тут обработка нажатия кнопок
     }
}
uk8amk
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Re: Таймеры/Счетчики

Сообщение uk8amk »

А на компе тоже задачи друг другу "мешают". Только их пишут так, что это почти незаметно.
Полной параллельности можно добится использованием FPGA, но к контроллерам это практически не относится.
Использовать delay_ms() - только в крайнем случае.
Касательно кода в первом посте - это называется вложенные прерывание. Но они также используются в экзотических ситуациях и при полном понимании происходящего.
pokk
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Re: Таймеры/Счетчики

Сообщение pokk »

alexey6522,А зачем вам вообще пауза(delay_ms) нужна? Делайте её так что бы в это время выполнялся другой кусок кода. Или по таймеру.

Почитайте вот тут про флаговые автоматы может это не много прояснит.
http://easyelectronics.ru/avr-uchebnyj- ... gramm.html
Так же ещё можно по смотреть статьи Владимира Татарчевского "Применение SWITCH-технологии при разработке прикладного программного обеспечения для микроконтроллеров".
И если у вас задача на опрос кнопок, то в 8 части там как раз приведен пример драйвера клавиатуры (без всяких прерываний).
Аватара пользователя
pazak
Прорезались зубы
Сообщения: 243
Зарегистрирован: Пт фев 26, 2010 03:33:02
Откуда: Донецк

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

Сообщение pazak »

Здравствуйте уважаемые коты.
Всех с Новым годом и Рождеством.
В общем такое дело, решил в новом году научиться программировать AVR, подопытный ATtiny2313. Светодиодом наморгался вволю, динамическую индикацию освоил, сейчас разбираюсь с Т/С1. Пытаюсь освоить режим захвата со входа ICP(PD6), Евстифеева мышкой до дыр затёр (и не только его). ДШ распечатал, но так и не нашёл как эту ногу (ICP) активировать, в каком регистре нужно поставить 1. B DDRD эта ножка вход, вектор прерывания указан, настройки таймера:

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

;========= инициализация TIM1 ================
 ldi   temp1,(1<<ICIE1)   ; разрешение прерывания по захвату ( ICP)
 out   TIMSK,temp1      ;
 ldi   temp1,(1<<ICES1)|(1<<CS10)   ; активный перепад 0>1, такт 1/1
 out   TCCR1B,temp1      ;
 sei         ;
 rjmp   Main      ;

В симуляторе студии если принудительно ставлю флаг этого прерывания то прога переходит в обработчик, а если "дрыгаю" ножкой в порту D, то прерывания не происходит. Что нужно ещё сделать?

С уважением.
Аватара пользователя
zero648
Вымогатель припоя
Сообщения: 650
Зарегистрирован: Пн июн 18, 2012 12:01:04
Откуда: Челябинская область, Копейск

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

Сообщение zero648 »

pazak писал(а): Что нужно ещё сделать?

Включи бит ACIC в регистре управления компаратором ACSR, т.е.
sbi ACSR,ACIC

P.S. на картинке видно что нужно для того, чтобы включился флаг прерывания захвата:
Изображение
Аватара пользователя
pazak
Прорезались зубы
Сообщения: 243
Зарегистрирован: Пт фев 26, 2010 03:33:02
Откуда: Донецк

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

Сообщение pazak »

Включил не помогло, да и как могло помочь если ACIC наоборот отключает вход ICP от таймера, а подключает выход компаратора. Выключил модуль компаратора совсем - без изменений. нет прерывания.

P.S. Ну в общем разобрался с симулятором, просто не давно работаю со студией и всех нюансов ещё не знаю. Оказывается сэмулировать сигнал на входе ICP можно только тогда, когда он настроен как выход :shock: И после наступления события захвата таймер не сбрасывается аппаратно, об этом нигде ни слова :dont_know: Ладно будем копать дальше.

С уважением.
Аватара пользователя
zero648
Вымогатель припоя
Сообщения: 650
Зарегистрирован: Пн июн 18, 2012 12:01:04
Откуда: Челябинская область, Копейск

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

Сообщение zero648 »

Да, действительно ACIC не нужен.
akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

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

Сообщение akl »

pazak писал(а): Оказывается сэмулировать сигнал на входе ICP можно только тогда, когда он настроен как выход...
Студии 3.21 и 4.19 отрабатывают чётко активный перепад на PIND6 (ICP1) независимо от настройки этой лапы.
pazak писал(а):... И после наступления события захвата таймер не сбрасывается аппаратно, об этом нигде ни слова...
В режиме захвата модуль ICP1 и не должен этого делать. Другое дело, использование модуля ICP1 в качестве регистра сравнения с автосбросом. Но для этого и нужна соответствующая настройка по Table 46. Waveform Generation Mode Bit Description(1)
Т.к. достоверно не знаю всех событий произошедших на лапе PIND6 (ICP1) до разрешения прерываний, чищу флаг ICF1

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

;========= инициализация TIM1 ================
 ldi   temp1,(1<<ICIE1)   ; разрешение прерывания по захвату ( ICP)
 out   TIMSK,temp1      ;

        OUT TIFR,temp1 ;!!!!!!!!!!!!!!!!!!!!!

 ldi   temp1,(1<<ICES1)|(1<<CS10)   ; активный перепад 0>1, такт 1/1
 out   TCCR1B,temp1      ;
 sei         ;
 rjmp   Main      ;
Ответить

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