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.

Erratic output - help with A/D

Status
Not open for further replies.

bsodmike

New Member
Hello All!

The following code should do as it says. What I am taking for granted is that with the Vref == Vdd that the A/D res is 5/255 = 19.6mv per 'bit'.

Today I tested this on the PIC (had to disable internal OSC as it was complaning of not being able to find the calibration value @ that address) and @ 0v input the output was 15hz and 3.8v was giving 480 - 500Hz...

The Duty Cycle was 98% o_O.....

Nigel your help would be greatly appreciated!

Code:
;=======Subroutines========================================================
;~~~~~~~Delay Loop~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

delay	movfw	half_t		; copy half_t to accu
	subwf	_tmr0,w		; perform tmr0 - w, result in w

	btfss	_status,2	; check if tmr0 = 0, return
	goto	delay		; tmr0 != 0, so loop.

	retlw	0		; else, return

;-------Untested
;delay	clrf	_tmr0		; Start tmr0
;dloop	movfw	_tmr0		; Read tmr0 into w, w holds time
;	sublw	half_t		; Time - half_t
;	btfss	_status,2	; Check Time - half_t = 0
;	goto	dloop		; Time is not = half_t 
;	retlw	0		; Time is half_t, return 

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

So how this code works:

testing for 0.4v I check to see if the A/D res is over '26' if it is not, go back to the start and check again. If it is over then I set half_t (half of the frequency == half the period) as 105hz/2 = 53hz and pulse the DC signal high for that time and low again for that time (i.e. 50% duty cycle)...

However, this code is driving the PIC 'essentially' nuts....

Any help will be greatly appreciated!

Ohh and a free PIC programmer to anyone that can help solve this ;)
 
1.25v gives 122hz with it dropping to 99hz randomly but the duty cycle is 99.49% o_O

3v gives the output swinging erratically from 18hz to 579hz with an avg of 425hz......

So part 1, the delay loop needs fixing, not sure what is wrong with it hrm...
 
bsodmike said:
1.25v gives 122hz with it dropping to 99hz randomly but the duty cycle is 99.49% o_O

3v gives the output swinging erratically from 18hz to 579hz with an avg of 425hz......

So part 1, the delay loop needs fixing, not sure what is wrong with it hrm...

I don't see what you are trying to do in the 'delay' routine?, presumably you are wanting to delay the time 'half_t', but you don't seem to do anything with the value?. You subtract it from TMR0, but put the result back in W - how does this help?.

Also, why don't you use the MicroChip include files?, why add your own equates at the beginning of the program, when you can simple include the official MicroChip ones?.
 
Equates: this is something I picked up @ uni but they use a custom 'header' file (only for the 16F84). As this is my first time working with a different chip thought I'd do it this way.

edit Something just hit me ....as I am not 'altering' tmr0 I need to copy tmr0 to a temp holder to see that I count up from the temp value to half_t...

The untested code would work (because I just simulated it) but this alters tmr0. Actually for this code, altering tmr0 isn't a problem but I want to try the other way as it is more elegant and I can re-use it in future code.

So thinking out loud here:

copy tmr0 to tmr0temp
copy tmr0temp to w

subwf tmr0,w ; this is the extra bit we have gone u
subwf half_t,w ; this is the differance between target and current of tmr0temp
btfss status,zerobit ; are they equal
goto loop
else return
.....

gah, got to run out, seems the car has a flat tire...will be back and check for updates..
 
bsodmike said:
Equates: this is something I picked up @ uni but they use a custom 'header' file (only for the 16F84). As this is my first time working with a different chip thought I'd do it this way.

I guess the reason for the 'crazy' out put is because of a defective delay loop.

As I understand it with SUBWF you can either store the value in the accu or back into the file register. I don't want to alter 'tmr0' so I put it in the accu. Are you suggesting I do this:

Code:
delay	movfw	half_t		; copy half_t to accu
	subwf	_tmr0,w		; perform tmr0 - w, result in w

                movwf	half_t		; update half_t

	btfss	_status,2	; check if tmr0 = 0, return
	goto	delay		; tmr0 != 0, so loop.

	retlw	0		; else, return

I don't see how that code affects the timer either?.

With almost all PIC instructions, you can either write the result back to W or F, depending where you want it to go.

Presumably the point of your delay routine is to alter the value of tmr0, but it doesn't change it anywhere?.

Personally I usually use simple delay loops, it's easier to understand and works first time :lol:
 
Sorry Nigel, was editing that post while you replied, check out my new idea ;) tee hee!

Thanks, now I got to drive the car (on a partial flat) to the garadge...bbl in about 40mins
 
Code:
delay	movfw	_tmr0
	movwf	tmr0temp

dloop	movfw	tmr0temp
                subwf	_tmr0,w		; this is the extra bit we have gone up
	subwf	half_t,w	; diff between target and current of tmrtmp

	btfss	_status,2	; are they equal?
	goto	dloop		; not equal so loop

	retlw	0		; equal so return

What do you think Nigel?

edit Wow it works!

Before - just when half_t - tmr0temp = 0
**broken link removed**

After - you can see it exiting the delay!
**broken link removed**
 
I've only just realised what you are doing! - because it's so silly :lol:

You're repeatedly reading the tmr0 register, and comparing it with the value in the W register. This is a very strange thing to do!.

When tmr0 overflows (from 0xFF to 0x00) it sets a flag in a register, so all your delay routine should do is write the required value to tmr0 (bearing in mind it counts upwards). Then wait for the tmr0 flag to change.
 
I just linked 2 shots of before and after. What you are suggesting of actually 'clearing' the tmr0 and then comparing it to what I need? Which bit are your refering to, tmr0 Interrupt?

Anyways, this way works and doesn't alter tmr0 and doesn't involve interrupts...

Again you post when I am editing a post :lol:
 
bsodmike said:
I just linked 2 shots of before and after. What you are suggesting of actually 'clearing' the tmr0 and then comparing it to what I need? Which bit are your refering to, tmr0 Interrupt?

I'm not suggesting clearing it (unless you want the longest delay possible), but writing a value to it - by writing a value to tmr0 it starts counting from that value, so setting tmr0 to 250 will cause an overflow in only 6 clock cycles (actually 8 clock cycles, see the datasheet, you lose two cycles when you write to tmr0). You can set it so tmr0 overflowing causes an interrupt, or (as in the sample below) simply poll the flag.

This is the code for polling the overflow bit:

Code:
CheckAgain
	btfss 	INTCON,T0IF 	;timer overflowed?
	goto 	CheckAgain 	;no check again

Anyways, this way works and doesn't alter tmr0 and doesn't involve interrupts...

This way doesn't use interrupts either, and doesn't have any potential overflow problems - it's the way MicroChip do it in their application notes.

Again you post when I am editing a post :lol:

I do it on purpose 8)
 
Thanks.

My most recent snafu is with this bit of code:
Code:
	list p = 12C672

	org	00h		; the reset vector is defined as address 00hex
	call	07FFh		; get intosc calib info into wreg 

	bsf	_status,5	; move into bank 1
	movwf	_osccal		; calibrate the Int Osc
	bcf	_status,5	; move into bank 0

   	goto	setup		; and we tell it to go to 'setup'

In the 12C672 datasheet they explain that a call to 07FFh will result in invoking a 'retlw xx', so that I can move this to 'osccal' to calibrate it.

ICProg tells me 'No such calibration value found @ that address, may I use something else'...I said yes and well since then that was 2quid down the toilet.

Any ideas?

From the datasheet:

In addition, a calibration instruction is programmed into
the last address of the program memory which contains
the calibration value for the internal RC oscillator. This
value is programmed as a RETLW XX instruction where
XX is the calibration value. In order to retrieve the calibration
value, issue a CALL YY instruction where YY is
the last location in program memory (03FFh for the
PIC12C671 and the PIC12CE673, 07FFh for the
PIC12C672 and the PIC12CE674). Control will be
returned to the user’s program with the calibration
value loaded into the W register. The program should
then perform a MOVWF OSCCAL instruction to load the
value into the internal RC oscillator trim register.

ICProg tries to use 03FFh for the 12C672!
 
Ohh another question (for my ref) when I am accessing a Bank 1 register can I use it's bank 0 address when setting Rp0 to enter and exit bank 1 or does this matter at all?

I ask this because this is how it is done by my dept (at least in their header....)

Thanks!
 
OTP woes are driving me nuts. Ported the code to a 12F675 thanks to your tutorial nigel. Actually your right, it's all in the datasheets. Using ADRESH (left shifted) to use it as a 8bit A/D...

however....one question. Is the resolution now 5v/1024 or still 5v/256?
 
First off, 16C672 calibration byte, all you need to do is start your program like this:
Code:
org 0x00 ;start address
MOVWF	OSCCAL
The reset vector is the top of memory, so it loops round to 0x00 with the calibration value in the W register.

Your problem with ICProg reporting 'no calibration byte found' is probably because you have erased a UV chip - this erases the calibration byte, and you have to restore it. You 'should' have made a note of the value before erasing it, but presumably you haven't?.

bsodmike said:
OTP woes are driving me nuts. Ported the code to a 12F675 thanks to your tutorial nigel. Actually your right, it's all in the datasheets. Using ADRESH (left shifted) to use it as a 8bit A/D...

however....one question. Is the resolution now 5v/1024 or still 5v/256?

The resolution is 5V/256 - as you are now using 8 bit resolution.
 
Wonderful..Thanks

Ohh another question (for my ref) when I am accessing a Bank 1 register can I use it's bank 0 address when setting Rp0 to enter and exit bank 1 or does this matter at all?

I guess this is selfexplanatory. I.e. when you shift to bank0 even if the registers address in bank1, it will correctly translate it to the bank0 address and access it...yes?

Thanks!
 
bsodmike said:
Wonderful..Thanks

Ohh another question (for my ref) when I am accessing a Bank 1 register can I use it's bank 0 address when setting Rp0 to enter and exit bank 1 or does this matter at all?

I guess this is selfexplanatory. I.e. when you shift to bank0 even if the registers address in bank1, it will correctly translate it to the bank0 address and access it...yes?

I ignored this before, because I didn't understand the question - and I still don't :lol:

Try giving a code sample of what you you mean.
 
Code:
w	EQU	00h
_tmr0	EQU	01h
_status	EQU	03h
_option	EQU	01h
_gp	EQU	05h
_osccal	EQU	0Fh
_adcon0	EQU	1Fh
_adcon1	EQU	1Fh
_adres	EQU	1Eh

Take a look at this please. So lets concentrace on adcon1 and adcon0 for example. adcon 1 is in bank 1 so when I am setting it up I do this:

Code:
                bsf	_status,5	;move into bank 1

	movlw	b'00000110'	;
	movwf 	_adcon1	;

	bcf	_status,5	;back to bank 0

	movlw	b'10000001'	;Turn on A/D converter & set Fosc/32 to give
	movwf 	_adcon0		;a Tad of 32Tosc => 8µs @ 4Mh

and well it works.

BUT if you look @ my register declaration I've given Adcon0 and 1 the SAME address.

So my question rephrased: In the event one addresses a register in the bank 1 is it 'incorrect' to declare it with it's bank 0 address, or does this matter at all?

I just want to understand this... Ohh and the way I've been doing it, it seems to be working fine...

Thanks!
 
Yes, that's all fine - I think your confusion comes from not using the official MicroChip include files - in which case you wouldn't even know that they gave the same number, because you don't usually look at them.

I'm still totally bemused why you should want to use other than the official include files, it's just so bizarre!.
 
ROFLMAO!

Maybe I like doing things the hardway. also this way I just *feel* more in control..... ahh the power is mine muwahahaha

....just kidding :lol:

Thanks for everything. Right now I'm waiting for the flash chip to arrive (can't get any PICs here...) and then I can test my code while it is attached to my ICSP programmer :D

...but Fluke have initiated a recall of the test leads I purchased in March this year in Singapore...ohh well I'll find a work around...
 
Ohh just brilliant.

Sent off the final OTP code for testing (with the new delay).

This is the response:

the pwm output sits at about 38 Hz at 0.4v input.
As you wind up the input voltage, the output just goes erratic, but never goes above about 40 hz it just jitters around between 28hz and 40hz

This is interesting. from 122hz/550hz to 28/40hz....

Bleh, can't do any testing untill the 12F675 arrives....that teaches me to use OTP...

edit: Using the following delay now:

Code:
delay	clrf	_tmr0		;Start tmr0

dloop	movf	_tmr0,w		;Read tmr0 into w, w holds time

	subwf	half_t,w	; half_t - time

	btfss	_status,2	;Check Time - half_t = 0
	goto	dloop		;Time is not = half_t 

	retlw	0		;Time is half_t, return

This is what you suggested. Right now I just want to get this done, rather than bothering about elegance :lol:
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top