PDA

View Full Version : Sampling rate - PIC16F877



Tomas
- 10th April 2004, 01:32
Hi,
Can anybody please tell me how i can modify the code, adcx.bas as found at: http://www.melabs.com/resources/samples/x1/pbp/adcx.bas

to take samples every 10mS. Would it be enoght if i just change the PAUSE 10 command in the mainloop to PAUSE 100. The comment in the code says that pausing for 10 is doing the conversion about 10 times a second. If this is equvalent to taking 10 samples a second can i take 100 samples a second by pausing for 100? Or am i thinking wrong?

Thanks in advance,
Regards,
Tom.

Melanie
- 14th April 2004, 15:55
Close but no cigar...

Here is the code for 10 times per second...

mainloop:
Gosub getx ' Get x value
Gosub gety ' Get y value
Gosub getz ' Get z value
Lcdout $fe, 1, "x=", #x, " y=", #y, " z=", #z ' Send values to LCD
Pause 100 ' Do it about 10 times a second
Goto mainloop ' Do it forever

that 'Pause 100' means you're going to wait 100mS between samples... and, if you were awake during your maths class at school, you'll remember there's ten 100mS periods in every second.

(1mS=1/1000th of a second)

So, you change the Pause 100 to Pause 10, now there are one-hundred 10mS periods in one second so you will therefore do one-hundred loops...

Melanie

ivancho
- 14th April 2004, 22:18
I would change all those jumps and use ADCIN.

<b>
Define LOADER_USED 1

' Define LCD pins
Define LCD_DREG PORTD
Define LCD_DBIT 4
Define LCD_RSREG PORTE
Define LCD_RSBIT 0
Define LCD_EREG PORTE
Define LCD_EBIT 1

' Allocate variables
x var byte
y var byte
z var byte

ADCON1 = 4 ' Set PortA 0, 1, 3 to analog inputs
Low PORTE.2 ' LCD R/W line low (W)
Pause 100 ' Wait for LCD to start

mainloop:
ADCIN 0, x ' Read channel 0 to x
ADCIN 1, y ' Read channel 1 to y
ADCIN 3, z ' Read channel 3 to z

Lcdout $fe, 1, "x=", #x, " y=", #y, " z=", #z ' Send values to LCD
Pause 100

mainloop
</b>

This code will cause the same effect as the example.

Ivancho

Melanie
- 15th April 2004, 01:33
Yes, that is a lot cleaner from a code point of view, but the original query was how to convert the adcx.bas code to give 100 samples per second. I believe that sample code was written long before PBP acquired the ADCIN command and would be valid for any version. ADCIN is actually overkill, as it is simpler and more code efficient to just access the registers directly.

Tomas
- 21st April 2004, 14:53
Melanie, hope i will get cigar soon . . .

Have been figuring out how to sample some of my analog signals every 20mS. The code (http://www.melabs.com/resources/samples/x1/pbp/adcx.bas) have been modifies like you expalined to me. The problem i'm having now is how can sample one of the three signals every 20mS. In the code all three are sampled every 10mS. Does Timer0 works while the watchdog timer is off? If it does can i use Timer0 interrupt to take samples every 20mS?

Best Regards,
Tom

Melanie
- 21st April 2004, 22:03
Putting in...

Pause 20

...will give you a 20mS delay... is there a problem simply using this in your code?

TMR0 is independant from the Watchdog Timer although they share usage of the prescaler (though not simultaneously). Turning WDT on or off has no effect on TMR0.

Since TMR0 is an 8-bit timer, that means you can only time 256uS (using a 4MHz clock) without using the prescaler. Obviouly adding in the prescaler will allow you to time further (depending on the prescaler setting chosen).

Melanie

Tomas
- 21st April 2004, 22:39
well, the problem is i want still sample some of the signals every 10mS and one of the signals every 20mS so if i put 20mS in the mainloop this will result in sampling the signals every 20mS (all of them).

Where can i put the 20mS in the program to sample only one of the signals every 20mS and the rest in 10mS (the program still need to start from mainloop)?

This code is just an exaple i'm refering, in my project i'm reading 6 analog signals connected to PORTA (to the A/D channels) so out of these 1 of them has to be sampled every 20mS.

I turn off the Watchdog timer because i wanted to use the @ SLEEP command to put the PIC in sleep mode. So will TMR0 still work while the PIC is in SLEEP mode? If it does, do you have any example i can look at which shows how to use TMR0 with prescaler which time it to 20mS (Since Watchdog timer and TMR0 shares the prescaler, is it possible to use the prescaler only for TMR0?)

Thanks,
Tom.

Melanie
- 22nd April 2004, 00:37
There's no need to make life difficult when there's no need...

SampleToggle var Bit

Loop:
Gosub GetSampleA
Gosub GetSampleB
Gosub GetSampleC
Gosub GetSampleD
Gosub GetSampleE
If SampleToggle=0 then
Gosub GetSampleF
SampleToggle=1
else
SampleToggle=0
endif
Pause 10
Goto Loop

Here, samples A thru E get sampled every 10mS, but sample F only gets invoked at every other pass through the loop - ie every 20mS.

Yes, you can switch the prescaler away from the WDT and onto TMR0. Go look at bits zero thru 3 of the OPTION_REG Register.

Melanie

Tomas
- 22nd April 2004, 11:45
Thanks, Melanie.
Like you said if this routine does the job there is no need for using TMR0.

I have got another problem though, i'm storing my digital value on 24LC256 EEPROM. This device has got 512 pages each of which with size of 64B. I want to store a value in one of the pages, and when i come to this loop for second time i want to store the new digital value in the next page. I'm going to use only three pages of the device. So when i finish the loop i should read three different digital values from three different pages. I tried the code below:

B0 VAR WORD

storingLOOP:
FOR B0 = 0 TO 63 STEP 2
B0 + 64 'Increment page counter
I2CWRITE SDA,SCL,EE_addr,B0,[str data1\64]
NEXT B0

When i try this code the pages never get incremented. Shall i have another counter which keep track of number of pages accessed? If not, how do i incerement the pages?

And how do i read exactly these three pages using I2CREAD?

Thanks,
Tom.

Melanie
- 23rd April 2004, 03:29
Nope, you still missed that cigar... but you're close...

StorePage var word
StartAddress var Word

StoreData:
StartAddress=StorePage*64
I2CWRITE SDA,SCL,EE_addr,StartAddress,[str data1\64]
Return

Consider the above subroutine. Before it is called, you set the Page Number that you wish to store your 64 bytes of data into. Since you wish only to store 3 pages, the variable StorePage can be 0, 1 or 2, but in fact for the 24LC256 can be any number between 0 and 511 (max 512 pages as you said).

The first line takes the Page number and converts it to a linear address pointer, so that for example, if your Page is zero, the address will point to zero. Page=1 then Address=64. Page=2 then Address=128 and so on...

The I2CWRITE line will save 64 bytes in one hit from your array data1 (providing your EE_addr is set correctly).

That's it... all there is to it.

To read back, just preset your StorePage accordingly and create a similar ReadData subroutine using I2CREAD...

Melanie

Tomas
- 23rd April 2004, 11:24
Hi Melanie,
Thank you again, i'm still trying my best to get that cigar . . .
To read back the data you said i should preset StorePage, is it like set it back to zero again so that it will start reading from page 0. If so, shall i set it to zero at the start of the program? I think it is because of this, not presetting it correctly, i'm still reading the last newest store data.

If i store three different data in three different pages of one 24LC256 device i should be able to read back these three different data from those page where the data were stored, am i right? store 12, 58 and 92 in three different pages and read back 12, 58 and 92 back . . . am i still losing the cigar?

Regards,
Tom

Melanie
- 23rd April 2004, 12:00
Assuming you have 64 bytes of data in your array Data1. You now go save that data using...

StorePage=17:Gosub StoreData

Your data will be saved into the EEPROM with the first byte starting at address 1088 (Decimal) and the last byte at address 1151 (Decimal).

Just preset the StorePage you want to write to before calling the subroutine. StorePage will not automatically change or preset for you.

To read back that data into your array, simply...

StorePage=17:Gosub ReadData

where the ReadData subroutine is something like...

ReadData:
StartAddress=StorePage*64
I2CREAD SDA,SCL,EE_addr,StartAddress,[str data1\64]
Return

As you can see this is pretty much identical to the write routine.

When you mention storing 12, 58 and 92 then if those are bytes of data, you must have them in your data1 array before you call the StoreData subroutine.

Tomas
- 23rd April 2004, 12:43
My code looks something like as shown below, i get a converted result from the getad subroutine the put the value in data1. Then i select device, finally go to store the data. Now i'm thinking to have storePage before calling StoreData (as you told me).

The problem is i think i need to increment storePage as i come to getch0 subroutine more than once.

Can i set storePage to 0 first and second time i come to the routine 1 and so on, so that it will be updated every time getch0 is called.
Something like

storePage = storePage + 1

before calling StoreData . . .


data1 VAR BYTE [64]

getch0:
ADCON0 = $41 ' Set A/D to Fosc/8, Channel 0, On
Gosub getad ' go to the conversion routine
data1 = ADRESL ' put the digital result in data1
EE_addr = $A0 ' pass device address


Gosub StoreData
Return

. . .

Start
gosub getch0 'called 3 times


Regards,
Tom

Melanie
- 23rd April 2004, 13:45
I'm confused here Tomas.

Theres some basic things wrong here from what I can gather.

Your create a 64 byte array called data1. But then you incorrectly address that array with the statement...

data1=ADRESL.

Why have you got a 64 byte array and then save ONE byte. isn't that kinda wasteful? Notwithstanding that, you should have addressed data1 in the correct form...

data1[x]=ADRESL

where x is the location (0-63) of the byte in the array in which to store the data.

Let's have a look at your GetAD subroutine. I think we've a heap of problems to address first before we get to saving and reading our EEPROM pages.

Tomas
- 23rd April 2004, 14:35
Initially i was attempting to use Page write mode and that is why data1 is declared as an array of 64 bytes. To write each page with the read value value.

I did this to save the 10mS required to write each page and to have only one 10mS for each page.

Now i kept the declaration of the data1 as it is, i though i'm writing 64 bytes at a time, it is wrong isn't it.
What i want to do is after reading the result of the converted signal i want to store it in the EEPROM when i call getch0.

So everytime i come to getch0 with new digital data i want to store it in a different location and later read all of my stored data and display it.


My A/D is shown below:

getad:
Pauseus 50 ' Wait for channel to setup

ADCON0.0 = 1
ADCON0.2 = 1 ' Start conversion
notFinished:
Pause 5
if ADCON0.2 = 1 Then notdone 'wait for low on bit-2 of ADCON0, conversion finished
data1 = ADRESL 'move HIGH bit of result to adval

Pauseus 50 ' Wait for conversion

Return

Melanie
- 23rd April 2004, 14:46
Are you using 10 bit or 8 bit AD?
and what exactly have you done with ADRESH?

Are you trying to take just ONE sample (three times) and save it?
or are you trying to take an EEPROM page full of samples, and save three pages worth?

As a final thought, if you're only taking a few samples, why are you using an external EEPROM instead of the PIC's internal EEPROM?

Tomas
- 23rd April 2004, 15:15
I'm trying to store each page of the EEPROM full with read data. I have six input signals each of these are connected to different channels of '877 and i convert each and store them in different EEPROMs as the 6 variables represent different things.

The reason i said three pages was, i though i'm accessing only three pages as i'm calling getCh0 three times. The sampling rate is 10mS like we discussed previously. There should be 100 samples to be stored in a second. . .

I think i have got the basics wrong, i want to sample five of the signals every 10mS one every 20mS and store the result of each samples-converion in six different EEPROMs (one EEPROM for one signal). Then, finally read the stored data from each EEPROM.

If i can sample and store correctly i could call I2CWRITE and I2CREAD for each signal.

I thought as the inputs change, when i read the EEPROMs i should get different data.

I didn't do anything with ADRESH. I set the result as right justified (ADCON1 = %10001001 - i have got two digital signals as well). I should have done something with it, i think. But i'm interested in only the 8-bits.

Best regards,
Tom

Melanie
- 23rd April 2004, 15:28
Are you just sampling for ONE second, or will this run continuously... if continuous, what happens when you fill up the EEPROM?

If you are saving to SIX EEPROMS, have you considered that it will take 10mS to write to EACH of them... that's 60mS total. What is the consequences of taking a 60mS window out of your sampling sequence?

Tomas
- 23rd April 2004, 15:48
I'm sampling until a pin is set to high from external switch. Once the swich is high i stop sampling. The reason i want to use external switch is that i could not use TMR0 correctly to time 65s. If i can time it to some period round 65s i would rather have that.

I thought the 10mS for writing the EEPROMs is requied for only the EEPROM-device. I though while the 24LC256 is writing the data the PIC will be free to do other stuff (the feeling i got from PicBasic Pro manual). I didn't totaly think about the 60mS window . . .

What if i sample every 10mS and 20mS for 65s and then do the writng. Will still the 60mS window be there? If thi is the case i got a lot of things wrong . . . how can solve this problem?

Best Regards,
Tom.

Melanie
- 23rd April 2004, 18:55
If you are taking five samples every 10mS and sending those to five EEPROMs, you will have a delay of 50mS each time you write. Every other 10mS (the 20mS tick) you take six samples and you send that to six EEPROM's, so every other 10mS you have a 60mS EEPROM write delay. Obviously you can see the figures don't add up.

Upto six ADC samples every 10mS for 65 seconds, you therefore have 65*100*6 samples (assuming worst-case of 6 inputs). That's 39000 8-bit samples to store. Too small for one 24LC256 with 32k (bytes) of space.

To make page-write smoother (and since we cannot cross a page boundary) we should really write in a multiple - or less - of 64 bytes).

If therefore we take 6 samples each 10mS (omitting every other 10mS the sixth ADC reading and just saving a zero for convenience), we can take 60 samples into RAM and page write the lot once every 100mS. There will be four bytes left over on every page, but that wastage is offset by being able to access our data in neat 100mS slices. That means we're going to need to write 650 pages (too much for a single 24LC256).

You either need two 24LC256's or a single 24LC512. Which is your preference? and I'll do you some code to get you started accordingly.

Tomas
- 23rd April 2004, 19:26
So i need only two 24LC256 to store the six samples samples every 10mS (one sampled every 20mS).
As i have six EEPROMs on board can i use six of them to store, say input number 1 in EEPROM number 1 and so on. I know it is a waste of EEPROM but is it possible? If it is, we can sample faster and we can have more data to store (10mS and 20mS is the lowest rages in the requirments).

Otherwise i will have 2 of 24LC256 (i have got six of these and i wanted to use them as i explained above) as i don't have 24LC512.

I'm not quite following what you explained to me just before the last paragraph of you message. The RAM . . . can please you explain to me a bit more

Thanks,
Tom

Melanie
- 23rd April 2004, 20:21
Let me explain...

If you take six ADC samples (one byte for each channel), it is pointless saving them if you are going to do a Page Write of upto 64 bytes, because you've only got 6 bytes of valid Data.

You might as well save those samples up (in your Data array) until you've got 60 samples (100mS worth if you're capturing six every 10mS - therefore you'll have acquired 60 samples across 100mS).

Now once you've got 60 bytes of data (bytes 0-59 of the Page), it's worthwhile doing an EEPROM page write. The last four bytes of each page (bytes 60-63) are unused.

Also, out of each set of 6 bytes (samples from the ADC's), byte 6 is only valid every other byte because you only wanted to sample the 6th input every 20mS. Wasting one byte in twelve might seem wasteful, but I get the feeling you're not experienced enough as yet to deal with the concept of an eleven byte 20mS sample, where the first six bytes belong to the first 10mS period, and the remaining five bytes belong to the 2nd 10mS period.

Like I said before, you CAN'T write to any more than ONE EEPROM AT A TIME, because it'll take 10mS to access each one.

The way we get around this is that although we need to store 650 pages of captured data (remember each page is 60 bytes long, comprising of ten sets of 6 samples, each set being captured every 10mS - therefore each EEPROM page is 100mS worth of data, and 650 pages equals the target 65 seconds you require), we save the first 512 pages sequentially into EEPROM 1, and the remaining 148 pages sequentially into EEPROM 2.

That way, we only ever access ONE EEPROM at a time, so our write delay will only be 10mS (ie Pages 0-511 get written to EEPROM 1, whilst pages 512-649 get written to EEPROM 2).

Melanie
- 23rd April 2004, 20:55
Study the concept of the program I've written below. It took me about 20 minutes, which in real money is the cost of half a shop full of Thorntons chocolate...

When Green LED lights, press the button to start taking 65 seconds worth of samples at 10mS intervals. When the samples are being taken, the RED LED is illuminated. There is no need to keep the button pressed - it's just there to start the process... timing is within the program thereafter.

It'll capture SIX ADC's the first 10mS into six bytes, one for each ADC. In the next 10mS, it'll omit the 6th ADC, the sixth byte in this case will be a dummy preset to zero. The following 10mS it'll revert back to saving all six samples, and so on.

After 100mS worth of samples (ten times 10mS) you've captured 60 bytes of data. This is then written out as an EEPROM 'Page'. Although 64 bytes are written out, only the first 60 are data, and the four on the end are unused.

This continues for 650 pages. The first 512 pages are saved into EEPROM 1 (24LC256 device address $A0), and the remaining 138 pages are saved into EEPROM 2 (Address $A1).

Once 65 seconds worth of samples are stored, the Green LED blinks to tell you all is done.

Study what's going on line by line BEFORE you ask any questions... and bear in mind that I'll probably won't get around to answering until next week - which gives you lots of time to study and sort out things on your own.

' Start Button and LED's
' =====================
StartButton var PortB.0
' Button connected between this PIC pin and Vss
' Pin is pulled-up by using internal Weak Pull-up's
' 65 Second Sampling commences when this button is pressed
' ie PIC pin goes to 0v.
' Button does NOT need to be held down for the duration
' as 65 second counting is done in the program.
GreenLED var PortB.1
' LED connected between Vdd and this pin via Resistor
' Green LED indicates Ready to Sample
' When Green LED blinks, this indicates Sampling Completed
RedLED var PortB.2
' LED connected between Vdd and this pin via Resistor
' Red LED indicates Sampling in Progress
'
' ADC's
' =====
' AN0 through AN4 are sampled every 10mS
' AN5 is only sampled every 20mS
'
' External EEPROM
' ===============
SCL var PortB.3
SDA var PortB.4
'
' RAM Usage
' =========
EEAddress var Byte
' Used to Address the physical EEPROM (ie EEPROM 1 or EEPROM 2)
EEPageStart var Word ' Pointer to start of Page boundary
PageAddress var Byte ' Location of Data in Page
PageCount var Word ' Counter for number of completed Pages
PageData var Byte [64] ' 100mS Data Buffer
SampleCount var Byte ' Counter for number of Sample Batches
'
' Constants
' =========
LoopCount con 650
' number of loops to perform...
' (650 pages of 100mS worth of samples equals 65 seconds)

'
' Initialise Program
' ==================
TRISA=%11111111
' All pins input
ADCON1=%00000000
' Left-Justify ADC Results
' Read 8-bit Results from ADRESH Register only
' Enable all ADC's
TRISB=%00000001
OPTION_REG.7=0 ' Enable Weak Pull-Up's
Pause 1000 ' Wait for external world to settle
High GreenLED ' OFF LED's
High RedLED
PageData[60]=0 ' Zero unused Portion of Databuffer
PageData[61]=0
PageData[62]=0
PageData[63]=0
'
' Ready to Sample
' ===============
Low GreenLED ' Indicate Ready to take sample
While StartButton=1:Wend
'
' Start Logging Sample
' ====================
High GreenLED ' Green OFF
Low RedLED ' Red ON to indicate sampling in progress
PageCount=0 ' Start at beginning of EEPROM
PageCountLoop:
PageAddress=0 ' Start each page at beginning of Data Buffer
SampleCount=0 ' Reset Page Sample Counter
SampleCountLoop:
'
' Read the Five Channels AN0-AN4
' ------------------------------
ADCON0=%01000001:Gosub GetSample:PageData[PageAddress]=ADRESH
ADCON0=%01001001:Gosub GetSample:PageData[PageAddress+1]=ADRESH
ADCON0=%01010001:Gosub GetSample:PageData[PageAddress+2]=ADRESH
ADCON0=%01011001:Gosub GetSample:PageData[PageAddress+3]=ADRESH
ADCON0=%01100001:Gosub GetSample:PageData[PageAddress+4]=ADRESH
'
' Read the Sixth Channel AN5 only every other 10mS
' ------------------------------------------------
If SampleCount.0=0 then
ADCON0=%01101001:Gosub GetSample:PageData[PageAddress+5]=ADRESH
else
PageData[PageAddress+5]=0 ' Save dummy (zero) sample
endif
'
' Determine if PageWrite dump to EEPROM required
' ----------------------------------------------
SampleCount=SampleCount+1 ' Increment Completed Sample Count
PageAddress=PageAddress+6 ' Increment Buffer Data Pointer
If SampleCount < 10 then
Pause 10 ' Wait 10mS
Goto SampleCountLoop ' Loop for next Capture Sequence
Endif
'
' Dump entire Data Buffer to EEPROM Page
' This takes 10mS to complete so there's no Pause in this section
' ================================================== =============
' I've assumed that 24LC256 EEPROM 1 is wired for Address $A0
' and EEPROM 2 is wired for Address $A1
If PageCount < 512 then
EEAddress=$A0
EEPageStart=PageCount*64
else
EEAddress=$A1
EEPageStart=(PageCount-512)*64
endif
I2CWRITE SDA,SCL,EEAddress,EEPageStart,[str PageData\64]
PageCount=PageCount+1 ' Increment completed EEPROM Page Counter
'
' Loop around for next 100mS Data Slice
' =====================================
If PageCount < LoopCount then goto PageCountLoop
'
' Indicate Sampling Completed
' ===========================
High RedLED ' Red OFF
CompletedLoop:
Low GreenLED ' Blink Green to indicate samples captured
Pause 750
High GreenLED
Pause 750
Goto CompletedLoop

'
' Subroutine Captures ADC Sample
' ------------------------------
GetSample:
PauseUS 50
' 50uS Pause to allow sampling Capacitor to charge
ADCON0.1=1
' Start Conversion
While ADCON0.1=1:Wend
' Wait for conversion to complete
Return

'
End


PS. ensure you spell my name right on either the college certificate or preferably the client cheque... *smiles*

Melanie

Tomas
- 24th April 2004, 11:39
Thank you very much Melanie, i will study it carefully and try it. Most of my PORTB pins are busy especially PORTB.0 as external interrupt input. Hope i should be able to use other PORTB pins.

Can i use PORTC pins? I don't think they have weak pull-up resistors though. How can i connect the resistors exteranlly?

I will try it and let you know.

Kind regards,
Tom.

Melanie
- 26th April 2004, 10:55
Yes, you can switch to whatever Port or pins you wish.

If you are not using weak pull-up's on PortB, delete the appropriate line in my code as it's not required.

You will then need an external pull-up Resistor, say 10K, connect it between the PIC pin that you are using and Vdd (+5v). The Push-Button is as usual connected between the PIC pin and Vss (0v).

Melanie

meetpeter
- 29th January 2011, 06:09
hey guys,
i am new here and i am in search of actual rates bcoz i could not find it any where.
can any one help?????
thanks in advance!!!!

Acetronics2
- 29th January 2011, 11:00
Hi, Meetpeter

Did you just read previous posts ??? :rolleyes:

Alain