Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

code confusion

Status
Not open for further replies.
Hetal said:
well but its funny tht was a simple code and all this while i was trying al the hard stuff.. :p

aneways i guess this way i learnt how to .. do a/d conversion and timer interrupts.. soo a quick question though .. when is the actual need for an interrupt can u give me a good example..

thnks a lot for the time and effort u took to help me for the code.... really appreciated.. :) now i feel from a person who knew nothing about the assembly language seems to .. understand

The only one of my tutorials that uses them is the seven segment tutorial, where I use a timer interrupt to multiplex the display.

Multiplexing requires you to display each digit in turn (in this case there's just two of them), and requires the same amount of time for each - or you can see the brightness difference between the digits.

So in the tutorial the interrupt routine is called at specific accurate intervals, the first time it's called it displays one digit, the next time it displays the other digit, this ensures exactly equal timing for each digit - it could easily be extended to drive more digits if required.

So the timer interrupt is doing the multiplexing, all we need to do in the main program is transfer the number we want to display to the correct variable, in this case 'Ones' and 'Tens'.

The main program code looks like this:

Code:
    Main
		call	Delay255
		call	Delay255
		call	Delay255
		call	Delay255
		incf	ones,	f
		movf	ones, 	w	;test first digit
		sublw	0x0A
		btfss	STATUS, Z
		goto	Main
		clrf	ones
		incf	tens,	f
		movf	tens, 	w	;test second digit
		sublw	0x0A
		btfss	STATUS, Z
		goto	Main
		clrf	tens
		goto	Main		;loop for ever

It simply counts from 0 to 99, and loops back to zero. Notice that in the entire routine there's no mention of ports or displays or anything - it's simply incrementing a two digit decimal counter consisting of two GPR's.

Everything else is done by the interrupt routine, from the main routine point of view you don't even need to know it exists, it's completely transparent.

Another classic example is a real time clock, using timer interrupts the clock can run even while you're doing something else!.
 
Code:
#include<P16f877.inc>

    LIST p=16F877
	errorlevel 1,-302	;to disable MPLAB bank warnings.
;**** Declare registers

STATUS	equ	 03h
PIE1	equ  8Ch
PIR1	equ  0Ch
DATA1   equ  2fh
;***Port Initilisation

	bsf	  STATUS,5        ;change to bank 1 
	movlw b'00001001'       ; RA0 and RA3 are inputs 
	movwf TRISA
             movwf 00h
	movwf TRISB
	bcf   STATUS,5

;*** A/D converter initialization

	movlw	b'10000001'       ;ADCS=10 CHS=AN0 ADON=ON
	movwf	ADCON0
	bsf     STATUS,RP0        ;move to bank 1
	movlw	b'00000101'		  ;ADFM=0 PCFG=0101
	movwf	ADCON1			  ;set adcon1 register
 	bcf     STATUS, RP0       ;return to bank 0
             call    ADC

;*** PWM initialization
	clrf    CCPR1L
	clrf    TMR2
	bsf 	STATUS,5
	movlw	3Fh               ; value of pr2 calculated came upto be 63
	movwf	PR2
             call    GETDATA;get the output of adc conversion as input to pwm duty cycle
             movf     DATA1,0;get data1 into w
	clrf        INTCON ;disable interrupts 
	bcf	STATUS,5
	movlw	H'99'               ; 60 percent duty cycle as the output 
	movwf	CCPR1L
	bsf        CCP1CON,CCP1Y    ; 
	bcf	CCP1CON,CCP1X
	bsf	STATUS,5	
	bcf 	TRISC,2
             clrf         PIE1
	bcf	STATUS,5                                                                                                                                                                                                                                                                                                                                                                 	
						
	movlw	b'0000100'     ; the prescaler is 1:1 and setting the tm2on
	movwf	T2CON 
;*** enable pwm mode
    movf CCP1CON, W
    andlw 0x30              ;mask all but prev. set duty cycle bits
    iorlw 0x0f              ;and enable PWM mode
    movwf CCP1CON
    return

GETDATA 
   bsf   STATUS,5
   movf  ADRESL,0 ; get the lsb byte of the output of adc
   bcf   STATUS,5
   movwf DATA1
   btfsc DATA1,0;check bit d0 from ADC output
   bsf   CCP1CON,4 ; if D0=1 set D4 in CCP1CON(bit D0 in PWM input)
   btfsc DATA1,1 ;check bit D1 from ADC output
   bsf   CCP1CON,5 ; if D1=1 set D5 in CCP1CON(bit D1 in PWM input)
   rrf   DATA1,1;rotate D0 into the carry bit   
   rrf   DATA1,1;rotate D1 into the carry bit
   bcf   DATA1,6;clear bit D8 into the carry bit   
   bcf   DATA1,7;clear bit D9 into the carry bit
   btfsc ADRESH,0
   bsf   DATA1,6
   btfsc ADRESH,1
   bsf   DATA1,7
   return


ADC   bsf ADCON0,GO	     	;start the A/D conversion

Wait  btfsc ADCON0,GO	;wait until conversion is done
	  goto  Wait
      return	     	;no then keep checking
   
  end

thnks for the informations ..i have that program working. however since i have written this code, i hope u could review this code. i am not using any interrupts here... and this prgramm will basically place the output of the a/d conversion in the pwm duty cycle and hence the output....
however when i simulated this programe i got one error, which i dont understand

CORE-E0002: Stack under flow error occurred from instruction at 0x000024


if you could pls help me out:confused: :)
 
Hetal said:
thnks for the informations ..i have that program working. however since i have written this code, i hope u could review this code. i am not using any interrupts here... and this prgramm will basically place the output of the a/d conversion in the pwm duty cycle and hence the output....
however when i simulated this programe i got one error, which i dont understand

CORE-E0002: Stack under flow error occurred from instruction at 0x000024


if you could pls help me out:confused: :)

You're still not writing the program correctly, where does it loop round? - it doesn't, it just runs until it reaches a spurious 'return' and crashes.

It's also written very confusingly, with a strange mixture of using the include file names and not, so it's hard to try and understand.

You're also declaring register names that are already declared in the include file, a further cause of confusion and possible mistakes.

The code itself seems rather long winded and complicated?, I would also like to see an ORG to set the program start address.
 
never get things right :(

Nigel Goodwin said:
You're still not writing the program correctly, where does it loop round? - it doesn't, it just runs until it reaches a spurious 'return' and crashes.

Well where shoutld i include the loop? I Thought the program runs on its own and then loops bak to the initial position. could u help me as to where i should include the loop. and the reason i wrote .. return was when callign a subroutine i thot i must write a return to get bak to the prog.

It's also written very confusingly, with a strange mixture of using the include file names and not, so it's hard to try and understand.

You're also declaring register names that are already declared in the include file, a further cause of confusion and possible mistakes.

i have deleted the register names and only included the data1 register .

The code itself seems rather long winded and complicated?, I would also like to see an ORG to set the program start address


i guess the reason its long is cos of adding the analogue inputs into the
CCPR1L register.. here i dont have a fixed duty cycle .. so it reads the inuts and places it accordingly ... instead of writing the code

Code:
             movf  ADRESH,W
    	movwf CCPR1L

i wrote this
Code:
  GETDATA 
   bsf   STATUS,5
   movf  ADRESL,0 ; get the lsb byte of the output of adc
   bcf   STATUS,5
   movwf DATA1
   btfsc DATA1,0;check bit d0 from ADC output
   bsf   CCP1CON,4 ; if D0=1 set D4 in CCP1CON(bit D0 in PWM input)
   btfsc DATA1,1 ;check bit D1 from ADC output
   bsf   CCP1CON,5 ; if D1=1 set D5 in CCP1CON(bit D1 in PWM input)
   rrf   DATA1,1;rotate D0 into the carry bit   
   rrf   DATA1,1;rotate D1 into the carry bit
   bcf   DATA1,6;clear bit D8 into the carry bit   
   bcf   DATA1,7;clear bit D9 into the carry bit
   btfsc ADRESH,0
   bsf   DATA1,6
   btfsc ADRESH,1
   bsf   DATA1,7
   return

so is it enuff if i had used the previous code ??/



this is my code with some modifications. however i would want to know where all i need to make further changes...should i include a loop at the end of pwm... ??

Code:
#include<P16f877.inc>

    LIST p=16F877
	errorlevel 1,-302	;to disable MPLAB bank warnings.
;****************  Program Start  ***********************
        org     0x00               ;Reset Vector
        goto    init
;**** Declare registers

DATA1   equ  2fh

;***Port Initilisation
init 
	bsf	  STATUS,5        ;change to bank 1 
	movlw b'00001001'       ; RA0 and RA3 are inputs 
	movwf TRISA
             movwf 00h
	movwf TRISB
	bcf   STATUS,5

;*** A/D converter initialization

	movlw	b'10000001'       ;ADCS=10 CHS=AN0 ADON=ON
	movwf	ADCON0
	bsf     STATUS,RP0        ;move to bank 1
	movlw	b'00000101'		  ;ADFM=0 PCFG=0101
	movwf	ADCON1			  ;set adcon1 register
 	bcf     STATUS, RP0       ;return to bank 0
   
            call    ADC

;*** PWM initialization
	clrf       CCPR1L
	clrf        TMR2
	bsf 	STATUS,5
	movlw	3Fh              
	movwf	PR2
   
             call       GETDATA;   
             movf     DATA1,0;get data1 into w
	clrf        INTCON ;disable interrupts 
	bcf	STATUS,5
	movlw	H'99'              
	movwf	CCPR1L
	bsf		CCP1CON,CCP1Y    
	bcf		CCP1CON,CCP1X
	bsf		STATUS,5	
	bcf 	TRISC,2
             clrf    PIE1
	bcf		STATUS,5                                                                                                                                                                                                                             movlw	b'0000100'          ; the prescaler is 1:1 and  tm2on
	movwf	T2CON 

;*** enable pwm mode
    movf CCP1CON, W
    andlw 0x30              ;mask all but prev. set duty cycle bits
    iorlw 0x0f              ;and enable PWM mode
    movwf CCP1CON
    

GETDATA 
   bsf   STATUS,5
   movf  ADRESL,0 ; get the lsb byte of the output of adc
   bcf   STATUS,5
   movwf DATA1
   btfsc DATA1,0;check bit d0 from ADC output
   bsf   CCP1CON,4 ; if D0=1 set D4 in CCP1CON(bit D0 in PWM input)
   btfsc DATA1,1 ;check bit D1 from ADC output
   bsf   CCP1CON,5 ; if D1=1 set D5 in CCP1CON(bit D1 in PWM input)
   rrf   DATA1,1;rotate D0 into the carry bit   
   rrf   DATA1,1;rotate D1 into the carry bit
   bcf   DATA1,6;clear bit D8 into the carry bit   
   bcf   DATA1,7;clear bit D9 into the carry bit
   btfsc ADRESH,0
   bsf   DATA1,6
   btfsc ADRESH,1
   bsf   DATA1,7
   return




ADC    bsf ADCON0,GO	     	;start the A/D conversion

Wait  btfsc ADCON0,GO	;wait until conversion is done
	  goto  Wait
      	     	
  end
:(
 
another code :(

i am sorrry ..but i am really confused.. i keep looking at a lot of tutorials and i come up with the code.. this is another code that i have formulated... could u tell me which one isbetter.. i now understand wht u meant by loop

Code:
#include <P16f877.inc>
   __CONFIG _RC_OSC & _CP_OFF & _WDT_OFF & _PWRTE_ON &_LVP_OFF
 	errorlevel 1,-302	;to disable MPLAB bank warnings.
  org 0
;set A/D Conversion

	movlw	b'10000001'       ;ADCS=10 CHS=AN0 ADON=ON
	movwf	ADCON0
	bsf     STATUS,RP0        ;move to bank 1
	movlw	b'00000101'		  ;ADFM=0 PCFG=0101
	movwf	ADCON1			  ;set adcon1 register
 	bcf     STATUS, RP0       ;return to bank 0
;Set the PWM period (976Hz = 1.025ms) by writing to the PR2 register
   

	movlw   3Fh         ;255-dec = 0xff-hex
	bsf     STATUS,RP0    ;use bank 1
	movwf   PR2            ;setting the period of PWM
	bcf     STATUS,RP0    ;return to bank 0

;Set the PWM Duty Cycle by writing to the CCPR1L register and CCP1CON<5:4> bits. 

	 movlw  H'99'            ;10000000-bin = 0x80-hex
	 movwf  CCPR1L          ;load 0x80 in W to CCPR1L
	 bcf    CCP1CON,CCP1X;  ;set bit 1 of the duty cycle
	 bcf    CCP1CON,CCP1Y;  ;set bit 0 of the duty cycle
;Make the CCP1 pin an output by clearing the TRISC<2> bit 
    
	 bsf    STATUS,RP0      ;move to bank 1
	 movlw  0xfb            ;11111011-bin = 0xfb-hex
	 andwf  TRISC          ;clear TRISC<2>
	 bcf    STATUS,RP0      ;return to bank 0

;Set the TMR2 prescale value and enable TMR2 by writing to T2CON.

	 movlw  b'0000100'            ;TMR2 on, prescale = 4
 	 movwf  T2CON          ;load 0x05 into T2CON reg

;Start the A/D conversion by setting ADCON0<2>

start:  nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
    	bsf ADCON0,GO        ;start the A/D conversion
Wait: 	btfsc ADCON0,GO      ;wait until conversion is done
		goto Wait

;Write the 8 most significant bits located in ADRESH (since we setup the registers to be left justified) to Value
	 movf ADRESH,W
	 movwf CCPR1L      ;write value into PWM
	 bcf CCP1CON,CCP1X
	 bcf CCP1CON,CCP2Y

;Configure the CCP1 module for PWM 
 	movf CCP1CON, W
 	andlw 0x30              ;mask all but prev. set duty cycle bits
 	iorlw 0x0f              ;and enable PWM mode
	 movwf CCP1CON
	 goto start
    END
:confused:


sorry for the trouble

its just that i have to give this code by evening today

and after u chek this i want to go forward with the timer interrupt for the led
 
Like I posted before, something like this:

Code:
Initialise PIC
Initialise PWM
Initialise A2D
Loop
    Read A2D
    Modify PWM
    Delay (may be required to give time for PWM change to settle)
Goto Loop

You can't just let a program carry on running, it has to have a specific program flow, or you're just asking for disaster!
 
Code:
org 0
[COLOR="Sienna"];Initialise PIC [/COLOR]

    bsf	  STATUS,5          ;change to bank 1 
	movlw b'00001001'       ; RA0 and RA3 (Vref+) are inputs 
	movwf TRISA
    movwf 00h
	movwf TRISB
	bcf   STATUS,5

[COLOR="sienna"];Initialise PWM[/COLOR]

      ;Set the PWM period (976Hz = 1.025ms) by writing to the PR2 register
   
	movlw   3Fh         ;255-dec = 0xff-hex
	bsf     STATUS,RP0    ;use bank 1
	movwf   PR2            ;setting the period of PWM
	bcf     STATUS,RP0    ;return to bank 0

       ;Set the PWM Duty Cycle by writing to the CCPR1L register and CCP1CON<5:4> bits. 

	 movlw  H'99'            ;10000000-bin = 0x80-hex
	 movwf  CCPR1L          ;load 0x80 in W to CCPR1L
	 bcf    CCP1CON,CCP1X;  ;set bit 1 of the duty cycle
	 bcf    CCP1CON,CCP1Y;  ;set bit 0 of the duty cycle
       
       ;Make the CCP1 pin an output by clearing the TRISC<2> bit 
    
	 bsf    STATUS,RP0      ;move to bank 1
	 movlw  0xfb            ;11111011-bin = 0xfb-hex
	 andwf  TRISC          ;clear TRISC<2>
	 bcf    STATUS,RP0      ;return to bank 0

       ;Set the TMR2 prescale value and enable TMR2 by writing to T2CON.

	 movlw  b'0000100'            ;TMR2 on, prescale = 4
 	 movwf  T2CON          ;load 0x05 into T2CON reg
       ; Configure the CCP1 module for PWM 
 	
    movf CCP1CON, W
 	andlw 0x30              ;mask all but prev. set duty cycle bits
 	iorlw 0x0f              ;and enable PWM mode
    movwf CCP1CON
[COLOR="sienna"];Initialise  A/D Conversion[/COLOR]

	movlw	b'10000001'       ;ADCS=10 CHS=AN0 ADON=ON
	movwf	ADCON0
	bsf     STATUS,RP0        ;move to bank 1
	movlw	b'00000101'		  ;ADFM=0 PCFG=0101
	movwf	ADCON1			  ;set adcon1 register
 	bcf     STATUS, RP0       ;return to bank 0

;Start the A/D conversion by setting ADCON0<2>

[COLOR="sienna"]Loop [/COLOR] :  nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
    	bsf ADCON0,GO        ;start the A/D conversion
Wait: 	btfsc ADCON0,GO      ;wait until conversion is done
		goto Wait

    	 movf ADRESH,W
	     movwf CCPR1L      ;write value into PWM
	     bcf CCP1CON,CCP1X
	     bcf CCP1CON,CCP2Y
		 [COLOR="sienna"]goto Loop[/COLOR]
    
END

welll ihave modified it accordingly .. so is it right now ????
 
Hetal said:
welll ihave modified it accordingly .. so is it right now ????

Well I haven't gone entirely through the code, but it's certainly looking a lot more possible!.

However, I suggest you may need a LOT more delay in the loop, to allow the PWM changes time to take effect.
 
got the code rite . now step 2..

well yea i would be adding more delay ..

now since i have this code workig .. ..i have to use timer interrupt for .. the led..rite?

so from ur tutorial .. i would just have to include the .. led working in the interrupt vector... ????

one more question for putting the .. duty cycle value in the ccpr1l register... .. the first value i put should it be .. ffh that is the maximum (100 percent ) always ? or can i input the value as .. 60 percent ?

second .. since i am using 78.12 khz ...the maximum resolution is 8 bits so i dont have to worry abt the lower 2bits ??
 
Last edited:
Only if you want to use interrupts to do it!, the lights could easily be done in the main loop along with the PWM. Even using timer interrupts it would probably be best to do the control in the main loop, and use timer interrupts to generate a clock count in GPR's, your main loop then checks the values in the GPR's and switches the lights accordingly.

But for a start I would suggest getting the PWM/A2D part built and tested, far easier to do jobs in sections!.
 
pwm code query

ok i am workign on programing it on .. the chip however i had 2 more ques for the .. pwm code

one more question for putting the .. duty cycle value in the ccpr1l register... .. the first value i put should it be .. ffh that is the maximum (100 percent ) always ? or can i input the value as .. 60 percent ?

second .. since i am using 78.12 khz ...the maximum resolution is 8 bits so i dont have to worry abt the lower 2bits ??
 
one more question sorry ..

the a2d loops forever.. however .. if i had initialised the pwm in the beginnign .. does it continue to operate in the background?


and moreover.. in the loop after the value is written in the ccpr1l register.. do i have to initialise the pwm again in the loop ????
 
The PWM is completely seperate to anything you do, you set it up, give it a value - and it then runs independently. When you alter the PWM value this is simply stored in the PWM module, when it reaches it's next cycle it will use that value instead of the previous one. It's SO easy to use!.

Check my PWM tutorial, which actually uses the two PWM channels in a 16F876 (which also uses 8 bit resolution).

However, it's seem unlikely that simply copying the A2D value to the PWM will do what you want? - you are likely to have to perform some maths on the value first.
 
so how do i code the maths

do u have a code on how i can... do the maths...

pls help me programmin this part..


say if my analogue input is ..10 volts .. my output will always remain 6 volts

so basically my new duty cycle will be .. 6/10 ..

if input is .. 8 volts then 6/8

its a buck converter operation

sorry for the trouble

[i thought that by just puttng the value from a2d in the pwm register.. the duty cycle will vary accdgly.. ]
 
For a start you need to subtract it from a fixed value - if you're using 8 bits then subtract it from 255. As it is, as the A2D readings gets larger you're INCREASING the PWM value, which will make it larger still - until the PWM is running at maximum. It needs to work the other way - as the A2D gets larger, you need to REDUCE the PWM, and as the A2D gets smaller, you need to INCREASE the PWM. A simple subtraction will probably do as a starting point?.
 
Nigel,

You should have been a teacher. You get my vote for the most tolerant contributer.

Mike.
 
Hetal said:
do u have a code on how i can... do the maths...

pls help me programmin this part..


say if my analogue input is ..10 volts .. my output will always remain 6 volts

so basically my new duty cycle will be .. 6/10 ..

if input is .. 8 volts then 6/8

its a buck converter operation

sorry for the trouble

[i thought that by just puttng the value from a2d in the pwm register.. the duty cycle will vary accdgly.. ]

You said you copied the code from somewhere. Did it come with a electronic schematic?

There are a couple points I would like to raise:

First, was already pointed out by Nigel. How does the PWM signal control the buck converter. Is the series pass transistor ON when the PWM high? In this case, increasing the value of the CCPR1L register would raise the output voltage. Or you can invert the signal and turn OFF the transistor when the PWM signal is high. In this other case, raising the value of CCPR1L will lower the output voltage.

Second, the maximum voltage the PIC A/D converter input can accept is Vcc. Therefore, to measure a 6-10V signal, you need to scale the voltage down using a voltage divider.

It would help to post a schematic before any specific code can be presented.
 
the circcuit

hey motion i have added a simple circuit representation of the circuit..

basically its like a buck converter .. the max input voltage is arnd 10 volts and the output will be arnd 6 volts and i am using the pic to regulate the voltage to arnd 6 volts. i havent elaborated the diag.

nigel and motion thanks a lot for all the efforts .

i just wanted to ask now the only part left is .the working of the leds.. so .besides interrupts is there another way .. and if there are interrupts ..so i have to initialise the interrupts and .. in the interrupt routine inclide the workign of the leds...

and by this .. as u mentiond they will work in particular time periods? will these time periods be short that it will look lik the leds are looping forever..
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top