LED FLASHING RATE CONTROL USING PIC16F684

Thread Starter

Don Omar

Joined May 5, 2017
49
The PWM drives the LED at the brightness level set by the duty cycle which is in turn set by the value of CCPR1L. As the flow chart says
Read ADC channel 0
Put that value into CCPR1L to set the duty cycle


Slow down and read my previous post AND the comments in the ReadADC_Ch0 subroutine i.e.
Also, look at the other places where ReadADC is used to see how to call it and how to use the result.
So after you call the read ADC routine in ON-3 where is the result and what do you do with it? True it is still in ADRESH but the subroutine is designed to put the result in those RAM registers for your convenience so you don't have to change banks to get the lower byte of the result from the PIC's ADC result registers directly. Take the time to read through that subroutine, line by line, then you'll understand how to use it. Where the flow chart refers to ADCRESH, use ADCresultH.

Be sure to look at Figure 11-3 SIMLIFIED PWM BLOCK DIAGRAM in the datasheet for PWM operaton.
@johnlntx
hey john,
this is what i did for ON4
Code:
TITLE "pwm_led.asm" ;
  List P=PIC16F684, R=DEC
  INCLUDE "p16f684.inc"
  ERRORLEVEL -302 ; suppress 'not in bank' messages

  ; data segment
  CBLOCK 0x20
  temp: ; local temp variable
  FlashCounter:1 ; declare one byte for 1ms flash counter
  del:1 ; delay parameter - 1ms increments

  ADCresultH:1  ; Left justified output of 'ReadADC' subroutine
  ADCresultL:1  ; high and low bytes.  dddddddd dd000000
  ENDC

  ; code segment
  __CONFIG _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT

;****************** PROGRAM BEGINS ******************************

  ORG 0  ; start program at the beginning of mem

Init:
  clrf PORTA  ; initialize PORT A
  clrf PORTC  ; initialize PORT C
  movlw 0x07
  movwf CMCON0  ; comparators OFF

  ;----------------------------
  ;RAM BANK 1
  bsf STATUS,RP0  ; select memory bank 1
  movlw B'00000011'  ; RA0-RA1 are inputs
  movwf TRISA  ;
  movlw B'11000000'  ; RC6-RC7 are inputs
  movwf TRISC

  ; ADC and PWM configuration
  movlw B'00000011'  ; AN0 to AN1 are analog inputs
  movwf ANSEL  ; Bank 1
  movlw b'01110000'  ; set ADC Frc clock
  movwf ADCON1
  movlw 0xFF
  movwf PR2  ; PWM period 244Hz

  ;----------------------------
  ;RAM BANK 0
  bcf STATUS, RP0  ; back to BANK 0

  movlw B'00000001'  ; left justified A/D result, VDD as ref, ADC ON
  movwf ADCON0
  movlw B'00000111'
  movwf T2CON  ; enable Timer 2 with 1:16 prescaler
  movlw 0x0C  ; enable single output PWM
  movwf CCP1CON

main_loop:
  ;-------------
  ;ON-1  ; Read flash rate for ON half of cycle
  call  ReadADC_Ch1 ; ADC conversion ->ADCresultH,ADCresultL in RAM

  ;-------------
  ;ON-2
  movf  ADCresultH,W ; MSbyte of ADC is msec 'ON' time
  movwf  FlashCounter ; counts 1ms clicks

  ;-------------
  ;ON-3
wait_while_LED_on:
  call  ReadADC_Ch0 ; Channel 0 is PWM brightness
  ; returns value of ADC channel to RAM registers
  ;-------------
  ;ON-4

  ;** set PWM duty cycle from ADCresultH, ADCresultL in RAM **
movf ReadADC
movwf CCPR1L

  ;-------------
  ;ON-5
call  delay_1ms

  ;-------------
  ;ON-6  ; test flash counter and loop if not 0 yet
  ;ON-7  ; both steps are done by the decfsz, sorry!
  decfsz FlashCounter,F
  goto wait_while_LED_on

  ;-------------
  ;ON-8
  ; 'ON' time has elapsed. Turn PWM OFF by setting its duty cycle to 0%
  ; then proceed to time the OFF time.

  movlw 0  ; set PWM duty cycle to 0%
  movwf CCPR1L  ; to turn LED off

  ;-------------
  ;OFF-1
  call  ReadADC_Ch1 ; Read channel 1 using subroutine

  ;-------------
  ;OFF-2
  movf  ADCresultH,W ; MSbyte of result is msec to delay
  movwf  FlashCounter

  ;-------------
  ;OFF-3
wait_while_LED_off:
call  delay_1ms
  ;-------------
  ;OFF-4
  ;OFF-5
  decfsz FlashCounter,F
  goto wait_while_LED_off

  goto main_loop ; 'OFF' time has elapsed, back the 'ON' sequence


  ;**************** UTILITIES ****************************
  ; Two entry points:
  ; delay_1ms: delays for 1 ms always
  ; delay: delays for variable 'del' ms
  ; Expects/returns bank 0
delay_1ms:
  movlw  .1
  movwf  del
  ;*
delay:
  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

  ;------------------- READ ADC  -------------------------
  ; Reads current channel of ADC, posts result in ADCresultH
  ; and ADCresultL in RAM so you don't have to read different
  ; banks each time.
  ;
  ; Expects, returns bank 0
  ; 3 Entry Points:
  ; ReadADC_Ch0  ; reads channel 0 (PWM brightness)
  ; ReadADC_Ch1  ; reads channel 1 (Flash Rate)
  ; ReadADC  ; reads current channel

ReadADC_Ch0:
  bcf  ADCON0,CHS0  ; select channel 0
  goto  ReadADC

ReadADC_Ch1:
  bsf  ADCON0,CHS0  ; select channel 1
  ;*
ReadADC:
  call  delay_1ms  ; let channel settle
  bsf  ADCON0,GO  ; start conversion

_waitADCdone:
  btfsc  ADCON0, GO  ; and wait for its completion
  goto  _waitADCdone

  movf  ADRESH,W  ; get MSbyte of conversion result
  movwf  ADCresultH
  bsf  STATUS,RP0  ; select bank 1
  movf  ADRESL,W  ; get LSbyte of conversion result
  bcf  STATUS,RP0  ; select bank 0
  movwf  ADCresultL
  return

  END
Mod edit: code tags
 
Last edited by a moderator:

Thread Starter

Don Omar

Joined May 5, 2017
49
/??
Look at ON-1 and ON-2 to see how to use the ADC.
What is the difference between movf and call??
@johnlntx
Call : means call Subroutine
movf: move the contents of the register f to the w register
looking at ON1 and ON2

call ReadADC
movf ReadADC
movwf CCPR1L
 

djsfantasi

Joined Apr 11, 2010
9,237
Ok, over 60 posts and no one has been kind enough so as to explain how to post code. I for one, am tired of having to wade through screens of code.

It is recommended to post code using code tags. To insert said tags, find the appropriate icon in the area before the message. In the bottom row, the one that starts with a smiley face, click on the fourth icon from the left. It looks like a memo.

The forum will insert the tags. Insert you code between the first ] and the second [.

That's it. Your code will be inserted in a scrollable window in your post.
 

JohnInTX

Joined Jun 26, 2012
4,787
@johnlntx
Call : means call Subroutine
movf: move the contents of the register f to the w register
looking at ON1 and ON2
call ReadADC
movf ReadADC
movwf CCPR1L
I don't see a register named ReadADC.. That is not where the ReadADC routine puts its result. And the way you have written the movf, it doesn't load W.

Re-read the comments/instructions starting at line 137 in the code above. They tell you how the subroutine works AND WHERE TO FIND THE RESULT OF THE CONVERSION.
Re-read the code in the OP-1 and OP-2 blocks. That shows you how to do it. What about those is so hard to understand?

And yes, code tags would be helpful. I've been putting them in when I can but you should do it as a matter of course.
 
Last edited:

Thread Starter

Don Omar

Joined May 5, 2017
49
I don't see a register named ReadADC.. That is not where the ReadADC routine puts its result. And the way you have written the movf, it doesn't load W.

Re-read the comments/instructions starting at line 137 in the code above. They tell you how the subroutine works AND WHERE TO FIND THE RESULT OF THE CONVERSION.
Re-read the code in the OP-1 and OP-2 blocks. That shows you how to do it. What about those is so hard to understand?

And yes, code tags would be helpful. I've been putting them in when I can but you should do it as a matter of course.
@Johnlntx
the resutlts its on the ADCresultH,ADCresultL
so this what i did :
movf ADCresultH
movwf CCPR1L
 

Thread Starter

Don Omar

Joined May 5, 2017
49
make -f nbproject/Makefile-default.mk SUBPROJECTS= .build-conf
make[1]: Entering directory 'C:/Users/omar/Desktop/PIC16F684 PROJECT.X'
make -f nbproject/Makefile-default.mk dist/default/production/PIC16F684_PROJECT.X.production.hex
make[2]: Entering directory 'C:/Users/omar/Desktop/PIC16F684 PROJECT.X'
make[2]: 'dist/default/production/PIC16F684_PROJECT.X.production.hex' is up to date.
make[2]: Leaving directory 'C:/Users/omar/Desktop/PIC16F684 PROJECT.X'
make[1]: Leaving directory 'C:/Users/omar/Desktop/PIC16F684 PROJECT.X'

BUILD SUCCESSFUL (total time: 240ms)
Loading code from C:/Users/omar/Desktop/PIC16F684 PROJECT.X/dist/default/production/PIC16F684_PROJECT.X.production.hex...
Loading completed
 

JohnInTX

Joined Jun 26, 2012
4,787
Hmmm...
movf ADCresultH
should generate a message that it is using the default destination of the file register. All it does as written is move ADCresultH to itself, not to W so I'm not sure how it is working.. The value left over in W is actually the 2 LSbits of the ADC reading which isn't what you want. To load W with ADCresultH you need to specify the destination as W i.e.
movf ADCresultH,W
 

JohnInTX

Joined Jun 26, 2012
4,787
Beats me. No messages means that it didn't use the default destination. I assembled it in X and with a Clean and Build, and get the message as expected when I don't use ,W.
I think you are being lucky. Use the ,W. Without it, the value that you are writing to the CCP is the low byte of the ADC result (its left over from the ReadADC subroutine).

Personally, I would use the PICKit debugger to see why it behaves like that. Be sure to try that Clean and Build without the ,W. If no messages then, maybe MPASM has new tricks..
 
Top