In this project we use two built-in features of PIC16F684: Analog to Digital Converter (ADC) and Pulse Width Modulation (PWM). The goal is to design a circuit that control the brightness of an LED. It turns out that by adding a motor interface the same program can control the motor rotation speed.
The PIC reads the voltage coming out of the pot, which is in the range 0..5V, and redirects it to a built-in ADC with a 10-bit resolution. The ADC value, which is in the range 0..1023, is used to set up the duty cycle ratio of the PWM running at 244Hz (the minimum frequency achievable by running the PIC @4MHz). The PWM resolution in this case is 1024, hence matching the one of the ADC. The PWM output is available at pin RC5 drives LED through a current-limiting resistor. This way effective voltage on the LED is proportional to the pulse width of the PWM, which affects its brightness.
Schematic | Layout | |
The PWM runs in the single and active-high mode, thus coming out at pin PC5 by default and leaving 3 other PWM-related registers available for other usage. The PWM period 1μsec·16·256 = 4.096msec (which corresponds to approx. 244Hz frequency) is provided by setting PR2 with the value of 255 and using Timer2 1:16 prescaler. The program starts with a necessary setup of the control registers and then falls into an infinite loop. At each iteration of this loop the PIC reads the voltage at pic RA0, digitizes it and updates the duty cycle ratio of PWM. The 8 higher bits of the ADC are available in ADRESH register, while the two lower bits are in ADRESL. Those two bits are first shifted twice to the right to come to a proper place and then are ANDed with the other bits of the corresponding control register. After a 20msec delay this process repeats over and over. The oscillograms below show the output at pin RC5, corresponding to a dimmer and brighter LED, respectively.
PWM duty cycle ratio 1/4 (approx.) | PWM duty cycle ratio 3/4 (approx.) | |
![]() |
![]() |
---|
By adding a motor interface circuit L293D containing 4 buffers for building a full H-bridge, the same code can be used for controlling the motor rotation speed.
Schematic | Layout | |
The code is as follows:
TITLE "pwm_led.asm" ; PWM test with LCD List P=PIC16F684, R=DEC INCLUDE "p16f684.inc" ; data segment CBLOCK 0x20 del ; variable used for delay temp ; local temp variable ENDC ; code segment PAGE __CONFIG _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT org 0 ; start program at the beginning of mem bcf STATUS, RP0 ; activate BANK 0 clrf PORTA ; initialize PORT A clrf PORTC ; initialize PORT C movlw 0x07 movwf CMCON0 ; comparators OFF bsf STATUS, RP0 ; change to BANK 1 ; ADC and PWM configuration bsf TRISA ^ 0x80, 0 ; enable input on pin A0 bsf ANSEL ^ 0x80, 0 ; configure A0 as analog input movlw b'01110000' ; set ADC Frc clock movwf ADCON1 ^ 0x80 movlw 0xFF movwf PR2 ^ 0x80 ; PWM period 244Hz bcf TRISC ^ 0x80, 5 ; enable RC5 for output bcf STATUS, RP0 ; back to BANK 0 bsf ADCON0, 0 ; Left justify, Vdd Vref, AN0, On movlw 7 movwf T2CON ; enable Timer 2 with 1:16 prescaler movlw 0x0C ; enable single output PWM movwf CCP1CON loop movlw 20 movwf del call delay ; 20 msec delay bsf ADCON0, GO ; start ADC operation btfsc ADCON0, GO ; and wait for its completion goto $-1 bsf STATUS, RP0 ; change to BANK 1 movf ADRESL ^ 0x80, w ; read 2 lower bits of ADC bcf STATUS, RP0 movwf temp rrf temp, f rrf temp, f movf temp, w iorlw b'11001111' andwf CCP1CON, f ; setup the 2 lower bits of PWM movf ADRESH, w ; get high 8 bits of ADC movwf CCPR1L ; setup PWM duty cycle goto loop ; endless loop ; procedures delay ; a delay for del milliseconds movlw 200 sublw 1 ; this loop takes 5us*200 = 1ms sublw 0 ; for PIC16F684 @ 4 MHz btfss STATUS, Z goto $-3 decfsz del, f goto delay return end |
Download pwm_led.asm
Last modified:Mon, Jan 23, 2023.