programming in spin
in Propeller 1
The new nuts volts mag, April issue 2017.. There is an article on a garage or parking sentinel using the Propeller Project Board USB. Now, I'm totally new the propeller world but I did get the program to compile but when I tried to run it nothing happened. I looked at the the signal pin on the 3 terminal ultrasonic unit and there are no pulses. Looking at the compiled program I noticed that the I2C portion of the code is red and pink. The I2C title is red and everything below it is pink. I don't know if that is normal or not. the rest of the code is blue. Is that where the problem is? If so how do I fix the problem? if not, what could it be?

Comments
Thanks for the quick response
I notice in the article the author said he powered the Ping with 3.3V. I don't think the Ping is reliable at 3.3V.
I suggest powering the Ping with 5V and use a 4.7k ohm resistor in series on the signal line.
There are other things you can do test each component but I suggest trying the above with the Ping sensor.
The colors of the sections of code you described are normal.
A 2k resistor is out of specs for the Propeller. The current on an input pin needs to be limited to 500uA. This requires about are resistor value of at least 3k. You don't want to use too high of a value or the Ping might now see the 3.3V signal. I've used 4.7k myself many times.
You 2k resistor will probably be okay but you're putting the I/O pin at risk.
My standard procedure of debugging a program is to add debug statements.
I haven't tested the code below but hopefully it will give you a clue of what the program is doing.
I left out the "Calmode" method for now.
Give the code below a try and let us know what you see in the terminal window. The program requires input from the terminal to start so it won't work without being connected to a computer.
CON _xinfreq = 5_000_000 ' specify 5 MHz xtal _clkmode = xtal1 + PLL16X ' and set clock to 80 MHz clkpermsec = 80_000 ' define one millisec ' I/O pin assignments pinger = 7 medshortdist = 0 ' Red LED lamp longdist = 1 ' Amber LED lamp calbutton = 6 ' calibration push button, active low ' EEPROM constants eepAdrLd = $8000 ' non-volatile, long distance thhreshold eepAdrMed = $8008 ' non-volatile, medium/short threshold eepromSel = $A0 ' EEPROM select code promSCL = 28 ' EEPROM SCL (clock) pin promSDA = 29 ' EEPROM SDA (data) pin BAUD = 115200 OBJ i2c : "Basic_I2C_Driver" Pst : "Parallax Serial Terminal" VAR long millisec, microsec ' timing constants in system clock counts long duration long echostart, loopstart long flashflag long distance ' distance to object, centimeters long pinouts ' pattern written to output pins long farmark, nearmark ' zone demarcations (cm) long caltime ' length of cal button press, milliseconds long calstart, calontime PUB Main millisec := clkfreq/1_000 ' define timing constants microsec := clkfreq/1_000_000 Pst.Start(BAUD) repeat Pst.Str(string(11, 13, "Press any key to begin.")) waitcnt(clkfreq / 2 + cnt) until Pst.RxCount Pst.RxFlush dira[medshortdist..longdist]~~ ' set up indicator pins as output dira[calbutton]~ ' read zone demarcation distances from EEPROM farmark := i2c.ReadLong(promSCL,eepromSel,eepAdrLd) nearmark := i2c.ReadLong(promSCL,eepromSel,eepAdrMed) repeat 'IF ina[calbutton] == %0 ' Calmode Pst.Str(string(11, 13, "About to trigger Ping.")) loopstart := cnt ' begin timed loop !flashflag ' toggle flash status flag dira[pinger]~~ ' ping a short pulse outa[pinger]~~ waitcnt(50*microsec + cnt) dira[pinger]~ ' wait for return repeat until ina[pinger]==%1 echostart := cnt ' begin duration measurement repeat until ina[pinger]==%0 duration := cnt - echostart ' echo delay in sys counts distance := duration/4936 ' distance in cm ( 6.17 msec/meter ) Pst.Str(string(11, 13, "distance = ")) Pst.Dec(distance) IF distance => 260 ' both LEDs off pinouts := %00 Pst.Str(string(11, 13, "both LEDs off")) IF distance<260 ' amber on pinouts := %10 Pst.Str(string(11, 13, "amber on")) IF distance<farmark ' red steady on pinouts := %01 Pst.Str(string(11, 13, "red steady on")) IF distance<nearmark ' red flashes IF flashflag AND %1 == %1 pinouts := %01 ELSE pinouts := %00 Pst.Str(string(11, 13, "red flashes")) outa[longdist..medshortdist] := pinouts waitcnt(250*millisec + loopstart)I couldn't find a Ping handy, else I would have created a new version of this project using my objects.
I'll post it in a few minutes.
The I/O pins controlling the lights can now be on any I/O pins. They don't need to be next to each other as they were in the original program.
CON _xinfreq = 5_000_000 ' specify 5 MHz xtal _clkmode = xtal1 + PLL16X ' and set clock to 80 MHz MILLISECOND = 80_000 ' define one millisecond MICROSECOND = 80 ' define one microsecond PING_TRIGGER_TIME = 50 * MICROSECOND LOOP_INTERVAL = 250 * MILLISECOND ' I/O pin assignments PING_PIN = 7 RED_PIN = 0 ' Red LED lamp AMBER_PIN = 1 ' Amber LED lamp BAUD = 115200 CONVERT_TO_CM = 4936 CONVERT_TO_INCH = 12537 ACTIVE_CONVERSION = CONVERT_TO_INCH CON '' Distance Constants '' Change these constants to set ranges. TOO_CLOSE_THRESHOLD = 24 ' inches CLOSE_ENOUGH_THRESHOLD = 36 ' inches APROACHING_THRESHOLD = 48 ' inches OBJ Pst : "Parallax Serial Terminal" VAR long duration long loopstart long flashflag long distance ' distance to object, centimeters long pinouts ' pattern written to output pins PUB Main Pst.Start(BAUD) dira[RED_PIN] := 1 dira[AMBER_PIN] := 1 repeat Pst.Str(string(11, 13, "About to trigger Ping.")) loopstart := cnt ' begin timed loop !flashflag ' toggle flash status flag dira[PING_PIN] := 1 ' ping a short pulse outa[PING_PIN] := 1 waitcnt(PING_TRIGGER_TIME + cnt) dira[PING_PIN] := 0 ' switch to input to sense echo duration := -cnt ' begin duration measurement waitpne(0, |< PING_PIN, 0) ' Wait for pin to go high; this more accurate than the ina loop. duration += cnt ' echo delay in sys counts distance := duration / ACTIVE_CONVERSION ' distance in inches ( 6.17 msec/meter ) Pst.Str(string(11, 13, "distance = ")) Pst.Dec(distance) if distance < TOO_CLOSE_THRESHOLD ' red flashes !outa[RED_PIN] outa[AMBER_PIN] := 0 Pst.Str(string(11, 13, "Too close!")) Pst.Str(string(11, 13, "Less than ")) Pst.Dec(TOO_CLOSE_THRESHOLD) Pst.Str(@unitsName) elseif distance < CLOSE_ENOUGH_THRESHOLD outa[RED_PIN] := 1 outa[AMBER_PIN] := 0 Pst.Str(string(11, 13, "Good distance!")) Pst.Str(string(11, 13, "Less than ")) Pst.Dec(CLOSE_ENOUGH_THRESHOLD) Pst.Str(@unitsName) elseif distance < APROACHING_THRESHOLD outa[RED_PIN] := 0 outa[AMBER_PIN] := 1 Pst.Str(string(11, 13, "Getting close but not there yet.")) Pst.Str(string(11, 13, "Less than ")) Pst.Dec(APROACHING_THRESHOLD) Pst.Str(@unitsName) else outa[RED_PIN] := 0 outa[AMBER_PIN] := 0 Pst.Str(string(11, 13, "Too far away.")) Pst.Str(string(11, 13, "You are at least ")) Pst.Dec(APROACHING_THRESHOLD) Pst.Str(@unitsName) Pst.Str(string(" away.")) waitcnt(LOOP_INTERVAL + loopstart) DAT unitsName byte " in", 0 'unitsName byte " cm", 0I used inches as the unit of distance since you mentioned feet in an earlier post.
To change the thresholds of when the various lights will turn on and off you just need to edit these constants.
As the code is now, it has four distance zones. It wouldn't be hard to add a fifth zone had have the amber light blink as one of the zones.
I haven't tested this code. If it doesn't work as expected, let me know and I'll dig out a PING sensor and test it myself.
Does the distance display correctly?
Does it repeatedly output "Too close!"?
I figured there was a good chance I did something wrong but once in a while I get lucky with an untested program.
I'll wire up a sensor and try the program myself.
The code below works for me.
Make sure and change the distance values to fit your need.
CON _xinfreq = 5_000_000 ' specify 5 MHz xtal _clkmode = xtal1 + PLL16X ' and set clock to 80 MHz MILLISECOND = 80_000 ' define one millisecond MICROSECOND = 80 ' define one microsecond PING_TRIGGER_TIME = 50 * MICROSECOND LOOP_INTERVAL = 250 * MILLISECOND ' I/O pin assignments PING_PIN = 7 RED_PIN = 0 ' Red LED lamp AMBER_PIN = 1 ' Amber LED lamp BAUD = 115200 CONVERT_TO_CM = 4936 CONVERT_TO_INCH = 12537 ACTIVE_CONVERSION = CONVERT_TO_INCH CON '' Distance Constants '' Change these constants to set ranges. TOO_CLOSE_THRESHOLD = 24 ' inches CLOSE_ENOUGH_THRESHOLD = 36 ' inches APROACHING_THRESHOLD = 48 ' inches OBJ Pst : "Parallax Serial Terminal" VAR long duration long loopstart long distance ' distance to object, centimeters PUB Main Pst.Start(BAUD) dira[RED_PIN] := 1 dira[AMBER_PIN] := 1 repeat Pst.Str(string(11, 13, "About to trigger Ping.")) loopstart := cnt ' begin timed loop dira[PING_PIN] := 1 ' ping a short pulse outa[PING_PIN] := 1 waitcnt(PING_TRIGGER_TIME + cnt) dira[PING_PIN] := 0 ' switch to input to sense echo waitpne(0, |< PING_PIN, 0) ' Wait for pin to go high. duration := -cnt ' begin duration measurement waitpeq(0, |< PING_PIN, 0) ' Wait for pin to go low; this more accurate than the ina loop. duration += cnt ' echo delay in sys counts distance := duration / ACTIVE_CONVERSION ' distance in inches ( 6.17 msec/meter ) Pst.Str(string(11, 13, "distance = ")) Pst.Dec(distance) if distance < TOO_CLOSE_THRESHOLD ' red flashes !outa[RED_PIN] outa[AMBER_PIN] := 0 Pst.Str(string(11, 13, "Too close!")) Pst.Str(string(11, 13, "Less than ")) Pst.Dec(TOO_CLOSE_THRESHOLD) Pst.Str(@unitsName) elseif distance < CLOSE_ENOUGH_THRESHOLD outa[RED_PIN] := 1 outa[AMBER_PIN] := 0 Pst.Str(string(11, 13, "Good distance!")) Pst.Str(string(11, 13, "Less than ")) Pst.Dec(CLOSE_ENOUGH_THRESHOLD) Pst.Str(@unitsName) elseif distance < APROACHING_THRESHOLD outa[RED_PIN] := 0 outa[AMBER_PIN] := 1 Pst.Str(string(11, 13, "Getting close but not there yet.")) Pst.Str(string(11, 13, "Less than ")) Pst.Dec(APROACHING_THRESHOLD) Pst.Str(@unitsName) else outa[RED_PIN] := 0 outa[AMBER_PIN] := 0 Pst.Str(string(11, 13, "Too far away.")) Pst.Str(string(11, 13, "You are at least ")) Pst.Dec(APROACHING_THRESHOLD) Pst.Str(@unitsName) Pst.Str(string(" away.")) waitcnt(LOOP_INTERVAL + loopstart) DAT unitsName byte " in", 0 'unitsName byte " cm", 0Many of my programs run a generic background cog; I use this to keep a running timer and process specialty IO so that the foreground doesn't have to be bothered. In some of my Escape Room apps, I even have a monotonic music player that can play notes and simple musical runs while the foreground code happily does its thing.
If I were building this project I would monitor the Ping in a background cog so the foreground simple had a value to deal with. In this case, the value is distance to target in microseconds which is easily converted to cm or inches.
This also shows how to measure a pulse with a counter module so that you don't get trapped by waitpeq/waitpne if there is a sensor problem. The counter is put into POS Detect mode which counts the number of ticks the input line is high. Note that the Ping measurement is broken into discrete states so that it can be folded into the background process. At the moment, there is just the timer and the Ping, but you can do other things.
Here's the background code -- very typical of many of my projects.
var long bgcog long bgstack[32] long millis pri background | t millis := 0 pingstate := 0 ctra := %01000 << 26 | PING ' set ctra for pos detect frqa := 1 ' background loop t := cnt repeat waitcnt(t += MS_001) ++millis scan_ping var long pingstate long pingus pri scan_ping ' scan/measure every 100ms ' case pingstate 0 : outa[PING] := 1 ' ping output high dira[PING] := 1 waitcnt(cnt + constant(US_001 << 3)) ' wait 8+ us dira[PING] := 0 ' set to input phsa := 0 ' clear accumulator 19 : pingus := phsa / constant(US_001 << 1) ' distance to target in us 99 : pingstate := -1 ' reset ++pingstatewww.jonmcphalen.com