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.

Need some help troubleshooting by project

Status
Not open for further replies.

Kai-Itza

New Member
Hey guys :)

I'm in a bit of a muddle with a little home project of mine and am wondering if any of you want to help.

I'm building a very simple light sensing circuit using a 1M ohm LDR (with the 1M value being the max value when in the dark), as it's getting dark the program (written in Assembler) will monitor and test the incoming ADC values until it reaches ~60% of the LDR's resistance value through the voltage that it carries, once it reaches this threshold the program would then activate a simple LED to symbolise this. Easy right? Yeah, that's what I thought until I found out that I can't get it to work :(.

This is but the first stage of a much larger project, of which I want to build up in 'building blocks', this project would eventually grow to that which looks after plantlife within my conservatory so I don't have to.

I'm relatively new to programming in general and I thought that Assembler was a good place to start, I know all the basics as I've been learning this through the Version 3 PICmicro® microcontroller development board from Matrix Multimedia, it's a little old I know being as it is a evaluation board that was released way back in 2003 and it still has usage in it yet. So I'll be developing this project off of this for the time being.

I'm using the PIC:16F88 for this project.

And the following is the Program that I've been working on for the last 2 weeks:

Code:
;PROGRAMMING OPTIONS************************************************
;
; When programming the PIC 16f88 using the Assembler (ASM:IDE), the following options are selected:
;
; Oscillator selection; EXTRC as clock-out
;Watchdog timer - disabled
; Power up timer - disabled
; Pin function select; MCLR
; Brown-out protection - enabled
; Code Proection - diabled
;Low Voltage program - enabled
; data EE read protect - disabled
;Flash program write enable: Write protect - disabled
;Background debug - disabled
;CCP1 Mux pin; RB0
;code proect - disabled
;fail-safe clock monitor - enabled
;internal/eternal switch over mode - enabled
;
;I/O ALLOCATION*****************************************************
;
;INPUTS...........................................................
;
;Analogue sensors (input)	AN4-AN6(VDD = 5.0V)	; There is only going to be one temperature sensor to be used through one of these pins, the reason why three have been selected is for other sensors to be added after the temperature sensor has been tried and tested successfully
;Digital I/O 		RA0-RA3 		
;
;OUPUTS...........................................................
;
; LED
;
;PORT DATA DIRECTION CODES REQUIRED...............................;
;
;
;ADC SETUP********************************************************
;
;ANSEL	bit	7	0= unimplimated
;	bits	6543	1= analog input
;	bits 	210	0= digital I/O
;
;ANSEL = 01111000	
;
;ADCON1	bit	7	1= right justify result in ADESH/ADRESL
;	bit	6	0= disabled (not needed)
;	bits	54	10== VREF-VSS
;	bits	3210	0= unimplemented
;
;ADCON1 = 1010000
;
;ADCON0 	bits	76	0= A/D clock = f/8
;	bits 	543	channel select (AN0-AN7)
;	bit	2	GO=1/DONE=0
;	bit	0	A/D Module enable = 1
;
;ADCON0 = 01111001
;
;	Create  list file and select processor :
	list p = 16f88
;
#DEFINE	PAGE0 BCF STATUS,5
#DEFINE	PAGE1 BSF STATUS,5
;
;	Include file containing register labels:
	Include "p16f88.inc"
;
STATUS	EQU H'03'	; STATUS register
count 	EQU 020		; assign General Purpose Register, Bank 0 for counter 
z	EQU 2		;Zero flag
;
;set origin at address 000
org	0x000

				
	ORG	0		; Reset vector
	GOTO	5		; Goto start of program
	ORG	4		; Interrupt vector
	GOTO	5		; Goto start of program
	ORG	5		; Start of program memory

	; set up code for 16F88 ports
	BSF	3,5	;switch to page 1
	CLRF	H'9b'	;clear ansel file - set ports to digital io
	BCF 	3,5	;switch to page 0
;
;SETUP STATUS REGISTER............................................
;

;
;SETUP ADC........................................................
;
	banksel	ANSEL		;select register bank
	movlw	b'01111000'	
	movwf	ANSEL		;write A/D control word
;
	banksel	ADCON1		;select register bank
	movlw	b'10100000'	
	movwf	ADCON1		;write A/D control word
;
	banksel	ADCON0		;select register bank
	movlw	b'01111001'
	movwf	ADCON0		;write A/D control word
;
;SUBROUTINE TO WAIT ABOUT 0.8MS..................................
;
delay	movlw	256		;load time delay of 256x3=768
	movwf	count		;load counter	down	decfsz	count		;decrement and test counter
	goto 	count
;
;SUBROUTINE TO GET ANALOGU INPUT - 20US SETTLING TIME.............
;
A2D	movlw	007		;time delay of 7x3=21us
	movwf	count		;load counter
again	decfsz	count		;decrement until zero
	goto 	again		;decrement until zero
;
;GET ANALOGUE INPUT..............................................
;
	movlw	b'01000001'
	movwf	ADCON0
adc	bsf	ADCON0, GO	;start a2d conversion
wait	btfsc	ADCON0, GO	;wait for conversion to complete
	goto 	wait
	movf	ADRESL, h'08'	;place in register location for testing
	movf	ADRESH,	h'09'	;place in register loaction for testing
;
	movlw	H'66'		;place the total of 614-bits
	movwf	h'35'		;in two empty locations of memory bank 0
	movlw	H'02'		;these are to test the thermistor component
	movwf	H'36'		;to see if it is >60% of it's original value
;	
	movf	H'35', w		
	subwf	H'08', H'08'	;subtract loaded ADC value from 102-bytes and place into memory
	movf	H'36', w
	subwf	H'09', H'09'	;subtract loaded ADC value from 2-bytes and palce into memory
;
	btfsc	h'08', z	;and test ADRESL...
	goto 	part2
	movlw	H'0F'		;...if the thermistor is >60% of it's original value, place the value 0F...
	movwf	H'4B'		;...into an empty register
;
part2	btfsc	H'09', z	;and then test ADRESH...
	goto	adc
	movlw	H'0F'		;...if the thermistor is >60% of it's original value, place the value 0F...
	movwf	H'4A'		;...into an empty register
;
;TEST TO SEE IF BOTH ADRESL AND ADRESH ARE BOTH POSITIVE.................
;
	movf	H'4A', w	;load the value of ADRESH into the working register
	ADDWF	H'4B', H'4A'	;add both ADRESH's and ADRESL's positive 'flags' (the values of 0F for both results), which would make the value of H'1E'
	btfss	H'4A', H'1E'	;...and test to see if this result is positive
	goto	adc
	goto	ledop		;if it is; turn on LED RB0
;
;
;
;LED OUTPUT IF THERMISTOR READS 61% OF ITS MAXIMUM VALUE..........
;
ledop 	CLRF	6		; set all Port B pins to logic 0 
 	BSF	3,5		; instruct program that a Page 1   
		 	 	; command comes next 
 	CLRF	6		; set all Port B pins as outputs 
 	BCF	3,5		; instruct program that a Page 0   
		 	 	; command comes next 
 	BSF	6,0		; set Port B pin 0 to logic 
	goto	adc		;keep testing and provide outputs as per programme parameters

	end

I've connected this up like this, the board itself is connected to the mains supply using an adapter set to 13.5v. The ADC inputs uses a +Vref of 2.55v connected into pin 2(Vref) and from that, this is then connected to the LDR which is connected to the ADC input pin 17 (AN0). The LED is already part of the Eval. Board itself.

References to the relevant datasheets can be found in the following:

PIC:16F88
Version 3 PICmicro® microcontroller development board

And, I'm using the ASM:IDE v1 debugger for assembling/debugging/building it onto the PIC:16F88

If there's anything that I missed let me know and I reply as best as I'll can, as I don't really know what's wrong with it for as far as I know, the programming and connections are correct. Can someone help me on this as I'm getting a bit confused over this :(.

Thanks for your time.


-Kai-Itza-
 
hi Kai-Itza,
I have looked thru your program and there are lots of errors, too many to list.
I would suggest that you are making the program over complicated for what you are trying to do.

Connect the LDR via a resistor to +5V and the other end of the LDR to 0V.
Choose the value of the series LDR resistor so that when its 'dark' , the junction of the LDR and resistor is approx 2.5V.
So if the LDR is 1megOhm when dark, use a 1megOhm series resistor.
NOTE: having such a high input resistance will mean the adc conversion will not be accurate, but as the rate of change of the LDR's resistance is slow, it may be acceptable, if not I could post a circuit for the LDR.

Set the PIC's adc for Right Justify, so that you are only using ADRESL [ 0 to 255 counts], use the PIC's internal 5Vref for the adc.
Using a voltmeter determine what the voltage is at the junction of the LDR and resistor when you want the LED to light.
For example say the voltage is 2V when its just getting dark.
In the program this would be a count of [2v/5v] * 255= 102, so compare the actual adc count against 102.
When the adc value is greater than 102 turn ON the LED and when less than 100 say, turn it OFF.

This is a very simple description, if you want more details, please ask.
 
Set the PIC's adc for Right Justify, so that you are only using ADRESL [ 0 to 255 counts],

From my studying of the 16F88, see that both ADRESH and ADRESL makes up 8-bits each, and to set the ADC to Right Justify it says that the 6 MSB will be set to 0, meaning that there are 2 LSB left on the ADRESL. Do I need to use them or should I just ignore ADRESH completely and use the whole 8-bits of ADRESL?

use the PIC's internal 5Vref for the adc.

Do I need to set a Pin for this or do I just use the same supply rail as the one powering the PIC? Sorry for the noobish question but I'm a little confused as to how this can be done, about a fortnight ago I've decided to re-revise the subject after a 2 year hiatus so, as you can tell, I'm quite a bit rusty!

In the program this would be a count of [2v/5v] * 255= 102, so compare the actual adc count against 102.
When the adc value is greater than 102 turn ON the LED and when less than 100 say, turn it OFF.
.

I can't see how this can be done if there's no IF/ELSE/>/= etc. instructions included in the 16F88's datasheet, neither can I find these in the examples found in the tutorials as these seem to me that they are part of the C language. Is it possible to do this in Assembler in another format?

I seem to learn better by using examples and seeing them in front of me, in code, diagrams etc. and you said that there's loads of errors in the code that I've written from my re-learning experience I can see none of this, can you help me by cleaning it up, so that I can see my mistakes as I am still a learner after working through the tutorials - the tutorials never mentioned any of the more special functions and how they can be used, this is what I'm trying to do here; Making the ADC work and learning from this experience.
If you can't than I'll understand :).


-Kai-Itza-
 
From my studying of the 16F88, see that both ADRESH and ADRESL makes up 8-bits each, and to set the ADC to Right Justify it says that the 6 MSB will be set to 0, meaning that there are 2 LSB left on the ADRESL. Do I need to use them or should I just ignore ADRESH completely and use the whole 8-bits of ADRESL?

If you use right justify, use only the ADRESL 8 bit value, ignore the the 2 high order bits in the ADRESH,.

If you prefer to have a 0 to 255 count representing 5Vinp to the adc then Left justify and use the value in in ADRESH.
So then you could compare say 2.5V for dark/light as 127counts.

I would use this for your project.

Just use ADRESH or ADRESL 8 bit value and compare a simple Byte.

If you do not set one of the adc pins as Vref, the +5V internal ref is automatically used.


Do I need to set a Pin for this or do I just use the same supply rail as the one powering the PIC? Sorry for the noobish question but I'm a little confused as to how this can be done, about a fortnight ago I've decided to re-revise the subject after a 2 year hiatus so, as you can tell, I'm quite a bit rusty!



I can't see how this can be done if there's no IF/ELSE/>/= etc. instructions included in the 16F88's datasheet, neither can I find these in the examples found in the tutorials as these seem to me that they are part of the C language. Is it possible to do this in Assembler in another format?

I seem to learn better by using examples and seeing them in front of me, in code, diagrams etc. and you said that there's loads of errors in the code that I've written from my re-learning experience I can see none of this, can you help me by cleaning it up, so that I can see my mistakes as I am still a learner after working through the tutorials - the tutorials never mentioned any of the more special functions and how they can be used, this is what I'm trying to do here; Making the ADC work and learning from this experience.
If you can't than I'll understand :).


-Kai-Itza-

hi,
Regards the IF ELSE.
Consider a simple subtraction that returns a ZERO flag or not.
eg: Current adc value - stored DARK value, if the result sets the the STATUS ZERO flag, then its dark else its light.
To give some hysteresis in the switching from dark/light/dark use a stored LIGHT value which is different from the dark value.

So when you have set the LED on as its dark, now start test the current value against the stored light value in order to switch off the LED.
eg: Current adc value - stored LIGHT value, if the ZERO is set its still DARK
OK.?
 
Last edited:
hi,
Regards the IF ELSE.
Consider a simple subtraction that returns a ZERO flag or not.
eg: Current adc value - stored DARK value, if the result sets the the STATUS ZERO flag, then its dark else its light.
To give some hysteresis in the switching from dark/light/dark use a stored LIGHT value which is different from the dark value.
So when you have set the LED on as its dark, now start test the current value against the stored light value in order to switch off the LED.
eg: Current adc value - stored LIGHT value, if the ZERO is set its still DARK
OK.?

That's what I tried to do with the previous program I wrote where then, I included the contents within the ADRESH register location. Now I've changed that to the point where I'm only comparing the contents of ADRESHL to provide an LED output, that is variable by the LDR.

So thanks for the head's up :)

I've made changes to the code and I'm getting some really weird readings.

The internal +Vref is not at the AN3 (pin 2) output, instead pin 18 (AN1) is output with 4.7v and pin 17 (AN0) is at 0.6v, I think AN0 is fine as this could be the small amount of voltage that the ADC input needs to actually read the incoming voltage values. But it's that other pin that made me raise an eyebrow, as from the set-up code AN1 is not supposed to output.

Code:
;PROGRAMMING OPTIONS************************************************
;
; When programming the PIC 16f88 using the Assembler (ASM:IDE), the following options are selected:
;
; Oscillator selection; EXTRC as clock-out
;Watchdog timer - disabled
; Power up timer - disabled
; Pin function select; MCLR
; Brown-out protection - enabled
; Code Proection - diabled
;Low Voltage program - enabled
; data EE read protect - disabled
;Flash program write enable: Write protect - disabled
;Background debug - disabled
;CCP1 Mux pin; RB0
;code proect - disabled
;fail-safe clock monitor - enabled
;internal/eternal switch over mode - enabled
;
;I/O ALLOCATION*****************************************************
;
;INPUTS...........................................................
;
;Analogue sensors (input)	AN4-AN6(VDD = 5.0V)	; There is only going to be one temperature sensor to be used through one of these pins, the reason why three have been selected is for other sensors to be added after the temperature sensor has been tried and tested successfully
;Digital I/O 		RA0-RA3 		
;
;OUPUTS...........................................................
;
; LED
;
;PORT DATA DIRECTION CODES REQUIRED...............................;
;
;
;ADC SETUP********************************************************
;
;ANSEL	bit	7	0= unimplimated
;	bits	6543	1= analog input
;	bits 	210	0= digital I/O
;
;ANSEL = 00011111	
;
;ADCON1	bit	7	1= right justify result in ADESH/ADRESL
;	bit	6	0= disabled (not needed)
;	bits	54	01== AVdd-REF
;	bits	3210	0= unimplemented
;
;ADCON1 = 10010000
;
;ADCON0 	bits	76	0= A/D clock = f/8
;	bits 	543	channel select (AN0-AN7)
;	bit	2	GO=1/DONE=0
;	bit	0	A/D Module enable = 1
;
;ADCON0 = 01111001
;
;	Create  list file and select processor :
	list p = 16f88
;
#DEFINE	PAGE0 BCF STATUS,5
#DEFINE	PAGE1 BSF STATUS,5
;
;	Include file containing register labels:
	Include "p16f88.inc"
;
PORTA	EQU	H'05'
PORTB	EQU	H'06'
TRISB	EQU 	H'86'	; Port B direction register
TRISA	EQU 	H'85'	; Port A direction register
STATUS	EQU	H'03'	; STATUS register
z	EQU	2	;Zero flag
count 	EQU	H'20'	; assign General Purpose Register, Bank 0 for counter 
;
;set origin at address 000
org	0x000
;
;				
	ORG	0		; Reset vector
	GOTO	5		; Goto start of program
	ORG	4		; Interrupt vector
	GOTO	5		; Goto start of program
	ORG	5		; Start of program memory
;
	; set up code for 16F88 ports
	BSF	3,5		;switch to page 1
	CLRF	H'9b'		;clear ansel file - set ports to digital io
	BCF 	3,5		;switch to page 0
;
	CLRF	PORTB		;clear port b data register
	PAGE1			;PAGE1
	CLRF 	TRISB		;set all Port B as output (clear
		       		;direction reg)
       	PAGE0			;PAGE 0
;
	clrf	PORTA		;clear port a data register
	PAGE1			;PAGE1
	bsf	TRISA,H'1F'	;set all port a as inputs (set direction register)
	PAGE0			;PAGE 0
;
;SETUP STATUS REGISTER............................................
;
;
;
;SETUP ADC........................................................
;
	banksel	ANSEL		;select register bank
	movlw	b'00011111'	
	movwf	ANSEL		;write A/D control word
;
	banksel	ADCON1		;select register bank
	movlw	b'10010000'	
	movwf	ADCON1		;write A/D control word
;
	banksel	ADCON0		;select register bank
	movlw	b'01111001'
	movwf	ADCON0		;write A/D control word
;
;
;SUBROUTINE TO GET ANALOGU INPUT - 20US SETTLING TIME.............
;
A2D	movlw	007		;time delay of 7x3=21us
	movwf	count		;load counter
again	decfsz	count		;decrement until zero
	goto 	again		;decrement until zero
	return
;
;GET ANALOGUE INPUT..............................................
;
get	movlw	b'01000001'
	movwf	ADCON0
	call	A2D
;
	movf	ADRESL, H'08'	;place in register location for testing
;
	movlw	H'1A'		;place the total of 26-bits
	movwf	H'35'		;in a empty location within memory bank 0
;
;	
;
;
;TEST TO SEE IF THE THERMISTOR IS IN THE DARK.................
;
	movf	H'35', w
	subwf	H'08', H'36'
	btfss	STATUS, Z		;check if Zero flag (bit 2) of
;		       	 	; STATUS = 1
	goto	ledoff		;is the Zero flag is not set make the LED RB0, logic = 0
	goto	ledon		;if it is; turn on LED RB0, logic = 1
;
;
;
;
;LED OUTPUT..........
;
ledon 	bcf 	STATUS,z	 	; clear zero flag
	clrf	PORTB		; set all Port B pins to logic 0 
 	bsf	3,5		; instruct program that a Page 1   
;		 	 	; command comes next 
 	clrf	PORTB		; set all Port B pins as outputs 
 	bcf	3,5		; instruct program that a Page 0   
		 	 	; command comes next 
 	bsf	PORTB,0		; set Port B pin 0 to logic 
	goto	get		;keep testing and provide outputs as per programme parameters
;
ledoff 	bcf 	STATUS,z	; clear zero flag
	bcf	PORTB,0		; clear Port B pin 0 
;
	end
Also, the output is not active when the voltage passes the threshold, so I've must've done something wrong here, but what am I missing/misplaced?

I'll check the code again, maybe I've placed set-up bits in the wrong areas

Thoughts?


-Kai-Itza-
 
hi Kai-Itza
I will run your program today.
A point you may find useful is that if you have a spare ADC pin, is to connect a 10K pot across +5V and 0V, the wiper to the spare adc input.
Use this pot to set the light/dark compare value, in that way you can easily change the On/Off without changing the program.

EDIT:
There are still lots of errors in the program.
When you call the ADC, and the values are in ADRESH/L you do not have to save them to a another register. The values will remain in the ADRES SFR's until you call the ADC again.
So compare the DARK value with the ADRES register.
You do not require to set an ADC pin to Vref, use the PIC's internal 5Vref.

Code:
;
;SUBROUTINE TO GET ANALOGU INPUT - 20US SETTLING TIME.............
;
A2D	movlw	007		;time delay of 7x3=21us
	movwf	count		;load counter
again	decfsz	count		;decrement until zero
	goto 	again		;decrement until zero
	[COLOR=Red]return[/COLOR]  ; where is this returning too.??? its causing a STACK under flow
;
;GET ANALOGUE INPUT..............................................
;
get	movlw	b'01000001'
	movwf	ADCON0
	call	A2D
 
Last edited:
I've made a little discovery yesterday, as I was searching through the ASM:IDE v3 tutorials and found in a hidden corner an example for ultilising and using ADC! It's strange as there's nothing in the tutorials themselves that even mentions the usage of the ADC throughout the tutorial topics. So I delved into this program and took a minute to understand its guts, after this I modified it to do what I wanted.

When I downloaded the finished result onto the 16F88, using the 10k potentiometer to act as the LDR, the potentiometer didn't work as the development board's on-board LDR kicked in automatically, which made testing the PIC all the more annoying as I found out that the program had worked, only to the point where it only turns on the LED output when it exactly on the testing value; in this case its 102 (decimal) - I found this out buy measuring the relevant pins with my DMM, of which gave me 2.04 volts.
I spent the last 2 1/2 hours running through this new program; checking it step-by-step theoretically, tinkering with the setups, the layout of the main code and its subroutines trying to find a way for the output LED to stay on whilst in the dark.

As you can see in the code that I provided, the output of the LED is decided by the zero bit of the STATUS register which by my observation of the code, it should still be turned on even when it exceeds the testing threshold of 102 (decimal) so, what am I missing now?:/

Code:
; TUTAADC.INC 23MAR04
; illustrating use of ADC
;
;	Create  list file and select processor :
	list p = 16f88
;
#DEFINE BANK0 BCF STATUS,5
#DEFINE BANK1 BSF STATUS,5
#DEFINE BLOCK0 BCF STATUS,7             ; clear STATUS bit 7 (IRP)
#DEFINE BLOCK1 BSF STATUS,7             ; set   STATUS bit 7 (IRP)
;
#DEFINE CHAN0 iorlw B'00000000'
#DEFINE CHAN1 iorlw B'00001000'
#DEFINE CHAN2 iorlw B'00010000'
#DEFINE CHAN3 iorlw B'00011000'
#DEFINE CHAN4 iorlw B'00100000'
#DEFINE CHAN5 iorlw B'00101000'
#DEFINE CHAN6 iorlw B'00110000'
#DEFINE CHAN7 iorlw B'00111000'
;
;	Include file containing register labels:
	Include "p16f88.inc"
;                 
	CBLOCK
ADCMSB
	ENDC
;
PORTA	EQU	H'05'
PORTB	EQU	H'06'
TRISB	EQU 	H'86'	; Port B direction register
TRISA	EQU 	H'85'	; Port A direction register
STATUS	EQU	H'03'	; STATUS register
z	EQU	2	;Zero flag
count 	EQU	H'20'	; assign General Purpose Register, Bank 0 for counter
;
	; set up code for 16F88 ports
	BSF	3,5		;switch to page 1
	CLRF	H'9b'		;clear ansel file - set ports to digital io
	BCF 	3,5		;switch to page 0
;
; *********** SETTING PORTA FOR ANALOGUE ***********
;
                BLOCK0
                BANK1
                clrf	TRISB             ; PORTB as output
                movlw	B'00000000'       ; set Left justify, RA0, RA1, RA3 as analog inputs
                movwf	ADCON1            ; with RA, RE digital, ref to +VE and 0V
                movlw	B'11011011'       ; RA0, RA1, RA3, RA4 as input, RA2, RA5 as output
                movwf	TRISA
                BANK0
;
; *********** SETTING ADC CHANNEL AND READING ITS VALUE *****
;
          movlw	B'01000101'	; set AD on, Fosc/8
          CHAN0			; set for CHAN0 - RA0
          movwf	ADCON0
          call	DELAY          	; short delay following channel change
start     bsf	ADCON0,GO       	; start data conversion
	call	DELAY
          call	GETADC          	; get ADC value
          goto	start
;
; ******** GET ADC VALUE FROM SELECTED PORT PIN *****
;
GETADC          btfsc	ADCON0,GO
                goto	GETADC
                movf	ADRESH,W          ; get ADC MSB val
                movwf	ADCMSB            ; store it into ADCMSB
;
;
;******* TEST ADC VALUE AGAINST "DARK TIME" VALUE
;
		movlw	D'102'
		movwf	H'35'
		movf	ADCMSB, w
		subwf	H'35', H'36'
		btfss	STATUS, z
		goto	ledoff
		goto	ledon
		return
;
;SUBROUTINE TO GET ANALOGUE INPUT - 20US SETTLING TIME.............
;
DELAY	movlw	007		;time delay of 7x3=21us
	movwf	count		;load counter
again	decfsz	count		;decrement until zero
	goto 	again		;decrement until zero
	return
;
;******** If ZERO BIT IS ON, LED GOES ON ********
;
ledon	clrf	PORTB
	bsf	PORTB,0		; set Port B pin 0 to logic 
	return
;
ledoff	clrf	PORTB
	bcf	PORTB,0
	bcf	PORTB,0		; clear Port B pin 0 
	return
;
;
	END


-Kai-Itza-
 
hi Kai,

I get this error in assembly using Oshonsoft.

Code:
movlw    D'102'
        movwf    H'35'
        movf    ADCMSB, w
0082:        subwf    H'35', H'36'; [B]Argument out of range.  Least significant bits used.[/B]

        btfss    STATUS, z
        goto    ledoff
        goto    ledon
        return
 
Code:
movlw    D'102'
        movwf    H'35'
        movf    ADCMSB, w
0082:        subwf    H'35', H'36'; [B]Argument out of range.  Least significant bits used.[/B]

        btfss    STATUS, z
        goto    ledoff
        goto    ledon
        return

I don't get this, as whatever the result is after the subtraction, the result should be lower than 255 (decimal). So why is this error popping up saying that the result is too large? It shouldn't be 2's compliment, as I've disabled it in the setup.

Thanks for the head's up, eric :).



-Kai-Itza-
 
The funny thing is, that the assembler I'm using says there is no such error in the list file, how strange is that?

I think it's something to do with the way that the ADC's value is calculated, being as follows:

ADRESH*(255 + ADRESL) = ADC

Although, if this is the case, then why isn't the output LED on at the lower levels? Chances are I think I'm missing something really obvious.


hi Kai,
Do you need any help in writing this program.?:)

If I didn't, then i wouldn't have started this thread ;), I would be grateful for any advice, tips, hints and any other help that would go towards the solving of this little mystery, and the continuation of this little project. It may be completely obvious to more experienced programmers, but for a beginner like me, it's annoying, as I'm only fresh off of tutorial learning to try out new things that the tutorials didn't mention, like the special function registers and what they can be used for.
 
hi Kai,
OK, I will try to post a program by tomorrow, that should help you to proceed.
Which assembler are you using.?
 
hi Kai,
OK, I will try to post a program by tomorrow, that should help you to proceed.
Which assembler are you using.?

Matrix Multimedia's ASM:IDE v1

It's pretty old (8 years) but it has an excellant tutorial called ASM for PICmicros microcontrollers - version 3, I learnt pretty much everything about PIC's in just this one tutorial.

Thanks :)


-Kai-Itza-
 
hi kai,
Unzip this zip.
It has asm.hex and bas files.
I have included the basic file as it will help you follow the asm subroutines.
It works OK in the Oshonsoft simulator.
 

Attachments

  • kaizip1.zip
    2 KB · Views: 135
  • kaizip3.zip
    177.3 KB · Views: 134
  • kaiv2zip.zip
    1.6 KB · Views: 137
Last edited:
Sorry for not getting back to you sooner, it was my Mum's birthday last weekend :D

As I was looking through the program that you've written, I spied a little bit of information about the subwf instruction that I've completely overlooked. As it turns out I've stupidly overlooked (several times) that the 16f88's subwf instruction uses the 2's compliment method of carrying out this calculation, it's been over a year since I actually used 2's compliment for anything so it's a pretty easy mistake to overlook such a feature, the screenshot of this is shown below:

**broken link removed**

So, with this new knowledge I modified the comparing code from this:

Code:
1.	;******* TEST ADC VALUE AGAINST "DARK TIME" VALUE
2.	;
3.			movlw	D'102'		;102 decimal threshold, 
4.			movwf	H'35' 		;the ADC input goes over this the LED will go on
5.			movf	ADCMSB, w	;move ADRESH (ADCMSB) value to the working register
6.			subwf	H'35', H'36'	;subtract ADRESH (ADCMSB) from 102 decimal
7.			btfss	STATUS, z	;is the zero flag active?
8.			goto	ledoff		;no: turn off LED
9.			goto	ledon		;yes: turn on LED
10.			return

To this:

Code:
;******* TEST ADC VALUE AGAINST "DARK TIME" VALUE
;
		movlw	D'01100110'	;102 decimal threshold
		movwf	H'35'		;the ADC input goes over this
;					;the LED will go on
		movf	ADCMSB, w	;move ADRESH (ADCMSB) input value
;					;to the working register
		subwf	H'35', H'36'	;subtract ADRESH (ADCMSB) from 102 decimal
		btfss	STATUS, c	; is the carry flag active?
		goto	ledon		;yes: turn on LED
		goto	ledoff		;no: turn off LED
		return

Actually just by comparing them, it looks like I’ve solved this through only 3 lines of code. But I’ve finally got the output LED working in the way that I wanted it, and your code made me realise this without actually using it!

I’ll place the full, working program as follows:

Code:
; TUTAADC.INC 23MAR04
; illustrating use of ADC
;
;	Create  list file and select processor :
	list p = 16f88
;
#DEFINE BANK0 BCF STATUS,5
#DEFINE BANK1 BSF STATUS,5
#DEFINE BLOCK0 BCF STATUS,7             ; clear STATUS bit 7 (IRP)
#DEFINE BLOCK1 BSF STATUS,7             ; set   STATUS bit 7 (IRP)
;
#DEFINE CHAN0 iorlw B'00000000'
#DEFINE CHAN1 iorlw B'00001000'
#DEFINE CHAN2 iorlw B'00010000'
#DEFINE CHAN3 iorlw B'00011000'
#DEFINE CHAN4 iorlw B'00100000'
#DEFINE CHAN5 iorlw B'00101000'
#DEFINE CHAN6 iorlw B'00110000'
#DEFINE CHAN7 iorlw B'00111000'
;
;	Include file containing register labels:
	Include "p16f88.inc"
;                 
	CBLOCK
ADCMSB
	ENDC
;
PORTA	EQU	H'05'
PORTB	EQU	H'06'
TRISB	EQU 	H'86'	; Port B direction register
TRISA	EQU 	H'85'	; Port A direction register
STATUS	EQU	H'03'	; STATUS register
z	EQU	2	;Zero flag
c	EQU	0
count 	EQU	H'20'	; assign General Purpose Register, Bank 0 for counter
;
	; set up code for 16F88 ports
	BSF	3,5		;switch to page 1
	CLRF	H'9b'		;clear ansel file - set ports to digital io
	BCF 	3,5		;switch to page 0
;
; *********** SETTING PORTA FOR ANALOGUE ***********
;
                BLOCK0
                BANK1
                clrf	TRISB             ; PORTB as output
                movlw	B'00000000'       ; set Left justify, RA0, RA1, RA3 as analog inputs
                movwf	ADCON1            ; with RA, RE digital, ref to +VE and 0V
                movlw	B'11011011'       ; RA0, RA1, RA3, RA4 as input, RA2, RA5 as output
                movwf	TRISA
                BANK0
;
; *********** SETTING ADC CHANNEL AND READING ITS VALUE *****
;
          movlw	B'01000101'	; set AD on, Fosc/8
          CHAN0			; set for CHAN0 - RA0
          movwf	ADCON0
          call	DELAY          	; short delay following channel change
start     bsf	ADCON0,GO       	; start data conversion
	call	DELAY
          call	GETADC          	; get ADC value
          goto	start
;
; ******** GET ADC VALUE FROM SELECTED PORT PIN *****
;
GETADC          btfsc	ADCON0,GO
                goto	GETADC
                movf	ADRESH,W          ; get ADC MSB val
                movwf	ADCMSB            ; store it into ADCMSB
;
;
;******* TEST ADC VALUE AGAINST "DARK TIME" VALUE
;
		movlw	b'01100110'
		movwf	H'35'
		movf	ADCMSB, w
		subwf	H'35', H'36'
		btfss	STATUS, c
		goto	ledon
		goto	ledoff
		return
;
;SUBROUTINE TO GET ANALOGUE INPUT - 20US SETTLING TIME.............
;
DELAY	movlw	d'007'		;time delay of 7x3=21us
	movwf	count		;load counter
again	decfsz	count		;decrement until zero
	goto 	again		;decrement until zero
	return
;
;******** If ZERO BIT IS ON, LED GOES ON ********
;
ledon	clrf	PORTB
	bsf	PORTB,0		; set Port B pin 0 to logic 
	return
;
ledoff	bcf	PORTB,0		; clear Port B pin 0 
	return
;
;
	END

I'll now tidy this up and then contine with my little project :)

Thanks for your help, Eric, here’s some Rep.


-Kai-Itza-
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top