Обсуждаем контроллеры компании Atmel.
Ответить

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

Ср ноя 08, 2017 06:24:36

viiv, Спасибо за правки.
По поводу CurrentFlag функция включения планируется использоваться если CurrentFlag изначально имеет флаг FALSE.
И Соответственно как видно в теле функции она будет возвращать CurrentFlag до тех пор пока не выполниться условия (TimerToStart>=TimeVar)

Добавлено after 2 minutes 2 seconds:
А по поводу 4294967295UL то есть если к нему прибавить +1, он как я понял обнулится ?

Добавлено after 6 minutes 26 seconds:
Столкнулся только с одной проблемой при испытаниях кода переменная TIMER.MS была == uint16_t.
Если зафиксируем время допустим в 65530 TIMER.MS а TimeVar установим больше 5 то TIMER.MS обнулялся раньше чем выполниться условия (TimerToSTOP >= TimeVar) и соответственно происходил сбой в работе.

Добавлено after 28 minutes 25 seconds:
Как я понимаю надо делать проверку на подобие ((MAX_UINT32-TIMER.Channel[Number].TimeCountingON)>TimeVar) и если она не выполнилась использовать еще одну переменную для подсчета ?

Добавлено after 6 minutes 12 seconds:
Без доп переменной пришла такая идея, правда не знаю насколько она правильная.

Код:
Код:
uint8_t OnAfterTimeMS(uint32_t TimeVar,uint8_t Number,uint8_t CurrentFlag)
{
   cli();
   uint8_t OutFlag=0;                  //Переменная отвечает за RETURN f().
   TIMER.TimeCurrent=TIMER.MS;            //Присваиваем текущие значение МС
   if (TIMER.Channel[Number].FlagTimersON==0)      //Условия для захвата времени вызова функции и установки флага работы
   {
      TIMER.Channel[Number].TimeCountingON=TIMER.MS;
      TIMER.Channel[Number].FlagTimersON=1;
   }
   uint32_t TimerToStart = TIMER.TimeCurrent-TIMER.Channel[Number].TimeCountingON;
   if ((TimerToStart >= TimeVar)&((MAX_UINT32-TIMER.Channel[Number].TimeCountingON)>TimeVar))         //Если время до старта == TimeVar, то OutFlag=1 и обнуляем Флаг работы.
   {
      OutFlag=1;
      TIMER.Channel[Number].FlagTimersON=0;
      TIMER.TimeCurrent=0;
      TIMER.Channel[Number].TimeCountingON=0;
      TimerToStart=0;
   }
   else
   {
      OutFlag=CurrentFlag;
      if (((MAX_UINT32-TIMER.Channel[Number].TimeCountingON)<TimeVar))
      {
         TIMER.MS=0;
         TIMER.Channel[Number].TimeCountingON=0;
      }
   }
   sei();
   return OutFlag;
}

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

Ср ноя 08, 2017 06:52:50

7seg писал(а):Столкнулся только с одной проблемой при испытаниях кода переменная TIMER.MS была == uint16_t.
Если зафиксируем время допустим в 65530 TIMER.MS а TimeVar установим больше 5 то TIMER.MS обнулялся раньше чем выполниться условия (TimerToSTOP >= TimeVar) и соответственно происходил сбой в работе.
Это происходит потому что условие проверок надо делать в прерывании ISR (TIMER0_OVF_vect). Тогда условие будет контролировать каждый тик таймера.
А в основном цикле проверять флаги работы таймера.
К примеру так
А в основном цикле

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

Ср ноя 08, 2017 08:58:57

На самом деле при использование uint32_t это незначительно.
Есть вот такой код в функции Algoritm(); которая вызывается в цикле while();
Код:
R01TOP=OnAfterTimeMS(1200,1,R01TOP);
R01TOP=OFFAfterTimeMS(1300,2,R01TOP);

Соответственно он работает не совсем правильно каждый момент включения на 100ms увеличиваеться еще на 100ms
т.е 100/200/300 итд.
При использование кода:
Код:
void Algoritm()
{
   if (R01TOP==0)
   {
      R01TOP=OnAfterTimeMS(1200,1,R01TOP);
   }
   R01TOP=OFFAfterTimeMS(1300,2,R01TOP);
}

Все работает как и задумывалось включение каждые 1300ms на 100ms.
Как думаете Можно ли поправить функции ON/OFF Чтобы избавиться от дополнительных проверок вне функции ?.
Код:

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

Ср ноя 08, 2017 09:01:49

не перестаю удивляться тому, как простые вещи можно сделать сложными...

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

Ср ноя 08, 2017 09:12:51

Просто проще на самом деле не получается (

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

Ср ноя 08, 2017 09:14:50

Просто проще на самом деле не получается (

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

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

Ср ноя 08, 2017 11:16:24

По поводу CurrentFlag функция включения планируется использоваться если CurrentFlag изначально имеет флаг FALSE.
И Соответственно как видно в теле функции она будет возвращать CurrentFlag до тех пор пока не выполниться условия (TimerToStart>=TimeVar)


Ну не понять мне. CurrentFlag - всегда признак, что таймер не истек? Так функция "знает" об этом признаке и без CurrentFlag.
Зачем смешивать в кучу? У Вас есть абстракция - таймер. Так? Так введите простой и понятный интерфейс:
1) включение таймера (timer_arm ())
2) если необходимо, проверку, что таймер включен (timer_armed ())
3) проверку, что таймер истек timer_expired ()


Все, теперь "наворачивайте" свою логику

А по поводу 4294967295UL то есть если к нему прибавить +1, он как я понял обнулится ?


В си переполнения никак не контролируются. Т.е. то, что Вы написали выше - верно.

Столкнулся только с одной проблемой при испытаниях кода переменная TIMER.MS была == uint16_t.
Если зафиксируем время допустим в 65530 TIMER.MS а TimeVar установим больше 5 то TIMER.MS обнулялся раньше чем выполниться условия (TimerToSTOP >= TimeVar) и соответственно происходил сбой в работе.

Как и писал выше, в си переполнение никак не контролируется.
Код:
uint16_t TimeCountingON = 65530; // тик начала работы таймера
uint16_t MS = 0; // текущий тик (было переполнение)
// разница между текущим тиком и тиком начала работы таймера
uint16_t ticks_passed = MS - TimeCountingON; // ticks_passed будет 6!!!


Добавлено after 1 hour 13 minutes 3 seconds:
Просто проще на самом деле не получается (


Все работает как и задумывалось включение каждые 1300ms на 100ms.


Код:
/* включает/выключает что надо :-) */
void on_off (bool_t on)
{
 .....
}

static soft_timer_t on_off_timer;
static bool_t on;

/*включение каждые 1300ms на 100ms*/
void Algoritm()
{
   soft_timer_t *t = &on_off_timer;

   if (soft_timer_expired (t)) { /* таймер истек */
       /* переключаем */
       on ^= 1; on_off (on);
       /* и перезапускаем таймер */
       soft_timer_arm (t, on ? 100 : 1200);
   }
}



Код:
   /* выключаем и стартуем таймер */
   on_off (on = 0);
   soft_timer_arm (&on_off_timer, 1200);

   while(1)
   {
      SpiOutRegister();
      Algoritm();
   }


Так не проще?

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

Ср ноя 08, 2017 14:18:16

viiv писал(а):
Все работает как и задумывалось включение каждые 1300ms на 100ms.

Так не проще?
Нет, не проще.
Не даром у него забабахано
Код:
#define AMOUNT_TIMERS 6      //Количество используемых таймеров
Скорее всего он имел ввиду так
Плохо что мы невидим полностью поставленную задачу.

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

Ср ноя 08, 2017 14:40:42

Полностью поставленную задачу пока не могу описать(. на данном этапе реализовал нужное количество IO и работу с таймерами(которых пока не известное количество ) сейчас принялся вкуривать как организовать управление по ModBus.
Так как хочу управлять всем с панели :
http://systemcontrol.ru/magazin/aon/kin ... /mt4532tte
Если со слейвом все просто так как есть уже готовые либы, то с мастер придется писать ручками ( пока что пред пологаю для управления использовать доп МК на котором будет реализован Master Modbas и слейв i2c.

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

Ср ноя 08, 2017 15:11:18

когда-то давно мне тоже приспичило сделать "много гибких таймеров"... я сделал примерно так:
Код:
// установка очередного таймера. если успешно, возвращает номер таймера, если не успешно, возвращает TIMER_ERROR
uint8_t set_timer(timer_t t);
// проверка указанного таймера. Если истек, возвращает 1, если не истек, возвращает 0, если номер не корректный - возвращает TIMER_ERROR
uint8_t timeout(uint8_t timer_id);

typedef uint16_t timer_t;

static timer_t timers[TIMER_CNT];

ISR(TIMER0_OVF_vect){
   for(uint8_t i=0; i<TIMER_CNT; i++){
      if(timers[i] != TIMER_FREE){
         if(timers[i]) timers[i]--;
      }
   }
}

uint8_t set_timer(timer_t t){
   if(t > TIMER_MAX) return TIMER_ERROR;
   for(uint8_t i=0; i<TIMER_CNT; i++){
      ATOMIC_BLOCK(ATOMICK_RESTORE_STATE){
         if(timers[i] == TIMER_FREE){
            timers[i] = t;
            return i;
         }
      }
   }
   return TIMER_ERROR;
}

uint8_t timeout(uint8_t timer_id){
   if(timer_id >= TIMER_CNT) return TIMER_ERROR;
   ATOMIC_BLOCK(ATOMICK_RESTORE_STATE){
      if(timers[timer_id] == TIMER_FREE) return TIMER_ERROR;
      if(timers[timer_id] != 0) return 0;
      else {
         timers[timer_id] = TIMER_FREE;
         return 1;
      }
   }
}
лишнее я выкинул - определение констант всяких и т.п.... по-моему, мой вариант гораздо проще и понять, и работать с ним.

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

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

Чт ноя 09, 2017 03:00:05

а в чем разница между обычным выполнением и ATOMIC_BLOCK(ATOMICK_RESTORE_STATE) ?

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

Чт ноя 09, 2017 07:02:43

ATOMIC_BLOCK обеспечивает атомарное выполнение операций в своем блоке. в отличие от традиционного запрета-разрешения прерываний ATOMIC_BLOCK не портит текущий контекст разрешения прерываний, т.е. не разрешит их, если до этого они были запрещены.

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

Чт ноя 09, 2017 07:35:15

Вот 16 таймеров. Хватит?

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

Пт ноя 10, 2017 10:11:05

Доброго времени суток.
Подскажите что делаю не так?
Хочу настроить таймер0 микроконтролера атмега8 на приривание по переполнению но ничево не получается.
Использую програму codevisionavr и симулятор Proteus.

Код:
/*****************************************************
This program was produced by the
CodeWizardAVR V2.05.0 Evaluation
Automatic Program Generator
© Copyright 1998-2010 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date    : 10.11.2017
Author  : Freeware, for evaluation and non-commercial use only
Company :
Comments:


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

#include <mega8.h>

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Place your code here
  PORTC.0=1;
}

// Declare your global variables here

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

// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x00;

// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=Out
// State6=T State5=T State4=T State3=T State2=T State1=T State0=0
PORTC=0x00;
DDRC=0xff;

// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
TCCR0=0x07;
TCNT0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=0xFFFF
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=0xFF
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
MCUCR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x01;

// USART initialization
// USART disabled
UCSRB=0x00;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

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

// SPI initialization
// SPI disabled
SPCR=0x00;

// TWI initialization
// TWI disabled
TWCR=0x00;

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

while (1)
      {
      // Place your code here
       
      }
}

Заметил что когда ставить делитель на 128 в регистре TCCR0=0x05 то преривание работает, а если ставить 256 и 1024 то не работает.В чем может быть проблема?
Зарание спасибо за помощь.

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

Пт ноя 10, 2017 10:26:06

Код:
TCCR0=0x07;
External clock source on T0 pin. Clock on rising edge. Подайте частоту на PD4/T0

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

Пт ноя 10, 2017 10:41:21

Код:
TCCR0=0x07;
External clock source on T0 pin. Clock on rising edge. Подайте частоту на PD4/T0

А как настроить от внутреннего генератора?

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

Пт ноя 10, 2017 10:54:15

выбираете нужный предделитель и всё. Лучше всё таки пользоваться DS на ATmega8
Вложения
TCCR0_M8.PNG
(79.26 KiB) Скачиваний: 458

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

Пт ноя 10, 2017 11:57:38

Спасибо разобрался :beer: ))))
У меня просто рускоязычный перевод даташита и там была неточность. Вчера весь вечер не мог понять в чем дело)))
Так что нужно учить английский :))

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

Вт дек 05, 2017 17:57:11

Всем добрый день.
Вопросик есть, мне нужен таймер, с 2мя каналами на atmega8 или 328, к сожалению программную среду атмег я почти не знаю. Тем не менее хочу спросить может кто поможет.
Суть, нужно что-бы канал работал допустим 10ч а потом был выключен 14ч, 2й так-же но независимо от первого, и фоторезистор который не останавливает таймеры но блокирует работу обоих каналов, то есть если я посветил светом, канал отключиться но когда наступит темнота если время рабочего состояния на таймере еще не истекло он включит канал.

Я поискал на просторах интернета и нашел некоторые схемы и прошивки к ним но они все с дисплеями и ручными настройками, я ищу вариант без дисплея где у меня есть 1 кнопка RESET которая коротким нажатием запускает таймер одного канала и начинает его отсчет а последующим коротким нажатием запускает таймер второго канала и начинает его счет, а долгим нажатием сбрасывает оба, настройка интервалов таймеров через исходники.
Схему вроде собрать могу а вот программную часть не знаю как реализовать...

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

Вс янв 14, 2018 14:08:22

Привет! Кто сталкивался с такой проблемой?

Очищаю и запускаю таймер вот так:

По идее таймер должен запуститься, досчитать до 124 и вылететь в прерывание. В симуляторе 4й студии так и есть. А вот в протеусе (в версиях 7.1 и 8.6) прерывание вылетает как только счетчик сделает один тик, т.е. когда TCNT0 меняет свое значение с 0 на 1. Шо за БАГ? Может неправильная последовательность запуска и очистки? До выполнения приведенного кода таймер использовался в другом режиме с другим делителем.
Ответить