Rude Crude Serial Dude.. (Homebrew serial comms)
GICU812
Posts: 289
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
MAINIO
DO
IF Attn = 1· THEN
DO WHILE Attn= 1
HIGH Ack
LOOP
LOW Ack
COUNT Sdl, RecTime, Inner ' Serial output at Inner 1-25
DEBUG CR, "Input recieved", DEC Inner,CR
ENDIF
LOOP
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
LEDon(1);
LEDoff(3);
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) ;
}
·
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
MAINIO
DO
IF Attn = 1· THEN
DO WHILE Attn= 1
HIGH Ack
LOOP
LOW Ack
COUNT Sdl, RecTime, Inner ' Serial output at Inner 1-25
DEBUG CR, "Input recieved", DEC Inner,CR
ENDIF
LOOP
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
LEDon(1);
LEDoff(3);
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) ;
}
·
Comments
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.
Shiftin/shiftout are much harder to implement.
LLike I said, if you want to walkme through it, I'll use seriial commands.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- Stephen
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.
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.
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
Initialize:
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)
.end
Post Edited (GICU812) : 9/19/2008 7:47:20 AM GMT
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
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
····_Init232();
····if (_GetBaudRate() != BAUD9600)
··· {
········_SetBaudRate(BAUD9600);
··· }
····_SendString232((long)"\n\rType chars followed by ENTER: ");
····while (1)
····{
········cmd = _Wait232(); ······// Wait for a character
········if ( cmd == '\r' ) ········ ·// Is it ENTER?
············break;
········_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
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
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.
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
c:\Program Files\Mikroelektronika\RSC4X-mikroC\Examples\soft SPI\
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[noparse][[/noparse]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[noparse][[/noparse]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
do
{
/*
* prompt user to repeat the keyword
*/
_PlaySnd(SND_Repeat, (long)&SNDTBL_LEDLIGHTSHOW, SX_FULL_VOL) ;
confStruct.dc[noparse][[/noparse]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
break;
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
break;
default: // first record is not successful
err++ ; // increment error counter
retry = 0 ; // no other try
}
if(err) // if an error occured
{
confStruct.dc[noparse][[/noparse]slot] = 0 ; // clear keyword LED
confStruct.dc[noparse][[/noparse]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[noparse][[/noparse]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.