Hallo,
I noticed that when I wanted to use timer1 in CTC mode, and set a value inside OCR1A and match interrupt, it doesn't matter whether I set WGM12 or not, it works as required, the interrupt just fires, what is the reason for this?
Hallo,
I noticed that when I wanted to use timer1 in CTC mode, and set a value inside OCR1A and match interrupt, it doesn't matter whether I set WGM12 or not, it works as required, the interrupt just fires, what is the reason for this?
Which model of AVR? Show the code.
(I suspect you are setting WGM12 in the wrong register - a lot of AVRs split four WGM bits with 2 in one register and 2 in another)
Here you go, it doesn't matter if I set WGM12 or not, it simply works..
/***************************************************** Project : Dimmer Version : 1.3 Date : 21/02/2008 - 3/11/2011 Author : Ehab Anwar - Modified by MeTaL Company : BDR Electronics Chip type : ATmega8L Program type : Application Clock frequency : 8.000000 MHz Memory model : Small External SRAM size : 0 Data Stack size : 256 *****************************************************/ #include#include // Alphanumeric LCD Module functions #asm .equ __lcd_port=0x18 ;PORTB #endasm #include unsigned char LightIntensity=50; ////////////////////////////////////////////ok void show_number(char a,char c,char temp) { unsigned char number[3]; char b; for(b=0;b<3;b++) { number[b]=temp%10; temp/=10; _lcd_ready(); lcd_gotoxy(a+1-b,c); lcd_putchar(number[b]|0x30); } } //////////////////////////////////////////// /////////////////////////////////////////////////////////ok // Timer 1 output compare A interrupt service routine interrupt [TIM1_COMPA] void timer1_compa_isr(void) { //if (LightIntensity==0) PORTD.4=0; //else //PORTD.4=0; } ///////////////////////////////////////////////////////// /////////////////////////////////////////////////////////ok // Analog Comparator interrupt service routine interrupt [2] void external_int0(void) { if (LightIntensity!=0) PORTD.4=1; else PORTD.4=0; TCNT1H=0x00; TCNT1L=0x00; } ///////////////////////////////////////////////////////// ///////////////////////////////////////////////////////// void SetTimers(void) { OCR1A=((unsigned int)(LightIntensity)*100); if(LightIntensity==100) TCCR1B = 0; else TCCR1B |= (1 << WGM12)|(1 << CS11); //OCR1B=((int)(200-LightIntensity)*100); } /////////////////////////////////////////// // Declare your global variables here void main(void) { // Declare your local variables here //char loop; // 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=In // State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTC=0xff; DDRC=0x00; // 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=0x11; // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: Timer 0 Stopped TCCR0=0x00; TCNT0=0x00; // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 7.813 kHz // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Discon. // Noise Canceler: Off // Input Capture on Falling Edge // Timer 1 Overflow Interrupt: Off // Input Capture Interrupt: Off // Compare A Match Interrupt: On // Compare B Match Interrupt: Off TCCR1A=0x00; TCCR1B=0x0A; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; // OCR1AH=0x13; // OCR1AL=0x88; // OCR1BH=0x3a; // OCR1BL=0x98; // Timer/Counter 2 initialization // Clock source: System Clock // Clock value: Timer 2 Stopped // Mode: Normal top=FFh // OC2 output: Disconnected ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00; // External Interrupt(s) initialization // INT0: ON - Low triggered, I think better than falling edge and more reliable // INT1: Off GICR=0x40; MCUCR=0x00; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x10; // Analog Comparator initialization // Analog Comparator: Off // Interrupt on Output Toggle // Analog Comparator Input Capture by Timer/Counter 1: Off ACSR=0x80; SFIOR=0x00; // LCD module initialization lcd_init(16); // Global enable interrupts PORTD.4=1; SetTimers(); #asm("sei") lcd_gotoxy(0,0); lcd_putsf("Light Intensity"); show_number(1,1,LightIntensity); while (1) { while(PINC.5==0) { if(LightIntensity<99) LightIntensity+=5; SetTimers(); lcd_gotoxy(0,0); lcd_putsf("Light Intensity"); show_number(1,1,LightIntensity); delay_ms(150); } while(PINC.2==0) { if(LightIntensity>0) LightIntensity-=5; SetTimers(); lcd_gotoxy(0,0); lcd_putsf("Light Intensity"); show_number(1,1,LightIntensity); delay_ms(150); } }; }
TCCR1A=0x00; TCCR1B=0x0A;
So that is WGM10=0, WGM11=0, WGM12=1, WGM13=0. So that selects mode 4 which is CTC mode (OCR1A = TOP) and if you set WGM12=0 that selects "normal" mode.
So I guess your question is what's the difference between CTC and normal mode then?
Until PINC.2 or PINC.5 is set then I don't see anything touching OCR1A so it will hold 0x0000 I guess.
No, I understand the difference very well, my question is that, if I TCCR1B=0x02; and I never set WGM12, it also works, even when in mode 0, and the interrupt of match/compare simply fires after setting OCR1A, thu I don't set WGM12, why is that?
CTC mode means that hardware resets TCNT1 as soon as it matches OCR1A. e.g. TCNT1 goes 0 -> 1234 -> 0 -> 1234
The COMPA interrupt fires at the match (1234)
If you are in regular mode, TCNT1 goes 0 -> 1234 -> 65535 -> 0 -> 1234 -> 65535 ...
You will get both the COMPA and OVF interrupts.
Now since 0-1234 (1235 ticks) is a lot shorter than 65536 ticks, the COMPA fires but a lot less frequently. i.e. F_CPU/div/65536 Hz instead of F_CPU/div/1235 Hz.
David.
the difference doesn't actually appear in the behavior, because TCNT1 is reset in INT0 handler.
If CTC is to be used, then it will reset TCNT1, then I have to add more lines to turn timer1 0ff, I think the code without WGM12 is better.
I think the code without WGM12 is better.
No, it was OK. Actually, after I read about CTC, I thought to use it, the code is not mine, it behaved the same, the point was that timer1 was set to 0 in INT0 handler, which yielded similar results.
I was wondering, once the COMPA interrupt is fired, while the top is OCR1A, inside the handler, should I set timer1 registers to 0 after I stop timer1 in order to ensure correct counting next time?
If you are actually stopping the timer, then yes, you should set TCNT1 to 0 before starting the timer again.
Hi again, I've seen semitone using this formula to calculate the phase angle control timings, how can I implement it correctly in my case? I don't really understand how to do it, I know perl, but there are many things I understand not, can someone please explain what these formulas do, how can I make it 100 steps? Once I gain more understanding, I can modify perl code to generate a c array. Actually, I need to understand these lines and how to modify them correctly:
my $use_period = 8.4 / 1000; # seconds
my $timer_start = 880; # old: 54200;
my $pulse_width = 16;