Мистика с Timer1 Attiny85

Soyer
Offline
Зарегистрирован: 25.06.2022

Всем здрасьте!

вопрос собственно вот в чем:

в своем проекте на 85 тиньке использую timer1, согласно даташиту настраиваю:

TCNT1 = 0;
TCCR1 = 0;
OCR1C = clock_RESET;
OCR1A = OCR1C;
TCCR1 |= (1 << CTC1); //режим CTC
TCCR1 |= (1 << CS12) | (1 << CS11)| (1 << CS10); //clk/64 (prescaler)

управление таймером выполняю с помощью макросов:

#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
	#define TCNT_REG TCNT1  //register of timer-counter
	#define TIMER_INT ISR(TIMER1_COMPA_vect) //the timer interrupt service routine
	#define EN_TIMER {TCNT_REG=0; TIMSK |= (1 << OCIE1A); TIFR|=(1<<OCF1A);} //enable timer interrupt
       #define DIS_TIMER (TIMSK  &= ~(1 << OCIE1A)) // disable timer interrupt
#endif

 таймер запускается аппаратным прерыванием и должен срабатывать исходя из:

#define OWT_RESET 480
#define clock_MC (F_CPU / 1000000L )
#define clock_RESET (OWT_RESET/(64/clock_MC)

по теории должно все работать, но на практике время через которое срабатывает прерывание таймера в разы больше (это первый вопрос), поэтому для теста ставлю OCR1A = OCR1C = 7, но, время срабатывания начинает "гулять" (т.е. пару мкСек в большую или  меньшую сторону (и это второй вопрос)). по идее, можно бы было уменьшить деление (prescaler) до 32, и увеличить значение OCR1A и OCR1C в 2 раза, но на деле никакого результата не дает (и это третий вопрос).

Поиск в интернете ничего конкретного не дал, кроме того нашел калькулятор для расчета таймеров, за то убедился что что таймер инициализирую правильно. Кроме того на atmega328p timer2 работает как надо, а с тинькой такая вот беда, уже 3 дня голову ломаю. Люди добрые, подскажите что я делаю не так, век благодарен буду!

ссылка на калькулятор: https://www.arduinoslovakia.eu/application/timer-calculator

 

 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Полный код покажите ... Может вы боретесь с wiring за один и тот же таймер ....

Soyer
Offline
Зарегистрирован: 25.06.2022

согласно wiring.с milliis, micros и delay используют Timer0.

//OWSLAVE.cpp

#include "OWSLAVE.h"
#include "Arduino.h"
#include <avr/io.h>
#include <avr/interrupt.h>


//================================================
 #ifndef __ASSEMBLER__
#ifdef __cplusplus
extern "C" {
#endif	

 void delMcrscnds(uint8_t);  
	
#ifdef __cplusplus
} // extern "C"
#endif
#endif
//==============================================================

#if defined (__AVR_ATmega328P__)
    #define delMcs(n) (delayMicroseconds(n))
#else
	#define delMcs(n) (delMcrscnds(n))
#endif


volatile uint8_t  *Intrrpt_Msk_Rgstr_Addr;
volatile uint8_t  *Intrrpt_Flg_Rgstr_Addr;
volatile uint8_t  *Ext_Intrrpt_Cntrl_Rgstr_Addr;
volatile uint8_t *reg, *out;
uint8_t INTx, INTFx, ISC0_bit, ISC1_bit, _bit, _port;


#define EN_INT {*Intrrpt_Msk_Rgstr_Addr|=(1<<INTx);*Intrrpt_Flg_Rgstr_Addr|=(1<<INTFx);}  //enable interrupt 
#define DIS_INT (*Intrrpt_Msk_Rgstr_Addr&=~(1<<INTx))  //disable interrupt
#define SET_RISING (*Ext_Intrrpt_Cntrl_Rgstr_Addr=(1<<ISC1_bit)|(1<<ISC0_bit))  //set interrupt at rising edge
#define SET_FALLING {*Ext_Intrrpt_Cntrl_Rgstr_Addr &= ~(1 << ISC0_bit);*Ext_Intrrpt_Cntrl_Rgstr_Addr|=(1<<ISC1_bit);} //set interrupt at falling edge
#define SET_CHANGE {*Ext_Intrrpt_Cntrl_Rgstr_Addr &= ~(1 << ISC1_bit) ;*Ext_Intrrpt_Cntrl_Rgstr_Addr|=(1<<ISC0_bit);}//set interrupt at change edge
#define CHK_INT_EN (*Intrrpt_Msk_Rgstr_Addr|=(1<<INTx))==(1<<INTx) //test if interrupt enabled





 #define SET_LOW {*reg |= _bit;}  //линия 1-Wire на выход и на низкий уровень  *out &= ~_bit;
 #define ENTR_LINE {*reg &= ~_bit;}  //линия 1-Wire на вход и Z уровень
 #define READ_HIGH (*portInputRegister(_port) & _bit)//считать высокий сигнал с линии
 #define READ_LOW (!(*portInputRegister(_port) & _bit))//считать низкий сигнал с линии

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))


#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
	#define TCNT_REG TCNT1  //register of timer-counter
	#define TIMER_INT ISR(TIMER1_COMPA_vect) //the timer interrupt service routine
	#define EN_TIMER {TCNT_REG=0; TIMSK |= (1 << OCIE1A); TIFR|=(1<<OCF1A);} //enable timer interrupt
        #define DIS_TIMER (TIMSK  &= ~(1 << OCIE1A)) // disable timer interrupt
	
	#define on (sbi(PORTB, PB1))
        #define off (cbi(PORTB, PB1))
#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
	


#elif defined (__AVR_ATmega328P__)
	#define TCNT_REG TCNT2  //register of timer-counter
	#define TIMER_INT ISR(TIMER2_COMPA_vect) //the timer interrupt service routine
	#define EN_TIMER {TCNT_REG=0;TIMSK2|= (1 << OCIE2A); TIFR2|=(1<<TOV2);} //enable timer interrupt
	#define DIS_TIMER (TIMSK2 &=~(1<<OCIE2A))// disable timer interrupt 
	
	#define on (sbi(PORTB, 5))
        #define off (cbi(PORTB, 5))
#endif 



#define OWT_RESET 460
#define clock_MC (F_CPU / 1000000L )
#define clock_RESET (OWT_RESET/(64/clock_MC))





volatile uint8_t mode=0; //state
volatile uint8_t bitmask=1;// счетчик битов
volatile uint8_t rsv_byte=0;// принятый байт
volatile uint8_t rbit=0;
volatile uint8_t wmode=0;
volatile uint8_t status=0;
volatile uint8_t actbit=0;
volatile uint8_t ByteP=0;

volatile uint8_t bit_send;
volatile uint8_t bit_recv;

uint8_t OWSLAVE::errno;
volatile uint32_t old_previous = 0;

bool presence();
/* Access variable for ISRs */
static OWSLAVE *instance = NULL;
void (*p_function)();   // указатель на p_function
//===========================================================================

ISR (INT1_vect, ISR_ALIASOF (INT0_vect));
ISR (INT0_vect){
        on;
	EN_TIMER;
  }

  
//the timer interrupt service routine for ATmega328P and Attiny X5
TIMER_INT {
  off;
  DIS_INT;
  DIS_TIMER;
  presence();
  EN_INT;
}



void attachFunction(void (*function)()) { // передача указателя на функцию
  p_function = *function;
}

OWSLAVE::OWSLAVE(uint8_t pin){
		_bit = digitalPinToBitMask(pin);
		_port = digitalPinToPort(pin); 
		if (_port == NOT_A_PIN) return; 
		out = portOutputRegister(_port);
		reg = portModeRegister(_port);
		#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
			Intrrpt_Msk_Rgstr_Addr=&GIMSK;
			Intrrpt_Flg_Rgstr_Addr=&GIFR;
			Ext_Intrrpt_Cntrl_Rgstr_Addr=&MCUCR;
			if (pin==2){
				INTx=INT0;
				INTFx=INTF0;
				ISC0_bit=ISC00;
				ISC1_bit=ISC01;
			}

			
			TCNT1 = 0;
                        TCCR1 = 0;
			OCR1C =7;
			OCR1A = OCR1C;
			TCCR1 |= (1 << CTC1); //режим CTC
			TCCR1 |= (1 << CS12) | (1 << CS11)| (1 << CS10); //clk/64 (From prescaler)
			//TCCR1 |= (1 << CS12) | (1 << CS11); //clk/32 (From prescaler)
			//TCCR1 |= (1 << CS12) | (1 << CS10);//clk/16 (From prescaler)
                        DIS_TIMER;
		#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
			Intrrpt_Msk_Rgstr_Addr=&GIMSK;
			Intrrpt_Flg_Rgstr_Addr=&GIFR;
			Ext_Intrrpt_Cntrl_Rgstr_Addr=&MCUCR;
			if (pin==2){
				INTx=INT0;
				INTFx=INTF0;
				ISC0_bit=ISC00;
				ISC1_bit=ISC01;
			}
		#elif defined (__AVR_ATmega328P__)
			Intrrpt_Msk_Rgstr_Addr=&EIMSK;
			Intrrpt_Flg_Rgstr_Addr=&EIFR;
			Ext_Intrrpt_Cntrl_Rgstr_Addr=&EICRA;
			if (pin==2){
				INTx=INT0;
				INTFx=INTF0;
				ISC0_bit=ISC00;
				ISC1_bit=ISC01;
			}else if(pin==3){
				INTx=INT1;
				INTFx=INTF1;
				ISC0_bit=ISC10;
				ISC1_bit=ISC11;
			}
			
			TCCR2A = 0; 
                        TCCR2B = 0;
			TCNT2 = 0;
			TIMSK2 = 0;
			OCR2A=clock_RESET;
			TCCR2A |=(1<<WGM21);
			TCCR2B |=(1<<CS22) | (0<<CS21) | (0<<CS20);//clkT2S/64 (From prescaler)
			DIS_TIMER;	
		#endif 
	}

//================================================================================



i

void OWSLAVE::begin(void (*callback)(uint8_t retv), uint8_t *rom) {//по прерыванию
	cli();//откл. глоб.прер.
	ENTR_LINE;//пин на вход
	SET_FALLING;
	//setRom(rom);
	attachFunction(Process);
	instance = this;
	//CallbackCommand_ = callback;
	EN_INT;
	sei(); // enable interrupts
}


bool presence(){
   while (READ_LOW);
    delMcs(30);
    SET_LOW;
    delMcs(70);
    ENTR_LINE;
   while (READ_LOW);
   delMcs(30);
   return 1;
}

 

//OWSLAVE.S

#define __SFR_OFFSET 0x00

#include "avr/io.h"


.global on
.global off
.global delMcrscnds
delMcrscnds:
cli
LOOP_02:
#if ((F_CPU / 1000000L)==8)
ldi r25,1
#elif ((F_CPU / 1000000L)==16)
ldi r25,2
#endif
LOOP_01:
nop
nop
nop
nop
nop
dec r25
brne LOOP_01
dec r24
brne LOOP_02
sei
ret


         
on:
sbi   PORTB, 5 
ret

off:
cbi   PORTB,5  
ret

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

а тактируетесь от чего? ядро какое?

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

ua6em пишет:

а тактируетесь от чего? ядро какое?

А, главное, тактовая-то какая?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

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

ua6em пишет:

а тактируетесь от чего? ядро какое?

А, главное, тактовая-то какая?

судя по иерархии заданных вопросов - да! ;-)))

Soyer
Offline
Зарегистрирован: 25.06.2022

8Mhz внутренний, без кварца

Soyer
Offline
Зарегистрирован: 25.06.2022

решил не мучиться и перешел на 16Мгц, таймер работает нормально, но теперь с delayMicroseconds() заморочка (держат больше раза в 2-3 чем надо), на ATmega328p такого нет, только на тиньках (84 и 85). Ассемблерные функции не спасают, подскажите есть ли выход из этой беды.

на Тиньке 84 проблемы с таймером 1 нет, но такая же беда с delayMicroseconds(). Использую ATTinyCore в ArduinoIDE.

И еще, есть ли возможность при инициализации библиотеки проверить реальную частоту ядра (без использования F_CPU / 1000000L), как то подсчитать количество тактов за единицу времени?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

под этим Core эта программа использует все таймеры, частота 8 интернал, проблем нет

Soyer
Offline
Зарегистрирован: 25.06.2022

проблема с таймерами пропала, нужно решить как то проблему с delayMicroseconds

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

Soyer пишет:

на Тиньке 84 проблемы с таймером 1 нет, но такая же беда с delayMicroseconds(). Использую ATTinyCore в ArduinoIDE.

Да, есть такая проблемка. Сам недавно столкнулся. https://arduino.ru/forum/programmirovanie/diy-attiny-core