Years ago I put up my first video on YouTube. It was a very poorly shot and edited video on PWM with a PIC 16F690. However as its a reasonably difficult process writing for this chip and the chip is quite popular as it came with the PICKIT 2 it has had a fair few views. I have added some content here from what I remember about the PIC for those who are using it. First here is the original video.
This is an example of a Microchip PIC16F690 PWM (Pulse Width Modulation) example. Used to vary the brightness on an LED or as a speed controller on a DC motor.
PWM in a PIC basically involves reading the current ADC port register values
(ie a memory location which changes its value as the incoming analog voltage changes) and then using a calculation to convert them and copy them directly in to the PWM register.
REGISTERS are memory locations that are connected to physical hardware. We probably all understand that memory is somewhere you can store a value, but with a REGISTER, the memory contents are connected to hardware.
For example, a row of 6 pins are all part of the same PORTA register, the first 2 pins are being driven OFF and the next 4 pins are being driven ON by an external circuit.
The value of the PORTA register when read would be 111100 in binary.
The state of the pins actually effect the memory directly! Dig it?
Now if i was to write the value 001100 to the PORTA register, can you guess what would happen? The pins would now have 5 volts or 0 volts ie ON or OFF depending on the register values i had written, in this case 1 and 2 OFF, 3 and 4 ON, 5 and 6 OFF. Now your getting the picture?
The main routines in this microcontroller example involve moving values from the ADC memory register to the working memory – (MOVLW) then reformatting and resizing the value till its suitable to be moved again to the PWM register – (MOVWF)
SO ESSENTIALLY – the value on the analog pin is copied to the PWM output pin.
We start by giving all the data values/memory locations plain english names, well sort of.. (some are also defined already inside the included libraries as standard names for things)
Then we do some setup, write to some registers that set hardware options inside the chip rather than hardware outside the chip (cool isn’t it! This is SO RETRO!)
We do all this by making up a value, usually in HEX, and copying it to a thing we call the working memory register, basically a holding location, then we move it on the the finally resting place in memory, that we want to put it.
Example movlw 0xF7 , this moves hexadecimal F7 into the working memory.
Example movwf ANSEL , this moves the content of the working memory to the ANSEL register.
Because we can’t transfer directly from one location to another, it has to go through the working memory. After all, that’s really what a processor does.
once the initialising routine is complete, we basically just loop between reading the ADC register, ie, the incoming voltage, and writing the value to the PWM register.
Example movf ADRESH,w ; Copy the value to the working memory from ADC result
Example MOVWF CCPR1L ;Copy the working memory contents to the PWM register
I hope the code is still valid for everybody..
Unfortunately YouTube seems to be destroying the formatting. PM me for a better version if you need it.
; 16F690 PWM out on RC5 0-5V, and in via RA0, using potentiometer to control PWM duty cycle.
LIST P=16F690, W=2, X=ON, R=DEC
cblock 0x20 ;start of general purpose registers
temp ;temp storage
duty ;final duty cycle
movlw 0x10 ; A2D Clock Fosc/8
bcf STATUS,RP0 ; back to Register Page 0
movlw 0xF7 ; we want all Port A pins Analog, except RA3
bcf STATUS,RP0 ; address Register Page 0
movwf ADCON0 ; configure A2D for Channel 0 (RA0), Left justified, and turn on the A2D module
START CALL Initialise
BANKSEL ADCON1 ;turn off A2D
MOVLW 0 ;set PORTC as all outputs
MOVF CCP1CON,W ;set CCP1 as PWM
MOVLW 126 ;set highest PWM value
BANKSEL PR2 ;over this (127) is permanently on
MOVF T2CON,W ;set prescaler to 16
ANDLW 0xF8 ;PWM at 2500HZ
MOVF T2CON,W ;set postscaler to 1
CLRF CCPR1L ;set PWM to zero
BSF T2CON, TMR2ON ;and start the timer running
Pwm: ;use value in W to set speed (0-127)
nop ; wait 5uS for A2D amp to settle and capacitor to charge.
nop ; wait 1uS
nop ; wait 1uS
nop ; wait 1uS
nop ; wait 1uS
bsf ADCON0,GO ; start conversion
btfss ADCON0,GO ; this bit will change to zero when the conversion is complete
movf ADRESH,w ; Copy the value to the working memory