Мистика с Timer1 Attiny85
- Войдите на сайт для отправки комментариев
Всем здрасьте!
вопрос собственно вот в чем:
в своем проекте на 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
Полный код покажите ... Может вы боретесь с wiring за один и тот же таймер ....
согласно 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а тактируетесь от чего? ядро какое?
а тактируетесь от чего? ядро какое?
А, главное, тактовая-то какая?
а тактируетесь от чего? ядро какое?
А, главное, тактовая-то какая?
судя по иерархии заданных вопросов - да! ;-)))
8Mhz внутренний, без кварца
решил не мучиться и перешел на 16Мгц, таймер работает нормально, но теперь с delayMicroseconds() заморочка (держат больше раза в 2-3 чем надо), на ATmega328p такого нет, только на тиньках (84 и 85). Ассемблерные функции не спасают, подскажите есть ли выход из этой беды.
на Тиньке 84 проблемы с таймером 1 нет, но такая же беда с delayMicroseconds(). Использую ATTinyCore в ArduinoIDE.
И еще, есть ли возможность при инициализации библиотеки проверить реальную частоту ядра (без использования F_CPU / 1000000L), как то подсчитать количество тактов за единицу времени?
под этим Core эта программа использует все таймеры, частота 8 интернал, проблем нет
проблема с таймерами пропала, нужно решить как то проблему с delayMicroseconds
на Тиньке 84 проблемы с таймером 1 нет, но такая же беда с delayMicroseconds(). Использую ATTinyCore в ArduinoIDE.
Да, есть такая проблемка. Сам недавно столкнулся. https://arduino.ru/forum/programmirovanie/diy-attiny-core