Вы находитесь на странице: 1из 24

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
DConAtmega8@4MHzexternalcrystal.BecauseAtmega8
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.

Вам также может понравиться