Working With Atmel AVR Microcontroller Basic Pulse Width Modulation (PWM) Peripheral - Ermicroblog
Working With Atmel AVR Microcontroller Basic Pulse Width Modulation (PWM) Peripheral - Ermicroblog
MicrocontrollersandElectronicsProjectBlog
Home
About
CopyrightandDisclaimer
eBooks
ContactUs
BlogEntry
Adsby Google
ArduinoPWM PWMCircuit
SearchThisSite
AVRATMEGA8 AtmelAVR
Search
CustomSearch
WorkingwithAtmelAVRMicrocontrollerBasicPulseWidthModulation
(PWM)Peripheral
April30,2011byrwb,underMicrocontroller.
Registertoget10pcsfor
Free
Free10pcs
PulseWidthModulation(PWM)isatechniquewidelyusedinmodernswitchingcircuittocontroltheamount
ofpowergiventotheelectricaldevice.ThismethodsimplyswitchesONandOFFthepowersuppliedto
FuturePost
ControllingtheMotorisoneof
interestingtopicsintheembedded
worldespeciallyfortherobotics
enthusiasts,onthenextpostwewill
learnthebasicofmotorelectronic
circuitaswellashowtocontrolitwith
microcontroller.
Thereforedon'tmissit,staytuneon
thisblog!
theelectricaldevicerapidly.Theaverageamountofenergyreceivedbytheelectricaldeviceis
correspondingtotheONandOFFperiod(dutycycle)thereforebyvaryingtheONperiodi.e.longeror
shorter,wecouldeasilycontroltheamountofenergyreceivedbytheelectricaldevice.TheLightEmitting
Diode(LED)willrespondtothispulsebydimmingorbrightenitslightwhiletheelectricalmotorwill
respondtothispulsebyturningitsrotorsloworfast.
Registerto
get10pcs
forFree
TheabovepictureshowatypicalPulseWidthModulation(PWM),thePWMdutycycleistheproportionof
thesignalONtimetooneperiod(T)ofthesignaltime.ThedutycyclewillbehigherwhentheONtimeis
longerthantheOFFtimeandviceversa.Dutycycleisexpressedinpercentagethereforeyoucould
definethedutycycleofPWMsignalasfollow:
ChinaFree
PCB13
daysshipping,
Registernow!
The100%PWMdutycyclemeansitsfullyONandwecouldsaythat100%ofthepowerorenergyis
deliveredtotheelectricaldevice,while15%dutycyclemeansonly15%ofthepowerisbeingdelivered
totheelectricaldevice.Thisaverageinpowercouldbepresentedasaverageinvoltageasfollow:
Free10pcs
Subscribe
Posts|
Comments
SubscribewithBloglines
ThePWMsignalnormallyhasafixedfrequency(period)withadutycyclethatcouldvaryfrom0%to
100%.NowyouunderstandthatbyjustadjustingthePWMdutycyclewecouldeasilycontroltheLED
AddtoTechnoratiFavorites
brightnessortheelectricalmotorspinningspeed.
TodaymostofmodernmicrocontrollerhasabuildinPWMperipheralinsidethismakegeneratingPWM
signalisbecomeeasyandstraightforward,youcouldreadmoreaboutnonmicrocontrollerPWMbase
generatoronTheLM324QuadOpAmpLineFollowerRobotwithPulseWidthModulationarticleonthis
blog.OnthistutorialwearegoingtouseAtmelAVRATMega168microcontrollerwhichsupportupto6
PWMoutputsimultaneouslyandattheendofthistutorialwewilltakeadvantageofalltheavailablePWM
peripheraltomakeaniceRGBLEDLightandSoundShow.
AddtoWindowsLiveFavorites
AddtoMyMSN
FeatureProduct
PICJazz20PINBoard
PICJazz20PINBoard
Categories
SelectCategory
Blogroll
ermicroshop
ermicroblogAmazonStore
ermicroblogonYouTube
ermicroblogvideoonMetacafe
Archives
SelectMonth
Adsby Google
AVRATMEGA8
TheAVRMicrocontrollerPWMPeripheral
MostofthemicrocontrollerPWMperipheraldependsontheTIMERperipheraltoprovidethePWMsignals
frequency.ThePWMperipheralwillusetheTIMERcounterregister(TCNT)asadigitalstepup/downand
continuouslycomparetothepredeterminedutycycleregister(OCRoutputcompareregister)value.
WhenTCNTequaltoOCRvaluethewavegeneratorcircuitwillset(ON)orreset(OFF)thecorresponding
microcontrollerPWMI/Oports.ThefollowingpictureshowasimplifiedversionofAtmelAVRATMega168
microcontrollerPWMperipheral(pleaserefertotheAtmelATMega48/88/168/328datasheetformore
information):
PWMLED
EachoftheAVRATMega168microcontrollersTIMERhastwoPWMchannelsnamedchannelAandchannel
B,whereeachchannelhasitsownoutputcompareregister(OCR).Fromthediagramaboveyoucould
seethatbothchannelsharethesameTIMERcounterregister(TCNT),thismeanyoucouldonlyhaveone
PWMfrequencyforeachTIMER(TIMER0,TIMER1,andTIMER2)butyoucouldhavedifferentdutycycleon
eachchannel(AandB).TheAVRATMega48/88/168/328microcontrollerprovidesthreePWMmodes
whichareFastPWMMode,PhaseCorrectPWMMode,andPhaseandFrequencyCorrectMode.Thelast
modeisonlyavailableonTIMER1(16bittimer).Okbeforewecontinueletslistdownthehardwareand
softwareneededforthistutorial:
1.AVRJazzMega168orAVRJazzUltimate28Pboard(Iusedinthisproject),youcouldalsouseanyAVR
ATMega168boardorbareATMega168,whateveravailabletoyou(theelectronicscomponentslistedhere
isjustforthefinalproject)
2.OneBreadboard
3.Resistors:10K(1),15K(1),and18(1)
4.One10KTrimpot
5.NonpolarCapacitor0.1uF(3)and0.01uF(1)
6.PolarCapacitor220uF/16V(1)and10uF/16V(1)
7.One5mmRGBLED
8.NationalSemiconductorLM386IC
9.OnewhitepingpongballfordefusingtheRGBLEDlight
10.OneSpeaker
11.ThelatestAtmelAVRStudio(inthisprojectIusedv4.18)andWinAVRGNUCCompiler(inthisproject
IusedWinAVR20100110)
12.AVRMicrocontrollerProgrammer
13.AtmelATMega48/88/168/328andLM386datasheet.
TheAVRFastPWMMode
TheAVRfastPWMmodecouldgeneratethemosthighfrequencyPWMwaveformcomparedtotheother
twoPWMmodes(i.e.PhaseCorrectorPhaseandFrequencyCorrectmode).ThisPWMmodesimplyuses
theTIMERcounterregister(TCNTn,wherenrepresenttheTIMER0,TIMER1,andTIMER2respectively)
incrementalvaluewhichisstartfrom0x00(BOTTOM)to0xFF(8bitTOP)or0xFFFF(16bitTOP).
WhentheTIMERcounterregisterreachtheoutputcompareregister(OCRnAorOCRnB)valuethenthe
wavegeneratorcircuitwillCLEAR(logicallow)theoutputcomparebitchannel(OCnAorOCnB).Whenthe
TIMERcounterregistervaluereachtheTOPvaluethenitwillSET(logicalhigh)theoutputcomparebit
channelandthewholeprocesswillrepeatagainfromBOTTOM.ThisPWMgenerationprocesscouldbe
shownonthisfollowingdiagram:
Asshownonthediagramabove,thebehaviorofoutputcomparebitchannel(OCnAorOCnB)output
couldbesettononinverting(CLEARandSET)orinverting(SETandCLEAR)modebysettingthecompare
matchchannelbit(COMnA1,COMnA0,COMnB1,andCOMnB0)onTimer/CounterregisterA(TCCRnA).
TheFastPWMmodecouldbesetbysettingthewavegenerationmodebit(WGM01andWGM00)on
Timer/CounterregisterA(TCCRnA)andWGM02bitonTCCRnBregister.WhentheTIMERcounter
register(TCNTn)equaltoOutputCompareRegister(OCRnAorOCRnB)itwillgeneratetheOutput
CompareinterruptandwhentheTCNTnregisterreachTOPitwillgeneratetheTIMERoverflowinterrupt
(TOV).
AsyouseeattheAtmelAVRmicrocontrollerPWMperipheraldiagramabovewhenweupdatetheOutput
CompareRegister(OCRnAandOCRnB)value,thevaluewillbeupdatedontheOutputCompareRegister
BufferfirstandwhentheTIMER0CounterRegister(TCNT0)reachTOPthentheOCRnregisterwillbe
updatedwiththeOCRnbuffervalueandatthesametimetheOutputCompareBits(OCnAorOCnB)will
beset.
OnthisfollowingCcode,wearegoingtouseTIMER0FastPWMmodeonbothchannelAandchannelB.
//***************************************************************************
//FileName :avrpwm01.c
//Version
:1.0
//Description:AVRTIMER0FastPWMMode
//Author:RWB
//Target:AVRJazzUltimate28PINBoard
//Compiler:AVRGCC4.3.3;avrlibc1.6.7(WinAVR20100110)
//IDE:AtmelAVRStudio4.18
//Programmer:AVRJazzMega168STK500v2.0Bootloader
//:AVRVisualStudio4.18,STK500programmer
//LastUpdated:21March2011
//***************************************************************************
#include<avr/io.h>
#include<util/delay.h>
intmain(void)
{
unsignedcharduty_cyc_a,duty_cyc_b;
//InitialPORTUsed
DDRD=0b11111111;//SetPORTD:Output
PORTD=0x00;
//InitialTIMER0FastPWM
//FastPWMFrequency=fclk/(N*256),WhereNisthePrescaler
//f_PWM=11059200/(64*256)=675Hz
TCCR0A=0b10100011;//FastPWM8Bit,ClearOCA0/OCB0onCompareMatch,SetonTOP
TCCR0B=0b00000011;//Used64Prescaler
TCNT0=0;//ResetTCNT0
OCR0A=0;//InitialtheOutputCompareregisterA&B
OCR0B=0;
duty_cyc_a=0;//InitialDutyCycleforChannelA
duty_cyc_b=255;
//InitialDutyCycleforChannelB
for(;;){//LoopForever
while(duty_cyc_a<255){
OCR0A=duty_cyc_a++;
OCR0B=duty_cyc_b;
_delay_ms(10);
}
while(duty_cyc_b<255){
OCR0A=duty_cyc_a;
OCR0B=duty_cyc_b++;
_delay_ms(10);
}
}
return0;
}
//StandardReturnCode
/*EOF:avrpwm01.c*/
TheTIMER0FastPWMmodeisactivatedbysettingtheWaveGenerationModebitsWGM02=0,
WGM01=1,andWGM00=1onTIMER0Timer/CountercontrolRegisters(TCCR0AandTCCR0B)as
follow:
//InitialTIMER0FastPWM
//FastPWMFrequency=fclk/(N*256),WhereNisthePrescaler
//f_PWM=11059200/(64*256)=675Hz
TCCR0A=0b10100011;//FastPWM8Bit,ClearOCA0/OCB0onCompareMatch,SetonTOP
TCCR0B=0b00000011;//Used64Prescaler
ThereforebyassigningtheClockSetBitCS02=0,CS01=1,andCS00=1respectively,wetellthe
TIMER0touse64asaprescaler,thereforeyoucouldcalculatethePWMfrequencyifweuse11059200Hz
externalcrystalasfollow:
PWMFrequency=FreqClock/(prescalerx256)=11059200/(64x256)=675Hz
YoucouldfreelychooseorexperimentwithanyPWMfrequencythatworkbestwiththeelectricaldevices
thatyouwanttocontrolwiththeFastPWMmodesignal.
OneofdisadvantageusingtheFastPWMmodetogeneratethePWMsignalisthePWMphaseisshifted
whenwechangethePWMdutycycle.ThisbecausewhentheTIMER0CounterRegister(TCNTn)reach
TOPandstartfromBOTTOMitwillalwaysSET(orCLEAR)theOutputCompareBits(OCnAorOCnB)
despitetheOutputCompareRegister(OCRnAandOCRnB)valuethereforewhenwechangetheduty
cycleinFastPWMmodethePWMsignalphaseisalwaysshiftedasillustratedonthisfollowingdiagram:
ThismaketheFastPWMmodeisnotsuitablewhenwewanttouseforcontrollingthemotorspeed
preciselythereforeonournextdiscussionwewillcorrectthisshiftedphaseeffectbyusingtheAVR
microcontrollerPhaseCorrectPWMmodeforgeneratingthePWMsignal.
NowasyouunderstandofhowtousetheFastPWMmodeonTIMER0,youcouldeasilyadaptthisprincipal
toTIMER1(16bit)andTIMER2(8bit).PleaserefertotheAtmelATMega48/88/168/328datasheetfor
completeinformation.
TheAVRPhaseCorrectPWMMode
DifferfromtheFastPWMMode,thePhaseCorrectPWMmodeisusingdualslopeTIMERcounter.Basically
theTIMERcounterregister(TCNTn)willincreaseitsvalue(upcounter)fromBOTTOMtoTOPandthen
decreaseitsvalue(downcounter)fromTOPtoBOTTOM.WhentheTIMERcounterregisterequaltothe
OutputCompareRegister(OCRnAandOCRnB)thenthewavegeneratorbitwillsimplytoggletheOutput
Comparechannel(OCnAandOCnB)asshownonthisfollowingdiagram:
AsshownonthediagramaboveyoucouldseethatthePhaseCorrectPWMmodewillhavehalfofthe
PWMsignalfrequencycomparedtothefastPWMmode.Becauseofthedualslopetechniqueusedinthe
PhaseCorrectPWMmodetogeneratethePWMsignal,thereforethephasecorrectPWMmodeismore
precisionandsuitabletobeusedasamotorcontroller,becauseaswechangethePWMsignaldutycycle
thephasebetweeneachdutycyclesremainthesameasillustratedonthisfollowingdiagram:
OnthisfollowingCcode,wearegoingtouseTIMER0PhaseCorrectPWMmodeonbothchannelAand
channelB.
//***************************************************************************
//FileName :avrpwm02.c
//Version
:1.0
//Description:AVRTIMER0PhaseCorrectPWMMode
//Author:RWB
//Target:AVRJazzUltimate28PINBoard
//Compiler:AVRGCC4.3.3;avrlibc1.6.7(WinAVR20100110)
//IDE:AtmelAVRStudio4.18
//Programmer:AVRJazzMega168STK500v2.0Bootloader
//:AVRVisualStudio4.18,STK500programmer
//LastUpdated:21March2011
//***************************************************************************
#include<avr/io.h>
#include<util/delay.h>
intmain(void)
{
unsignedcharduty_cyc_a,duty_cyc_b;
//InitialPORTUsed
DDRD=0b11111111;//SetPORTD:Output
PORTD=0x00;
//InitialTIMER0PhaseCorrectPWM
//FastPWMFrequency=fclk/(N*510),WhereNisthePrescaler
//f_PWM=11059200/(64*510)=338.82Hz
TCCR0A=0b10100001;//PhaseCorrectPWM8Bit,ClearOCA0/OCB0onCompareMatch,SetonTOP
TCCR0B=0b00000011;//Used64Prescaler
TCNT0=0;//ResetTCNT0
OCR0A=0;//InitialtheOutputCompareregisterA&B
OCR0B=0;
duty_cyc_a=0;
duty_cyc_b=255;
//InitialDutyCycleforChannelA
//InitialDutyCycleforChannelB
for(;;){//LoopForever
while(duty_cyc_a<255){
OCR0A=duty_cyc_a++;
OCR0B=duty_cyc_b;
_delay_ms(10);
while(duty_cyc_b<255){
OCR0A=duty_cyc_a;
OCR0B=duty_cyc_b++;
_delay_ms(10);
}
return0;
}
//StandardReturnCode
/*EOF:avrpwm02.c*/
TheTIMER0PhaseCorrectPWMmodeisactivatedbysettingtheWaveGenerationModebitsWGM02=0,
WGM01=0,andWGM00=1onTIMER0Timer/CountercontrolRegisters(TCCR0AandTCCR0B)as
follow:
//InitialTIMER0PhaseCorrectPWM
//FastPWMFrequency=fclk/(N*510),WhereNisthePrescaler
//f_PWM=11059200/(64*510)=338.82Hz
TCCR0A=0b10100001;//PhaseCorrectPWM8Bit,ClearOCA0/OCB0onCompareMatch,SetonTOP
TCCR0B=0b00000011;//Used64Prescaler
ThereforebyassigningtheClockSetBitCS02=0,CS01=1,andCS00=1respectively,wetellthe
TIMER0touse64asaprescaler,thereforethePhaseCorrectPWMfrequencycouldbecalculatedas
follow:
PWMFrequency=FreqClock/(prescalerx510)=11059200/(64x510)=338.82Hz
AgainyoucouldeasilyadaptthisprincipaltoTIMER1(16bit)andTIMER2(8bit)aswell(pleasereferto
AtmelATMega48/88/168/328datasheetforcompleteinformation).
TheAVRPhaseandFrequencyCorrectPWMMode
ThePhaseandFrequencyCorrectPWMModefeatureisonlyavailableonTIMER1(16bit).Basicallythe
PhaseandFrequencyCorrectPWMmodeusethesamedualslopetechniqueusedinPhaseCorrectPWM
modetogeneratethePWMsignal.ThesetwomodesactuallyareidenticalifweneverchangethePWM
signalfrequency,butifweneedtochangethePWMsignalfrequencyonfly,thenweneedtousetheAVR
ATMega168microcontrollerPhaseandFrequencyCorrectmodetogeneratethePWMsignal.
DifferfromthePhaseCorrectPWMMode,inPhaseandFrequencyCorrectPWMModetheOutputCompare
Register(OCRnAandOCRnB)isupdatedfromthebufferwhentheTimerCounterRegister(TCNTn)
reachesBOTTOMinsteadofTOPinPhaseCorrectPWMMode.Thefrequencycouldbechangebychanging
theTOPvalue,hereyoucouldunderstandwhyweneedtousethePhaseandFrequencyCorrectPWM
mode,becauseaswechangethefrequencyandatthesametimethePWMperipheralupdatetheOutput
Compareregister(OCRnAandOCRnB)thentherewillbeaglitchinthePWMfrequencysignal.
InPhaseandFrequencyCorrectPWMmodebecausetheOutputCompareRegisterisupdatedatthe
BOTTONthereforetherisingandfallinglengthofthePWMsignalisalwaysequalthisresultinfrequency
beingcorrectedwhenwechangethefrequencyonfly.
TypicallyincontrollingtheelectricaldevicewithPWMsignalweseldomchangethePWMfrequencyonfly,
thereforethecommonapplicationforthismodeistogeneratethesound.OnthisfollowingCcode
exampleIusedthePhaseandFrequencyCorrectPWMtogeneratedtone.Anotherexampleofusingthis
PWMmodecouldbereadinAVRTwinkleTwinkleSongUsingPWMProjectarticleonthisblog.
//***************************************************************************
//FileName :avrpwm03.c
//Version
:1.0
//Description:AVRTIMER0PhaseandFrequencyCorrectPWMMode
//Author:RWB
//Target:AVRJazzUltimate28PINBoard
//Compiler:AVRGCC4.3.3;avrlibc1.6.7(WinAVR20100110)
//IDE:AtmelAVRStudio4.18
//Programmer:AVRJazzMega168STK500v2.0Bootloader
//:AVRVisualStudio4.18,STK500programmer
//LastUpdated:21March2011
//***************************************************************************
#include<avr/io.h>
#include<util/delay.h>
//NotesFrequencyfromhttp://www.phy.mtu.edu/~suits/notefreqs.html
//TheOriginalfrequencyvalue(decimal)isconvertedtotheintegervalue
#defineC4262
#defineCc4277
#defineD4294
#defineDc4311
#defineE4330
#defineF4349
#defineFc4370
#defineG4392
#defineGc4415
#defineA4440
#defineAc4466
#defineB4494
#defineC5523
#defineCc5554
#defineD5587
#defineDc5622
#defineE5659
#defineF5698
#defineFc5740
#defineG5783
#defineGc5831
#defineA5880
#defineAc5932
#defineB5988
#defineC61047
//LEDDisplayvariables
unsignedcharledstat,led_out;
//PlayNotesfunction
voidPlayNotes(unsignedintnote_frequency,unsignedintduration)
{
unsignedinttop_value,duty_cycle;
//CalculatetheTopValue
//TOP=BoardClockFrequency/(2xNxNotesFrequency)
//WhereNisPrescler:8
topvalue=(F_CPU/(16*note_frequency));
//ResettheTIMER116bitCounter
TCNT1H=0;
TCNT1L=0;
//SettheTIMER1CounterTOPvalueonICR1HandICR1L
ICR1H=(top_value>>8)&0x00FF;
ICR1L=top_value;
//SettheTIMER1PWMDutyCycleonOCR1AHandOCR1AL
//AlwaysusehalfoftheTOPvalue(PWMDuctyCycle~50%)
duty_cycle=top_value/2;
OCR1AH=(duty_cycle>>8)&0x00FF;
OCR1AL=duty_cycle;
//TurnONtheTIMER1Prescalerof8
TCCR1B|=(1<<CS11);
//NotesDelayDuration
_delay_ms(duration);
//TurnOFFtheTIMER1Prescalerof8
TCCR1B&=~(1<<CS11);
//DelayBetweenEachNotes1/5duration
_delay_ms(duration*1/5);
}
//DisplayLEDfunction
voidDisplayLED(void)
{
if(ledstat){
PORTD=led_out;
led_out=led_out<<1;
if(led_out>=0x80)ledstat=0;
}else{
PORTD=led_out;
led_out=led_out>>1;
if(led_out<=0x01)ledstat=1;
}
}
intmain(void)
{
unsignedintnotes[25]={C4,Cc4,D4,Dc4,E4,F4,Fc4,G4,Gc4,A4,Ac4,B4,
C5,Cc5,D5,Dc5,E5,F5,Fc5,G5,Gc5,A5,Ac5,B5,C6};
inticount;
unsignedcharpstat;
unsignedintidelay;
//InitialPORTUsed
DDRD=0b11111111;//SetPORTDasOutput
PORTD=0b00000000;
DDRB=0b11111110;//SetPB0asInputandotherasOutput
PORTB=0b00000000;
//InitialtheADCPeripheral
ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1);
//UseFreerunningMode
ADCSRB=0b00000000;
//DisabledigitalinputonChannel0
DIDR0=0b00000001;
//InitialTIMER1PhaseandFrequencyCorrectPWM
//SettheTimer/CounterControlRegister
TCCR1A=0b11000000;//SetOC1Awhenupcounting,Clearwhendowncounting
TCCR1B=0b00010000;//Phase/FreqcorrectPWM,topvalue=ICR1,Prescaler:Off
//InitialVariables
icount=0;
pstat=1;
led_out=1;
ledstat=1;
for(;;){//LoopForever
//ReadingUserTrimpotonAnalogChannel0
ADMUX=0;
//StartconversionbysettingADSConADCSRARegister
ADCSRA|=(1<<ADSC);
//waituntilconvertioncompleteADSC=0>Complete
while(ADCSRA&(1<<ADSC));
//GettheADCResult
idelay=ADCW;
DisplayLED();
if(pstat){
PlayNotes(notes[icount++],idelay);
if(icount>24){
icount=24;
pstat=0;
}
}else{
PlayNotes(notes[icount],idelay);
if(icount<0){
icount=0;
pstat=1;
}
}
}
return0;
}
//StandardReturnCode
/*EOF:avrpwm03.c*/
Togenerateacontrollabletone,weneedtoproducetheexactfrequencyoneachnotes,thenotes
frequencycouldbefoundatthiswebsiteaddresshttp://www.phy.mtu.edu/~suits/notefreqs.html.Inorder
togeneratetheC5notewehavetoproducethePWMfrequencyof523.23Hzat50%dutycycle.
ThereforebysettingtheWaveGenerationModeBitsWGM13=1,WGM12=0,WGM11=0,and
WGM10=0respectively,wechoosetheTIMER1PhaseandFrequencyCorrectPWMmodewhichhasTOP
valuesetonTIMER1InputCaptureRegistersICR1HandICR1LthePulseWidthissetonTIMER1Output
CompareRegistersOCR1AandOCR1B.
Withtheprecalerbeingsetto8andboardfrequencyof1109200Hz,wecouldeasilycalculatetheTOP
valueoftheC5noteasfollow:
PWMFrequency=FreqClock/(2xNxTOP)=FreqClock/(16xTOP)
Or
TOP=FreqClock/(16xPWMFrequency)=11059200/(16x523)=1322
NowbyassigningtheTOPvaluetotheInputCaptureRegisters(ICR1HandICR1L)andhalfoftheTOP
valuetotheOutputCompareRegister(OCR1AHandOCR1AL)wecouldproducetheC5noteswith50%
dutycycleasshownonthisfollowingCcode:
//CalculatetheTopValue
//TOP=BoardClockFrequency/(2xNxNotesFrequency)
//WhereNisPrescler:8
topvalue=(F_CPU/(16*note_frequency));
//SettheTIMER1CounterTOPvalueonICR1HandICR1L
ICR1H=(top_value>>8)&0x00FF;
ICR1L=top_value;
//SettheTIMER1PWMDutyCycleonOCR1AHandOCR1AL
//AlwaysusehalfoftheTOPvalue(PWMDuctyCycle~50%)
duty_cycle=top_value/2;
OCR1AH=(duty_cycle>>8)&0x00FF;
OCR1AL=duty_cycle;
BecausetheICR1HandICR1Larethe8bitregisters,thereforeweusetheClanguageshiftright
operatortoassigntheupper8bittop_valuetoICR1Handthelower8bitTOPvaluetoICR1L.Weuse
similarprincipaltobothOCR1HandOCR1LforthePWMdutycyclevalue(duty_cycle).ThecompleteC
codeisimplementedinPlayNotes()function,whichacceptthefrequencyanddurationparametersto
producetheneededsound.TheAVRATMega168microcontrollerADCperipheralisusedtocontrolthe
playingnotesdelaybypassingthetrimpotvoltagereadingconnectedtoADCchannel0(PC0),wecould
controlthenotesdurationasshownonthisfollowingCcode:
//ReadingUserTrimpotonAnalogChannel0
ADMUX=0;
//StartconversionbysettingADSConADCSRARegister
ADCSRA|=(1<<ADSC);
//waituntilconvertioncompleteADSC=0>Complete
while(ADCSRA&(1<<ADSC));
//GettheADCResult
idelay=ADCW;
...
...
PlayNotes(notes[icount++],idelay);
FormoreinformationaboutusingAtmelAVRmicrocontrollerADCperipheralyoucouldreadAnalogto
DigitalConverterAVRCProgrammingarticlesonthisblog
TheRGBLEDLightandSoundShow
OnthislasttutorialwewillputalltogethertheAVRATMega168basicPWMlessonsthatwevelearnedand
makingsomeinterestingRGBLEDandSoundshowasshownonthisfollowingschematic:
ThisRGBlightandSoundshowprojectusedthewellknownLM386linearamplifierICfromNational
SemiconductorwhichrecentlyhasbeenacquiredbyTexasInstrument(April2011)toproduceaquite
loudsoundfromtheTIMER1PhaseandCorrectFrequencyPWMmodethroughthespeaker.TheTIMER1
OutputCompareChannelA(PB1)PWMsignalisbeingpassedthroughthepassivelowpassfilter(isalso
calledanintegratorcircuitforanonsinusoidalinputsignalsuchassquarewaveandtrianglewave)in
ordertoshapethesquarewaveformstobecomethesinusoidalwaveformsbeforebeingamplifiedbythe
LM386IC.
Tomakethelowpassfilter(LPF)becomeagoodintegratorcircuitwehavetochoosetheLPFcutoff
frequencymuchlessthanthelowestfrequencyproducedbythePWMsignalbutatthesametimestill
produceanadequatesignalleveltodrivetheLM386amplifierinput.ThecutofffrequencyofLPFcouldbe
calculatedasthisfollowingformula:
Frequency=1/(2xpixRC),wherepi=3.14159,RisresistanceinOhm,andCiscapacitanceinFarad
ThelowestfrequencyproducebyPWMsignalis262Hz(C4note),thereforebychoosingR=15KandC
=0.1uF,wecouldcalculatetheLPFcutofffrequencyasfollow:
Frequency=1/(2x3.14159x15000x0.0000001)=106.10Hz
Thismethodisusedtoensurethatwecouldgetaquitenicesoundproducedonthespeakerinsteadof
justusingrawsquarewavesignalasshownonthisfollowingoscilloscopepicture:
EachoftheRGBLEDcathodesisdrivenbyTIMER0FastPWMchannelA,channelB,andTIMER2Phase
CorrectPWMchannelBrespectively.ThefollowingisthecompleteCcodeforourRGBLEDLightand
SoundShowfinalproject:
//***************************************************************************
//FileName :avrpwm04.c
//Version
:1.0
//Description:AVRTIMER0PhaseandFrequencyCorrectPWMMode
//Author:RWB
//Target:AVRJazzUltimate28PINBoard
//Compiler:AVRGCC4.3.3;avrlibc1.6.7(WinAVR20100110)
//IDE:AtmelAVRStudio4.18
//Programmer:AVRJazzMega168STK500v2.0Bootloader
//:AVRVisualStudio4.18,STK500programmer
//LastUpdated:22March2011
//***************************************************************************
#include<avr/io.h>
#include<util/delay.h>
#include<avr/interrupt.h>
#include<stdlib.h>
//NotesFrequencyfromhttp://www.phy.mtu.edu/~suits/notefreqs.html
//TheOriginalfrequencyvalue(decimal)isconvertedtotheintegervalue
#defineC4262
#defineCc4277
#defineD4294
#defineDc4311
#defineE4330
#defineF4349
#defineFc4370
#defineG4392
#defineGc4415
#defineA4440
#defineAc4466
#defineB4494
#defineC5523
#defineCc5554
#defineD5587
#defineDc5622
#defineE5659
#defineF5698
#defineFc5740
#defineG5783
#defineGc5831
#defineA5880
#defineAc5932
#defineB5988
#defineC61047
volatileunsignedcharduty_cyc_a,duty_cyc_b,duty_cyc_c,led_a,led_b,led_c;
volatileunsignedinttempo;
//TIMER1OverflowInterrupt
ISR(TIMER1_OVF_vect)
{
cli();//DisableInterrupt
//ReadingUserTrimpotonAnalogChannel0
ADMUX=0;
//StartconversionbysettingADSConADCSRARegister
ADCSRA|=(1<<ADSC);
//waituntilconvertioncompleteADSC=0>Complete
while(ADCSRA&(1<<ADSC));
//GettheADCResult
tempo=ADCW;
if(led_a){
if(duty_cyc_a<255){
OCR0A=duty_cyc_a++;
}else{
led_a=0;
}
}else{
if(duty_cyc_a>0){
OCR0A=duty_cyc_a;
}else{
led_a=1;
duty_cyc_a=TCNT1L;
}
}
if(led_b){
if(duty_cyc_b<255){
OCR0B=duty_cyc_b++;
}else{
led_b=0;
}
}else{
if(duty_cyc_b>0){
OCR0B=duty_cyc_b;
}else{
led_b=1;
duty_cyc_b=(unsignedchar)rand()%255;;
}
}
if(led_c){
if(duty_cyc_c<255){
OCR2B=duty_cyc_c++;
}else{
led_c=0;
}
}else{
if(duty_cyc_c>0){
OCR2B=duty_cyc_c;
}else{
led_c=1;
duty_cyc_c=TCNT1H;
}
}
sei();//EnableInterrupt
}
//PlayNotesfunction
voidPlayNotes(unsignedintnote_frequency,unsignedintduration)
{
unsignedinttop_value,duty_cycle;
//CalculatetheTopValue
//TOP=BoardClockFrequency/(2xNxNotesFrequency)
//WhereNisPrescler:8
topvalue=(F_CPU/(16*note_frequency));
//ResettheTIMER116bitCounter
TCNT1H=0;
TCNT1L=0;
//SettheTIMER1CounterTOPvalueonICR1HandICR1L
ICR1H=(top_value>>8)&0x00FF;
ICR1L=top_value;
//SettheTIMER1PWMDutyCycleonOCR1AHandOCR1AL
//AlwaysusehalfoftheTOPvalue(PWMDuctyCycle~50%)
duty_cycle=top_value/2;
OCR1AH=(duty_cycle>>8)&0x00FF;
OCR1AL=duty_cycle;
//TurnONtheTIMER1Prescalerof8
TCCR1B|=(1<<CS11);
//NotesDelayDuration
_delay_ms(duration);
//TurnOFFtheTIMER1Prescalerof8
TCCR1B&=~(1<<CS11);
//DelayBetweenEachNotes
_delay_ms(duration*1/5);
}
intmain(void)
{
unsignedcharsong_index;
//InitialPORTUsed
DDRD=0b11111111;//SetPORTDasOutput
PORTD=0b00000000;
DDRB=0b11111110;//SetPB0asInputandotherasOutput
PORTB=0b00000000;
//InitialtheADCPeripheral
ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1);
//UseFreerunningMode
ADCSRB=0b00000000;
//DisabledigitalinputonChannel0
DIDR0=0b00000001;
//InitialTIMER0FastPWM
//FastPWMFrequency=fclk/(N*256),WhereNistheprescaler
//f_PWM=11059200/(64*256)=675Hz
TCCR0A=0b10100011;//FastPWM8Bit,ClearOCA0/OCB0onCompareMatch,SetonTOP
TCCR0B=0b00000011;//Used64Prescaler
TCNT0=0;//ResetTCNT0
OCR0A=0;//InitialtheOutputCompareregisterA&B
OCR0B=0;
//InitialTIMER1PhaseandFrequencyCorrectPWM
//SettheTimer/CounterControlRegister
TCCR1A=0b11000000;//SetOC1Awhenupcounting,Clearwhendowncounting
TCCR1B=0b00010000;//Phase/FreqcorrectPWM,topvalue=ICR1,Prescaler:Off
TIMSK1=(1<<TOIE1);//EnableOverflowInterrupt
//InitialTIMER2PhaseCorrectPWMMode
//PhaseCorrectPWMFrequency=fclk/(N*512),WhereNistheprescaler
//f_PWM=11059200/(64*512)=337.5Hz
TCCR2A=0b00100001;//FastPWM8Bit,ClearOC2BonCompareMatch,SetonTOP
TCCR2B=0b00000011;//Used64Prescaler
TCNT2=0;//ResetTCNT2
OCR2B=0;//InitialtheOutputCompareregisterA&B
duty_cyc_a=(unsignedchar)rand()%255;
led_a=1;
duty_cyc_b=(unsignedchar)rand()%255;
led_b=1;
duty_cyc_c=(unsignedchar)rand()%255;
led_c=1;
sei();//EnableInterrupt
song_index=0;
tempo=0;
for(;;){//LoopForever
//Playing"WhataWonderfullWorld"SongNotes
PlayNotes(G4,300+tempo);PlayNotes(A4,100+tempo);
PlayNotes(C5,500+tempo);PlayNotes(C5,450+tempo);
PlayNotes(G5,1150+tempo);PlayNotes(A5,350+tempo);
PlayNotes(A5,350+tempo);PlayNotes(A5,150+tempo);
PlayNotes(G5,1150+tempo);PlayNotes(F5,450+tempo);
PlayNotes(F5,300+tempo);PlayNotes(F5,250+tempo);
PlayNotes(E5,1150+tempo);PlayNotes(D5,600+tempo);
PlayNotes(E5,175+tempo);PlayNotes(D5,100+tempo);
PlayNotes(C5,1050+tempo);
PlayNotes(C5,550+tempo);PlayNotes(C5,175+tempo);
PlayNotes(C5,100+tempo);PlayNotes(C5,100+tempo);
PlayNotes(C5,150+tempo);PlayNotes(C5,1300+tempo);
PlayNotes(C5,600+tempo);PlayNotes(B4,200+tempo);
PlayNotes(C5,200);PlayNotes(D5,200+tempo);
if(song_index>=1){
PlayNotes(C5,1600+tempo);
if(song_index==3){
_delay_ms(100+tempo);
PlayNotes(C5,550+tempo);PlayNotes(C5,175+tempo);
PlayNotes(C5,100+tempo);PlayNotes(C5,100+tempo);
PlayNotes(C5,150+tempo);PlayNotes(C5,1300+tempo);
PlayNotes(C5,800+tempo);PlayNotes(B4,400+tempo);
PlayNotes(C5,300+tempo);PlayNotes(D5,300+tempo);
PlayNotes(C5,2300+tempo);
song_index=0;
}else{
song_index=2;
}
}else{
PlayNotes(E5,1100+tempo);PlayNotes(E5,800+tempo);
PlayNotes(D5,1600+tempo);
song_index=1;
}
if(song_index==2){
_delay_ms(100+tempo);
PlayNotes(C5,450+tempo);PlayNotes(D5,150+tempo);
PlayNotes(D5,50+tempo);PlayNotes(D5,50+tempo);
PlayNotes(D5,1+tempo);PlayNotes(D5,1000+tempo);
PlayNotes(G4,450+tempo);PlayNotes(E5,150+tempo);
PlayNotes(E5,50+tempo);PlayNotes(E5,50+tempo);
PlayNotes(E5,1+tempo);PlayNotes(E5,1000+tempo);
PlayNotes(C5,350+tempo);PlayNotes(D5,250+tempo);
PlayNotes(D5,100+tempo);PlayNotes(D5,75+tempo);
PlayNotes(D5,350+tempo);PlayNotes(C5,150+tempo);
PlayNotes(D5,250+tempo);PlayNotes(E5,1000+tempo);
PlayNotes(E5,250+tempo);PlayNotes(G5,175+tempo);
PlayNotes(A5,450+tempo);PlayNotes(A5,100+tempo);
PlayNotes(E5,150+tempo);PlayNotes(G5,1000+tempo);
PlayNotes(A5,100+tempo);PlayNotes(A5,50+tempo);
PlayNotes(E5,150+tempo);PlayNotes(G5,1000+tempo);
PlayNotes(A5,100+tempo);PlayNotes(A5,50+tempo);
PlayNotes(E5,150+tempo);PlayNotes(G5,1000+tempo);
PlayNotes(F5,450+tempo);PlayNotes(E5,650);
PlayNotes(D5,1300+tempo);
song_index=3;
}
}
return0;
}
//StandardReturnCode
/*EOF:avrpwm04.c*/
FromtheCcodeaboveyoucouldseethatweusealltheavailableAVRATMega168microcontrollerPWM
sourcestodriveboththeRGBLEDandatthesametimeplayingWhataWonderfulWorldsong.Byusing
theTIMER1overflowinterrupt(TOIE1=1inTIMER1interruptmaskregisterTIMSK1)wecoulddisplaythe
RGBLEDandatthesametimeplayingthesongnotes.
TheRGBLEDPWMdutycycleisachievedbyassigningbothrandomvalueandthe16bitTIMER1counter
value(TCNT1HandTCNT1L)totheOutputCompareRegister(OCRn)inISR(TIMER1_OVF_vect)
functionroutine.WiththismethodwecouldgetthedesiredRGBLEDlighteffectwhichisdependonthe
songnotes.Ofcourseyoucouldexperimentwithotherregistervalueaswell(e.g.ICR1HandICR1L
registers).
NowitstimetowatchallthebasicAVRPWMexperimentswevedoneonthisfollowingvideo:
TheFinalThought
KnowingthebasicworkingprincipaloftheAtmelAVRmicrocontrollerPWMperipheralisoneofknowledge
thatshouldbelearnedbyanyonewhowanttoinvolveintheembeddedworldprofessionallyorjustasa
hobbyists.IhopethisbasicAVRPWMtutorialwillgiveyouasolidAVRPWMknowledgetobeusedinyour
nextembeddedproject.
BookmarksandShare
RelatedPosts
BuildingtheI2CSmartDCMotorControllerwithAtmelAVRMicrocontrollerPart1
BuildYourOwnMicrocontrollerBasedPIDControlLineFollowerRobot(LFR)SecondPart
UsingMaximDS1307RealTimeClockwithAtmelAVRMicrocontroller
AVRTwinkleTwinkleUsingPWMProject
AVRLCDThermometerUsingADCandPWMProject
18ResponsestoWorkingwithAtmelAVRMicrocontrollerBasicPulseWidthModulation(PWM)
Peripheral
14.08.11
#1
Commentbyiziccoz.
IsitpossibletomakePWMoutputonnonPWMoutput?
Forexample,IhaveATMEGA8whichhasthreePWMchannel,
butIneed4channelPWMonmyproject.Isitpossible?
Thanks.
14.08.11
#2
Commentbyrwb.
Yes,youcouldreadtheworkingprincipleonthisfollowing
article:
BuildingyourownSimpleLaserProjectorusingtheMicrochip
PIC12F683Microcontroller
20.08.11
#3
Commentbyjoerfrada.
Hi,rwb.
Ineedyourhelp.HowtomakePWMoutputwithL293Dmotor
[email protected]
makesUARTSerialRFRX/TX433MHz,butIgottheRFRX/TX
433MHz,itworks.PleaseexplainmeabouttomakePWM
outputwith4MHzexternalcrystal.
Ihopeyouranswersoon.
Regards,
JoeRonaldFlrezRada
fromColombia.
20.08.11
#4
Commentbyrwb.
YoucouldgetmoreinformationofhowtodrivetheL293Ddual
HBridgemotorcontrollerwithPWMonthisfollowingarticles:
BuildYourOwnMicrocontrollerBasedPIDControlLine
FollowerRobot(LFR)SecondPart
23.10.11
#5
CommentbyBF1Quang.
Whatagreatproject,Ivejustjoinedyourblog.Imdoingmy
projectaboutrobotarm!Yourblogisverygreatandhavea
lotofinformationformetolearn.Thankyouverymuch!
Ihaveaquestionforyou,wouldyoupleasetoanswerme:):
Howtopreciselycontrolservomotor(FutabaS3003)rotation
usingtrimport(varistor)!
SorryifImindyou!Imlookingforwardtoyouransweror
clues!
Bestregards!
23.10.11
#6
Commentbyrwb.
Theservomovementbasicallyiscontrolledby1.5ms
(center),0.71.0ms(CW),and1.72.0ms(CCW)PWM
signal.ThereforebyprovidingthisPWMsignaloncertain
period(e.g.50ms)wecouldmovetheservosarmtothe
certaindegree.ThusbyconvertingthisPWMsignalperiodto
thedegreeofmovementwecouldeasilymaptheanalog
trimpotvalue(usedtheADCperipheral)totheservo
movement(e.g.5degree=50ms).Youcouldreadmore
aboutbasicservoonthisfollowingarticle:
BasicServoMotorControllingwithMicrochipPIC
Microcontroller
25.10.11
#7
CommentbyBF1Quang.
Ivereadthatarticle!Itsreallyreallygrateful!:),Thankyou
verymuch!AndmayIaskyouthatwhichPWMModeshould
beusedintheproject?ImusingAVRATmega8!
Niceday!
25.10.11
#8
Commentbyrwb.
YoucoulduseeitherfastorphasecorrectPWMmode.
21.05.12
#9
Commentby.
ThereisabigtradeoffbetweenbetterPWMresolutionand
higherPWMfrequency.
17.03.13
#10
CommentbyJohnOwensChina.
ThanksforthePWMinstructions.
IhadtoaddthefollowingfunctiontoevenbuildonAVRStudio
6:
voiddelay_ms(intms)
{
for(inti=0i<msi++)
{
delay_ms(1)
}
}
Thisisbecauseyoucanonlysendaconstantto_delay_ms.
However,itonlyproducesanoisy~300hzsoundandall3
ledsareonbutnotchanging.
Arethereanyotherupdatesrequired?
Ididn'thavethecrystalinthediagram,soIhavetriedboth
withoutthecrystalandusinga2Mhzxtal,bothwiththesame
result.The10KpotonPC0doesnothaveanyeffectonsound
orLEDoutput.
Thanksforyourhelp.
17.03.13
#11
Commentbyrwb.
Sinceyouuseddifferentcrystalfrequency,youneedtoadjust
thecodetosuitethecrystalfrequencyforthegeneratedPWM.
18.03.13
#12
CommentbyJohnOwensChina.
Thanks,Iwilltryboth.specifiedcrystalandchangingthe
code.
Whatisthe10KpotonPC0usedfor.Icouldnotseethis
mentionedinthetextorinthecode.
24.03.13
#13
CommentbyJohnOwensChina.
Ipurchasedthecorrectcrystal,butitstilldoesnotwork.
MaybeIneedtosettheclocksourceinthefuses.ButIdont
knowhowtodothiswithAVRStudio6.
Canyoupleasetellmehowtosetthis?Isearchedthe
datasheetandtheAVRStudiohelpfile,butitseemslikeAVR
Studioparametersaredifferentthanwhatisshowninthedata
sheet.
Thanksforyourhelp.
John
31.05.13
#14
Commentbymusteno.
I`minterestedhowdidyouwriteasong.Iunderstandthe
partforchords,butiwanttoknowhowyoumanagewith
delays.
02.06.13
#15
Commentbyrwb.
TryandError,andifyouamusicplayerthenthisstagewill
beshorter.
07.10.13
#16
Commentbyyaqub.
Iwantmakemicforinput>lm386>thenIwantread
frequencyandamplitudeinatmega.WhatshouldIdoorI
modify?
08.10.13
#17
Commentbyrwb.
Youwillneedtowriteyourowncodes,basicallyyouwantto
buildanoscilloscopeusingAVRATmegamicrocontroller
24.03.15
#18
Commentbytushki.
hi
actuallyiamusingArduinoDuecontrollerinwhichihaveto
generateSPWMsignals.canyouguidemehowtogenerate
SPWMsignals
freq.:50Hz
carrierfreq.:5000Hz
Copyright20082016Byermicro.PoweredbyWordPress.