First SX Project! - ADC TO PC
A friend of mine needed a cheap device for datalogging sensors in a SharePoint database project. I've been sitting on a couple SX28's for a while, and this was a good project to get me acquainted with SX 2.0. When i jumped into the SX , after years of BS2 I was a bit overwhelmed, but with some help from ya'll at this forum, I was able to wrap my head around it all.
Special Thank to JonnyMac for helping with the Max1270, and Jon Williams for writing all the Serial Comm Routines.
Heres my SX2.0 code, if you can make it better please share with the rest of the class!
Thanks Again Forum!
Special Thank to JonnyMac for helping with the Max1270, and Jon Williams for writing all the Serial Comm Routines.
Heres my SX2.0 code, if you can make it better please share with the rest of the class!
' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
' Reads the all channels from a MAX1270 ADC, then spits out a string to a
' PC via a MAX232 Driver.
' ie: *,CH1, CH2, CH3, CH4, CH4, CH5, CH6, CH7, CH8, <repeat>
' -------------------------------------------------------------------------
' Conditional Compilation Symbols
' -------------------------------------------------------------------------
' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------
ID "1270SPIT"
DEVICE SX28, OSCxt2, TURBO, STACKX, OPTIONX, BOR42
FREQ 4_000_000
IRC_CAL IRC_4MHZ
' -------------------------------------------------------------------------
' I/O Pins
' -------------------------------------------------------------------------
SClock PIN RA.0 OUTPUT ' shift clock
SIn PIN RA.1 INPUT ' shiftin data
Sout PIN RA.2 OUTPUT ' shiftout data
CS1270 PIN RA.3 OUTPUT ' max1270 chip select
PCin PIN RB.0 INPUT
PCout PIN RB.1 OUTPUT
' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------
' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------
chan VAR Byte
chLevel VAR Word
tmpB1 VAR Byte ' work vars
tmpB2 VAR Byte
tmpB3 VAR Byte
tmpB4 VAR Byte
tmpW1 VAR Word
tmpW2 VAR Word
nStr VAR Byte (5) BANK ' for STR and HEXSTR
' -------------------------------------------------------------------------
' Subroutine / Function / Task Declarations
' -------------------------------------------------------------------------
DELAY_MS SUB 1, 2 ' shell for PAUSE
GET_ADC FUNC 2, 1 ' get value from ADC
TX_BYTE SUB 1 ' transmit a byte
TX_STR SUB 2 ' transmit a string
TX_DEC SUB 1, 3 ' tx value in DEC format
' =========================================================================
PROGRAM Start
' =========================================================================
Start:
PLP_B = %0000_0000
PLP_C = %0000_0000
CS1270 = 1 ' deselect ADC
Main:
tx_str "*, " ' send marker char
FOR chan = 0 TO 7
chLevel = GET_ADC chan ' get adc
tmpW1 = chLevel ** $3880
chLevel = chLevel + tmpW1 ' convert to milivolts
tx_dec chlevel, 5 ' send milivolts out
tx_str ", " ' send deliminate char
delay_ms 100 ' delay makes serial better?
WATCH chan, 8, udec ' use Debug --> Run
WATCH chLevel, 16, udec
BREAK
NEXT
GOTO Main
' -------------------------------------------------------------------------
' Subroutine / Function / Task Code
' -------------------------------------------------------------------------
' Use: DELAY_MS milliseconds
' -- shell for PAUSE
SUB DELAY_MS
mSecs VAR __WPARAM12
\ SB __PARAMCNT.1
\ CLR mSecs_MSB
PAUSE mSecs
ENDSUB
' -------------------------------------------------------------------------
' Use: TX_BYTE aByte
SUB TX_BYTE
SEROUT PCOUT, T9600, __PARAM1
ENDSUB
' -------------------------------------------------------------------------
' Use: TX_DEC value {, digits }
' -- transmits "value" in DEC format
' -- "digits" MUST be specified with word values
' -- DEC3 or DEC5 format is used if "digits" not specified or invalid
SUB TX_DEC
dValue VAR tmpW1
dDigits VAR tmpB1
dIdx VAR tmpB2
dChar VAR __PARAM1
IF __PARAMCNT = 1 THEN ' byte w/o digits
dValue = __PARAM1
dDigits = 3
ELSEIF __PARAMCNT = 2 THEN ' byte w/digits
dValue = __PARAM1
dDigits = __PARAM2
ELSE ' word w/digits
dValue = __WPARAM12
dDigits = __PARAM3
ENDIF
IF dDigits = 0 THEN ' validate digits
dDigits = 5
ELSEIF dDigits > 5 THEN
dDigits = 5
ENDIF
STR nStr, dValue ' to decimal string
dIdx = 5 - dDigits ' point to first char
DO WHILE dIdx < 5
TX_BYTE nStr(dIdx)
INC dIdx
LOOP
ENDSUB
' -------------------------------------------------------------------------
' Use: TX_STR [noparse][[/noparse]String | Label]
' -- pass embedded string or DATA label
SUB TX_STR
strAddr VAR tmpW1
sChar VAR __PARAM1
strAddr = __WPARAM12 ' get offset/base
DO
READINC strAddr, sChar ' read a character
IF sChar = 0 THEN EXIT ' if 0, string complete
TX_BYTE sChar ' send the byte
LOOP
ENDSUB
' -------------------------------------------------------------------------
' Use: aVar = GET_ADC
' -- reads MAX1270 and places value into 'aVar'
FUNC GET_ADC
adcChan VAR tmpB1
adcResult VAR tmpW1
adcChan = __PARAM1 ' capture channel
adcChan = adcChan & %0000_0111 ' limit, 0 - 7
READ Adc_Cfg + adcChan, adcChan ' convert to config bits
SClock = 0 ' get ready
CS1270 = 0 ' select max1270
SHIFTOUT SOut, SClock, MSBFIRST, adcChan ' send config/channel
CS1270 = 1 ' done
NOP
CS1270 = 0
SHIFTIN Sin, SClock, MSBPRE, adcResult\12 ' get raw adc data
CS1270 = 1 ' done
RETURN adcResult ' store
ENDFUNC
' =========================================================================
' User Data
' =========================================================================
' 0 - +5 , channels 1-8
Adc_Cfg:
DATA %11110000, %11100000, %11010000, %11000000
DATA %10110000, %10100000, %10010000, %10000000
Thanks Again Forum!

Comments
I've updated your program to 2.00.16 features and improved the TX_DEC routine (I needed it for myself this week).
Slight confusion here.........
I built this project and I seem to be getting 1/2 the full scale output value when I run with a 20 MHz resonator & at 115200 Baud (ADC channel connected to +5VDC).
Went back and installed a 4 MHz resonator and running at 9600 Baud and now I'm getting full scale output.
What am I missing?
Complied w/2.00.18, 2.00.19, & 2.00.20.·Same results with·ALL versions
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Mike
Post Edited (Mike Cook) : 4/11/2009 7:19:51 PM GMT
I'm using Jon's example as-is posted on 3-14-09.
The problem seems to happen when I compile @ 20Mhz @ ANY baud rate.
Compiled at 4Mhz, max baud rate of 57600 and I DO get full scale output.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Mike
Sampling an in line resistor (current measurement) at 10mS, and at 4MHz @ 57600 I'm getting 105 samples per second. Good enough for right now but will need to add an interrupt to dial it in to 10 mS samples per second.
Would like to get the baud rate up to 115200, most of out test equipment operates at this speed. Our programmers give me a funny look when I bring in a piece of “glue hardware” that operates at a different baud rate than that!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Mike
Don’t have a resonator, to try, in between 4MHz to 20 MHz.
Seems, to me, like SHIFTIN is dropping the last bit, over 4MHz, just an "un-educated Guess"!
Project built on a Parallax PN: 45301 Proto Board.
Attached the code, Incase I've done something 'Bone Headed'.
Thanks
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Mike
I have two other MAX1270BCNG chips (got to love www.maxim-ic.com's sampling policy!)
Will try them next to see of there is a difference.
Thanks for the suggestions!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Mike
Thanks for the help, hopefully I'm missing something simple.· Might port this to a Propeller to see if I get the same results.
Your example as posted works quite well.
I just need a faster & timed (10mS) output.
Thanks Again,
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Mike
Post Edited (Mike Cook) : 4/12/2009 10:37:04 AM GMT
As usual you were correct!
Probably not the correct way to fix my problem but changed the GET_ADC function from:
To:
' ------------------------------------------------------------------------- ' Use: aVar = GET_ADC ' -- reads MAX1270 and places value into 'aVar' FUNC GET_ADC adcChan VAR tmpB1 adcResult VAR tmpW1 adcChan = __PARAM1 ' capture channel adcChan = adcChan & %0000_0111 ' limit, 0 - 7 READ Adc_Cfg + adcChan, adcChan ' convert to config bits SClock = 0 ' get ready CS1270 = 0 ' select max1270 SHIFTOUT SOut, SClock, MSBFIRST, adcChan ' send config/channel CS1270 = 1 ' done - de-select max1270 [b]for idx = 0 to 11 ' 11 was the smallest delay @ 20MHz NOP next[/b] CS1270 = 0 ' select max1270 SHIFTIN Sin, SClock, MSBPRE, adcResult\12 ' get raw adc data CS1270 = 1 ' done - de-select max1270 RETURN adcResult ' store ENDFUNCNow this works at 20 MHz @ 115200 baud, but I have to 'fiddle' with the delay loop for 50 MHz, to get the same results.
Next task is to determine how long a NOP is at 20 MHz and put in the proper delay so the function will return the correct value at any MHz other than 4Mhz.
Thanks for the 'bread crumbs' !
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Mike
for idx = 0 to 11 ' 11 was the smallest delay @ 20MHz
NOP
next
Why not use something like
PAUSEUS 10 ' may need to play with value
Which basically does the same thing (a delay loop) but then you can adjust in microseconds and know that you'll get the same delay even if you move the code or use a different FREQ (i.e. the PAUSEUS will work the same even if you change the project to 50mhz or 8mhz, etc)
P.S. -- NOP always takes 1 cycle -- so at 50mhz it takes 1/50th of a micro second, at 20 mhz, 1/20 of a micro second etc. In your loop, in fact, the instructions that comprise the for/next loop actually take most of the time cycles, not the NOP itself. Again PAUSEUS will give you consistent results (once you decide the correct the delay time) regardless of frequency or device.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php
Post Edited (Zoot) : 4/14/2009 12:51:10 PM GMT
Thanks for the reply!
Yes that was my idea of determining how long a NOP is at 20MHz, by using PAUSEUS that will save me some reading and math calculations!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Mike
PAUSEUS 6
was the answer! Now works properly from 4 to 50Mhz.
Thanks to ALL for the help!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Mike