ATmega328PB 16-bit Timer TC1 – CTC Mode

Posted

in

by

Timers are essential components in microcontrollers that allow precise timing and synchronization for various applications. The ATmega328PB microcontroller offers several timer/counters, including Timer/Counter 1 (TC1), which is a 16-bit timer with advanced features. In this blog post, I will explore how to utilize Timer 1 in CTC (Clear Timer on Compare Match) mode on the ATmega328PB microcontroller.

Hardware Setup

Before we proceed with the code, ensure you have the necessary hardware setup. You will need an ATmega328PB microcontroller, a 16MHz crystal oscillator, and any additional components required for your specific application. Connect the crystal oscillator to the XTAL1 and XTAL2 pins of the microcontroller to provide a stable clock signal.

UART Communication Initialization

In this example, we will utilize UART communication for debugging or output purposes. Make sure you have already implemented the necessary UART functions or library. The UART initialization code should include setting the baud rate, enabling the transmitter and receiver, and configuring the data format (e.g., number of data bits, parity, and stop bits). We will also redirect the stdout stream to the UART using the stdio.h library, allowing us to use the printf function for UART output.

Timer 1 Configuration in CTC Mode

Let’s dive into the code and configure Timer 1 in CTC mode. Here’s an example code snippet:

/*
* main.c
*
* Created: 7/9/2023 12:47:23 AM
*  Author: abhay
*/
#define F_CPU 16000000

#include <xc.h>
#include <stdio.h>
#include "util/delay.h"
#include <avr/interrupt.h>
#include "uart.h"

// Function to send a character via UART
int UART_putchar(char c, FILE *stream) {
	if (c == '\n')
	UART_putchar('\r', stream);  // Add carriage return before newline
	while (!(UCSR0A & (1 << UDRE0))); // Wait for the transmit buffer to be empty
	UDR0 = c; // Transmit the character
	return 0;
}

// Create a FILE structure to redirect the printf stream to UART
FILE uart_output = FDEV_SETUP_STREAM(UART_putchar, NULL, _FDEV_SETUP_WRITE);
ISR(TIMER1_COMPA_vect){
	printf("2. compare match A\n");
}
ISR(TIMER1_COMPB_vect){
	printf("1. compare match B\n");
}
int main(void)
{
	USART_Init();
	// Redirect stdout stream to UART
	stdout = &uart_output;
	DDRB |= (1<<5);	// set Data direction to output for PB5
	PORTB |= (1<<5); // set output to high
	/*
	* Timer 1 
	* Mode of operation : CTC
	*		When Output Compare A register value equals the 
	*		Timer Counter register (TCNT1) it resets the Timer-Counter-register value
	*		and generates a interrupt. 
	* Only OCR1A will reset the timer counter. 
	* OCR1B can be used to generate a compare match between TCNT1 = 0 and OCR1A
	*
	*/
	TCNT1 = 0;		// Timer counter initial value = 0
	OCR1BH = 0x3D;	// Output Compare B value = 0x3d09 or 1 second
	OCR1BL = 0x09;
	OCR1AH = 0x7a;	// Output Compare A value = 0x7a12 or 2 second
	OCR1AL = 0x12;
	TCCR1B |= (1<<WGM02)|(1 << CS12)|(1 << CS10);	// CTC Prescaler: 1024
	TIMSK1 |= (1 << OCIE1B)|(1 << OCIE1A)|(1<<TOIE1);
	
	sei();	// Enable Global Interrupt
	while(1)
	{

		
		printf("  This is Main:\n");
 		_delay_ms(2500);
	
		//TODO:: Please write your application code
		
	}
}

In this code snippet, we first initialize the UART communication and redirect the stdout stream to the UART output using the FDEV_SETUP_STREAM macro. The UART_putchar function is used to send a character via UART, ensuring that newline characters (\n) are preceded by a carriage return character (\r) for proper line endings.

Next, we configure Timer/Counter 1 (TC1) for CTC mode and set the prescaler to 1024, which divides the clock frequency to generate a suitable timebase. The TCCR1A and TCCR1B registers are set accordingly.

We then set the compare values (OCR1A and OCR1B) to determine the time intervals at which we want to generate interrupts. In this example, OCR1A is set for 2 second delay, and OCR1B is set for approximately 1 seconds delay.

Finally, we enable the Timer/Counter TC1 compare match interrupts (OCIE1A and OCIE1B) using the TIMSK1 register, and we enable global interrupts with the sei() function.

Interrupt Service Routines (ISRs)

The code snippet defines two Interrupt Service Routines (ISRs): TIMER1_COMPA_vect and TIMER1_COMPB_vect. These ISRs will be executed when a compare match occurs for Output Compare A and Output Compare B, respectively. In this example, we use these ISRs to print messages to the UART output. You can modify these ISRs to perform any desired actions based on your specific application requirements.

Putting It All Together

Once you have set up the UART communication, configured Timer 1 in CTC mode, and defined the necessary ISRs, you can utilize the precise timing capabilities of Timer 1 in your main program loop. Use the printf function to output information via UART, and the compare match interrupts will handle the precise timing events.

while (1) {
   printf("  This is Main:\n");
 		_delay_ms(2500);
    // Additional code and operations
    // ...
}

In the above example, the main program loop will execute continuously, printing “This is the main program loop” every 1 second using the printf function. The _delay_ms function provides a delay of 2500 milliseconds (2.5 second) between each iteration of the loop.

Conclusion

Utilizing Timer 1 in CTC mode on the ATmega328PB microcontroller provides precise timing capabilities for various applications. By configuring Timer 1, setting compare match values, and utilizing compare match interrupts, you can achieve accurate timing control in your embedded systems. When combined with UART communication, you can easily monitor and debug your code by printing relevant information via the UART interface.

Remember to consult the ATmega328PB datasheet and relevant documentation for more details on Timer 1, CTC mode, and other timer features. Ensure that you have correctly configured your hardware setup, including the crystal oscillator and UART connection, to match the code requirements.

Using Timer 1 in CTC mode

with UART communication opens up a range of possibilities for precise timing and debugging capabilities in your projects. Experiment with different compare match values and integrate this functionality into your applications to enhance timing accuracy and control.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *