Generate sine wave modulated PWM with AVR microcontroller

This example will show how ease can sinewave modulated PWM modulated using an AVR microcontroller and a few code lines. For this example, I used Atmega8 MCU. All project is set up in VMLAB simulator.

To achieve this, I saved a sinewave lookup table in a Program memory (don’t forget to include interrupt.h header file):

const uint8_t sinewave[] PROGMEM= //256 values {0x80,0x83,0x86,...};

PWM is generated by using Phase and frequency correct PWM using a 16-bit timer in Atmega8. Modulation is done by updating the OCR1A value with one from the sinewave table when comparing matches.

Reading from flash program memory is done simply:

OCR1A=pgm_read_byte(&sinewave[i]);

The line above is placed inside the output compare interrupt for OCR1A service routine.

Resulting signal in scope simulator:

Download project Sinewave modulated PWM source code if you want to try it by yourself.

This way, you can modulate PWM with any signal shape that is stored in the lookup table.

Updated AVRStudio4 project files!

35 Comments:

  1. Very nice article. I am quite new with using embedded systems, at the moment I am working with an AT90CAN128 microprocessor. I am trying to adapt this program to generate PWMs on that type of microprocessor, but I’m not having any luck. Does anybody have an idea of how you can generate PWMs on the AT90CAN128? Thanks, Andrei.

  2. Hei Andrei contact me by email, sallesroberto@yahoo.com.br . I have this code working to AT90CAN128 , I can send you!. Salles

  3. hi, i need a mickoC program that generates a sine wave, triangle wave and an impuls with freqv between 100khz-1Mhz and the amplitude of the wave form between 0,1V-5V and the kind of wave form can be modified by “string” or input keyboard .
    i am using a PIC16F877A…. please help….

  4. thanks a lot,very simple and explicit…
    is there another way to generate SPWM waveform?

  5. thanks for simple and explicit describe
    i cant open the source file that you told for downloading…(when open with codevision ,an error accure:bad data in project file)
    what can i do??

  6. The source code is written for WinAVR. Actualy All project is set up in VMLAB simulator which uses WinAVR GCC compiler.

  7. I begin my search on single phase inverter with true sinewave o/p i need some paper or books that explain the digital syntheses for spwm
    plz send me any help on my mail
    thank you

  8. Hello
    Gud work man.
    I want to make sine inverter and can i use this technique but i have made square wave UPS and that requires 2 pin wave generated like one cycle is generated from pin 1 and 2nd pin remains low and vice versa.So is this possiable to make sine wave Invreter if y then please guide me

  9. I wanna create a sine wave for an ATmega64 in AVR
    ucing C language
    Any hints will help >> would be awesome

  10. hi guys!can somebody help me with the code to generates PWM by using AVR ATmega169

  11. Hello,
    good program.
    Why do you designate port D pins as input? Can you send me schematic?
    thank you,
    Vlad

  12. Don’t mind PortD settings. These were left from other project template. Actually I updated project files for AVRStudio4. You’ll find them at the end of article.
    And there is no specific schematic – signal is generated directly on PinB1 (OC1A) pin. Any general Atmega8 circuit will do for testing.

  13. thank you,
    i actually thought about using the external counter source T1 on Bit5 of PortD;
    By changing frequency of external clock source we can change the frequency of output sine wave, right?
    Vlad

  14. Thats right. Never tried this but should work fine once T1 frequency is at least twice lower than main clock frequency for correct sampling.

  15. thank you for the prompt answer.
    I use stk500 board and atmega8. When clock frequency is intern 8mhz, the frequency of sinusoide is around 100hz. When i connected external crystal 16mhz to the board and changed fuses, the signal frequency changed to 220hz.
    This is is max frequency for atmega. How can i make output frequency higher?

  16. In example code there is a correct phase and frequency mode used where dual slope timer counting is used. If you need higher frequency then you should try Fast PWM mode. It uses single slope counting – this should lead to twice bigger max frequency.

  17. Yes, i understand that, thank you.
    how can i calculate the relationship between clk frequency (8 mhz in your program) and frequency of output sinusoidal signal?

  18. Ok, mode is phase correct so we can calculate pwm frequency by formula found in datasheet:
    fPWM=FCLK/(2*N*TOP)=8000000/(2*255)=15686 Hz
    one pwm coded sine period is generated at 15686/256=61 Hz

  19. Hi, I implemented your code, but a I have some issues. I used a 16mHz crystal as main clock and i used phase correct pwm as you. But in my oscyloscope i mesured 220Hz sin wave frecuency when I expected 122Hz.

    fPWM=FCLK/(2*N*TOP)=16000000/(2*255)=31372 Hz /256=122 Hz

    I fix the problem using the timer overflow interrupt (not the OC1A interrupt vector) in order to update the OCR1A but i can’t understand why. Can you Help me? Thanks. (Sorry for my english)

  20. plz if any body have the sine pwm generation program in microcontrolller then send me or provide the link.

  21. how i can send this sine wave on uart and check this waveform in Labview

  22. simply instead of using

    OCR1A=pgm_read_byte(&sinewave[i]);

    you can write:

    uartSendByte(pgm_read_byte(&sinewave[i]););

    of course you should have initialized usart.

  23. Hi, I have a question about your project. how did you calculated value of sinwave array? Thanks!

  24. This is easy. Simply take sine period 2*PI and divide in to 256 parts. Then calculate sine by incrementing angle by this value. Add DC offset (0x80 for 5V VCC) and multiply with amplitude (same 0x80). You can set up excel sheet for this and do for all 256 values. Hope this explains.

  25. ok. thanks. In Comment above of you. you said:
    fPWM=FCLK/(2*N*TOP)=8000000/(2*255)=15686 Hz
    one pwm coded sine period is generated at 15686/256=61 Hz.
    So if i want to change sin frequency, so What must I change in formula in formula because I think Top is variable we calculated, and here I think you used N=1???

  26. Yes you can change N – timer prescaller or change TOP value – count timer not to 255 but to lower values. Playing with those two values you can change signal frequency in small steps.
    This test was only to test signal generator, the main idea was to generate using DDS algorithm.

  27. but I think TOP was caculated in sinwave array in your code??? and in datasheet N just can 1, 8, 64, 256 or 1024.

  28. Ah, yes. Top is 255. You’d probably need a different timer algorithm to do what I meant.
    In this example you have only few available sine frequencies that are tied to timer prescaler. As I mentioned, this was only to test if hardware of DDS generator works properly.

  29. I’m sorry. I still don’t understand. can you say clear more? Example, in you program, sin frequency is 61Hz, so if I want frequency is 50Hz, so what must I do?

  30. If you are looking for fluent signal frequency change, take a look at DDS signal generator project, where this hardware was used: https://scienceprog.com/avr-dds-signal-generator-v20/

  31. No, my question is change and control frequency in this project of you. I needn’t create sinwave standard. I want create PWM change follow sin function.

  32. In this example PWM frequency can be changed by changing timer prescaler if main cpu clock is fixed. so if you have prescaler values of 1, 8, 64, 256, 1024. so if you put these values to formula above, you get available sine frequencies. This is because Timer compare register TOP value is related to sine table. You should look for other timer solutions if you need to be able to select frequency in small steps. As I mentioned one way is DDS algorithm or other way. This definitely asks for separate blog post or project on this topic.

  33. Hi. I generated sin wave from AVR. But when I drive Mosfet, it just is AC at haft cycle first. After Haft cycle it is DC. So Can you give me some suggestions?

  34. I need to write a BASCOM code for my Atmega16 Avr micro controller in order to generate a 1KHz sinewave signal using fast PWM technique.
    please kindly advise if possible.

  35. I need to drive a half-bridge circuit so I need a PWM signal for the first transistor while the sine wave is positive and a second PWM signal for the second transistor when I want to drive the sine wave negative.

Leave a Reply