AppleScripting -SerialPort
Contents |
Mac OS X 10.4 and 9-Pin RS-232 Serial interfaces?
Did you know that Macs running Mac OS X 10.4,5,6 can use an external serial port. They can’t do this natively, but for less than AUD$80.00 it can be done.
Obtain and install a free copy of the OSAX SerialPort X 1.1. Version 2.0 is also available for Mac OS X 10.6. Obtain a LINDY 42856/42811 (USB to RS232 converter) from LINDY Australia. The package contains a USB cable. It can be used with both a Mac and a PC. Don’t install the driver that comes with it on the CD-ROM- you may have difficulty using the mini disc CD-ROM. Obtain the latest driver directly from the website. From this point on you have a functional setup to access an RS232 device USING AppleScript. (actually it could also allow other languages/applications to use it as well if they had the requisite APIs). For example PICAXE products use a similar RS232c serial to USB converter in communicating with PICAXE products.
There are several other similar products (eg KeySpan) on the market but I have not tested them.
To test the Serial Port, I used a KT145 kit from | Ocean Controls. It is a 1-input temperature monitoring module. This is a very small module that you can buy either as a kit or already built for less than $40.00. if you have no soldering experience I suggest you buy the built module.
What did I do: Plug in the single temperature sensor IC provided to the DS1 port on the KT145. Plug in the KT145 module to the LINDY USB to Serial converter module Plug in the USB cable to the converter module and a free USB port on the Mac (make sure it can supply the full 500 mA current because the whole system is powered from the Mac USB port!). That’s it. For example do not plug it into a keyboard USB port that only supplies 100 mA. No harm will be done, but you will get a message that it won’t work.
I wrote a simple AppleScript using the SerialPort X 1.1 /SerialPort 2.0 OSAX to get data from the device AND then plant it in an Excel spreadsheet.
-- USB-Serial Port Interface Experiment - connection to KitsRUS K145 -- Ian Parker 2007 -- first worked on: 2007-10-10 last worked on 2007-10-10 -- open the serial port (handle usually = 9 or 10) set in_buffer to "" -- initialise the data buffer set use_port to item 2 of (get serialport list) set begin_logging to ASCII character (12) -- ^L set nextitem to 1 --index variable -- ---------------------------------------------------------------------- -- begin communication with K145 module with one sensor attached -- no error checking or graceful exit to make code shorter -- power cycle the (converter + KT145) -- ensure Excel is NOT running -- ---------------------------------------------------------------------- set RS232port to serialport open use_port bps rate 2400 data bits 8 parity 0 stop bits 1 display alert "Serial port opened, set to 2400, 8N1" serialport write begin_logging to RS232port -- for a continuous data stream delay 2 -- to let logger chip set up -- wait for some data (should not have to) repeat until (serialport bytes available RS232port) > 0 end repeat set in_buffer to serialport read RS232port -- so we can process serialport close RS232port -- because no longer needed set word_list to every word of in_buffer -- so we can process -- -------------------------------------------------------------------- -- process the information from the data logger stream -- -------------------------------------------------------------------- repeat until item nextitem of word_list is "C" -- scan buffer to begin set nextitem to nextitem + 1 -- to skip garbage and header words end repeat -- get the first item (they are not characters) after the header set PortNo to item (nextitem + 1) of word_list -- wipe leading zeros, and does not handle negative numbers set Portval to ((item (nextitem + 2) of word_list) as number) -- now just plant it in Excel (Uh? it's that easy??) tell application "Microsoft Excel" Activate Select Cell "R2C2" set Selection to "Port" -- header for the port column Select Cell "R2C3" set Selection to "Temp (°C)" -- header for the data Select Cell "R3C2" -- first column is port number set Selection to PortNo Select Cell "R3C3" set Selection to Portval end tell
Connection to a Garmin GPS18 C(RS232 serial)
-- USB-Serial Port Interface Experiments - connection to Garmin GPS18 PC
-- extract latitude, longitude and fix time
-- Ian W. Parker 2007-2008
-- first workd on: 2007-10-08 last worked on 2008-03-16
-- open the serial port (handle usually = 9 or 10)
set data_buffer to "" -- initialise the data buffer
try
set use_port to item 2 of (get serialport list)
set RS232port to serialport open use_port bps rate 4800 data bits 8 parity 0 stop bits 1
display alert "Serial port opened, set to 4800, 8N1"
if ((serialport bytes available RS232port) > 0) then
delay 2 -- allow the buffer to fill
set data_buffer to data_buffer & (serialport read RS232port)
end if
-- close the serial port handle, then process snapshot
serialport close RS232port
process_snapshot(data_buffer)
on error
display alert "Unable to connect to serial port" as warning
end try
-- ----------------------------------------------------------------
on process_snapshot(data_buffer)
try
set data_list to every word of data_buffer -- explode string buffer into a list
repeat with i from 1 to number of items in data_list
if (item i of data_list) is "GPGLL" then -- we've found a sentence marker
-- we forward look 4 items, convert to integer
set latitude to (((item (i + 1) of data_list) div 100) & " °" & (item (i + 2) of data_list)) as string
set longitude to (((item (i + 3) of data_list) div 100) & " °" & (item (i + 4) of data_list)) as string
set UTCtime to (item (i + 5) of data_list) as string
exit repeat -- because we found a valid sentence
end if
end repeat
-- post acquisition processing- so we have a formatted return record
set theHour to (characters 1 through 2 of UTCtime)
set theMinutes to (characters 3 through 4 of UTCtime)
return {loc_lat:latitude, loc_long:longitude, loc_fix:((theHour & "h " & theMinutes & "m") as string)}
on error
display alert "Garmin GPS18 not responding" as warning
end try
end process_snapshot
Connection to a Tri-Axis Accelerometer
Check out the reference site for the | SerAccel v5
-- USB-Serial Port Interface Experiments - connection to SparkFun SerAccel v5
-- extract X,Y,Z static and dynamic acceleration components
-- Ian Parker 2007
-- first workd on: 2007-10-10 last worked on 2007-10-10
-- open the serial port (handle usually = 9 or 10)
set x to "" -- initialise the data buffer
set use_port to item 2 of (get serialport list)
set begin_logging to ASCII character (12) -- ^L
set RS232port to serialport open use_port bps rate 9600 data bits 8 parity 0 stop bits 1
-- ----------------------------------------------------------------------
-- begin communication with the SparkFun SerAccel v5 module
-- ----------------------------------------------------------------------
display alert "Serial port opened, set to 9600, 8N1"
--serialport write (ASCII character (12)) to RS232port -- begin producing data
if ((serialport bytes available RS232port) > 0) then
set x to serialport read RS232port
end if
-- close the serial port handle
serialport close RS232port
-- explode the data stream BUT DOES NOT give SIGN of values
-- needs to be written to take this into account.
-- possubly using AS delimiter
set x to every item of x
set nextitem to 10 -- skip the first data item (unreliable)
-- --------------------------------------------------------------------
-- process the information
-- --------------------------------------------------------------------
repeat while item nextitem of x is not "X"
set nextitem to nextitem + 1
end repeat
set X_Accel to "" & (item (nextitem + 2) of x) & (item (nextitem + 3) of x) & (item (nextitem + 4) of x) & (item (nextitem + 5) of x) & (item (nextitem + 6) of x) & (item (nextitem + 7) of x) as number
-- get X value
repeat while item nextitem of x is not "Y"
set nextitem to nextitem + 1
end repeat
set Y_Accel to "" & (item (nextitem + 2) of x) & (item (nextitem + 3) of x) & (item (nextitem + 4) of x) & (item (nextitem + 5) of x) & (item (nextitem + 6) of x) & (item (nextitem + 7) of x) as number
repeat while item nextitem of x is not "Z"
set nextitem to nextitem + 1
end repeat
set Z_Accel to "" & ((item (nextitem + 2) of x) & (item (nextitem + 3) of x) & (item (nextitem + 4) of x) & (item (nextitem + 5) of x) & (item (nextitem + 6) of x) & (item (nextitem + 7) of x)) as number
set result to {Xval:X_Accel & " g", Yval:Y_Accel & "g", Zval:"" & Z_Accel & " g"}
Using Excel as a Datalogger item accumulator and Grapher
In this next version of a temperature datalogger, 30 measurements are accumulated at about 1200 B with a timing interval of about 10 seconds. Most people could type faster than that!
The elapsed time is recorded rather than the port number. We have true data logging, feeding data directly into an Excel spreadsheet. The resulting data list in Excel can then be highlighted, and a scatter graph constructed from the two columns. Keep the Excel spreadsheet “live”, re-run the script, and watch the data list being modified in situ AND this time the graph being modified in situ. Highly instructive at several levels!
-- Ian Parker 2007, 2008
-- first worked on: 2007-10-10 last worked on 2008-03-08
-- USB-Serial Port Interface Experiment Vers 1.1
-- requires USB-Serial Interface (eg. LINDY 42856)
-- requires KitsRUS K145 kit from Ocean Controls
-- K145 can deliver up to 4 readings at a time
-- each with an accuracy of 0.5°C
-- featuring logger power OFF between readings
-- featuring live data accumulation in Excel
-- optional live graphical display in Excel (manually set up)
property begin_logging : ASCII character (12) -- ^L
global in_buffer, next_item, use_port, RS232port, data_list, Excel_Row
set Excel_Row to 2 -- initial offset in the Excel column
set wait_interval to 8 -- for about (8 + 2) seconds between measurements
-- -------------------------------------------
set_up_Excel()
-- start logging time
set theStart to current date
repeat 30 times
set_up_port()
set data_list to next_data_slice()
-- search for 'C' in buffer to begin reading data as °C
-- if 'C' not found then recording in °F
set next_item to 1
repeat until item next_item of data_list is "C" -- scan buffer to begin
set next_item to next_item + 1 -- to skip garbage and header words
end repeat
set {PortNo, Portval} to next_port_val() -- extract list items
-- powers down the port
serialport close RS232port
send_to_Excel((current date) - theStart, Portval)
delay wait_interval
end repeat
-- indicate we have finished
beep 2
-- -------------------------------------------------------------
-- support routines
-- -------------------------------------------------------------
on set_up_port()
-- open the serial port (handle usually = 9 or 10)
global in_buffer, next_item, use_port, RS232port
set {next_item, inbuffer} to {1, ""} --index variable, initialise the data buffer
try
set use_port to item 2 of (get serialport list)
set RS232port to serialport open use_port bps rate 2400 data bits 8 parity 0 stop bits 1
-- for a continuous data stream
serialport write begin_logging to RS232port
delay 2 -- to accumulate data at 2400 B (this is slow!)
on error
serialport close RS232port
end try
end set_up_port
-- -------------------------------------------------------------
on next_data_slice()
global RS232port
try
-- load buffer with data slice
set in_buffer to serialport read RS232port
-- dice, then return as list of items
on error
serialport close RS232port
end try
return every word of in_buffer
end next_data_slice
-- -------------------------------------------------------------
on next_port_val()
global data_list
-- get the first item (they are not characters) after the header
-- currently unused
set PortNo to item (next_item + 1) of data_list
-- coerce to number to wipe leading zeros
set Portval to ((item (next_item + 2) of data_list) as number)
return {PortNo, Portval}
end next_port_val
-- -------------------------------------------------------------
on set_up_Excel()
tell application "Microsoft Excel"
Activate
set Width of ActiveWindow to 900.0
set Height of ActiveWindow to 500.0
Select Sheet "Sheet1"
-- elapsed time as integer display
Select Range "R2C2:R32C2"
set NumberFormat of Selection to "0"
Select Range "R2C3:R32C3"
-- temp with 0.1 resolution
set NumberFormat of Selection to "0.0"
Select Range "R2C2:R32C3"
set HorizontalAlignment of Selection to xlCenter
set VerticalAlignment of Selection to xlBottom
set WrapText of Selection to false
set Orientation of Selection to 0
Select Sheet "Sheet1"
Select Cell "R2C2"
-- header for the elapsed time column
set Selection to "Elapsed Time(s)"
Select Cell "R2C3"
-- header for the temperature data column
set Selection to "Temp (°C)"
end tell
end set_up_Excel
-- -------------------------------------------------------------
on send_to_Excel(e_time, Portval)
-- plant elapsed time and values in Excel columns
global Excel_Row
set Excel_Row to Excel_Row + 1
tell application "Microsoft Excel"
Select Sheet "Sheet1"
-- first column is elapsed time
Select Cell ("R" & Excel_Row & "C2")
set Selection to e_time
-- second column is temperature value
Select Cell ("R" & Excel_Row & "C3")
set Selection to Portval
end tell
end send_to_Excel
-- -----------------------------------------------------------