How to make 0-50hz wave(50% duty cycle) by timer0 ATMEGA8A?

Go To Last Post
35 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi everybody
as you understod, i have an atmega8a and want to make 0-50hz wave(50% duty cycle) by timer0.
i know, you want to ask me, why this timer?
actually, the timer2 is for RTC and the timer1 is for an especial function generator.
now, i want to make an function genrator by this timer(0) but it confused me. in your opinion, is it better that i changed my MCU(for example to ATMEGA16)?
or make by timer0-self of this mcu(ATMEGA8)? :roll:

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm don't understand your question, timer0 is the same on all mega avr's, so changing processor will not change how it works. Perhaps re-stating your question, or better, show us your code and state what you want it do.
Sorry :(

jc

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It helps if you state the resolution you need for the frequency.

Slightly OT: 0 Hz is an interesting case.. :D

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is surprising what you can do with a single timer. e.g. implement a jitter-free squarewave by 'preloading' the COMnx bits in TIMER_COMP interrupts.

In terms of low frequencies, an 8-bit timer is going to give poor resolution. 0Hz is about the only frequency you can get with any accuracy.

If you write down a list of requirements for your application on paper, you will probably get some good advice. As well as the requirements, you need to put some numbers on performance, accuracy etc.

Your other thread mentions 3MB of memory. We need numbers for acceptable write time. And availability of GPIO for extra address signals on top of 'external memory bus'.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jccordill wrote:
I'm don't understand your question, timer0 is the same on all mega avr's

Really?
did you saw the timer0 in Atmega8a's datasheet?
it has not any PWM, Fast PWM or etc mode.
JohanEkdahl wrote:
It helps if you state the resolution you need for the frequency.

Slightly OT: 0 Hz is an interesting case.. :D


Oh, Johan! :wink:
1 or 2 hz resolution. :)
i'm really eager to see your program when you been a newbie! :lol:

@David
Well,
my program is this:
when i turn on the mcu,
1 LED should blink for each 2 second. if i push a button, an other LED should start to blink each 2 second for 7 minute(the first LED shoud turn off). after finishing 7 minute, a buzzer should hoot for three times and again return to first LED and starting to blink untill again push that button(i think it's better that i use an external interrupt).
other side, i want to connect a microswitch to six pin of MCU. by selecting each pin, the mcu should make a wave by 20% duty cycle.
pin1 = 17.5khz
pin2 = 6.5khz
pin3 = 700hz
pin4 = 10khz
pin5 = 4.5khz
pin6 = 7khz

other side, i want to make a wave with this range: between 0(or maybe it's better i say 1) to 50 hz(50% duty cycle).

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

Last Edited: Sat. Aug 24, 2013 - 07:24 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Really?
did you saw the timer0 in Atmega8a's datasheet?
it has not any PWM, Fast PWM or etc mode.

But it >>does<< have:
Quote:
14. 8-bit Timer/Counter0
14.1 Features
• Single Channel Counter
• Frequency Generator
• External Event Counter
• 10-bit Clock Prescaler

As with nearly all timer questions, you need to tell what is the speed of your AVR clock.

The 8-bit timer can "reach" 50Hz or a little slower with an 8MHz AVR clock. But not down to the 1Hz range. Not a problem, really, if the accuracy requirements are not strict. Use a relatively fast timer "tick" of 1ms, or even as fast as 100us. Make a "soft timer" by counting these ticks, and do the pin action when the soft timer expires.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:

But it >>does<< have:
Quote:
14. 8-bit Timer/Counter0
14.1 Features
• Single Channel Counter
• Frequency Generator
• External Event Counter
• 10-bit Clock Prescaler

As with nearly all timer questions, you need to tell what is the speed of your AVR clock.

The 8-bit timer can "reach" 50Hz or a little slower with an 8MHz AVR clock. But not down to the 1Hz range. Not a problem, really, if the accuracy requirements are not strict. Use a relatively fast timer "tick" of 1ms, or even as fast as 100us. Make a "soft timer" by counting these ticks, and do the pin action when the soft timer expires.


Aow! lee,
but, i couldn't found any output port for timer0(what's the mean of Frequency Generator in this case?). :(
how much the accuracy of the soft timer?
yeah, i use 8mhz.

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
But it >>does<< have:
Actually what it has is prescaler bits and an overflow interrupt. So, no, natively it can not produce an output. But for the frequencies you want it is not necessary. As Lee said, just count overflows at some predetermined rate and toggle the outputs manually.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You could even use a DDS technique and get sub Hz resolution.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Steve,
Yes, i would make it at first time(at first time). my problem is i can't find any formula for it!
for 50hz i should make interrupt for each 10ms but for low frequency, i don't know it's suit or not?
can i change the prescaler when use the timer0(is it correct?)?

Kartman wrote:
You could even use a DDS technique and get sub Hz resolution.

Thanks Kartman,
but master said to me that he can't add any IC or other component to circuit. :roll:

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Who said anything about adding ics? You can easily implement DDS in software.

Set up a timer in ctc mode to, say, 1kHz

In the isr

static unsigned int acc;

acc+= phase_inc;
If (acc & 0x8000) set output bit else clear output bit;

Vary the value of phase_inc to vary the frequency. Fout = 1000/2/(phase_inc/32768)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
Who said anything about adding ics? You can easily implement DDS in software.

Set up a timer in ctc mode to, say, 1kHz

In the isr

static unsigned int acc;

acc+= phase_inc;
If (acc & 0x8000) set output bit else clear output bit;

Vary the value of phase_inc to vary the frequency. Fout = 1000/2/(phase_inc/32768)


The timer0 has not ctc mode, russell!
also, i can do it by the timer2, but if i do it, i shoud make a RTC with the timer0. also, i think it's not wisely! is it? :roll:

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

From a brief glance of your 'requirements' it appears you want:
1. output 7kHz-17.5kHz on one pin
2. output 1Hz - 50Hz on one pin
3. blink LEDs on two pins
4. buzzer on one pin
5. six input switches.

You can do the whole of this with Timer1 and the COMPA, COMPB interrupts. And you can make the squarewaves jitter-free.

I count 11 GPIO pins. So you can even do this with a tiny2313. A tiny2313 can't do a 32kHz TOSC, but your mega8 can with Timer2.

TOSC with a watch crystal can make a RTC. However, if you are mains-operated, why not do the RTC with a regular 8MHz crystal?

Do you see how making a numbered list of requirements can explain your project? And suggest solutions too.

Of course, I might have missed something. e.g. 'another' output signal.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
1. output 7kHz-17.5kHz on one pin

also, 700hz-17.5kHz :wink:
david.prentice wrote:
You can do the whole of this with Timer1 and the COMPA, COMPB interrupts. And you can make the squarewaves jitter-free.

I count 11 GPIO pins. So you can even do this with a tiny2313. A tiny2313 can't do a 32kHz TOSC, but your mega8 can with Timer2.


Ok!
but, i need the 1-50hz with those six frequency Simultaneously. i think i should use two timer because, the timer1 just has one output.
david.prentice wrote:
TOSC with a watch crystal can make a RTC. However, if you are mains-operated, why not do the RTC with a regular 8MHz crystal?

How?
can i make it with timer0? if i can make a RTC with the timer0, it can solve many my problems.
david.prentice wrote:
Do you see how making a numbered list of requirements can explain your project?

O! i can't good know your this question, David.

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
but, i need the 1-50hz with those six frequency Simultaneously. i think i should use two timer because, the timer1 just has one output.

Sorry, i think i do a mistake in this case.

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That is why I wrote a numbered list. Did you want?

1. output 700Hz-17.5kHz on six pins

You can obviously produce this in software, but there will be a certain amount of jitter. And your frequencies will not be exact.

Why have you chosen an ATmega8 ?
The mega88PA has far better peripherals. In fact you should be able to have six perfect square waves on the six OCnx pins.

The 1Hz - 50Hz output can be done in software. There will be a certain amount of jitter but it will be insignificant at such low frequencies.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
1. output 700Hz-17.5kHz on six pins

Oh!, No David!
i want to make that six frequency on one pin. I want to choose each frequency with microswitch and see it on one out put.
now, i think i can make 1-50hz on the OC1A and make those six frequency on the OC1B! is it correct? can i?
and finally make RTC by timer2! :)

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

David,
if you were me, How do this job?
it's confused me. especially those six frequency!
i don't know how to make those with 20% duty and custom frequency!

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You want 17.5kHz with say F_CPU=8MHz.
You interrupt after 91 cycles high, 366 cycles low. e.g.
17.5kHz -> 91, 366
10.0kHz -> 169, 640
7.0kHz -> 229, 914
6.5kHz -> 246, 985
4.5kHz -> 356, 1422
700Hz -> 2286, 9143

You set your COM1Ax bits to toggle on match
So for your 6.5kHz ISR() :

ISR(TIM1_OCR1A_vect)
{
    static uint8_t high;
    high = !high;
    if (high) OCR1A += 356;
    else OCR1A += 1422;
}

If you are paranoid, you can specifically set COM1Ax bits for the next match. (or you start toggle at the correct value)

You can do yout 1Hz - 50Hz COMPB interrupt in a similar way. However, the SLOW frequencies like 1Hz wold need you to count for N interrupts before you set the next COM1Bx values.

It is simple enough. Calculate the appropriate number of cycles required, and hand trace with pencil and paper.
e.g. 1Hz squarewave is 4000000 cycles high, 4000000 cycles low. 60 IRQs don't change COM1Bx settings, 61th IRQ will change for next match.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To solve the probem I would look at something like this, that can be done on any micro, and you can use any port pins you want.

I would not use any automatic timer outputs but solve it all by one timer interrupt.
Since you want a duty of 20% duty cycle on 17.5KHz (the highest freq you want) I would make a 5 times that timer interrupt (I don’t care witch timer you use :) ), equ. to 87500Hz interrupt, and let that be the heart beat for the hole thing.
If in 17.5 KHz mode make your port pin high in 1 out of every 5 interrups. (you can look at it as a DDS with a factor of 1).
If you want to make the 10KHz you use a factor of 10/17.5 = 0.5714… for a 8 bit DDS it would be add 146, and go to next step every time we run over. That will give 9980 Hz).
7KHz use 102 (give 6972 Hz)
6.5Khz use 95 (give 6494Hz)
…
…
700Hz use 10 (give 684 Hz).

If you use a 16 bit DDS the freq will be with in 1 Hz , (I don’t know what you need).
Eks.
700Hz use 2621 (give 699,88 Hz).

Now for the 1 to 50 Hz here you will need a 16 bit DDS, but since you want 50% duty cycle the update is simple just toggle your output pin.
This code you can call either wit 87500 Hz , or 17500 Hz (depending where in the code you place it).
Here I use the 17500Hz for the numbers.
For 50Hz you want to toggle the pin with 100Hz, that would be a DDS update of 374 (give 99,868 HZ toggle = 49,93 Hz).
To count the numbers use that a update of 1 give 0.2670288 Hz , so 10 give 2.2670288Hz etc.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi every Body ,
I know That maybe I'm in wrong topic to ask this question.I'm sorry , But I'm New in AVR and I want to work with software Capture Timer 1 ( not whit icp Pin hard wary) in mega 16. I don't know what is the instruction for it. I have read the data sheet but I couldn't get it.Please give the clear and simple example
Thank for your helping

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

maybe I'm in wrong topic to ask this question

No sh*t?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
Slightly OT: 0 Hz is an interesting case.. :D

The unit Hz cannot be written behind a 0, because zero vibration.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Especial thanks to dear David and dear sparrow2! :D
now, i have a small question:
How can i turn off or turn on timer1? by CS10,1,2?(i want to control turn on or turn off the timer) if yes, is it necessary that i configure the timer1 again?

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can stop the timer running with (0<<CS10)
You can start again with (1<<CS10) or other divider.

You have to stop the timer with my hardware method (i.e. COMnx bits).
If you use the software method of simply setting pins in an ISR(), you can leave the timer running but just disable interrupts.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
You can stop the timer running with (0<<CS10)
You can start again with (1<<CS10) or other divider.

O! David,
i set the prescaler to 8 divider, means, the 0<<CS10 is 0.
david.prentice wrote:
You have to stop the timer with my hardware method (i.e. COMnx bits).
If you use the software method of simply setting pins in an ISR(), you can leave the timer running but just disable interrupts.

i think it's better that i set the COMnx bits because i just want to disconnect the the OCX pin.

Thank you David! :)

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can stop the timer running with (0<<CS10)
You can start again with (2<<CS10) for div8.

If you want to 'disconnect' the OCnx pins, you can just set the DDR to input.

Explain exactly what you want to do.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
You can stop the timer running with (0<<CS10)
You can start again with (2<<CS10) for div8.

If you want to 'disconnect' the OCnx pins, you can just set the DDR to input.

Explain exactly what you want to do.

David.


David,
i just want to disconnect the OCnx pin(in other word, i don't want that the timer product wave on the pin.).
then i use the DDR register. i think it's suitable.
Thanks :wink:

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

David,
i have a C/C++ book. i saw at it for this part of your code but i can't know it :(
can you explain to me these two line?

high = !high;
if (high) OCR1A += 356;

i can't know, what does the two line do?

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
 high = !high;
if (high) OCR1A += 356;

'high' is just a boolean variable. It alternates between 0 and 1. (false and true)

From memory, I either add 356 or 1424. i.e. 20% high and 80% low. This makes your 20% duty cycle.

Note that nothing happens immediately. It just sets the conditions for the 'next' match.
If you do the maths with uint16_t arithmetic, the match still works correctly even if you roll over zero.

Whenever you find an 'unusual' sequence of code, just hand-trace it with paper and pencil. Believe me. Even clawson or johanekdahl will use a pencil to trace code.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Excellent David, Thank you.
unfortunately, i have problem for work by Comparison operators/relational operators, Logical operators, Bitwise operators and Compound assignment operators. :( i don't know how to solve this problem!
also, i think i'm not alone. i think many newbie and beginner have problem with these operators.
how you solve this problem?
i wrote my code. look:

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 

#include 

volatile bit L=0, A=0, C=1, B=0;
volatile int second=0, minute=0, x=0;
volatile unsigned int R, S=0, i=0, z=0, j=0, D=0, Fl, Fh;

#define ADC_VREF_TYPE 0x40

// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Reinitialize Timer 0 value
    TCNT0=0x9B;
    R =  read_adc(0);
    R = (R*50)/1024;
    D = 10000/(R*2);
    if(D==S && D>=1){
	    if(D==(i+1)){
		    i=0;
		    if(PORTB.3==0){
			    PORTB.3 = 1;
		    } else {
			    PORTB.3 = 0;
		    }
	    } else {
		    i++;
	    }
    } else {
	    D=S;
	    i=0;
    }
    if(0<=R<=15){
	    PORTC.2 = 1; PORTC.3 = 0; PORTC.4 = 0; 
    }
    if(0<=R<=15){
	    PORTC.2 = 0; PORTC.3 = 1; PORTC.4 = 0; 
    }
    if(0<=R<=15){
	    PORTC.2 = 0; PORTC.3 = 0; PORTC.4 = 1; 
    }// Place your code here

}

// Timer1 overflow interrupt service routine
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
    if(j==2){
	    if(z==3){
		    PORTB.1 = 1;
		    z=0;
	    } else{
		    z++;
		    PORTB.1 = 0;
	    }
	    j=0;
    } else {
	    j++;
    }
    OCR1AH = Fh;
    OCR1AL = Fl;
// Place your code here

}

// Timer2 overflow interrupt service routine
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
    if(A==1){
	    if(second==59){
		    second=0;
		    if(minute==7){
			    minute=0;
			    A=0;
			    C=0;
			    B=1;
		    } else {
			    minute++;
		    }
	    } else {
		    second++;
		    if(L==1){
			    PORTB.4 = 1;
		    } else {
			    PORTB.4 = 0;
		    }
		
	    }
	    if (L==0){
		    L=1;
	    } else {
		    L=0;
	    }
	    if(B==1){
		    if(L==1){
			    PORTB.5 = 1;
		    } else {
		    	PORTB.5 = 0;
		    }
		    if(x==5){
		    	x=0;
		    	B=0;
		    	PORTB.5 = 0;
		    }
		    x++;
	    }	
    }

}

void main(void)
{

PORTB=0x00;
DDRB=0x3A;

PORTC=0x00;
DDRC=0x1E;

PORTD=0x00;
DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 1000.000 kHz
TCCR0=0x02;
TCNT0=0x9B;

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

// Timer/Counter 2 initialization
// Clock source: TOSC1 pin
// Clock value: PCK2/128
// Mode: Normal top=0xFF
// OC2 output: Disconnected
ASSR=0x08;
TCCR2=0x05;
TCNT2=0x00;
OCR2=0x00;

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

// ADC initialization
// ADC Clock frequency: 125.000 kHz
// ADC Voltage Reference: AVCC pin
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x86;
// Global enable interrupts
#asm("sei")

while (1)
      {
      if(PIND.6==1){
	        DDRB.1 = 1;
            PORTC.1 = 0;
            if(C==1){
	        A=1;
            }
            if(PIND.0==1){
	            Fh=0x00;
	            Fl=0X5B;
	            j=2;
                }
            if(PIND.1==1){
	            Fh=0x00;
	            Fl=0xA0;
	            j=2;
                }
            if(PIND.2==1){
	            Fh=0x00;
	            Fl=0xE4;
	            j=2;
            }
            if(PIND.3==1){
	            Fh=0x00;
	            Fl=0xF6;
	            j=2;
            }
            if(PIND.4==1){
	            Fh=0x01;
	            Fl=0x63;
	            j=2;
            }
            if(PIND.5==1){
	            Fh=0x02;
	            Fl=0xF9;
            }
      } else{
	        DDRB.1 = 0;
            PORTB.4 = 0;
            C = 1;
            if(L==1){
	            PORTC.1 = 1;
            } else
            {
	            PORTC.1 = 0;
            }
      }

      }
}

what's your opinion about it?
if you want to suggest me for change some part, what do say?

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm not sure but, i think i did mistake in my code. :roll:

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think that you need to make lots of corrections to your code.

1. choose descriptive names for your variables.
2. add explanatory comments in English (or Farsi)
3. learn about Boolean logical operators.
4. use active-low push buttons.

You should spend some time writing an English description of what you want your program to do.

This would benefit you, and make your readers help you.

Incidentally, it is easier to just use OCR1A in an expression than to use its two 'halves' OCR1AL, OCR1AH. And sometimes a decimal number is easier to understand than a hexadecimal number.

Always use code that is simple and easy to understand. For example, I would use Timer interrupts but check push-buttons in the foreground code.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was bored. So I wrote this:

/*
* rohalamin_cv.c
*
* Created: 28/08/2013 13:24:31
* Author: David Prentice
*/

#include 
#include 
#include 

#define F_CPU _MCU_CLOCK_FREQUENCY_

volatile uint16_t highcnt, lowcnt, togglecnt, toggleovfs;

interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
	static uint8_t high;
	high = !high;
	if (high) {
		TCCR1A &= ~(1<<COM1A0);	// low on match
		OCR1A += highcnt;
		} else {
		TCCR1A |= (1<<COM1A0);	// high on match
		OCR1A += lowcnt;
	}
}

interrupt [TIM1_COMPB] void timer1_compb_isr(void)
{
	static uint8_t high, ovfs;
	if (ovfs > 0) {             // low frequencies have uint32_t counts
		ovfs--;
		return;
	}
	high = !high;
	if (high) {
		TCCR1A &= ~(1<<COM1B0);	// low on match
		} else {
		TCCR1A |= (1<<COM1B0);	// high on match
	}
	OCR1B += togglecnt;         // ready for next cycle
	ovfs = toggleovfs;
}

/*
17.5kHz -> 91, 366
10.0kHz -> 169, 640
7.0kHz -> 229, 914
6.5kHz -> 246, 985
4.5kHz -> 356, 1422
700Hz -> 2286, 9143
*/
uint16_t freqsduty[] = { 700, 4500, 6500, 7000, 10000, 17500};

void main(void)
{
	uint8_t freqindex = 0;       //which 20% duty frequency from list
	uint16_t freqtoggle = 50;    //what 1Hz-50Hz 50% duty frequency
	uint32_t count = 0L;         //temp variable
	DDRB |= (1<<1)|(1<<2);	     //OC1A, OC1B as outputs
	PORTD |= (1<<5)|(1<<4)|(1<<3)|(1<<2);	// pull-ups on PD2-PD5
	TCCR1A = (1<<COM1A1)|(1<<COM1B1);	// OC1A low on match,  OC1B low on match
	TCCR1B = (1<<CS10);	         //div1
	TIMSK |= (1<<OCIE1A)|(1<<OCIE1B);  //both compare interrupts
	#asm("sei");
	while (1)
	{
		// Please write your application code here
		if (count == 0 || PIND.2 == 0 || PIND.3 == 0 || PIND.4 == 0 || PIND.5 == 0) {
			if (PIND.2 == 0 && freqindex < 5) freqindex++;
			if (PIND.3 == 0 && freqindex > 0) freqindex--;
			if (PIND.4 == 0 && freqtoggle < 50) freqtoggle++;
			if (PIND.5 == 0 && freqtoggle > 1) freqtoggle--;
			highcnt = F_CPU/5/freqsduty[freqindex] - 1;
			lowcnt = (F_CPU * 4)/5/freqsduty[freqindex] - 1;
			count = F_CPU/2/freqtoggle - 1;  // non-zero after first loop
			togglecnt = count & 0xFFFF;
			toggleovfs = count >> 16;
			delay_ms(100);                   // allow one button press
		}
	}
}

Untested. The 20% should be on PB1, the 50% on PB2
Pushbuttons on PD2-PD5 should select UP or DOWN.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

WoOoW!!
you surprised me, David. :)
Thank you.

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!