Timer2 Serial Example

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

I have created a mini-project using the arduino uno via COM3 to test clocking time/per second. I am outputting at a much faster rate then anticipated but i believe that is because the Arduino's 16Mhz crystal. Would I have to de-solder the 16Mhz and utilize a 32khz crystal or is there a way to utilize XTAL1/2 on the board itself? I attempted use of F_CPU but no luck as I believe that would only effect Timer0?

 

/*variables*/
volatile unsigned char hours = 0;
volatile unsigned char minutes = 0;
volatile unsigned char seconds = 0;

void setup()
{
  Serial.begin (9600);

  TCCR2A = 0;                                                   // Timer/Counter Control Register A
  TCCR2B = 0;                                                   // Timer/Counter Control Register B
  TCNT2 = 0;                                                    // Timer/Counter Register

  OCR2A = 124;                                                  // Set compare match register for 32 Hz increments: 32000 / (8 * 32) - 1 (must be <256)
  TCCR2B |= (1 << WGM21);                                       // Configure timer 2 for CTC mode
  TCCR2B |= (1<<CS22)|(1<<CS20);                                // Set CS22, CS21 and CS20 bits for 128 prescaler
  ASSR = (1 << AS2);                                            // Enable asynchronous operation
  TIMSK2 |= (1 << OCIE2A);                                      // Output Compare Match A Interrupt Enable

  sei();                                                        // Enable global interrupts
}

void loop()
{
  Serial.print(hours);
  Serial.print(":");
  Serial.print(minutes);
  Serial.print(":");
  Serial.print(seconds);
  Serial.println("");
}

//The 32.686kHz interrupt handler
ISR(TIMER2_COMPA_vect)
{
  if(seconds < 60)
  {
    seconds++;
    if( seconds > 59)
    {
      seconds = 0;
      minutes++;
      if(minutes > 59)
      {
        minutes = 0;
        seconds = 0;
        hours++;
        if(hours > 23)
        {
          hours = 0;
          minutes = 0;
          seconds = 0;
        }
      }
    }
  }
}

 

This topic has a solution.
Last Edited: Wed. Sep 23, 2020 - 01:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you desolder the 16MHz crystal/resonator, you'll create way more problems for yourself.

 

Arduino has the millis() function. Write code to determine when a second has elapsed and update your time variables. Or use an external RTC ic/board.

 

Unfortunately, the mega328 can't have a 32kHz crystal and 16MHz crystal at the same time - if you want this, then go to a mega board that has a mega2560 chip.

 

Note: F_CPU doesn't determine the actual frequency! It has to be set correctly (ie per crystal frequency and fuse settings) and is used by various software functions to determine the operation frequency.

 

 

 

 

Last Edited: Sun. Sep 20, 2020 - 05:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If I decide to create a standalone, I would use TOSC1/2 pins for the 32khz crystal instead correct? Then set the uC fuses via avrdude?

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

Why do you need to add a crystal when the AVR is full of timers?  You can use them to generate any timing you want that is slower than the fastest clock tick.

What are you trying to do with timing?  Here are some tutorials

 

https://exploreembedded.com/wiki...

 

https://www.electroschematics.co...

 

https://www.avrfreaks.net/forum/...

 

 

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

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

'standalone' as in not using Arduino code? You'd probably do it much like the Arduino code does millis() in using a timer to give you a regular clock tick. 

 

As to using TOSC1/2 pins - depends on your application. If you are using serial, then you'd want to use a higher frequency crystal like the Arduino.

 

You've still not told us what you want to achieve. 

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

Kartman wrote:
Unfortunately, the mega328 can't have a 32kHz crystal and 16MHz crystal at the same time - if you want this, then go to a mega board that has a mega2560 chip.

RProietto wrote:
I have created a mini-project using the arduino uno via COM3

Surely with that many USARTS this must already be ATmega2560.

 

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

The Arduino code (specifically in wiring.cpp) configures the timers for use in Arduino functions such as millis(), micros() and delay() as well as the ADC channels.

 

I've found that this code seems to "mess up" the timers, even if I reprogram the TCCRxx registers myself.

 

What I do is, instead of using the stupid "setup" and "loop" thing, I just use int main(void).

 

This bypasses all the junk that Arduino code does such as programming the timers and setting the ADC inputs.

 

To call that code the way Arduino does, you use init(); at the beginning of your program. Otherwise, the analog inputs, millis and micros timers and delay will not work. Serial also will not work, but that it due solely to interrupts not being turned on. To use serial, simply put sei(); before the Serial.begin (baudrate); call (or after - doesn't matter - but serial won't work until you do an sei();)

 

Another thing... your program MUST end with while (1); (an endless loop) because Arduino is not an operating system... there's nowhere to exit TO. If you forget that, you will find that print statements may only print a few characters, then stop.

 

Here's a short example how to use Arduino without setup/loop... it's nicer this way because you have full control and no surprises:

 

// encoder test

volatile uint8_t state;
volatile int32_t position;

#define ENC_A (1 << 0) // encoder A (on PORTD)
#define ENC_B (1 << 1) // encoder B (on PORTD)
#define ENC_P (1 << 2) // encoder button (on PORTD)

#define ENC_OUT PORTD // encoder on port D
#define ENC_INP PIND
#define ENC_DDR DDRD

// int0 is PORTD, bit 0
ISR (INT0_vect)
{
	updEncoder();
}

// int1 is PORTD, bit 0
ISR (INT1_vect)
{
	updEncoder();
}

void updEncoder (void)
{
	state >>= 2;
	state |= (ENC_INP & ENC_A) ? 0b0100 : 0;
	state |= (ENC_INP & ENC_B) ? 0b1000 : 0;

	switch (state) {
		case 1: case 7: case 8: case 14: {
			position += 1;
			break;
		}
		case 2: case 4: case 11: case 13: {
			position -= 1;
			break;
		}
		default: {
			break;
		}
	}
}

int32_t readEncoder (void)
{
	int32_t val;
	cli();
	val = position;
	sei();
	return val;
}

void writeEncoder (int32_t val)
{
	cli();
	position = val;
	sei();
}

int main (void)
{
	int32_t oldval, newval;

	sei();
	Serial.begin (115200);

	ENC_OUT |= (ENC_A | ENC_B); // encoder input_pullup
	ENC_DDR &= ~(ENC_A | ENC_B);

	EICRA |= (1 << ISC00); // any edge int0
	EICRA |= (1 << ISC10); // any edge int1
	EIMSK |= ((1 << INT1) | (1 << INT0)); // enable int1 and int0

	writeEncoder (0); // "init" encoder

	while (1) { // note this is the endless loop
		newval = readEncoder();
		if (oldval != newval) {
			oldval = newval;
			Serial.print ("Encoder: ");
			Serial.print (newval);
			Serial.print ("\r\n");
		}
	}
}

 

Hope this helps.

 

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

Last Edited: Sun. Sep 20, 2020 - 09:55 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Krupski wrote:
all the junk (sic) that Arduino code does

Surely, the point and raison d'etre of Arduino is precisely that it does this stuff for you, so that you don't have to?

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For closure, I meant standalone as in an Atmega328 on breadboard with a 32khz crystal attached to pins XTAL1/2.
Currently in my code, the timer counts “seconds” which seem to spew out in the serial log in what appears as milliseconds. This is because I’m using the Arduino.
What I am asking is, if I put the Uc and 32khz crystal on breadboard would that resolve my problem? I tested this and it appears to not.

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

So I decided, to try to blink an LED with a32khz timer and I couldnt figure that out even. What am I not understanding about using this 32khz timer??? I am using breadboard with the following:

 

  • Atmega328 uC
  • 32 khz crystal with two 22pF caps to GND
  • LED connected to digital pin 13 of uC
  • 10K resistor to pin 1 uC

 

#ifdef F_CPU
#undef F_CPU
#define F_CPU 32768UL
#endif

int led = 13;

void setup() 
{
  pinMode(led, OUTPUT);
}

void loop()
{
    digitalWrite(led, HIGH); 
    delay(1000);
    digitalWrite(led, LOW); 
    delay(1000);
}

 

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

I don't get it  - if you have a timer interrupt and the period is too short why don't you simply count "events" until they add up to the timebase you are trying to use? You seem to be expecting timer2 to "tick" at exactly 1 second period but say it's 1/8s because F_CPU is too high then just count to 8 *then* increment the seconds count.

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

RProietto wrote:

For closure, I meant standalone as in an Atmega328 on breadboard with a 32khz crystal attached to pins XTAL1/2.

So what's this COM3 you confused us with in #1 ?

 

RProietto wrote:
What am I not understanding about using this 32khz timer???

The 32kHz watch crystal option is meant for clocking "8-bit Timer/Counter2 with Asynchronous Operation" But because ATmega328 only has one set of crystal pins, the only option to run the CPU at a decent/usable speed is to clock it from the Internal 8MHz RC Oscillator.

 

You'll have a much easier time of this if you swap to a MEGA type Arduino with ATmega2560 which has two sets of crystal pins. You can therefore leave the 16MHz crystal in place so that the Arduino Core runs correctly.

 

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

RProietto wrote:
32 khz crystal with two 22pF caps to GND

Watch xtals do not use the caps!

 

How are you loading your sketch?  Did you remove the M328 from an UNO, or did you purchase a bare M328, from a major distributor (digikey/mouser/farnel) or ebay/aliexpress?

What fuse settings are you using, and does the chip have a bootloader?

 

Jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

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

Hey, I was reading the atmega328 manual and saw that the caps were not needed as well for a crystal oscillator. As for my breadboard, I currently have the Atmega328P with a 10K resistor to pin1 and the 32Khz crystal to XTAL1/2. In regards to the uC, I also learned reading the manual that I can set the fuse bits to use the internal RC 8Mhz clock. I set the fuses using avrdude via usbTiny. I am currently attempting to sec Timer2 up properly to tick every 1 Seconds to match that of my ISR I have mentioned in my original code. I am currently reading about Timer2 Registers but am confused. I will come back once I learn a little more. So far I have the following for Timer2 settings..

 

I am confused as to why some people say that TCCR2B = (1<<WGM12) is incorrect and even in the user manual is says to use WGM21... However, I guess i just dont understand that part yet.

  TCCR2A = 0;                                                   // set entire TCCR2A register to 0
  TCCR2B = 0;                                                   // same for TCCR2B
  TCNT2  = 0;                                                   //initialize counter value to 0
  
  ASSR = (1 << AS2);                                            // Enable asynchronous operation
  TCCR2B = (1<<WGM12);                                          // Configure timer 2 for CTC mode
  TCCR2B |= (0 << CS22) | (1 << CS21) | (1 << CS20);            // Set CS22, CS21 and CS20 bits for 32 prescaler
  OCR2A = 249;                                                  // = 8000000 / (32 * 1000) - 1 (must be <256)
  TIMSK2 |= (1 << OCIE2A);                                      // Enable CTC interrupt

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So i figured out my problem! I'll post it here for any newbies that come by like myself. I learned via reading the data sheet that if use a 32khz crystal I can set a prescaler to lower the number to fit within the OCR register for the 8-bit timer. Thus, I used a prescaler of 256 which leaves me at 125 ticks and a remainder of 125 for the OCR which will fit! Therefore, I enable ASSR AS2 to enable asynchronous operation to utilize the 32khz crystal. With CTC mode set, I will generate a 1 second interrupt! After reading through the datasheet 20+ times and highlighting the heck out it (it bled through the back of the pages i printed). I learned something...

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

Are you using a 32kHz crystal or the more common 32768Hz watch crystal? 32768 is a 'nice' binary number (2^15) so a prescale of 256 should give you a OCR value of 127 (128-1).

 

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

I am using a 32kHz crystal, but thanks for bringing that to my attention.

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

RProietto wrote:
I am using a 32kHz crystal

Oh really - that very specialised.

 

Just had a quick look at Crystal Selectors - Yes indeed there are 32000Hz variants available:

 

Here a table of number of parts available.

 

  32768Hz 32000Hz
Farnell 437 5
Mouser 686 7

 

You did very well to find a 32000Hz variant.