Bit banging code for serial communication
Hi,
I have a device that I need to control with a BS2p40 via RS-232. The device requires 8 data bits and even parity, which are not supported by SERIN/SEROUT from the BS. Does anyone have bit banging code for serial communication I could use (in whole or at least as a starting point)?
The device settings are:
Baud 19200
1 start bit
8 data bits
1 even parity
1 stop bit
Any help would be greatly appreciated!!!
Thanks,
Alan
I have a device that I need to control with a BS2p40 via RS-232. The device requires 8 data bits and even parity, which are not supported by SERIN/SEROUT from the BS. Does anyone have bit banging code for serial communication I could use (in whole or at least as a starting point)?
The device settings are:
Baud 19200
1 start bit
8 data bits
1 even parity
1 stop bit
Any help would be greatly appreciated!!!
Thanks,
Alan

Comments
Thanks,
Alan
I hope you also ordered the necessary baud rate crystal!
There is a configuration word that sets various options. Once that is done, you can transmit data words, and the 9 lsbs contain your data. Note that the MAX3100 does not calculate parity. It expects your code to do that and to stuff it into the 9th bit.
evenparity = x.bit7 ^ x.bit6 ^ x.bit5 ^ x.bit4 ^ x.bit3 ^ x.bit2 ^ x.bit1 ^ x.bit0
There may be a trick fast way to do that, but I have forgotten. Ask if you have specific questions. Monday, huh?!
Thanks!
The MAX3100 on the other hand includes neither the charge pump nor the inverting driver/receiver, so you would have to add those in the form of a MAX232 or some such.
The crystal required is either 1.8432MHz or 3.6864MHz and it takes two 18pF or 20pF capacitors (either one will do). Or a resonator such as this one, which incorporates the capacitors.
One more question- if I know that the max data received will be 9 bytes, would I need to worry about the 8 byte buffer for received data not being enough? I wouldn't think so, but thought I'd ask anyways...
' MAX3110E Driver for Basic Stamp ' RS 232 Port settings 19.2k baudrate, 1 start, 1 stop, 8 data bits, even parity din CON 11 dout CON 10 clk CON 9 cs CON 8 datasend VAR Byte(13) ' 13 bytes of data to send datarec VAR Byte(8) ' 8 bytes of data to receive char VAR Word ' will combine 8-bit command/status and 8-bit data rts VAR char.BYTE1.BIT1 ' for data send cts VAR char.BYTE1.BIT1 ' for data read Pt VAR Bit ' even parity bit tst VAR Bit i VAR Byte AUXIO ' uses X i/o pins ' write to configuration register, 19.2k baudrate, 8 bits, parity enabled (1100 0000 0010 0000) writemode: LOW cs SHIFTOUT din, sclk, MSBFIRST,[$C020\16] HIGH cs ' transmit datasend senddata: FOR i = 0 TO 12 ' send all 13 bytes senddata1: char.BYTE0 = datasend(i) Pt = char.BYTE0.BIT7 ^ char.BYTE0.BIT6 ^ char.BYTE0.BIT5 ^ char.BYTE0.BIT4 ^ char.BYTE0.BIT3 ^ char.BYTE0.BIT2 ^ char.BYTE0.BIT1 ^ char.BYTE0.BIT0 ' calculate parity bit char.BYTE1 = $80 + Pt ' make rts high, adds parity bit senddata2: LOW cs PULSOUT sclk,4 ' get one bit tst = dout ' test that transmit buffer is empty HIGH cs IF tst = 1 THEN senddata2: ' loop back until ready LOW cs SHIFTOUT din, sclk, MSBFIRST,[char\16] HIGH cs i = i + 1 NEXT senddataend: LOW cs 'turn off rts pin SHIFTOUT din, sclk, MSBFIRST,[$8600\16] ' Is this right? Is this necessary? HIGH cs GOTO recdata '********************* ' now enter a loop to receive data, 8 bytes stored in datarec recdata: FOR i = 0 TO 7 LOW din LOW cs ' sequence to receive data, both 8-bit status and 8-bit data SHIFTIN dout, sclk, MSBPRE,[char\16] HIGH cs datarec(i) = char.BYTE0 NEXT MAINIO RETURN-Phil
-- For 19.2kbaud using a 3.6864MHz crystal, I think you want "A" for the baud rate choice:
SHIFTOUT din, sclk, MSBFIRST,[$C02A\16]
To make RTS high=stop I think the mask should be $20
char.BYTE1 = $20 + Pt ' make rts high=stop, adds parity bit
The code to turn RTS low= start, without transmitting data, should be $8400.
SHIFTOUT din, sclk, MSBFIRST,[$8400\16]
As to the question of whether RTS needs to be used to hold off a response from the peripheral until the transmission from the Stamp is finished, that depends on the peripheral. It is a non-issue if the peripheral has to receive the entire 13-byte command from the Stamp before it sends back its response. But if the peripheral starts sending back immediately, you will have to make allowances for that. You will notice that Al William's code bit-bangs the shiftin/shiftout, in order to allow transmission and reception at the same time, and Al explained his rationale for doing it that way. It depends on how the peripheral works, and there are workarounds too that still use the Stamp's SHIFTxxx commands.
- I forgot to specify that I'm using a 1.8432MHz crystal; is $C020 good?
- Regarding RTS (getting ready to send data), I was following your "fox" example, but I didn't copy over your entire comment "rts is bit 1, pin is made high when bit is low". This is preparing to send data. You also have "char.byte1=$80". Is that right?
sendfox:
char.byte1=$80 ' make rts high, red led on
' rts is bit 1, pin is made high when bit is low.
- I think I need to do the opposite for ending the transmission; I used your same values for turning off RTS (below). Is that right?
sendfoxend:
low cs ' now turn off RTS pin
' the TE\ bit=1, so no data is transmitted.
shiftout din,sclk,msbfirst,[$8600\16]
high cs
- I did notice how Al Williams allowed to receive while transmitting; my peripheral "shouldn't" respond until my last (13th) byte is transmitted. Then, it will respond with 8 bytes of it's own in one case, and in another case it will respond with 9 bytes (I will know when). Since the buffer for the MAX3110 is only 8 bytes, will that be a problem if the response is 9 bytes?
I forgot that the RTS bit is inverted at the RTS\ pin on the chip and will be inverted again when you jumper the RTS\ pin over to the T2in pin that then produces the RS232 output levels. See "Figure 13. RS-232 Typical Operating Circuit". So in that case, the RTS bit controls flow in the standard manner of logical high=start and low=stop.
The response of 9 bytes should not be a problem 1) if you can read out at least one byte before the peripheral sends the 9th, or 2) RTS can control the flow from the peripheral.
writemode: LOW cs SHIFTOUT din, sclk, MSBFIRST,[$C029\16] ' write to config register, 19.2k baudrate, 8 bits, parity enabled (1100 0000 0010 0000) HIGH cs HIGH 14 'turn on LED at X14 ' transmit datasend senddata: ' MAINIO ' LCD uses Mainio ' SEROUT PIN_LCDTX,BAUDMODE_LCD,[CLEAR,POSITION,68,"Sending",POSITION,81,"message"] ' PAUSE DISPLAY_DELAY ' AUXIO ' Com uses X i/o pins FOR i = 0 TO (sendbytes - 1) ' send # bytes according to type of command senddata1: char.BYTE0 = dataio(i) Pt = char.BYTE0.BIT7 ^ char.BYTE0.BIT6 ^ char.BYTE0.BIT5 ^ char.BYTE0.BIT4 ^ char.BYTE0.BIT3 ^ char.BYTE0.BIT2 ^ char.BYTE0.BIT1 ^ char.BYTE0.BIT0 ' calculate parity bit char.BYTE1 = $82 + Pt ' make rts high, adds parity bit DEBUG "Send byte ", DEC i, " " DEBUG HEX2 ? dataio(i) senddata2: LOW cs PULSOUT sclk,4 ' get one bit tst = dout ' test that transmit buffer is empty HIGH cs IF tst = 1 THEN senddata2: ' loop back until ready LOW cs SHIFTOUT din, sclk, MSBFIRST,[char\16] HIGH cs NEXT senddataend: LOW cs 'turn off rts pin SHIFTOUT din, sclk, MSBFIRST,[$8400\16] ' Set RTS low for inactive HIGH cs GOTO recdata '********************* ' now enter a loop to receive data, X bytes stored in datarec recdata: MAINIO ' LCD uses Mainio SEROUT PIN_LCDTX,BAUDMODE_LCD,[CLEAR,POSITION,68,"Receive",POSITION,81,"message"] PAUSE DISPLAY_DELAY AUXIO ' Com uses X i/o pins FOR i = 0 TO (sendbytes - 1) ' clear all send dataio bytes dataio(i) = 0 NEXT FOR i = 0 TO (recbytes - 1) LOW din LOW cs ' sequence to receive data, both 8-bit status and 8-bit data SHIFTIN dout, sclk, MSBPRE,[char\16] HIGH cs dataio(i) = char.BYTE0 DEBUG "Receive byte ", DEC i, " " DEBUG HEX2 ? dataio(i) NEXT LOW 14 'LED test light MAINIO RETURNMy code using SHIFT should also work, judging from what you have said about the command/response protocol of the device.
I am using SHIFT, as you recommended (I'm only using the hardware setup with MAX3110 from Al Williams' example, not the code).
With a multimeter, you should find that the output voltage from RS232 tx pin on the chip is -5V or thereabouts. And if you have the Stamp stream out ascii nulls as fast as possible, you should see that voltage flickering upward. The Stamp should be able to control the RTS output. These are just things to see if the chip is hooked up correctly. One common mistake with SHIFT commands is to have the Dout and Din lines reversed.
A device like the Saleae logic analyzer that Parallax sells can be almost more even more valuable than a cheap 'scope for this kind of situation, because it can decode the data that you can also see displayed on the computer screen.
Check pin 9 (X2) with a voltmeter to be sure the cystal is oscillating, it should be about 2.5V DC average. About the layout, this from the data sheet...
Note: It is very important to keep crystal, resonator, and
load-capacitor leads and traces as short and direct as
possible. Make the X1 and X2 trace lengths and ground
tracks short, with no intervening traces.
BTW, any idea of how I change this thread to "solved"?
' RS-232 COMMUNICATION dataio VAR Byte(13) ' NEEDS TO BE 13!!! used for sending and receiving char VAR Word ' will combine 8-bit command/status and 8-bit data rts VAR char.BYTE1.BIT1 ' for data send cts VAR char.BYTE1.BIT1 ' for data read Pt VAR Bit ' even parity bit tst VAR Bit comtype VAR Nib sendbytes VAR Nib recbytes VAR Nib i VAR Nib Initialize: OUTPUT 11111001000000 'Set direction status for outputs and unused pins '7,8,9,10,11,12,13,15 AUXIO 'Set direction for auxilliary pins as outputs except 10, dout OUTPUT 11101111111111 MAINIO 'Switch back to main I/O '--------------------------------------------------- 'Read Command Position Counter '--------------------------------------------------- ' Values for Command Position Read (always the same) ReadPositionSub: dataio(0) = $01 ' unit number dataio(1) = $03 ' Read command function code dataio(2) = $00 ' index address dataio(3) = $10 ' index address dataio(4) = $00 ' # regusters dataio(5) = $02 ' # registers (2) dataio(6) = $C5 ' CRC low dataio(7) = $CE ' CRC high comtype = poscom ' set communication type as read position GOSUB Communicate '--------------------------------------------------- 'RS-232 Communication with P70360 '--------------------------------------------------- Communicate: AUXIO ' uses X i/o pins IF comtype = poscom THEN GOTO ReadPosition ELSEIF comtype = movecom THEN GOTO MoveProfile ELSE GOTO StoreMove ENDIF ReadPosition: sendbytes = possendbytes recbytes = posrecbytes GOTO writemode MoveProfile: sendbytes = movesendbytes recbytes = moverecbytes GOTO writemode StoreMove: sendbytes = storesendbytes recbytes = storerecbytes writemode: LOW cs SHIFTOUT din, sclk, MSBFIRST,[$C029\16] ' write to config register, 19.2k baudrate, 8 bits, parity enabled (1100 0000 0010 1001) HIGH cs ' transmit datasend senddata: FOR i = 0 TO (sendbytes - 1) ' send # bytes according to type of command senddata1: char.BYTE0 = dataio(i) Pt = char.BYTE0.BIT7 ^ char.BYTE0.BIT6 ^ char.BYTE0.BIT5 ^ char.BYTE0.BIT4 ^ char.BYTE0.BIT3 ^ char.BYTE0.BIT2 ^ char.BYTE0.BIT1 ^ char.BYTE0.BIT0 ' calculate parity bit char.BYTE1 = $82 + Pt ' make rts high, adds parity bit ' DEBUG "Send byte ", DEC i, " " ' DEBUG HEX2 ? dataio(i) senddata2: LOW cs PULSOUT sclk,4 ' get one bit tst = dout ' test that transmit buffer is empty HIGH cs IF tst = 1 THEN senddata2: ' loop back until ready LOW cs SHIFTOUT din, sclk, MSBFIRST,[char\16] HIGH cs HIGH 0 ' test only- trigger after SHIFT complete NEXT senddataend: LOW cs 'turn off rts pin SHIFTOUT din, sclk, MSBFIRST,[$8400\16] ' Set RTS low for inactive HIGH cs GOTO recdata '********************* ' now enter a loop to receive data, X bytes stored in datarec recdata: FOR i = 0 TO (sendbytes - 1) ' clear all send dataio bytes dataio(i) = 0 NEXT FOR i = 0 TO (recbytes - 1) 'CHANGE TO recbytes!!! LOW din LOW cs ' sequence to receive data, both 8-bit status and 8-bit data SHIFTIN dout, sclk, MSBPRE,[char\16] HIGH cs dataio(i) = char.BYTE0 ' DEBUG "Receive byte ", DEC i, " " ' DEBUG HEX2 ? dataio(i) NEXT MAINIO RETURNThere should be a little dropdown box at the top of your message composition screen that lets you change the un/solved status.