Atmega8 Timer0 отключение ноги

3d_killer
Offline
Зарегистрирован: 13.06.2018

Добрый день, скажите пожалуйста, можно ли в Atmega8 использовать ногу PD4 (arduino - 4 нога), независимо от таймера T0, если он запущен, если такое возможно как это можно сделать?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А что Вы понимаете под "он запущен"? Давайте-ка код, а то всё утонет в уточнениях, заявлениях, что "у меня не так" и, в результате, перейдёт в срач.

Green
Offline
Зарегистрирован: 01.10.2015

Используйте. Если только никто не запретил.)

 

3d_killer
Offline
Зарегистрирован: 13.06.2018
ISR(TIMER1_COMPA_vect)
{
}
 //настройка таймера1
void setup()
{
   TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
   TIMSK |= (1 << OCIE1A); // Enable CTC interrupt
   OCR1A   = 15624; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64
   TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start timer at Fcpu/64
}
void loop()
{

}

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

Green
Offline
Зарегистрирован: 01.10.2015

Ну так не дёргайте ногу, какие проблемы?

3d_killer
Offline
Зарегистрирован: 13.06.2018

как?

 

Green
Offline
Зарегистрирован: 01.10.2015

Как, как и будет кучка. Читайте описание работы таймера 1. 

3d_killer
Offline
Зарегистрирован: 13.06.2018
TCCR1A |= _BV(COM1A1);                                 // activates the output pin

Это активация, а как деактивировать

Green
Offline
Зарегистрирован: 01.10.2015
Ну до чего ж народ то ленивый...
/*
   TCCR1A - Timer/Counter1 Control Register A 
    7      6      5      4      3      2      1      0
  COM1A1 COM1A0 COM1B1 COM1B0 FOC1A  FOC1B  WGM11  WGM10
  
  #define    WGM10           0       // Waveform Generation Mode
  #define    PWM10           WGM10   // For compatibility
  #define    WGM11           1       // Waveform Generation Mode
  #define    PWM11           WGM11   // For compatibility
  #define    FOC1B           2       // Force Output Compare 1B
  #define    FOC1A           3       // Force Output Compare 1A
  #define    COM1B0          4       // Compare Output Mode 1B, bit 0
  #define    COM1B1          5       // Compare Output Mode 1B, bit 1
  #define    COM1A0          6       // Compare Ouput Mode 1A, bit 0
  #define    COM1A1          7       // Compare Output Mode 1A, bit 1

    Clock Select Bit Description
  CS12 CS11 CS10  Description
   0    0    0    No clock source. (Timer/Counter stopped)
   0    0    1    clk io /1 (No prescaling)
   0    1    0    clk io /8 (From prescaler)
   0    1    1    clk io /64 (From prescaler)
   1    0    0    clk io /256 (From prescaler)
   1    0    1    clk io /1024 (From prescaler)
   1    1    0    External clock source on T1 pin. Clock on falling edge.
   1    1    1    External clock source on T1 pin. Clock on rising edge.

    Non PWM: 
  COM1A1, COM1A0 - Compare match Output A Mode:
  00 - Normal port operation, OC0A disconnected
  01 - Toggle OC0A on compare match
  10 - Clear OC0A on compare match
  11 - Set OC0A on compare match.
  
  COM1B1, COM1B0 - Compare match Output B Mode:
  00 - Normal port operation, OC0B disconnected
  01 - Toggle OC0B on compare match
  10 - Clear OC0B on compare match
  11 - Set OC0B on compare match.
*/

 

3d_killer
Offline
Зарегистрирован: 13.06.2018

Вот, измененный, упрощенный код библиотеки, он работает, но дергает в прерывании порт, не пойму почему:

TimerMy TimerNew;              // preinstatiate

ISR(TIMER1_OVF_vect)          // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  TimerNew.isrCallback();
}

void TimerMy::initialize(long microseconds)
{
  TCCR1A = 0;                 // clear control register A 
  TCCR1B = _BV(WGM13);        // set mode 8: phase and frequency correct pwm, stop the timer
  setPeriod(microseconds);
}

void TimerMy::setPeriod(long microseconds)		// AR modified for atomic access
{
  
  long cycles = (F_CPU / 2000000) * microseconds;                                // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
  if(cycles < RESOLUTION)              clockSelectBits = _BV(CS10);              // no prescale, full xtal
  else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11);              // prescale by /8
  else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10);  // prescale by /64
  else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12);              // prescale by /256
  else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10);  // prescale by /1024
  else        cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10);  // request was out of bounds, set as maximum
  
  oldSREG = SREG;				
  cli();							// Disable interrupts for 16 bit register access
  ICR1 = pwmPeriod = cycles;                                          // ICR1 is TOP in p & f correct pwm mode
  SREG = oldSREG;
  
  TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
  TCCR1B |= clockSelectBits;                                          // reset clock select register, and starts the clock
}

void TimerMy::attachInterrupt(void (*isr)(), long microseconds)
{
  if(microseconds > 0) setPeriod(microseconds);
  isrCallback = isr;                                       // register the user's callback with the real ISR
	TIMSK = _BV(TOIE1); 	// sets the timer overflow interrupt enable bit
	// might be running with interrupts disabled (eg inside an ISR), so don't touch the global state
  sei();
  resume();												
}

void TimerMy::detachInterrupt()
{
	TIMSK &= ~_BV(TOIE1);	 // clears the timer overflow interrupt enable bit 
	// timer continues to count without calling the isr
}

void TimerMy::resume()				// AR suggested
{ 
  TCCR1B |= clockSelectBits;
}

void TimerMy::restart()		// Depricated - Public interface to start at zero - Lex 10/9/2011
{
	start();				
}

void TimerMy::start()	// AR addition, renamed by Lex to reflect it's actual role
{
  unsigned int tcnt1;
  
  //TIMSK1 &= ~_BV(TOIE1);        // AR added 	
  TIMSK &= ~_BV(TOIE1);        // AR added 
  //GTCCR |= _BV(PSRSYNC);   		// AR added - reset prescaler (NB: shared with all 16 bit timers);

  oldSREG = SREG;				// AR - save status register
  cli();						// AR - Disable interrupts
  TCNT1 = 0;                	
  SREG = oldSREG;          		// AR - Restore status register
	resume();
  do {	// Nothing -- wait until timer moved on from zero - otherwise get a phantom interrupt
	oldSREG = SREG;
	cli();
	tcnt1 = TCNT1;
	SREG = oldSREG;
  } while (tcnt1==0); 
 
//  TIFR1 = 0xff;              		// AR - Clear interrupt flags
//  TIMSK1 = _BV(TOIE1);              // sets the timer overflow interrupt enable bit
//	TIFR&= _BV(TOIE1);
}

void TimerMy::stop()
{
  TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));          // clears all clock selects bits
}

тут же при инициализации стоит TCCR1A = 0; // clear control register A

получается он не должен дергать порт. 

3d_killer
Offline
Зарегистрирован: 13.06.2018

вот из-за этой строки такое поведение, но если ее убрать то таймер перестает работать

TIMSK = _BV(TOIE1); 	// sets the timer overflow interrupt enable bit

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Я Вас уже спрашивал, повторю ещё раз, что Вы понимаете под выражением "таймер работает"? Что Ва от него надо? Чтобы он дёргал ногу? Или чиобы срабатывало прерывание(я)? Какое(ие)? Объяснитесь толком.

3d_killer
Offline
Зарегистрирован: 13.06.2018

Мне нужно чтобы срабатывало прерывание (по переполнению), а ногой я мог отдельно управлять, независимо от таймера.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

3d_killer пишет:

Мне нужно чтобы срабатывало прерывание (по переполнению), а ногой я мог отдельно управлять, независимо от таймера.

Тогда нахрена Вы вообще конфигурите режим СТС (строки №№7-10 в посте #3 ???

Если Вам не нужен СТС - не конфигурируйте его вообще. Откройте прерывание по переполнению и обрабатывайте на здоровье.  Или Вы откуда-то сдули тот код не понимая, что в нём написано? Так?

-NMi-
Offline
Зарегистрирован: 20.08.2018

Мега то какая? Просто 8 или ишшо чё есть?  (просто на 8 меге на 0 таймере ничо нет, ШИМ имеется ввиду.

Вот для инита с прерываниями по переполнению:

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 8000.000 kHz
TCCR0=0x01;
TCNT0=0x00;

3d_killer
Offline
Зарегистрирован: 13.06.2018

ЕвгенийП пишет:

3d_killer пишет:

Мне нужно чтобы срабатывало прерывание (по переполнению), а ногой я мог отдельно управлять, независимо от таймера.

Тогда нахрена Вы вообще конфигурите режим СТС (строки №№7-10 в посте #3 ???

Если Вам не нужен СТС - не конфигурируйте его вообще. Откройте прерывание по переполнению и обрабатывайте на здоровье.  Или Вы откуда-то сдули тот код не понимая, что в нём написано? Так?

так мне нужно выставить свой интервал же

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

3d_killer пишет:

так мне нужно выставить свой интервал же

Так и выставляйте, а СТС то тут при чём?

Какой Вам нужен интервал?

3d_killer
Offline
Зарегистрирован: 13.06.2018

40 мкс

 

-NMi-
Offline
Зарегистрирован: 20.08.2018

йоптель, вы чокурите? фтеме таймер_0 а в коде таймер_1... дауЖ... )))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

3d_killer пишет:

40 мкс

UPDATE
только сейчас заметил, что у Вас 40мкс, а я написал для 40мс :-( Сами сумеете переделать? Идея-то та же самая.

Ну, и какие проблемы? При тактовой частоте 16МГц, для 40мс подойдёт один из трёх делителей

Делитель Тиков
64 10000
256 2500
1024 625

Берите какой Вам удобнее, допустим 256. Стало быть в 40мс у нас 2500 тиков. Чтобы прерывание по переполнению случилось через 2500 тиков, в регистр счётчика надо записать 65536 - 2500 = 63036

Вот и всё. При настройке таймера и в обработчике прерывания по переполнению надо запихать это число в TCNT1. и всего делов.

И никаких СТС близко не нужно. Вот пример на 40мс. Каждые 40мс он меняет уровень на PB5 на противоположный. Можете проверить осциллографом. 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

#define F_CPU	16000000UL

constexpr uint16_t timeStartValue = 63036u;

void setupTimer1(void) {
	cli();
	TCCR1A = 0; // нормальный режим
	TCCR1B = (1 << CS12); // делитель 256
	TIMSK |= (1 << TOIE1); // прерывание по переполнению
	TCNT1 = timeStartValue;
	sei();
}

ISR(TIMER1_OVF_vect) {
	TCNT1 = timeStartValue;
	//
	// ниже "переворачиваем" уровень на PB5
	static bool pb5Val = false;
	pb5Val = !pb5Val;
	if (pb5Val) PORTB |= (1 << PB5);
	else PORTB &= ~(1 << PB5);
}

int main() {
	DDRB |= (1 << PB5); // PB5 в OUTPUT
	setupTimer1();
	while (1);
	return 0;
}

Если у Вас другая тактовая или нужно не 40 - пересчитайте число timeStartValue так, как мы Выше его считали.

3d_killer
Offline
Зарегистрирован: 13.06.2018

Большое спасибо, буду разбираться