This demonstrates generating of Arbitrary waveforms including sine waves on a microcontroller.
It uses a wave lookup table, PWM and a low pass filter to make decent waveforms.
#define F_CPU 110000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
void setpwm(unsigned char x){
if(!x){TCCR0A &= ~ (1<<COM0B1);}
else {TCCR0A |= (1 << COM0B1);}
OCR0B = x;
}
int main(){
uint8_t tkr = 0;
static uint8_t PROGMEM lookup[64] = {
0x10, 0x11, 0x13, 0x14, 0x16, 0x17, 0x18, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1E,
0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A,
0x18, 0x17, 0x16, 0x14, 0x13, 0x11, 0x10, 0xF, 0xD, 0xC, 0xA, 0x9, 0x8, 0x6,
0x5, 0x4, 0x3, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x3,
0x4, 0x5, 0x6, 0x8, 0x9, 0xA, 0xC, 0xD, 0xF};
DDRB = 0x1A & ~_BV(PB3);
int CB = 0;
PORTB = 0x10 | _BV(PB3);
TCCR0A |= (1<<WGM00) | (1<<WGM01);
TCCR0B |= (1<<WGM02) | (1<<CS00);
OCR0A = 0x20;
while(1){
setpwm(pgm_read_byte(lookup +tkr));
tkr++;
if(tkr > 64){tkr = 0;}
//_delay_us(20);
}
}
This generates about a 60hz sine wave on PB1 with a 128khz clock
Changing the lookup table as follows (as well as change the 64 to a 16) results in a saw tooth wave:
static uint8_t PROGMEM lookup[18] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15};
The filter is just a dead simple RC low pass filter.
I used 2.2K with .56uf but change this based on operating frequency.