Log in

View Full Version : Can't reliably transfer over serial connection between two PICs



CuriousOne
- 28th September 2025, 15:04
Hello.
Having a strange issue.

PIC18F45K80 and PIC16F1936.

they are connected to each other via 22K resistor. PORTC.3 on both.

Trying to run the simple code:

TX: (1936)



barka:
serout2 portc.3,84,[345]
pause 100
goto barka


RX (45K80)



taka:
serin2 portc.3,84,[x]
if x=345 then stop
lcdout $fe, $c0, "X=", dec x, " "
goto taka


It does not work, it never receives "345". received value is always random, but quite often it is 89.
Variable types are proper, port configs also.
I tried to change direction and send from 18F to 16F - same issue.
Checked signals with scope - no issues.
Tried to various resistors - 1K, 10K, 22K - no difference.

Yes I know that hardware port should be used, but PCB is already made.
Distance from one chip to another is about 10 centimeters and they're both on the same PCB and same power supply. I've checked signals with scope and there are no issues, like low levels or noise.

I tried to make code more complicated, like sending 8 characters + control character (enter) -this improves it a bit, might say that at least one try from 10 delivers proper result. Sometimes, it starts to work fine, but then again messes up. Also tried reducing port speed to 1200bps - no change.


Any ideas?

Ioannis
- 28th September 2025, 22:13
1. How can you be sure that the receiving PIC will start "listening" just before the sending PIC? Better use a start character on the sender and use this character as a WAIT one on the receiving PIC to synchronize both.

2. How is variable x defined? BYTE or WORD? 345 is more than a BYTE can store. 345 in Binary is 101011001. So if x is byte, it will randomly store 01011001 which happens to be, guess what?
Exactly 89...!!!

Ioannis

CuriousOne
- 29th September 2025, 05:30
Yes, X is word type, and it sometimes get values over 8 bits, but never 345.
I tried sending lower numbers, like 4 or 16 or whatever - they also got distorted.

I also tried like this:

arraywrite textline, ["ABCD1234"]serout2 portc.3,84,[STR textline\8,13]

Sometimes whole string is delivered fine, sometimes it is all garbled.

As I understand, you suggest to use WAIT/WAITSTR statements?

Meanwhile, by help of AI, this crude bit-banging "protocol" was developed. By hand tuning PAUSEUS values, it works, but I'd prefer "factory" solution if possible.

Sender:


Main:
FOR TxValue = 0 TO 254
GOSUB SendNumber
PAUSE 300 ' Wait before sending next number
NEXT
GOTO Main


' --- Subroutine: SendNumber ---
SendNumber:
' Start bit (LOW pulse)
LOW DataPin
PAUSEUS 500
HIGH DataPin
PAUSEUS 500


' Send 4 bits (LSB first)
FOR BitMask = 0 TO 7
IF (TxValue >> BitMask) & 1 THEN
HIGH DataPin
ELSE
LOW DataPin
ENDIF
PAUSEUS 500
HIGH DataPin ' Return line HIGH between bits
PAUSEUS 500
NEXT
RETURN


Receiver



Mainx:
' --- Wait for start bit: must see line LOW ---
WaitForStart:
IF DataPin = 1 THEN WaitForStart ' Keep waiting while idle is HIGH
PAUSEUS 490 ' Wait a bit into LOW
IF DataPin = 0 THEN ' Still LOW? good start
GOSUB ReadBits
ENDIF
GOTO Mainx


' --- Subroutine: ReadBits ---
ReadBits:
' Wait until line goes back HIGH before first bit
DO
LOOP UNTIL DataPin = 1
PAUSEUS 1000 ' Move to middle of first bit period


RxValue = 0
FOR BitMask = 0 TO 6
IF DataPin = 1 THEN
RxValue = RxValue | (1 << BitMask)
ENDIF
PAUSEUS 1020 ' Move to middle of next bit slot
NEXT


' --- Ensure line is HIGH again before next frame ---
DO
LOOP UNTIL DataPin = 1


' --- Display received value on LCD ---
LCDOUT $FE,1 ' Clear display
LCDOUT "Received: ", DEC RxValue


RETURN

CuriousOne
- 29th September 2025, 05:57
I just tried this code, and it does not work:


TX:



Main:
FOR TxValue = 0 TO 255

SEROUT2 DataPin, 84, [100,5,200, TxValue]
PAUSE 500
NEXT
GOTO Main


RX:



LCDOUT $FE,1
LCDOUT "Waiting data..."






RxValue VAR BYTE


Mainx:


SERIN2 RxPin, 84, [WAIT (100,5,200), RxValue]


LCDOUT $FE, $C0, "Rx=", dec RXvalue, " "


GOTO Mainx

CuriousOne
- 29th September 2025, 06:07
if I reduce control values to 1 or two, then it works, but totally wrong data is being decoded.

Ioannis
- 29th September 2025, 21:41
How about this code:



x vart word
x=345
barka:
serout2 portc.3,84,["s",x]
pause 100
goto barka


RX (45K80)



x var word
taka:
serin2 portc.3,84,[wait("s"), x]
if x=345 then lcdout $fe, $c0, "X=", dec x, " "
goto taka


Ioannis

Jerson
- 30th September 2025, 03:07
Why 22k? It seems pretty high to have. Your post suggests you've tried a lower value like 1K; if both PICs are running at the same voltage levels, then altogether do away with the resistor. Due to the resistor, it is possible the logic low level is not being met. If you fix this and still get the problem, then continue below.

I suspect the problem could be the software serial not getting the start bit reliably.

What you can do - since you use the 1936 is to configure the receive pin as interrupt on change pin; I believe all pins have IOC ability on this chip.

When you get the IOC interrupt, invoke the serin2 command in the ISR

I cannot advise with code as I am not up-to-date with PicBasic since some time now.

CuriousOne
- 30th September 2025, 05:51
Both 1K and 22K are actually suggested in PBP manual.
So I tried both, I tried 100 ohm resistor, I tried direct connection. No practical difference - actual "junk" bytes are getting different, but proper one still not delivered. The above slow code, suggested by AI, works with either 100 ohm, 1K or 22K.

Currently I'm sending data from 1936 to K80 because K80 has LCD screen so I can use it for debugging. In the real life, K80 will be sending data to 1936.

As a side "improvement", I can use additional data line from K80 to 1836, so SHIFTOUT/SHIFTIN should work then. I guess it will be more reliable?

Ioannis
- 30th September 2025, 07:09
The 22K is used ONLY when you are driving the INPUT of the PIC from a real RS232 line, which does -12 to +12 Volts on the pulses!

No need to have it on TTL connection as in your case. Remove it.

The 1K is used ONLY when you drive from the OUTPUT of the PIC to the RS232 line, to lower the current that PIC is forced to supply.

Again no need to have it on TTL connection as in your case. Remove it.

Have you tested the code on #6 with no resistors?

Ioannis

richard
- 30th September 2025, 07:23
Have you tested the code on #6 with no resistors?

works ok in simulator, apart from initial sync issue due to the comms line not beginning at a proper tty level before reception enabled

and then again i used complete programs not snippets full of guess work


@Ioannis you missed the spam in faq section

CuriousOne
- 30th September 2025, 12:45
I haven't tried that code yet, will try it today later.

Regarding "other" code, there is none, except config and variable assignments.

Here's complete code for 16F1936 before I launch that part of code:



;----[16F1937 Hardware Configuration]-------------------------------------------
#IF __PROCESSOR__ = "16F1936"
#DEFINE MCU_FOUND 1
#CONFIG
cfg1 = _FOSC_INTOSC ; INTOSC oscillator: I/O function on CLKIN pin
cfg1&= _WDTE_OFF ; WDT disabled
cfg1&= _PWRTE_OFF ; PWRT disabled
cfg1&= _MCLRE_OFF ; MCLR/VPP pin function is digital input
cfg1&= _CP_ON ; Program memory code protection is enabled
cfg1&= _CPD_OFF ; Data memory code protection is disabled
cfg1&= _BOREN_OFF ; Brown-out Reset disabled
cfg1&= _CLKOUTEN_OFF ; CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
cfg1&= _IESO_ON ; Internal/External Switchover mode is enabled
cfg1&= _FCMEN_ON ; Fail-Safe Clock Monitor is enabled
__CONFIG _CONFIG1, cfg1


cfg2 = _WRT_OFF ; Write protection off
cfg2&= _VCAPEN_OFF ; All VCAP pin functionality is disabled
cfg2&= _PLLEN_OFF ; 4x PLL disabled
cfg2&= _STVREN_ON ; Stack Overflow or Underflow will cause a Reset
cfg2&= _BORV_19 ; Brown-out Reset Voltage (Vbor), low trip point selected.
cfg2&= _LVP_OFF ; High-voltage on MCLR/VPP must be used for programming
__CONFIG _CONFIG2, cfg2


#ENDCONFIG


#ENDIF


;----[Verify Configs have been specified for Selected Processor]----------------
; Note: Only include this routine once, after all #CONFIG blocks
#IFNDEF MCU_FOUND
#ERROR "No CONFIGs found for [" + __PROCESSOR__ +"]"
#ENDIF


'nixie led clock electronics direct drive





ADCON1=%11110011 'enable adc internal reference and justify
FVRCON=%11001111 'set internal reference to 4.096V
OSCCON=%11110000 'SET INTOSC TO 8MHZ
'ANSELE=%00000000 'enable adc input porte.2
ANSELA=%00000000 'disable ADC on A
ANSELB=%00000000 'disable ADC on B
'ANSELD=%00000000 'disable ADC on D
TRISC=%00000000 'set PORTC as output all
'TRISD=%00000000 'set PORTD as output all
TRISB=%00000000 'set PORTB as output all
TRISA=%00000000 'set PORTA 2 as input, others as output
TRISE=%00000000 'set PORTE as output all
WPUB=%00000000 'DISABLE B PULL UPS
OPTION_REG=%100000000
LCDCON=%00000000 'disable LCD controller pins
LCDSE0=%00000000
LCDSE1=%00000000
'LCDSE2=%00000000


DEFINE OSC 32 'set oscillator speed




;____[ For 12F/16F only - Interrupt Context save locations]_________________
wsave var byte $20 SYSTEM ' location for W if in bank0
'wsave var byte $70 SYSTEM ' Alternate save location for W
' if using $70, comment out wsave1-3
' --- IF any of these next three lines cause an error ?? -------------------
' Comment them out to fix the problem ----
' -- The chip being used determines which variables are needed -------------
wsave1 VAR BYTE $A0 SYSTEM ' location for W if in bank1
wsave2 VAR BYTE $120 SYSTEM ' location for W if in bank2
wsave3 VAR BYTE $1A0 SYSTEM ' location for W if in bank3
'---DO NOT change these-----------------------------------------------------
ssave VAR BYTE BANK0 SYSTEM ' location for STATUS register
psave VAR BYTE BANK0 SYSTEM ' location for PCLATH register


;----[ MIBAM Setup ]--------------------------------------------------------
BAM_COUNT CON 13 ; How many BAM Pins are used?
INCLUDE "MIBAM.pbp" ; Mirror Image BAM module




dta var porta.6 'LED PINS
clk var porta.7
FET var portc.2 'current control fet pin


VALUE VAR BYTE 'DIGIT DECODER VALUE VARIABLE
LOLD VAR BYTE 'OLD LEFT VALUE FOR DECODER
ROLD VAR BYTE 'OLD RIGHT VALUE FOR DECODER
'LED COLOR VALUES 'LEFT AND RIGHT
LR VAR BYTE
LG VAR BYTE
LB VAR BYTE
LX VAR BYTE 'LEFT BRIGHTNESS
PACKED VAR BYTE 'LED PACKER
'
RR VAR BYTE
RG VAR BYTE
RB VAR BYTE
RX VAR BYTE 'RIGHT BRIGHTNESS
new var byte 'current display value
old var byte 'old display value
maxbr var byte 'brightness holder
CURBR VAR BYTE 'CURRENT RELATIVE BRIGHTNESS HOLDER
ANIT var byte 'animation type digits
DOTA var byte 'dot animation type
x var word ' main small counter
y var word 'additional var
BR1 var byte 'brightness comparator 1
BR2 var byte '2
DCMODE var byte '6 or 10 digit mode selector






tmp var byte 'temporal var for counting
TEXTLINE VAR BYTE[8] 'MAIN ARRAY FOR TEXT STORAGE


'DIGIT PINS
D0 VAR BYTE
D1 VAR BYTE
D2 VAR BYTE
D3 VAR BYTE
D4 VAR BYTE
D5 VAR BYTE
D6 VAR BYTE
D7 VAR BYTE
D8 VAR BYTE
D9 VAR BYTE
DF VAR BYTE 'TEMPERATURE SIGN
DT1 VAR BYTE 'DOTS
DT2 VAR BYTE


eval var byte 'eeprom reader
ELOC VAR BYTE 'EEPROM LOCATION


ASM
BAM_LIST macro ; Define PIN's to use for BAM


BAM_PIN (PORTB,3, D0)
BAM_PIN (PORTA,0, D1)
BAM_PIN (PORTB,4, D2)
BAM_PIN (PORTC,4, D3)
BAM_PIN (PORTB,5, D4)
BAM_PIN (PORTC,7, D5)
BAM_PIN (PORTB,2, D6)
BAM_PIN (PORTC,5, D7)
BAM_PIN (PORTB,1, D8)
BAM_PIN (PORTB,0, D9)
BAM_PIN (PORTC,6, DF)
BAM_PIN (PORTA,3, DT1)
BAM_PIN (PORTA,2, DT2)

endm
BAM_INIT BAM_LIST ; Initialize the Pins
ENDASM

richard
- 30th September 2025, 13:05
And there is the answer, software timed serial reception and transmission will be mangled by the mibam interrupt
Proof yet again of the total worthlessness of snippets

CuriousOne
- 30th September 2025, 13:17
Don't think so.

Generated serial data is perfect (checked with scope), and my scope, in logic analyzer mode, easily and properly decodes data sent by 1936. Also, I've generated couple of PAUSE and PAUSEUS statements and they all seem to be working fine in terms of timing.

Ioannis
- 30th September 2025, 13:30
I am pretty sure that Richard is absolutely correct about MiBAM interrupts. Since they run all the time, surely will mess with other tasks. Maybe your scope did not trigger on the proper time.

@Richard. Did not quite follow thre FAQ thing...

Ioannis

richard
- 30th September 2025, 13:35
In FAQ the latest post "how to use code tags" is spam, cannot link it using phone as browser

CuriousOne
- 30th September 2025, 13:56
So since I can't get rid of MIBAM (it is essential) this means that I have to use that software protocol provided by AI?

tumbleweed
- 30th September 2025, 23:35
In general, ANY bit-banged protocol that's generated in software, whether it's SHIFTIN/SHIFTOUT/SERIN/SEROUT is going to be unreliable when used with interrupts running. That's one reason hardware peripherals exist.

A software-based receiver is notoriously unreliable even without interrupts since there's no buffering at all.

You can get simple examples and tests to work, but they'll be extremely fragile.

CuriousOne
- 1st October 2025, 04:52
Well, my use case is quite different.
The receiver (1936) which runs MIBAM, does nothing besides BAMing and checking serial input, if anything is delivered.
"Anything" is delivered in form of single byte, once per second, minute or hour.

I'll try to verify the code without MIBAM and see whenever it causes the issues.

And if I switch to hardware serial input, will it still work with MIBAM?

richard
- 1st October 2025, 06:04
Well, my use case is quite different.


Well, my use case is ̶q̶u̶i̶t̶e̶ ̶d̶i̶f̶f̶e̶r̶e̶n̶t̶.̶ exactly that. ie. bit-banged protocol that has its timing generated in software and is going to be unreliable when used with interrupts running

Ioannis
- 1st October 2025, 13:06
And if I switch to hardware serial input, will it still work with MIBAM?

Yes it will work because it has a two byte buffer and does not rely on software to catch that incoming byte.

@ Richard: I got it. Hope it is OK now. The spammer hit the road. I don't know why this was missed from all of thw mods...

Ioannis

CuriousOne
- 1st October 2025, 14:19
So I have 6 slave 1936 and 1 master K80.
Now they are all connected via independent pins to K80, where serial transfer goes now
And there is also one common pin, which connects them altogether (not used right now)
So my idea is, to use that common pin as serial data pin, and use these independent pins as enable input for that particular MCU ?

Ioannis
- 1st October 2025, 16:41
Or use the open output feature and tie all together on one pin.

Ioannis

CuriousOne
- 2nd October 2025, 19:36
Sorry I had a little time to check all suggestions, but if there's a timing issue, I have series of 16 APA102C leds connected to the same 1936, they are driven via SHIFTOUT and everything works properly. So if MIBAM is messing with SERIN2, it should mess with SHIFTOUT as well?

amgen
- 2nd October 2025, 21:17
just curious.... CuriousOne.......
how are you looping program ???
For timing critical and ser-in's, interrupts are best for not missing incoming stuff.
So how did you set up your receiver routines?