I have used this FAST PWM mode to trigger two interrupt service routines.
The timer compares register A sets the frequency.
I have not enabled the output compare pins. since it was used by some other peripheral. So by doing this, I generate a PWM signal by issuing a command in the ISR.
/*
* main.c
*
* Created: 10 July 2023 10:47:23 PM
* Author: abhay
*/
#define F_CPU 16000000
#include <xc.h>
#include <stdio.h>
#include "util/delay.h"
#include <avr/interrupt.h>
#include "uart.h"
#define LED_ON PORTB |= (1<<5)
#define LED_OFF PORTB &= ~(1<<5)
// 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(TIMER3_COMPA_vect){
PORTD |= (1<<6);
}
ISR(TIMER3_COMPB_vect){
PORTD &= ~(1<<6);
}
int main(void)
{
USART_Init();
// Redirect stdout stream to UART
stdout = &uart_output;
DDRB |= (1<<5); // set Data direction to output for PB5
LED_OFF; // set output to high
DDRD |= (1 << 6); //set PD6 as output
/*
F_CPU = 16000000
Prescaler = 64
Frequency = 50Hz
Period = 0.020 s
step time = 1/(F_CPU/Prescaler) = 0.000004 s
number of steps = 0.020/0.000004 = 5000
*/
TCNT3 = 0; // Timer counter initial value = 0
// Output Compare A value = 5000 or 20 Milli second
OCR3A = 5000;
// Output Compare B value = 500 or 2 Milli second
OCR3B = 500;
// Fast PWM
TCCR1A |= (1 << WGM31)|(1 << WGM30);
// Prescaler: 64
TCCR3B |= (1 << WGM32)|(1<<WGM32)|(1 << CS31)|(1 << CS30);
// Enable Timer Interrupt for Overflow, Compare match A and Compare Match B
TIMSK3 |= (1 << OCIE3B)|(1 << OCIE3A)|(1<<TOIE3);
// Enable Global Interrupt
sei();
while(1)
{
OCR3B = 250;//5% 1ms
_delay_ms(500);
OCR3B = 375;//7.5% 1.5ms
_delay_ms(100);
OCR3B = 500;//10% 2ms
_delay_ms(500);
}
}
Leave a Reply