Reputation: 21
I managed to create a perfect square wave by using 8-bit timer2 in atmega88 running @ 16MHz. I also managed the change the OCR2A in the code and change the frequency of the signal as expected. I checked everything with oscilloscope and no problem there.
However, I want to change the OCR2A (i.e. change the frequency) by sending one byte data to the Atmega via USART. When I do that I observe seemingly random frequency change.
I am using Cutecom in HEX mode and I also added a piece of code to check whether the data byte received is correct. (Toggle a LED if the received byte is 40). It shows that data received correctly. I also avoid using timer based delays function and timer0; I am using timer2 (and software delay function (_delay_ms) if I have to).
But, still cannot succeed. The original usart_receive function returned unsigned char, it did not work either.
Initial value of the OCRA is 38 and it produces perfect wave at 3205 Hz as expected. When I send 40 serially (0x28) the LED blinks confirming that the decimal 40 received. The frequency changes not to 3048 Hz as expected but to some strange value. When I send 38 (0x26) to atmega again, it does not go back to the initial frequency (i.e. 3205 Hz). (disregard blink function in the code).
Any help will be highly appreciated.
#include <avr/io.h>
#include <util/delay.h>
#include <stdbool.h>
#define FOSC 16000000 // Clock Speed
#define BAUD 19200
#define MYUBRR FOSC / 16 / BAUD - 1
#define CLR(x, y) (x &= (~(1 << y)))
#define SET(x, y) (x |= (1 << y))
#define maxOCR2A 255
#define minOCR2A 15
#define waitTime 20
int USART_Receive(void);
void USART_Init(unsigned int ubrr);
void blink(char x);
void loop(void);
int main()
{
USART_Init(MYUBRR);
// led
DDRB |= _BV(PORTB0);
blink(3);
// OC2A pin
DDRB |= _BV(PORTB3);
_delay_ms(150);
TCCR2B = 0; // reset timer 0 control registers
TCCR2A = 0;
// Toggle OC0A on compare match, (CTC)
TCCR2A = (1 << COM2A0) | (1 << WGM21);
// Start the timer, x prescalar
TCCR2B = (1 << CS22); // | (1 << CS20); // prescale 64
// TCCR0B = (1 << CS01); // prescale 8
OCR2A = 38;
loop();
}
void loop(void)
{
int t;
while (true)
{
t = USART_Receive();
if(t == 40) PORTB ^= _BV(PORTB0);;
TCNT2 = 0;
OCR2A = t;
}
}
int USART_Receive(void)
{
/* Wait for data to be received */
while (!(UCSR0A & (1 << RXC0)))
;
/* Get and return received data from buffer */
return UDR0;
}
void USART_Init(unsigned int ubrr)
{
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr >> 8);
UBRR0L = (unsigned char)ubrr;
/* Enable receiver and transmitter */
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
/* Set frame format: 8data, 1stop bit */
UCSR0C = ((1 << UCSZ01) | (1 << UCSZ00));
}
void blink(char x)
{
for (char i = 0; i < x; i++)
{
SET(PORTB, PORTB0);
_delay_ms(200);
CLR(PORTB, PORTB0);
_delay_ms(200);
}
}
Upvotes: 0
Views: 48
Reputation: 21
Solved it by replacing usart_receive with interrupt version.
ISR(USART_RX_vect)
{
PORTB ^= _BV(PORTB0);
OCR2A = UDR0;
}
Upvotes: 0