AVR ATmega32 Frequency Modulation - Quick start (Audio/tone/blockwave generator) - Page 1
Forum section: electronics / general

author: RMS95
author_rank: Contributor
timestamp: October 07, 2013, 08:16:25 pm
content: Hi EEVBloggers,Here is another tutorial, this time I will show you guys how to create a block-wave at a specific frequency. Connecting this to a speaker will give you a tone generator.Since I saw someone having trouble to fix this, I decided to make a tutorial.It works on an ATmega32, and with a little effort it works on most ATmega micro controllers with a 16 bit timer.Though, after reading this article you really don't need this code anymore because you will know how it works and get it to work on any micro controller. =)I refer to the following datasheet of the ATmega32a when using pagenumbers or registers:http://www.atmel.com/Images/doc8155.pdfSo, how does it work?The basic idea behind this is to create a PWM wave that has half the compare value(OCR) of the period (ICR).A 50% PWM is actually already a block wave. Adapting the PWM counters limit results in adapting the frequency.Code:____ ____ ________ ____ ____^ Start^ Compare, OCR1, set this to half ICR1 to get a block wave^ Reset, ICR1This will result in a block wave. By increasing or decreasing the maximum you can set different frequencies.So, you have to set your micro controller to (fast) PWM mode, and set the limit to the period of the desired output. Then divide that by two for the compare value (or bitwise right shift by 1).Put this code into your project if you don't want to make it yourself in the first placeCode:/// Use this once to initialize, call only once.void timer1_init(){/// Set PORTD5 as outputDDRD |= 0b00100000;// You might want to initialize registers here instead.}/// Set to the given frequencyvoid timer1_set(int frequency){/// Disable timer at 0Hzif (frequency == 0){TCCR1A = 0;TCCR1B = 0;return;}/// Set settings registers/* The settings you will be interested in:WGM11|WGM12|WGM13 = FAST PWM mode ICR1 as top, see datasheet page 114CS10 = No prescaler, you might want to change cs10-12 to create a slower acting generator. See datasheet page 115*/TCCR1A |= (1<<WGM11)|(1<<COM1A1);TCCR1B |= (1<<WGM12)|(1<<WGM13)|(1<<CS10);/// Write frequencyfrequency = F_CPU / frequency; // Note that 1 / F = t. F_CPU should be the timer frequency, which is in this case the same as F_CPUICR1 = frequency; // Set max to the periodOCR1A = frequency >> 1; // Set compare to half the period}InitializeCall the timer1_init() function at the start of your main.Set the frequencyWhenever you want to set the frequency in Hz, use timer1_set(0); to stop the generator.More infoI do strongly recommend reading the datasheet of your micro controller to check if you are using the best settings for your project instead of just using ctrl+c/v. =)I tested this at the ATmega 32a, but I guess it will work on comparable devices such as the 16, 128, etc. without large modifications.With some slight adapts it will work on most 16 bit PWM channels.Depending on your demand you might want to set the TCCR registers at the initialization.You might be interested in setting the prescaler as well if you need slower PWM.You're all done!Hope it helped you understanding block wave generation @ AVR!PS: This is my second at last Quick Start for now, if you like to see another Quick Start about something related to micro controllers or software development contact me!