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.

Reading analogue value of A/D convertor with PIC 16F877A. Need Help!!

Status
Not open for further replies.
You can't do movf ADRESH,PEAK :eek: This is not a valid instruction and should have produced at least a warning.

To get the peak value you need to do a subtraction like this,
Code:
		movfw	ADRESH		;get ADC result
		subwf	Peak,W		;do Peak-ADC
		btfss	STATUS,C	;C set if ADC>Peak
		goto	DoneMax		;not higher
		movfw	ADRESH		;is higher
		movwf	Peak		;so copy to peak
DoneMax
You also need to clr Peak before your Main loop.

Mike.
 
Hi,
I meant 50 us is for the total time taken for one sample of ADC. 20 us of acquisition time is more than enough, since your source impedance is so low. The conversion time (which is the time taken for the conversion of 10 bits result, the time where you wait for the GO bit to be cleared) takes approximately 12*Tad. Since your Tad is set to 2 us, the conversion time is 24 us. With the acquisition time of 20 us, the total time for one sample is 44 us (excluding the other instruction cycles), that's why I said it is around 50 us.

As I said before, use subtraction and check the carry bit after the conversion. You may need to enable AD interrupt to make life easier, but the time taken for saving and restoring the registers should also be counted, so it takes longer time.
 
Thanks a lot Pommie and bananasiong for your valuable advice.

Pommie, I was a bit confused about using that instruction [ movf ADRESH,PEAK] just because I was using the 18F PIC sometime ago so I mistakenly used the 18F movff instruction. Sorry about that.

Just a quick question on sampling rate as it's making my life hell. I need to have at least + or - 5 degree accuracy in my phase detection. That implies I have to have 360 deg/5 =72 levels in one cycle. Thus for 1kHz signal, I will be looking to sample at 72kHz. My knowledge about sampling rate is the amount of delay between the two samples. However I am very confused when bananasiong advised me to reduce the delay. If I reduce the delay, wouldn't it affect my phase detection part?

I apologise for asking you guys these silly questions.

Many thanks.
 
You will not be able to sample that fast. The fastest you can sample two channels is 80uS (12.5kHz).

Maybe you should approach this in a different way, if you use a diode and feed a capacitor it will charge to the peak voltage. You will need a largish resistor to slowly discharge it. You can also amplify the waveforms and feed them via resistors into port pins. As the waveform crosses zero it will cause the pin to go high, you can use this signal to work out the phase relationship. You could even use the comparators to detect the waveforms crossing the 2.5V point.

Mike.
 
Pommie said:
You can't do movf ADRESH,PEAK :eek: This is not a valid instruction and should have produced at least a warning.

To get the peak value you need to do a subtraction like this,
Code:
		movfw	ADRESH		;get ADC result
		subwf	Peak,W		;do Peak-ADC
		btfss	STATUS,C	;C set if ADC>Peak
		goto	DoneMax		;not higher
		movfw	ADRESH		;is higher
		movwf	Peak		;so copy to peak
DoneMax
You also need to clr Peak before your Main loop.

Mike.

Thanks Mike for your kind help. I will try and implement the above part in my code straight away.

Many thanks again.

Vili

Ps: The last thing you suggested was that the PIC will only sample max at 12.5 kHz. How could you get this value? :confused:

And will it improve if I use say 20MHz crystal?
 
Hi,
The minimum time taken for one sample is 44 us, somehow you still need to do other instructions in between that causes some delay time as well.
44 us is obtained by:
20 us of acquisition time
2 us * 12 = 24 us for the 10 bits data conversion

You can't improve the speed much by using higher oscillator. It is because the AD clock is from 1.6 us to 6 us. Anyway around 12 cycles of Tad needed for the conversion. Higher oscillator frequency can only improve the time for the instructions.

*EDIT: bolded
With 20 MHz, the ADC time can be improved a little by setting the Tad to be 1.6 us. Hence the minimum time for one sample will be 40 us.
 
Last edited:
bananasiong said:
Hi,
The minimum time taken for one sample is 44 us, somehow you still need to do other instructions in between that causes some delay time as well.
44 us is obtained by:
20 us of acquisition time
2 us * 12 = 24 us for the 10 bits data conversion

You can't improve the speed much by using higher oscillator. It is because the AD clock is from 1.6 us to 6 us. Anyway around 12 cycles of Tad needed for the conversion. Higher oscillator frequency can only improve the time for the instructions.

*EDIT: bolded
With 20 MHz, the ADC time can be improved a little by setting the Tad to be 1.6 us. Hence the minimum time for one sample will be 40 us.


Cheers for that bananasiong. You've been of great help.

Thanks.
 
Hello Pommie [Mike],

I have been struggling to do this task for the last 3-4 hours. :(

Even though I have used your bit of code, it's still not working. I know I have done a silly mistake somewhere in using your code.

The weird thing is when I am loading my code into PIC, all the LEDs [PORTC] are ON and they remain ON even when I am giving 1 kHz [2V half wave rectified] signal at RA0. :mad:
 
Last edited:
Your main code is falling through to your delay routine,
This is what I think you need to do,
Code:
Main
	call   Delay           ;wait for acquision time (20us)                          
	bsf   ADCON0,GO       ;Start A/D conversion                                  
Wait
        btfsc   ADCON0,GO       ;Wait for conversion to complete
        goto    Wait

      	movfw	ADRESH		;get ADC result
	subwf	Peak,W	            ;do Peak-ADC
	btfss	STATUS,C	;C set if ADC>Peak
	goto	DoneMax		;not higher
	movfw	ADRESH		;is higher
	movwf	Peak		;so copy to peak
[COLOR="Blue"]     ;removed goto	Main			;do it again![/COLOR]

DoneMax
	movf    ADRESH,W       ;Write **AMPLITUDE** result to PORTC
        movwf   PORTC           ;LEDs
[COLOR="blue"]     ;removed   clrf	Peak
	goto	Main		;added	[/COLOR]

I see you have the conversion clock at Fosc/8. If you are running at 20MHz then this is too fast. Check the table on page 131 of the datasheet.

The reason your LEDs stay on is probably because they are changing so fast you cannot see when they are off. Try putting a pot an A0 and move it slowly to see the effect.

Mike.
 
Pommie said:
Your main code is falling through to your delay routine,
This is what I think you need to do,


I see you have the conversion clock at Fosc/8. If you are running at 20MHz then this is too fast. Check the table on page 131 of the datasheet.

The reason your LEDs stay on is probably because they are changing so fast you cannot see when they are off. Try putting a pot an A0 and move it slowly to see the effect.

Mike.

Thank you very much for your kind suggestion Mike.

One last thing. I am still puzzled about the LEDs. I thought the LEDs will only light when the max value is detected? If my input is 2V halfwave, shouldn't the LEDs show 102? :confused:

PS: I am still using 4 MHz XT though.

Thanks again Mike.
 
But your not displaying the max value on the port.
Try,
Code:
DoneMax
	movf	Peak,W		;Write **AMPLITUDE** result to PORTC
	movwf	PORTC		;LEDs
	goto	Main

Mike.
 
Hi Mike,

I just downloaded the program but nothing happend ! :(

After changing the last part of my code i.e.
Code:
DoneMax
	movf	Peak,W		;Write **AMPLITUDE** result to PORTC
	movwf	PORTC		;LEDs
	goto	Main

to
             movf      ADRESH,W   ; changed again

The code seems to work [I am using a pot rather than AC signal]. I don't know why its not showing me the value using Peak,W instruction!!
I am a bit concerned about the
Code:
subwf  Peak,W ; do Peak-ADC
. Here we are doing Peak-ADC, but in the beginning of the code I have set Peak as 0 by clrf instruction. I may sound stupid but wouldn't it be wrong doing 0 - some value ?


Thanks again Mike.
 
Last edited:
I just noticed that you don't clear Peak before the main loop. Try adding that.

Mike.
 
I used clrf Peak just after the following instruction :

Code:
movf  Peak,W       ;Write **AMPLITUDE** result to PORTC
movwf   PORTB           ;LEDs
clrf	Peak
goto	Main
Still it's not showing me anything on PORTC.
:confused:
I am a bit concerned about the
code
Code:
subwf  Peak,W ; do Peak-ADC

Here we are doing Peak-ADC, but in the beginning of the code I have initialize Peak as 0 by clrf instruction. I may sound stupid but wouldn't it be wrong when the very first sample value will be substracted from 0 ?

I sincerely apologise for troubling you over this.

Thanks again Mike.
 
I missed your clrf Peak at the beginning of your code.

The instruction,
Code:
	subwf	Peak,W	            ;do Peak-ADC
When Peak is 0 and the ADC value is say 10 then, Peak-ADC is 0-10=-10 and a borrow is required and so the Carry bit is cleared.
From the above you can see I got the carry bit the wrong way around.
It should be,
Code:
Main
	call	Delay           ;wait for acquision time (20us)                          
	bsf	ADCON0,GO       ;Start A/D conversion                                  
Wait
	btfsc	ADCON0,GO       ;Wait for conversion to complete
	goto	Wait

      	movfw	ADRESH		;get ADC result
	subwf	Peak,W		;do Peak-ADC
	btfs[COLOR="Red"]c[/COLOR]	STATUS,C	;C clear if ADC>Peak
	goto	DoneMax		;not higher
	movfw	ADRESH		;is higher
	movwf	Peak		;so copy to peak

DoneMax
	movf	ADRESH,W		;Write **AMPLITUDE** result to PORTC
	movwf	PORTC		;LEDs
	goto	Main

Sorry,

Mike.
 
Thanks for the correction Mike.

I am afraid it didn't work again. :(

I don't know what is wrong. It's been 8 hours since I've been trying and it's 6.00 am in the morning. I might come back after a while and try it again.

I really appreciate your help and please let me know if you find any more corrections or ideas to solve this!

Many thanks.
 
Hi all,

I have made a few changes and it seems to work with DC. I would like you to bare with me for a couple of minutes and would like you to read and advise.

I think I know where the problem lies. Its my code for sure. Let me explain in detail and you guys might catch something. [Thanks to Mike for this idea :) ]
My code does this:
Let say I have a hafwave rectified wave of 2 V. So the samples [assuming] are occurring at 0, 1, 2 back to 1 and 0. Now my code takes an initial value 0 from the Peak register and subtract it from ADRESH value. If the result is positive, then carry bit is set and the ADRESH value is copied to Peak. Now it goes on till the next value is less than the peak and thus carry bit is clear and the max value is display on PORTC.

It works perfect with DC but when I use AC, it gives me a random incorrect value. I think this might be due to the fact that my code ONLY works for the first quarter cycle [from 0-2] and not for the rest of the quarter cycle [2 back to 0]. Thus when the signal arrives with a delay [say it starts from 2,1 to 0] and sampling begins, it might capture the voltage at say 1 and the rest of the values are obviously less than 1. Thus giving me 1 as peak which is totally wrong. :(

I think this can be sorted out by using some ZERO CROSSING. Thus program will wait for the zero to come and therefore, samples will begin from there after.

Could someone please advise on how to write a simple zero crossing code????:confused:

I apologise for writing this long explanation and it just to show what I think I have done wrong.

I will really really appreciate any help on this.

Many thanks.
 
Last edited:
Hi all,

I have made a few changes and it seems to work with DC. I would like you to bare with me for a couple of minutes and would like you to read and advise.

I think I know where the problem lies. Its my code for sure. Let me explain in detail and you guys might catch something. [Thanks to Mike for this idea :) ]

Code is:
Code:
      Wait              btfsc   ADCON0,GO       ;Wait for conversion to complete
                          goto    Wait	
      
		movfw	Peak		;get Peak value '0' to w
		subwf	ADRESH,1	;do ADC-Peak
		btfss	STATUS,C	;C set if ADC>Peak
		goto	DoneMax		;not higher
		movfw	ADRESH		;is higher
		movwf	Peak		;so copy to peak
		goto	Main			;do it again!

DoneMax
		movf   Peak      ;Write **AMPLITUDE** result to PORTC
                         movwf  PORTC           ;LEDs
		goto   loop_abc

loop_abc 
		clrwdt
		goto	loop_abc

My code does this:
Let say I have a hafwave rectified wave of 2 V. So the samples [assuming] are occurring at 0, 1, 2 back to 1 and 0. Now my code takes an initial value 0 from the Peak register and subtract it from ADRESH value. If the result is positive, then carry bit is set and the ADRESH value is copied to Peak. Now it goes on till the next value is less than the peak and thus carry bit is clear and the max value is display on PORTC.

It works perfect with DC but when I use AC, it gives me a random incorrect value. I think this might be due to the fact that my code ONLY works for the first quarter cycle [from 0-2] and not for the rest of the quarter cycle [2 back to 0]. Thus when the signal arrives with a delay [say it starts from 2,1 to 0] and sampling begins, it might capture the voltage at say 1 and the rest of the values are obviously less than 1. Thus giving me 1 as peak which is totally wrong. :(

I think this can be sorted out by using some ZERO CROSSING. Thus program will wait for the zero to come and therefore, samples will begin from there after.

Could someone please advise on how to write a simple zero crossing code????:confused:

I apologise for writing this long explanation and it just to show what I think I have done wrong.

I will really really appreciate any help on this.

Many thanks.
 
vili.chaudhary said:
Could someone please advise on how to write a simple zero crossing code????:confused:

I don't know what you exactly going to do?

Look your DoneMax routine it missing a W.It should movf Peak,W

To detect zero cross I'm doing like this

*wait for a zero cross
*turn on the timer 0<T<10mS
*after timer overflows do what ever you want to do.
*wait for the next zero cross

To detect zero cross you can use an external interrupt pin.

I still don't know what you trying to do.
 
Status
Not open for further replies.

Latest threads

Back
Top