View Full Version : Rude Crude Serial Dude.. (Homebrew serial comms)

09-19-2008, 05:36 AM
I am trying to interface another micro controller(from here on MC)·to my stamp.·MC programmed in C, which I know little of, but im getting by with a lot of trial\error and reverse engineering other's source code. I dont even want to imagine serial. As for IO, best I can do is switch LED's on and off, and look for button inputs (low on).

But I want to be able to have this talk to my stamp (BS2p40) Here's what I've rigged together so far.

When it has information for the Stamp, the MC shifts a LED on (Attn High)

When the Stamp cycles around and see's this, it shifts a line high, which·fires a NPN transistor·pulling Button_One down (ACK low)
The Stamp holds this until it sees the Attn line go low

The MC drops Attn when it see's Ack, and waits until Ack stops

Then the MC pulses out·LED 3·on for 40ms, then off for 40 ms until it has pulsed out the number (Sdl) +_+_+_ = 3
The Stamp watches the Sdl and runs a COUNT, counting the number of pulses it see's

This works great, but is slow. I have to COUNT for a couple of seconds to be able to accomodate·up to 25

Without going into·RS232 (unless you want to babywalk me through C), does anyone have a better suggestion for interfacing these two devices? If I could come up with a way of clocking the comms, I could use low as 0 and go into binary, needing only 4 signals to relay 16 options. But then I wouldnt be able to use the count command.

Basic Stamp Code (would sit in the "main" routine)

Attn PIN 14
Sdl PIN 15
Ack PIN 13
Inner VAR Byte
RecTime CON 7000······ ' 7000 with 40ms signalling 10000 with 50ms

IF Attn = 1· THEN
DO WHILE Attn= 1
COUNT Sdl, RecTime, Inner ' Serial output at Inner 1-25
DEBUG CR, "Input recieved", DEC Inner,CR

C code
void serout(int command){
uchar·· btn ;······· //MakeShift serial protocol
int count = 0;······ // 1.1 goes high to signal Attn
int timeout = 3;··· // pull 0.1 low to start· --· data is sent on 0.3 in pulses
····················· // 50ms delay works, 40 should work 30\35 is too fast will not work
do{count++ ;
if((btn = BUTTON_PORT) != BUTTON_MASK)······ // if a button is pressed
······················· {LEDoff(1);
······················· while(BUTTON_PORT != BUTTON_MASK) ;···· // yes, wait for release
······················· switch(btn) {
························· case BUTTON_One :
····························· count= 0 ;
····························· do{count++;
································ LEDon(3);······························· //command number of times to relay the command number
································ _DelayMilliSecs(40) ;
································ LEDoff(3);
································ _DelayMilliSecs(40) ;
······························· }
······························· while (count < command) ;
······················· return;
······························· break;· }
······················· }
·_DelayMilliSecs(100);· } // wait 100 ms and try again
while (count < timeout) ; // Timeout if no response in 300 ms
_PlaySnd(0,0, SX_FULL_VOL) ;_PlaySnd(0,0, 32) ;_PlaySnd(0,0, 32) ;·· // indicates comm failure
LEDoff(1) ;


Mike Green
09-19-2008, 05:51 AM
You could use something like SPI where one line acts as a clock (from the Stamp) and the other acts as either a transmit or receive line. You can even use the SHIFTOUT / SHIFTIN statements to do the shifting out / in on the Stamp side. Read the chapters on these two statements in the Stamp Manual. From the other microcontroller's standpoint, to transmit to the Stamp, just check for the "clock" line to be a one. If so, set the "data" line to be an output with the low order bit value you want to send. When the "clock" line changes to a zero, shift the data value to the right by one bit and make the "data" line an input. Keep track of the number of bits sent. When 8 bits have been sent, get a new 8-bit data value to send.

This technique suffers from an inability of the Stamp to tell whether the two devices are in sync. The easiest way is for the Stamp to issue a "long" clock pulse as a leading 9th bit. If the microcontroller times the clock pulse and it's longer than a few milliseconds, the microcontroller resets its bit counter, fetches a fresh value. In either case, the microcontroller waits for the clock pulse to finish. The Stamp uses a PULSOUT statement to produce this long pulse, then a SHIFTIN to get the data from the microcontroller.

If you have a spare I/O pin on each processor (3 total), you can implement ordinary SPI where the 3rd line acts as a device enable and reinitializes the next byte transfer.

09-19-2008, 06:11 AM
Oh, please, almost EVERY C library has some serial input/output routines. Typically using SERIN/SEROUT on the BS2 side, and those serial routines on the C side.

Shiftin/shiftout are much harder to implement.

09-19-2008, 07:49 AM
And Im sure its a cinch to order a pizza in japan, but if you dont know the first word of Japaneese it makes it a little tricky.

LLike I said, if you want to walkme through it, I'll use seriial commands.

allanlane5 said...
Oh, please, almost EVERY C library has some serial input/output routines. Typically using SERIN/SEROUT on the BS2 side, and those serial routines on the C side.

Shiftin/shiftout are much harder to implement.

09-19-2008, 08:39 AM
It would help if we knew which MC and which c compiler we were talking about.

- Stephen

09-19-2008, 09:39 AM
VR-Stamp MC with Mikro-C compiler, running through Python-SE for compiling, and using FluentChip something or other something (The Mikro-C has next to no commands in the help file, but the FC has all the commands.)

Mike might be onto something.

If I change the handshake, and read both pins with the stamp, I could use binary, and have zeros. Then I would only need five characters to convey 32 values.

It would still be slow, but it wouldnt be so horrendous. 500 ms or so to send a command instead of 3 seconds.

Mike Green
09-19-2008, 10:15 AM
Obviously, you can do it any way you want to, but SPI is supported by all the Stamps and, since devices using it are common, it's supported by many other microcontrollers (as is asynchronous serial). SPI is also simple and fast.

09-19-2008, 01:51 PM
Well I tried the SPI, and I found the serial commands for it, neither of which I was able to get working.

The SPI, I have all the files needed (according to the example), but it still errors out on the functions.

The serial commands look pretty simple, but I cant get the include files to work, they cause one error, or a dozen others. I cant seem to find the commands in any of the files either to just pull them out.

09-19-2008, 02:42 PM
Well I have scrounged up the serial commands for this program. As usual, the commands are simple, but the examples dont come close to compiling and are full of bugs.

Right off the bat, the includes dont work, the ' ' I dont think are proper syntax, and I've never seen .include in any of the working source Ive read, its always #include. If I try that, it errors out telling me these are not C files.
I cant find a way to make the includes work, and obviously nothing else works without them. So yea, it would be simple to use serial commands if I could get them to work.

.include 'stddev.inc'
.include 'techmacs.inc'
.include 'techdefs.inc'
.PUBLIC Initialize
.rseg _EXAMPLE, code

UserRamDs ; define local RAM storage
addr .DSB 4
testInt .DSB 2
testChar .DSB 1
UserRamDsEnd ; end local RAM storage

movQ addr, #89abcdefH ; init variables
movW testInt, #258
mov testChar, #13

Init232 ; enable RS232 (NOTE: only needed
; if level converter used)
Crlf232 ; start new line
Send232D8 testChar ; 013
Send232D16 testInt ; 00258
Send232H4 testChar ; D
Send232H8 testChar ; 0D
Send232H16Val testInt ; 0102
movW ab, testInt ; NOTE: ab will work here
Send232H16Val ab ; 0102

; NOTE: The following macros take a pointer as the argument
; NOTE: .regaddr needed if argument points to a banked register

movW r0r1, testInt ; NOTE: ab won't work here
Send232H16 #r0r1 ; 0102
Send232H24 #.regaddr addr ; ABCDEF
Send232H32 #.regaddr addr ; 89ABCDEF

Idle232 ; disable RS232 (see NOTE above)

Post Edited (GICU812) : 9/19/2008 7:47:20 AM GMT

09-19-2008, 07:42 PM
"Mikro-C compiler"? Really? Because your syntax doesn't match the Mikro-C at all.

Here's an example (cleaned up a little) from the Mikro-C PDF manual.

// Page 322
#define u_short unsigned short
u_short mydata = 0;
u_short byteloc = 0;
u_short * readptr;

void main()
· readptr = &byteloc;
· *readptr = '1';··· // So first 'while' pass works

· // Init software UART (8 bits, 2400 baud, no parity, non-invert)
· //· PORTB, pin 1 RX-pin, pin 2 TX-pin

· Soft_Uart(PORTB, 1, 2, 2400, 0);

· while(1)
· {
··· while(*readptr)· // Implied -- "is not null"
··· {
····· mydata = Soft_Uart_Read(readptr);
····· if (*readptr)
····· {
······· Soft_Uart_Write(mydata);
····· }
··· }
· }

Post Edited (allanlane5) : 9/19/2008 12:47:29 PM GMT

09-19-2008, 07:46 PM
The problem with SPI is that one device MUST be the "master", while a second device MUST be a 'slave'. Most CPU libraries insist each CPU is the 'master' -- the BS2 will not be a slave SPI device.

09-19-2008, 07:59 PM
Okay, apparently your "Mikro-C" was completely mistaken, your source is from the "FluentChip" C environment sold with the VR-Stamp package and *PHYTON* IDE.

It's critically important with all this stuff to spell everything properly, otherwise you'll send the people trying to help you down a lot of blind alleys.

Their RS232 example is:
#include <techlib.h>
#include <techdefs.h>

void main(void)
· uchar cmd;
· ·// Enable RS232 (only needed if level converter used),
···// ensure baudrate is correct, then send text

····if (_GetBaudRate() != BAUD9600)
··· {
··· }

····_SendString232((long)"\n\rType chars followed by ENTER: ");

····while (1)
········cmd = _Wait232(); ······// Wait for a character
········if ( cmd == '\r' ) ········ ·// Is it ENTER?
········_Put232(cmd); ··········// Echo the character
· ·}
···_Crlf232(); ················// Echo Carriage Return/Line Feed
···_Idle232(); ················// Turn off RS232
···_SleepIO(0,0,0); ···········// Low power sleep


Post Edited (allanlane5) : 9/19/2008 1:04:18 PM GMT

09-19-2008, 10:24 PM
Look in the C:\Sensory\FC3_1_4\source\rs232 folder. The·rs232.mca file may help.

09-19-2008, 10:56 PM
allanlane5 said...
Okay, apparently your "Mikro-C" was completely mistaken, your source is from the "FluentChip" C environment sold with the VR-Stamp package and *PHYTON* IDE.

It's critically important with all this stuff to spell everything properly, otherwise you'll send the people trying to help you down a lot of blind alleys.

I dont know what to tell you, the program I use is Mikro C, as for the source, I copied and pasted it right from the fluentchip help file. I didnt know the Mikro-C had a manual, there isnt jack as far as commands in the help section, and frankly, that seems to be on par for them.

I guess Im just frustrated with it because not a single piece of example code has compiled without modification, and the error messages are so cryptic or generic, its almost impossible to figure out what it wants. I even tried a program written on the same compiler, with the same software, on the same hardware, and that didnt work. Sensory had changed the include files and I had to email the guy to get him to reconfigure some things just to get it working. All I need is working code and I can reverse engineer almost anything, but there isnt very much I have been able to get to compile. It seems like when I try to add an include to make a new command work, it kills the program.

I have been able to write almost everything I need just from tearing apart the code from that one sample program, and tweaking with the commands.

BTW, all my includes and libraries are from fluentchip as well.

I will try adding the mca file first, then I'll look at the code posted, and im going to go download the manual for Mikro-C

09-19-2008, 11:51 PM
Where did you find the "manual" with that example in it?

Great... I added the code to my main program, and I think im out of space. At least I remember reading somewhere that is what it means when it says "No free room in address space 'REG' for segment '?REG_CLIB'

I believe the Mikro compiler limits you to half the chips actual space unless you buy thier upgrade.

I'll have to see what I can do about this.

09-19-2008, 11:55 PM
My favorite package for this sort of thing is "BoostC". They have a lovely compiler AND simulator, they're not based in Serbia, and it's been around quite a few years. AND their IDE incorporates other tool-chains pretty easily.

www.sourceboost.com (http://www.sourceboost.com) -- in addition, their "standard" compiler is $70, for commercial use $150. This comes with a set of "plug-ins" for the simulator -- LED's, push-buttons, etc -- basically GUI elements to run your simulation against.

Post Edited (allanlane5) : 9/19/2008 5:03:44 PM GMT

09-20-2008, 06:13 AM
See the SPI example program:
c:\Program Files\Mikroelektronika\RSC4X-mikroC\Examples\soft SPI\

09-20-2008, 12:52 PM
Remember that part in the begining where I said unless you want to baby step me thorugh it...

Heres the deal., I keep getting ":No free room in addresss space 'REG' for segment '??CD_REENT' "

I think that means im out of storage space, or rather I have exceeded the storage space of the demo compiler.

Heres my confusion.

If I wipe out the entire section of code listed below, I can only put in 7 more characters in the "_SendString232((long)"\n\rppppppp");" command
is there something about this command that is using huge amounts of space? I thought serial output characters only took up one byte each.

Here is the code I have to remove. Before I remove it I can only have up to "n\r\" one more character and I run out of space. after I remove all this, I can only add 7 more characters before im out of space again...

void learnWord(char slot)
uchar retry = MAX_RETRY ; // number of retries before giving up
uchar lfMask ; // learn flag mask
uchar err = 0 ; // error counter

confStruct.dc[slot] = 7 ; // blink LED

lfMask = 1 << slot ; // shift slot number to get mask

* prompt user to speak
_PlaySnd(0,0, SX_FULL_VOL) ;

_PlaySnd(msgTbl[slot], (long)&SNDTBL_LEDLIGHTSHOW, SX_FULL_VOL) ;

// _PutTmpltListBase(firstTmplt) ; // define template start

switch(_MakeTmpltSd(SETUP_TIMEOUT, 2, 2)) // record keyword, first time
case ERR_OK: // record is sucessful
_PutTmplt(slot) ; // save pattern in #slot number
* prompt user to repeat the keyword

confStruct.dc[slot] = 11 ; // change LED blinking duty cycle

switch(_MakeTmpltSd(SETUP_TIMEOUT, 2, 2)) // record keyword again
case ERR_OK: // new record is successful
_GetTmplt(slot) ; // read the previous template into internal memory
_PutTmplt(slot) ; // put the new template to external memory,
// so that successive tries are made with last records

switch(_TrainSd(slot, SD_DEF_LEVEL, 12, &res)) // compare & average templates
case ERR_OK: // training is successful
_PutTmplt(slot) ; // store the averaged template to the set #slot
retry = 0 ; // no retry needed
err = 0 ; // no error
default: // training is not successful
err++ ; // increment error counter
retry-- ; // one try less
break ;

default: // record is not successful
retry = 0 ; // no other try
err++ ; // set error flag
while(retry) ; // loop if needed

default: // first record is not successful
err++ ; // increment error counter
retry = 0 ; // no other try

if(err) // if an error occured
confStruct.dc[slot] = 0 ; // clear keyword LED
confStruct.dc[STATUS_LED] = 0 ; // clear trained status LED
_PlaySnd(SND_Failed, (long)&SNDTBL_LEDLIGHTSHOW, SX_FULL_VOL) ; // play the sound "try again"
else // learning is successful
{ //success
confStruct.dc[slot] = 255 ; // light keyword LED

_PlaySnd(SND_Accepted,(long)&SNDTBL_LEDLIGHTSHOW,64); // play the sound "thank you"


writeConfig(0) ; // save to EEPROM

Is that really only 7 bytes of storage, or am I missing something here.