PDA

View Full Version : Sampling ADCIN at 1ms for 1 second



macinug
- 30th April 2009, 12:41
Hi again,
Can anyone give me code for reading adcin at exactly 1ms intervals for 1 second. I'm using a 20Mhz OSC on a 16F876. The code below is too slow presumeably as I haven't allowed for the execution times of the other instructions. Any pointers gladly receved. Ta

for x = 1 to 1000
adcin 1,potv
hserout [dec x," ",dec potv,13,10]
pause 1 '1ms delay
next x

Melanie
- 30th April 2009, 17:12
Be sensible... you're NOT going to get a thousand HSEROUT's executed in ONE SECOND! Unless of course you've set a BAUD RATE of a couple of MILLION bps?

Get a calculator, work out how many bits ONE of your HSEROUT commands is going to send... then at your chosen BAUD rate how long that is going to take to transmit. From that, you can work out how many characters you'll be able to transmit in one second.

macinug
- 18th May 2009, 11:30
Thanks.
I will create an array before I send it to the PC. It's important that the sampling rate is 1ms.
Now to find out how to set up a 1000 element byte array!

Melanie
- 18th May 2009, 13:10
And it's NOT going to happen with a PIC16F876... it just hasn't got that much RAM!!!

You're going to need some high-speed external memory to hold your samples.

Charles Linquis
- 19th May 2009, 02:01
An 18F8723 (for example) can deal with 3000 byte arrays.

Darrel Taylor
- 19th May 2009, 03:53
Oh I don't know, doesn't sound that hard to me. :eek:

@ 20mhz, 115200 baud is easy with the USART, higher is also possible, but 115200 is all you need for this.
@115200 the bit period is ~8.7us, and a full byte (10-bits) is ~87us.
The longest HSEROUT line will be "1000 255",13,10 or 10 bytes. for a total of ~870us. (less than 1ms)

The ADCIN statement slows things down for no reason.
Since the ADC is only looking at 1 Channel, you don't have to worry about Acquisition times.
And by controlling the ADC manually, the conversion happens at the same time as the HSEROUT so it's influence will be negligible.

Then using a Timer to measure the 1ms intervals and ...
Here's an example ...
<font color="#000080">@ DEVICE HS_OSC, WDT_OFF
</font><font color="#008000"><b>DEFINE </b></font><b>OSC </b><font color="#800000"><b>20
</b></font><font color="#0000FF"><b><i>; Set your Analog Pins as needed here

</i></b></font><font color="#008000"><b>DEFINE </b></font><b>HSER_RCSTA </b><font color="#800000"><b>90</b></font><b>h </b><font color="#0000FF"><b><i>' Enable serial port &amp; continuous receive
</i></b></font><font color="#008000"><b>DEFINE </b></font><b>HSER_TXSTA </b><font color="#800000"><b>24</b></font><b>h </b><font color="#0000FF"><b><i>' Enable transmit, BRGH = 1
</i></b></font><font color="#008000"><b>DEFINE </b></font><b>HSER_SPBRG </b><font color="#800000"><b>10 </b></font><font color="#0000FF"><b><i>' 115200 Baud @ 20MHz, -1.36%

</i></b></font><b>GoDone </b><font color="#008000"><b>VAR </b></font><b>ADCON0</b>.<font color="#800000"><b>2 </b></font><font color="#0000FF"><b><i>; A/D start conversion bit
</i></b></font><b>T0IF </b><font color="#008000"><b>VAR </b></font><b>INTCON</b>.<font color="#800000"><b>2 </b></font><font color="#0000FF"><b><i>; TMR0 overflow flag
</i></b></font><b>x </b><font color="#008000"><b>VAR WORD </b></font><font color="#0000FF"><b><i>; sample counter
</i></b></font><b>TempB </b><font color="#008000"><b>VAR BYTE

</b></font><b>OPTION_REG </b>= <font color="#800000"><b>%11010100 </b></font><font color="#0000FF"><b><i>; TMR0 1:32 prescaler, internal clk
</i></b></font><b>ADCON0 </b>= <font color="#800000"><b>%10001001 </b></font><font color="#0000FF"><b><i>; Fosc/32, AN1, DONE, module ON
</i></b></font><font color="#008000"><b>HSEROUT </b></font>[<font color="#800000"><b>27</b></font>,<font color="#FF0000">&quot;[2J&quot;</font>] <font color="#0000FF"><b><i>; ANSI clear screen

</i></b></font><b>Ready</b>:
<font color="#008000"><b>HSEROUT </b></font>[<font color="#FF0000">&quot;Ready to take samples: Press any key to begin&quot;</font>]
<font color="#008000"><b>HSERIN </b></font>[<b>TempB</b>]
<font color="#008000"><b>HSEROUT </b></font>[<font color="#800000"><b>13</b></font>,<font color="#800000"><b>10</b></font>]

<font color="#008000"><b>FOR </b></font><b>x </b>= <font color="#800000"><b>1 </b></font><font color="#008000"><b>to </b></font><font color="#800000"><b>1000
</b></font><font color="#008000"><b>WHILE </b></font>!<b>T0IF </b>: <font color="#008000"><b>WEND
</b></font><b>TMR0 </b>= <font color="#800000"><b>100 </b></font><font color="#0000FF"><b><i>; load timer for 1ms
</i></b></font><b>T0IF </b>= <font color="#800000"><b>0 </b></font><font color="#0000FF"><b><i>; reset the overflow flag
</i></b></font><b>GoDone </b>= <font color="#800000"><b>1 </b></font><font color="#0000FF"><b><i>; start the A/D conversion
; The time it takes for the A/D conversion (~20us) is less than the
; time to send a single byte from the USART (~87us). So the conversion
; will always be complete by the time it gets to DEC ADRESH
</i></b></font><font color="#008000"><b>HSEROUT </b></font>[<font color="#008000"><b>DEC </b></font><b>x</b>,<font color="#FF0000">&quot; &quot;</font>,<font color="#008000"><b>DEC </b></font><b>ADRESH</b>,<font color="#800000"><b>13</b></font>,<font color="#800000"><b>10</b></font>]
<font color="#0000FF"><b><i>; The longest hserout line would be &quot;1000 255&quot;,13,10 (10 bytes)
; @ 115200 baud each byte takes 86.8us for a total of 868us (under 1ms)

</i></b></font><font color="#008000"><b>IF </b></font><b>T0IF </b><font color="#008000"><b>THEN HSEROUT </b></font>[<font color="#800000"><b>13</b></font>,<font color="#800000"><b>10</b></font>, <b>_
</b><font color="#FF0000">&quot;ERROR: Loop time too SLOW. T0IF bit already set.&quot;</font>,<font color="#800000"><b>13</b></font>,<font color="#800000"><b>10</b></font>]
<font color="#008000"><b>NEXT </b></font><b>x
</b><font color="#008000"><b>GOTO </b></font><b>Ready

</b>
I put a check at the end of the loop to warn if the loop took too long. It never does.
Tested on a 16F737.

Using Timer0, the interval is not EXACTLY 1ms, but the coding was easier. (+/- 6us per sample)
Switching to Timer1 would make it more accurate. (+/- 0.6 us)

macinug
- 3rd June 2009, 11:08
Thanks Darrel. This worked for me but...

When I add it to my code which initiates movement of the thing I wish to measure I get the timeout error T0IF at the 101st reading. I've tried understanding your code but the details are above my level! Any ideas where I'm going wrong? Here is the code:

@ DEVICE HS_OSC,LVP_OFF,WDT_OFF,PROTECT_OFF,BOD_OFF,PWRT_OF F
DEFINE OSC 20
DEFINE HSER_EVEN 1 'serial
DEFINE HSER_BITS 7 'serial
DEFINE HSER_BAUD 115200 'serial
DEFINE CCP1_REG PORTC ' Hpwm 1 pin port
DEFINE CCP1_BIT 2 ' Hpwm 1 pin bit
DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
DEFINE HSER_SPBRG 10 ' 115200 Baud @ 20MHz, -1.36%
DEFINE HSER_CLROERR 1 ' serial automatic clear overrun error

trisb = %11000000 ' set port b 0-5 o/ps 6&7 i/ps
OPTION_REG = %11010100 ; TMR0 1:32 prescaler, internal clk
ADCON0 = %10001001 ; Fosc/32, AN1, DONE, module ON

'declare variables
GoDone VAR ADCON0.2 ; A/D start conversion bit
T0IF VAR INTCON.2 ; TMR0 overflow flag
x var word
RCIF VAR PIR1.5
VB_TO_PIC VAR byte ' data from VB to PIC
PIC_TO_VB var byte ' data from PIC to VB

'initialise
portb.0 = 0
portb.1 = 0
portb.2 = 0
portb.3 = 0
hpwm 1,0,2000
PAUSE 100

MAIN:
portb.0 = 0
IF RCIF THEN
pause 100
sound portb.0,[60,10]
portb.0 = 0 'to avoid buzzer continuing...?
HSERIN [VB_TO_PIC] 'RCIF is reset by reading HSERIN (need twice??)
select case VB_TO_PIC
case "1"
gosub open_response
case "2"
HSEROUT [VB_TO_PIC," TWO",13,10]
case else
HSEROUT [VB_TO_PIC," Error",13,10]
end select
ENDIF
GOTO MAIN

open_response:
portb.1 = 1 'enable
portb.3 = 0 'open direction
hpwm 1,255,2000
'sample data
FOR x = 1 to 1000
WHILE !T0IF : WEND
TMR0 = 101 ; load timer for 1ms ##time out here##
T0IF = 0 ; reset the overflow flag
GoDone = 1 ; start the A/D conversion
; The time it takes for the A/D conversion (~20us) is less than the
; time to send a single byte from the USART (~87us). So the conversion
; will always be complete by the time it gets to DEC ADRESH
HSEROUT [DEC x," ",DEC ADRESH,13,10]
; The longest hserout line would be "1000 255",13,10 (10 bytes)
; @ 115200 baud each byte takes 86.8us for a total of 868us (under 1ms)
IF T0IF THEN HSEROUT [13,10, _
"ERROR: Loop time too SLOW. T0IF bit already set.",13,10]
NEXT x
gosub power_down
return

power_down:
portb.1 = 0 'disable H-Bridge
hpwm 1,0,2000 'Set PWM to zero
return

end

Darrel Taylor
- 3rd June 2009, 11:45
It's the ...
DEFINE HSER_EVEN 1 'serial
DEFINE HSER_BITS 7 'serial

It takes a lot of time to count bits and generate a parity for each byte.

Can you use 8-N-1?

macinug
- 3rd June 2009, 15:03
Genius!
I had dabbled with the port settings but was stabbing in the dark.
If the T0IF error text does occur it's gobbledygook but it doesn't occur often.
Thanks

Darrel Taylor
- 3rd June 2009, 20:11
It shouldn't happen at all.

Putting TMR0 = back to 100, (or 99), might help.
<br>