Simple Chat Between 2 PCs Over RS232 Serial Port

by sergei_iliev in Circuits > Microcontrollers

665 Views, 0 Favorites, 0 Comments

Simple Chat Between 2 PCs Over RS232 Serial Port

logo.png
logo.jpg

This tutorial will show you how to build a simple chat between 2 PC s using Arduino Mega 2560 Pro . It has 4 UART channels so we are going to utilize 2 of them to connect 2 PCs that run a simple Chat program with basic input/output interface. Firmware is build around Acorn micro-kernel.

Parts

rs232chat.png
  1. DB9 Serial RS232 Cables
  2. MAX3232 RS232 to TTL Serial Port Converter Module DB9 Connector
  3. Arduino Mega2560 Pro
  4. Two computers running Windows OS
  5. Acorn micro-kernel project documentation

Preparations

null_modem_wire.png
null_modem.png

DB2 cable wires need to be changed in order to have a correct transmission of data. Cable need to be converted to a Null Modem cable. This is accomplished by changing the RxD pin wire with TxD pin wire at one end of the cable as it shown in the picture.

The rest of the DB9 control wires are not needed so they can be discarded.

Firmware

Arduino Mega 2560 runs 4 tasks concurrently within Acorn micro kernel observing the Producer - Consumer design pattern.

Task #1 character producer for channel 1
Incoming bytes from Rx1 Interrupt handler RS232 channel 1(first PC) are fed into a circular queue-like buffer dedicated to channel 1.

rs232_ch1_task_producer:		 
rcall rs232_ch1_init
_THRESHOLD_BARRIER_WAIT InitTasksBarrier,TASKS_NUMBER

_INTERRUPT_DISPATCHER_INIT temp,RX1_INT_ID
;input
ldi ZL,low(buffer_input_one)
ldi ZH,high(buffer_input_one)

rcall queue8_init

rs232mainInt:
ldi ZL,low(buffer_input_one)
ldi ZH,high(buffer_input_one)

ldi axl,QUEUE_CLIENT_ONE_MAX_SIZE

_INTERRUPT_WAIT RX1_INT_ID
lds argument,rxByte1
rcall queue8_enqueue
_INTERRUPT_END RX1_INT_ID

;sbi PORTF,PF1
cpi argument,10
brne rs232mainInt
_EVENT_SET RX1_EVENT_ID, TASK_CONTEXT

rjmp rs232mainInt

Task #2 character consumer for channel 1
Tasks #1 notifies Task #2 by firing an event when End of Line character is encountered in input stream. Task #2 consumes all available characters and sends them sequentially to RS232 Channel 2 (second PC)

rs232_ch1_task_consumer:
_THRESHOLD_BARRIER_WAIT InitTasksBarrier,TASKS_NUMBER

rs232main1_consumer:
_EVENT_WAIT RX1_EVENT_ID
cons1_loop:
_DISABLE_TASK_SWITCH TRUE
;read current size of input bytes from client 1
ldi ZL,low(buffer_input_one)
ldi ZH,high(buffer_input_one)

ldi axl,QUEUE_CLIENT_ONE_MAX_SIZE

rcall queue8_dequeue

_DISABLE_TASK_SWITCH FALSE

mov argument,return
rcall rs232_send_byte2 ;send to channel 2

//test if empty
ldi ZL,low(buffer_input_one)
ldi ZH,high(buffer_input_one)

rcall queue8_is_empty
brtc cons1_loop ;drain the buffer

rjmp rs232main1_consumer

Task#3 character producer for channel 2
Incoming bytes from Rx2 Interrupt handler RS232 channel 2(second PC) are fed into a circular queue-like buffer dedicated to channel 2.

rs232_ch2_task_producer:		 
rcall rs232_ch2_init
_THRESHOLD_BARRIER_WAIT InitTasksBarrier,TASKS_NUMBER

_INTERRUPT_DISPATCHER_INIT temp,RX2_INT_ID
;input
ldi ZL,low(buffer_input_two)
ldi ZH,high(buffer_input_two)

rcall queue8_init

rs232mainInt2:
ldi ZL,low(buffer_input_two)
ldi ZH,high(buffer_input_two)

ldi axl,QUEUE_CLIENT_TWO_MAX_SIZE

_INTERRUPT_WAIT RX2_INT_ID
lds argument,rxByte2
rcall queue8_enqueue
_INTERRUPT_END RX2_INT_ID

;sbi PORTF,PF1
cpi argument,10
brne rs232mainInt2
_EVENT_SET RX2_EVENT_ID, TASK_CONTEXT

rjmp rs232mainInt2

Task #4 character consumer for channel 2

Tasks #3 notifies Task #4 by firing an event when End of Line(0x10) character is encountered in input stream. Task #4 consumes all available characters and sends them sequentially to RS232 Channel 1 (first PC)

rs232_ch2_task_consumer:
_THRESHOLD_BARRIER_WAIT InitTasksBarrier,TASKS_NUMBER

rs232main2_consumer2:
_EVENT_WAIT RX2_EVENT_ID

cons2_loop:
_DISABLE_TASK_SWITCH TRUE

ldi ZL,low(buffer_input_two)
ldi ZH,high(buffer_input_two)

ldi axl,QUEUE_CLIENT_TWO_MAX_SIZE

rcall queue8_dequeue

_DISABLE_TASK_SWITCH FALSE

mov argument,return
rcall rs232_send_byte1 ;Send to channel 1

//test if empty
ldi ZL,low(buffer_input_two)
ldi ZH,high(buffer_input_two)

rcall queue8_is_empty
brtc cons2_loop ;drain the buffer



rjmp rs232main2_consumer2

Needless to say Acorn micro-kernel synchronizes access to shared queue structures.

Communication

rs232_clients.png

Start the RS232Client.exe on 2 separate computers. Settings are hard codded to match those in firmware.

Typing text in one client will appear on the screen of the other client. Communication is asynchronous which accounts for receiving a line of text in small chunks and showing them on UI side on different lines in the text component. This could be fixed by gathering text in a buffer and showing text as a whole line when End of Line(0x10) character is encountered.