Shop OBEX P1 Docs P2 Docs Learn Events
stumped: trying to record values from mcp3208 to 27937 data logger — Parallax Forums

stumped: trying to record values from mcp3208 to 27937 data logger

Project5kProject5k Posts: 58
edited 2011-08-11 23:05 in Propeller 1
Using a Prop Proto Usb, mcp3208, 4 line LCD, and usb data logger, i'd like to read the 3208, store the values read, and be able to do some simple math, and a couple if/else 's to turn on a relay...

Where i am....
I can read the 3208, and i can display the values received on the LCD. What i havent figured out is how to get the values read, over to the USB for storage...

I've been messing whith "memStick_demo" and have been able to see a file written to the flash drive via the 27397, so i know my parts are working...

Ive also been playing around with "autodatalogger" with limited success....
I've cut and pasted my code together trying to get it to work, but for some reason, i'm just up against a wall, and i'm not sure what to try next...

Here is all of the code i'm using, and a pic of the hardware...
{
Project5k 
this will read all 8 chanels of a MCP3208 and display them on the 4line LCD

}
CON
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000

  TX_PIN        = 0
  BAUD          = 19_200

  dpin          = 2             'both din and dout of the mcp3208 are connected to this pin on the prop demo board.
  cpin          = 3             'the clock pin of the mcp3208 is connected to this pin on the prop demo board.
  spin          = 1             'the chip select pin of the mcp 3208 is connected to this pin on the prop demo board.

  rxpin         = 6             'Receive pin on the Propeller
  txpin         = 4             'Transmit pin on the Propeller
  ctspin        = 7
OBJ
  LCD : "FullDuplexSerial"
  adc : "MCP3208"
  USB : "Autodatalogger"

Var
  long filenameaddr
  
PUB main

  adc.start(dpin, cpin, spin, 255)  'Start the MCP3208 object and enable all 8 channels as
                                  'single-ended inputs.
  LCD.start(TX_PIN, TX_PIN, %1000, 19_200)
  waitcnt(clkfreq / 2 + cnt)
  
  lcdgetready

  filenameaddr := string("samples.txt")                 'this is the file name

  USB.init(rxpin, txpin, ctspin, filenameaddr, 10_000)   'the number is the count of samples per file

  usbnamecol
repeat

  lcdupdate
  waitcnt (clkfreq / 4 + cnt)
  usbwrite
  waitcnt (clkfreq / 4 + cnt)
  

    
pub lcdupdate
         
  LCD.str(string(128))
  LCD.str(string("Ch-1 ",133))
  LCD.dec(adc.in(0))
  LCD.str(string(138))
  LCD.str(string("Ch-2 ",143))
  LCD.dec(adc.in(1))
  LCD.str(string(148))
  LCD.str(string("Ch-3 ",153))
  LCD.dec(adc.in(2))
  LCD.str(string(158))
  LCD.str(string("Ch-4 ",163))
  LCD.dec(adc.in(3))
  LCD.str(string(168))
  LCD.str(string("Ch-5 ",173))
  LCD.dec(adc.in(4))
  LCD.str(string(178))
  LCD.str(string("Ch-6 ",183))
  LCD.dec(adc.in(5))
  LCD.str(string(188))
  LCD.str(string("Ch-7 ",193))
  LCD.dec(adc.in(6))
  LCD.str(string(198))
  LCD.str(string("Ch-8 ",203))
  LCD.dec(adc.in(7))


pub lcdgetready
  LCD.str(string(17))
    waitcnt(clkfreq / 2 + cnt)
  LCD.str(string(22))
    waitcnt(clkfreq / 2 + cnt)
  LCD.str(string(12))
  waitcnt(clkfreq / 2 + cnt)  
  LCD.str(string(128))

pub usbnamecol

'Set up the number of columns to log
  
  '           (address, digits, title)
  USB.addfield(@adc.in(0), 4, string("Ch-1"))
  USB.addfield(@adc.in(1), 4, string("Ch-2"))
  USB.addfield(@adc.in(2), 4, string("Ch-3"))
  USB.addfield(@adc.in(3), 4, string("Ch-4"))
  USB.addfield(@adc.in(4), 4, string("Ch-5"))
  USB.addfield(@adc.in(5), 4, string("Ch-6"))
  USB.addfield(@adc.in(6), 4, string("Ch-7"))
  USB.addfield(@adc.in(7), 4, string("Ch-8"))

pub usbwrite             'this is where i plan to write all the data to the usb...

I’m wondering if I need this bit….
PRI txstring(address, commabool) | length
{Will transmit a string to be written to the file
commabool determines whether or not to add a tail comma}

  serial.str(string("WRF "))
  serial.tx(0)
  serial.tx(0)
  serial.tx(0)
  length := strsize(address)
  if commabool
    length++
  serial.tx(length)
  serial.tx($0D)
  serial.str(address)
  if commabool
    serial.tx(",")
  serial.tx($0D)

  repeat until serial.rx == $0D
1024 x 768 - 150K

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-08-07 12:45
    I've used these data loggers some (all most everyday). I strongly dislike them. They (at least mine) tend to be very picky about what USB drives they will work with. I'm switching over to using SD cards in all my data logging projects.

    I haven't gone through your program completely but my bet is you're trying to store the data as straight data. You probably need (well want) to convert your data to ASCII characters. The LCD.dec method does this for you when you display the data to the LCD. You want a method that will convert the data to ASCII characters before you write them to the datalogger. Look at the dec method to see how this is done.

    If you are still having problems I'll look around for some code that does something similar to what you're doing and post it.

    Duane
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-08-07 12:51
    Depending on what object you use to write data to the datalogger you could do this.
    serial.dec(adc.in(0))
      serial.tx(13)
    

    I think that would work if you're using something like FullDuplexSerial in UART mode.
  • Project5kProject5k Posts: 58
    edited 2011-08-07 14:11
    I believe what i have set up is full duplex serial.. i have 4 "data" lines from the prop to the datalogger, and +5v and Gnd...

    I'm sitting here looking at the code, and i'm a little unclear, it seems to me that with the way i have things now, i would be asking "fullduplexserial" to communicate to 2 different devices... how do i do this without sending the wrong thing to the wrong place?

    do i set a second fullduplexserial up under another um, i dont know what to call it, abbreviation... like this
    go from :

    OBJ
    LCD : "FullDuplexSerial"
    adc : "MCP3208"
    USB : "Autodatalogger"

    to

    OBJ
    LCD : "FullDuplexSerial"
    adc : "MCP3208"
    USB : "Autodatalogger"
    usb2 : "FullDuplexSerial"

    i guess i'm just confused how to share it, and get the right variables to the right place at the right time...

    i supposed then the code would look more like


    usb2.dec(adc.in(0))
    usb2.tx(13)

    but it seems to me that somewhere above that i would need to start or init or something the usb2 one to send it its variables... wouldnt i?

    also, i'm not understanding the (13)... i'm just not finding the right ref... is that a command like move to position on an lcd?
  • StefanL38StefanL38 Posts: 2,292
    edited 2011-08-07 15:52
    you can name it even

    tea_party_is_bad : "FullDuplexSerial"

    and the second instance
    blabla : "FullDuplexSerial"

    of course each instance of FullDuplexSerial must be started through

    tea_party_is_bad.init(rxpin, txpin, ctspin, filenameaddr, 10_000)

    or

    blabla.init(rxpin, txpin, ctspin, filenameaddr, 10_000)

    For each USB-stick you have connected you need one instance of FullDuplexSerial

    As you have only one USB-stick one instance is enough.
    the above examples are just to show that you are free to choose a name which is some kind of an alias for the "FullDuplexSerial.SPIN"-objectfile

    If you want further advice please attach your WHOLE project to a psoting using the archive-function of the propeller-tool.
    and additionally attach the manual of your 27937 data logger.

    Without seeing your complete code and without knowing the methods of AutoDataLogger advsing is not advising but guessing through the fog.

    keep the questions coming
    best regards

    Stefan
  • Project5kProject5k Posts: 58
    edited 2011-08-07 17:00
    ok, here's the zip that i got from doing the archive thing.... is this the right thing?

    also was poking around and figured out that something in the usb.init is causing the lcd to not display... when i comment it out, the lcd works again...
  • StefanL38StefanL38 Posts: 2,292
    edited 2011-08-07 21:41
    thank you for uploading the code and the manual.

    In principle you did the right thing with archiving the code.
    Anyway this archive does not contain code that has to do with the datalogger.
    So you might have archived an earlier version of your code.

    For archiving the right code. Close all windows in the propellertool except the one containing the USB-datalogger code.

    If starting the USB-datalogger stops the LCD. Two things are possible:

    You are using the same IO-pins for LCD and datalogger
    you are using the same instance of FullDuplexSerial.

    For a real analyses that codeversion that is causing the problems must be uploaded

    keep the questions coming
    best regards

    Stefan
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-08-07 21:53
    I believe you also need to have compiled a project before it can be archived.

    Duane
  • Project5kProject5k Posts: 58
    edited 2011-08-08 10:32
    i hadnt closed a previous version... I'm still learning, sorry... ok, closed everything, and then did the compile, its running on the prop... with stuff commented out that is... and then did the archive...

    i have my pin settings in the CON block, but i'm starting to wonder if i'm calling to something, like the usb init, that has pin settings in it, and its ignoring that i'm "sending" it...and this is where my issue is... gotta stare at it for a while....

    something else i thought of, just as i was drifting off to sleep last night... i'm reading from the adc to the lcd, and i'm also gonna wanna use thoes readings for math, decision making, and storage... would i be better off to figure out how to read in from the adc into a set of variables, like num0, num1, and so forth, and then just use thoes var's in everything else? then that way i can display them the way i want, i can store them the way i want, in F deg, not counts that dont mean anything to me.... only ready from the adc once, do my display, math, and storage, and then read from the adc again, not read adc, display, read adc, math, read adc, store, and so forth... plus doing it that way, would mean that the math, display, and stored values could all be different... not what i want at all... thats for sure...
  • StefanL38StefanL38 Posts: 2,292
    edited 2011-08-08 14:10
    Thank you for uploading code that does compile.

    Your idea of reading the ADC-channels once and store the values into variables is the right way.

    Independant from that the object Autodatalogger needs pointers to variables. You get the pointer to variables by adding the "@"-operator to the variables name.

    coding
    USB.addfield(@adc.in(1), 4, string("Ch-2")) 
    

    does not work at all because "adc.in(1)" is not a variable but objectname.methodname(parameter) which is something complete different than a variable.

    As you coded this I recommend to go through the exercises of the PE-kit labs. This will take some time but will pay off a lot in the end.
    At the moment your knowledge is at a level that you do "graphical copying" things without understanding what it means.
    If you stay on that level allmost every detail that you change will end up in
    - it does not work - ask in the forum - try a new variant it does not work - ask in the forum - try a new variant and each step will take two days.
    Until it is running there will be 15-30 steps meaning 30-60 days. So taking 14 days time to go through the PE-Kit labs and then another 7 days to get it working will be faster.

    About PIN-assignment:
    If two objects like in your case USB (Autpdatalogger.spin) and store (FullDuplexSerial.spin) are using the same pins as you coded
    '  USB.init(rxpin, txpin, ctspin, filenameaddr, 1_000_000)   'the number is the count of samples per file
      store.start(rxpin, txpin, %1000, 19_200)
    

    They will disturb each other and nothing will work.
    You have to decide between using the autodatalogger-object or using the FullDuplexSerial-obect together with hand-coded commands to store data on the USB-stick.

    The filename (FullDuplexSerial.spin) can stay the same. Only the object-aliases (in your code "LCD" and "store" need to be different. That is enough.
    Again these two example shows your lack of understanding.
    If I write this - this is never never never meant as beating you. It is meant as clearly stating what I can conclude about your knowledge-level from your code.
    And based on that recommending going through the PE-Kit labs.

    You are very welcomed to ask hundreds of questions about the exercises in the PE-Kit Lab as this way your understanding and knowledge grows continually up from a basic level.

    It's like before you can drive a F1-racecar you have to do some exercising in a motorised go-cart, a F3-car and then switch over to the F1-car.

    keep the questions coming
    best regards

    Stefan
  • Project5kProject5k Posts: 58
    edited 2011-08-08 15:04
    i take no beating, i take no offence and i thank you for pointing me in a direction to learn... I will begin working on the labs this evening... and your right, i have a MAJOR lack of understanding, but, i'm not afraid to do the homework....

    thanks for helping me thus far, i'll keep tinkering with it, as i've already figured out how to read in the values from the adc, assign them to a variable, and then read that variable out to the lcd...

    time to hit the books...

    I'll be back...
  • Project5kProject5k Posts: 58
    edited 2011-08-11 19:59
    working through the labs, lots of reading... good stuff tho... i did come up with one question tho thats been eating at me... when i read in the value from the ADC, i place that into a variable, and then i can do what i want with it.... but i'm not sure what it is thats in that variable... cause when i try basic math on it, i'm not getting what i would expect... i guess really what it is that i'm having an issue with is getting it into a decimal value(hopefully a floating point value) that i can then carry out my math operations on... i see in the full duplex serial that there is a method called dec. this converts to a decimal value and spits it out to the lcd... but what i just cant get my head wrapped around is how its doing the conversion... cause thats the part i'm missing outta my project at this point... i dont know why i cant figure this one out, but i've stared at this so long i'm going loopy....

    can someone please "splain it to me lucy"??
    PUB dec(value) | i, x
    
    '' Print a decimal number
    
      x := value == NEGX                                                            'Check for max negative
      if value < 0
        value := ||(value+x)                                                        'If negative, make positive; adjust for max negative
        tx("-")                                                                     'and output sign
    
      i := 1_000_000_000                                                            'Initialize divisor
    
      repeat 10                                                                     'Loop for 10 digits
        if value => i                                                               
          tx(value / i + "0" + x*(i == 1))                                          'If non-zero digit, output digit; adjust for max negative
          value //= i                                                               'and digit from value
          result~~                                                                  'flag non-zero found
        elseif result or i == 1
          tx("0")                                                                   'If zero digit (or only digit) output it
        i /= 10                                                                     'Update divisor
    
    
  • StefanL38StefanL38 Posts: 2,292
    edited 2011-08-11 21:55
    Hi,

    variable i works as the divider.

    I will use lower values to explain it

    let's say i := 1000

    let's say variable (value) is 7082

    if value => i in my example if 7082 => 1000 this is true "=>" means bigger as or equivalent

    tx (a ASCII-coded byte)

    value / i 7082 / 1000 = 7 why not 7,082? because it s integer math truncating the digits behind the decimal point

    first digit of 7082 is 7
    theASCII-code of character "7" is 55
    ASCII-code of "0" 48
    ASCII-code of "1" 49
    ASCII-code of "2" 50
    ASCII-code of "3" 51
    ASCII-code of "4" 52
    ASCII-code of "5" 53
    ASCII-code of "6" 54
    ASCII-code of "7" 55
    ASCII-code of "8" 56
    ASCII-code of "9" 57

    + "0" gets compiled to + 48 through the hiphens "" the compiler knows you mean it ASCII-coded and ASCII-coded value of character "0" is 48
    so value / i + "0" means

    7 + 48 = 55

    value // i "//" is an operator 7082 / 1000 = 7 rest 82
    other examples

    81234 / 1000 = 81 rest 234

    724 / 1000 = 0 rest 724

    got to go to work now

    keep the questions coming
    best regards

    Stefan
    7 + 48
  • SRLMSRLM Posts: 5,045
    edited 2011-08-11 23:05
    In response to the code from your code in post #9:

    The autodatalogger object is intended to be the sole user of the Datalogger, but if you want to you can trade off access between autodatalogger and your own access code.

    Based on your first post, the code below should be a rough framework (untested and uncompiled and from a hazy memory of how things should work...).
    VAR
    
      long datasample
    
    
    OBJ
    
      ADC : "MCP3208_fast"
      USB : "autodatalogger"
      LCD : "FullDuplexSerialPlus"
    
    PUB Main
    
      'start ADC here
      'start LCD here
      'init USB here
    
      waitcnt(clkfreq*2 + cnt)
    
      USB.addfield(@datasample, 4, string("datasample_variable"))
      USB.start
    
      repeat 1000
        datasample := adc.in(channel)
        LCD.tx(cls)                 'cls is the clear screen code for the lcd...
        waitcnt(clkfreq/100 + cnt) 'most LCDs require a pause before sending the next command after a cls
    
        LCD.str(string("datasample == "))
        LCD.dec(datasample)
    
        waitcnt(clkfreq/10 + cnt)   'slow down the loop to ~10 Hz
    
    

    Also, if you are looking to having lots of ADC inputs then take a look at the attached code. It automatically samples from three MCP3208 ADCs, and you can tie the output of that to the input to the autodatalogger in addition to using the values in your math equations however you want.
Sign In or Register to comment.