RS-232 receive data

Just starting out? Need help? Post your questions and find answers here.
europa81
User
User
Posts: 24
Joined: Tue Oct 20, 2015 11:42 pm
Location: Southern Germany

RS-232 receive data

Post by europa81 »

Hi all,
I want to receive data from a µController (AVR 2560) and display. For that end I wrote a little programm which counts from 0 to 100 on the µController and sends it via COM9 @ 1200 Bd, 8, N, 1.

This little programme is supposed to read the COM9 and display the nrs. While in any Terminal the numbers count up correctly, this code does display Nrs. 48 ~ 56 and then garbage.

Code: Select all

#WindowColor=$FAFAFA

Define flags = #PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget
OpenWindow(0,0,0,250,250,"RS-232",flags)
WindowBounds(0,150,150, #PB_Ignore, #PB_Ignore)
SetWindowColor(0,#WindowColor)
TextGadget(0,10,10,80,30, "Data")
TextGadget(1,90,10,80,30,"Nrs")
OpenSerialPort(0,"COM9",1200,#PB_SerialPort_NoParity,8,1,#PB_SerialPort_NoHandshake,512,512)
AddWindowTimer(0,0,100)
Repeat
Select WaitWindowEvent()
    Case #PB_Event_Timer:Gosub rx
    Case #PB_Event_CloseWindow:CloseSerialPort(0):End
EndSelect
ForEver

rx:; Subroutine Receive
If AvailableSerialPortInput(0)>0
ReadSerialPortData(0,@byte,1)
SetGadgetText (1,StrU(byte, #PB_Byte))
EndIf
Return
It appears that the

Code: Select all

If AvailableSerialPortInput
is always executed.

And help would be appreciated with a hint how to understand the buffer within

Code: Select all

ReadSerialPortData
. Is it not possible to read a single byte directly from the serial port ?

Thanks in advance
infratec
Always Here
Always Here
Posts: 7582
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: RS-232 receive data

Post by infratec »

Hi,

try this:

Code: Select all

#WindowColor=$FAFAFA


Procedure CheckRx()
  
  Protected Byte.a
  
  While AvailableSerialPortInput(0)
    If ReadSerialPortData(0, @Byte, 1) = 1
      AddGadgetItem(0, -1, RSet(Hex(Byte, #PB_Byte), 2, "0") + #LF$ + Str(Byte) + #LF$ + Chr(Byte))
    EndIf
  Wend
  
EndProcedure



Define flags = #PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget
OpenWindow(0,0,0,250,250,"RS-232",flags)
WindowBounds(0,150,150, #PB_Ignore, #PB_Ignore)
SetWindowColor(0,#WindowColor)
ListIconGadget(0, 10, 10, 230, 230, "Hex", 60, #PB_ListIcon_FullRowSelect)
AddGadgetColumn(0, 1, "Dez", 60)
AddGadgetColumn(0, 2, "Ascii", 60)

OpenSerialPort(0,"COM9",1200,#PB_SerialPort_NoParity,8,1,#PB_SerialPort_NoHandshake,1024,16)
AddWindowTimer(0,0,100)
Repeat
  Select WaitWindowEvent()
    Case #PB_Event_Timer
      If EventTimer() = 0
        CheckRx()
      EndIf
    Case #PB_Event_CloseWindow
      CloseSerialPort(0)
      End
  EndSelect
ForEver

But if you do something with more data, you'll need an own thread for the serial stuff.

Bernd
Last edited by infratec on Sat Feb 13, 2016 10:54 pm, edited 1 time in total.
infratec
Always Here
Always Here
Posts: 7582
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: RS-232 receive data

Post by infratec »

Since it is windows, you can not access the port directly like in DOS.
Windows itself stores the received bytes inside a buffer which size is written in the OpenSerialPort()

With ReadSerialPortData() you can read one byte out of the receive buffer.
So you can build up a state machine for received data.

AvailableSerialPortInput() is 'nonblocking' it does not wait for serial data.

Bernd
europa81
User
User
Posts: 24
Joined: Tue Oct 20, 2015 11:42 pm
Location: Southern Germany

Re: RS-232 receive data

Post by europa81 »

infratec wrote:Since it is windows, you can not access the port directly like in DOS.
Windows itself stores the received bytes inside a buffer which size is written in the OpenSerialPort()

With ReadSerialPortData() you can read one byte out of the receive buffer.
So you can build up a state machine for received data.

AvailableSerialPortInput() is 'nonblocking' it does not wait for serial data.

Bernd
Hello Bernd,
thank you a lot. I have read your advice and am still at loss. That is because of the @-sign before the byte-variable. What does that stand for ? And you beat me into another sleepless night again with your

Code: Select all

If EventTimer() = 0
. Does it count to zero ?

The output of your programm is:

Image
so I might have the output wrong from the µController.

In the end I would like to communicate with a QuadCopter FlightController via RS-232, but the light at the end of the tunnel seems far !

Thomas
infratec
Always Here
Always Here
Posts: 7582
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: RS-232 receive data

Post by infratec »

Hi,

@ is the address operator
ReadSerialPorData() writes to a buffer not to a variable.
So you need the address of Byte and not the variable Byte.

Code: Select all

If EventTimer() = 0
Is only the security check that the event is really coming from Timer 0
(You can have more than one timer :) )

You did not run the latest version.

But it looks that you always sends '0' + CRLF

Bernd
europa81
User
User
Posts: 24
Joined: Tue Oct 20, 2015 11:42 pm
Location: Southern Germany

Re: RS-232 receive data

Post by europa81 »

infratec wrote:Hi,
You did not run the latest version.
But it looks that you always sends '0' + CRLF
Bernd
Hi Bernd,
ok, I got rid off the 10 & 13 with the Bascom-code on the µController:

Code: Select all

$regfile = "m2560def.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 16000000
$baud = 1200
Dim X As Byte
Do
For X = 0 To 100
Print X;
Waitms 300
Next X
Loop
End

But I only see the Nr. 48. Now, I shall spend the night on threads. At the end I would like to communicate with a NAZE32 Copter-FlightController.
Thomas
infratec
Always Here
Always Here
Posts: 7582
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: RS-232 receive data

Post by infratec »

Use PRINTBIN instead of PRINT
infratec
Always Here
Always Here
Posts: 7582
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: RS-232 receive data

Post by infratec »

PRINT prints always a string and always + CRLF

http://halvar.at/elektronik/kleiner_bas ... _computer/
infratec
Always Here
Always Here
Posts: 7582
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: RS-232 receive data

Post by infratec »

If you search in the 'Coding Questions' section you will find many examples (most by me :) ) for communication and threads.

Bernd
europa81
User
User
Posts: 24
Joined: Tue Oct 20, 2015 11:42 pm
Location: Southern Germany

Re: RS-232 receive data

Post by europa81 »

infratec wrote:PRINT prints always a string and always + CRLF

http://halvar.at/elektronik/kleiner_bas ... _computer/
Thank you for that hint. With Printbin it does kind of work. I beg to differ though on the CRLF. If you put a
";"
after the

Code: Select all

Print
-command, there will be no CRLF.

Now I will have to spend the night on your

Code: Select all

ListIconGadget
&

Code: Select all

AddGadgetComumn
. And those threads ....

Thomas
Last edited by europa81 on Sun Feb 14, 2016 12:44 am, edited 1 time in total.
infratec
Always Here
Always Here
Posts: 7582
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: RS-232 receive data

Post by infratec »

Then I wish you a 'good' night :mrgreen:
infratec
Always Here
Always Here
Posts: 7582
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: RS-232 receive data

Post by infratec »

A Thread example:

Code: Select all

EnableExplicit


CompilerIf Not #PB_Compiler_Thread
  MessageRequester("Info", "Enable Thread-Safe in compiler options!")
  End
CompilerEndIf

Enumeration #PB_Event_FirstCustomValue
  #Com_Event_RxBytes
  #Com_Event_TxBytes
  #Com_Event_RxComplete
  #Com_Event_Exit
EndEnumeration




Structure ComParameterStructure
  COM$
  Thread.i
  Semaphore.i
  Mutex.i
  Rx$
  Tx$
  Exit.i
EndStructure


Procedure ComThread(*Parameter.ComParameterStructure)
 
  Protected.a Byte
  Protected.i Port, RxLen, RxBytes, State
  Protected Rx$
 
  Port = OpenSerialPort(#PB_Any, *Parameter\COM$, 1200, #PB_SerialPort_NoParity, 8, 1, #PB_SerialPort_NoHandshake, 128, 128)
  If Port
   
    Repeat
     
      RxLen = AvailableSerialPortInput(Port)
      If RxLen
        While RxLen
          If ReadSerialPortData(Port, @Byte, 1) = 1
            RxBytes + 1
            PostEvent(#Com_Event_RxBytes, 0, 0, 0, RxBytes)
           
            Debug Byte
           
            Select State
              Case 0
                If Byte = #CR
                  State + 1
                Else
                  *Parameter\Rx$ + Chr(Byte)
                EndIf
                
              Case 1
                If Byte = #LF
                  PostEvent(#Com_Event_RxComplete)
                  WaitSemaphore(*Parameter\Semaphore)
                EndIf
                State = 0
                
            EndSelect
           
            RxLen - 1
          EndIf
        Wend
      ElseIf TryLockMutex(*Parameter\Mutex)
        If Len(*Parameter\Tx$)
          WriteSerialPortString(Port, *Parameter\Tx$, #PB_Ascii)
          *Parameter\Tx$ = ""
        EndIf
        UnlockMutex(*Parameter\Mutex)
      Else
        Delay(3)
      EndIf
     
    Until *Parameter\Exit
   
    CloseSerialPort(Port)
   
  EndIf
 
  PostEvent(#Com_Event_Exit)
 
EndProcedure




Define.i Event, Exit
Define ComParameter.ComParameterStructure

OpenWindow(0, 0, 0, 640, 480, "Com - Test", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)

ButtonGadget(0, 10, 10, 80, 25, "Connect")

CreateStatusBar(0, WindowID(0))
AddStatusBarField(100)
AddStatusBarField(100)
AddStatusBarField(100)
AddStatusBarField(100)

StatusBarText(0, 0, "disconnected", #PB_StatusBar_Center)
StatusBarText(0, 1, "Rx: 0", #PB_StatusBar_Center)
StatusBarText(0, 2, "Tx: 0", #PB_StatusBar_Center)

ComParameter\COM$ = "COM9"
ComParameter\Semaphore = CreateSemaphore()
ComParameter\Mutex = CreateMutex()

Repeat
 
  Event = WaitWindowEvent()
 
  Select Event
    Case #Com_Event_RxBytes
      StatusBarText(0, 1, "Rx: " + Str(EventData()), #PB_StatusBar_Center)
     
    Case #Com_Event_TxBytes
      StatusBarText(0, 2, "Tx: " + Str(EventData()), #PB_StatusBar_Center)
      
    Case #Com_Event_RxComplete
      StatusBarText(0, 3, ComParameter\Rx$, #PB_StatusBar_Center)
      Select ComParameter\Rx$
        Case "ping"
          LockMutex(ComParameter\Mutex)
          ComParameter\Tx$ = "pong"
          UnlockMutex(ComParameter\Mutex)
      EndSelect
      ComParameter\Rx$ = ""
      SignalSemaphore(ComParameter\Semaphore)
      
    Case #Com_Event_Exit
      ComParameter\Exit = #False
      SetGadgetText(0, "Connect")
      StatusBarText(0, 0, "disconnected", #PB_StatusBar_Center)
     
    Case #PB_Event_Gadget
      Select EventGadget()
        Case 0
          If IsThread(ComParameter\Thread)
            ComParameter\Exit = #True
          Else
            ComParameter\Thread = CreateThread(@ComThread(), @ComParameter)
            If ComParameter\Thread
              SetGadgetText(0, "Disconnect")
              StatusBarText(0, 0, "connected", #PB_StatusBar_Center)
            EndIf
          EndIf
      EndSelect
     
    Case #PB_Event_CloseWindow
      If IsThread(ComParameter\Thread)
        ComParameter\Exit = #True
        If WaitThread(ComParameter\Thread, 1000) = 0
          KillThread(ComParameter\Thread)
        EndIf
      EndIf
      FreeMutex(ComParameter\Mutex)
      FreeSemaphore(ComParameter\Semaphore)
      Exit = #True
      
  EndSelect
 
Until Exit
If you want a stable program, than don't show any text direct from inside the thread.
Use always the way with PostEvent().
At least in Linux and OS X you run in big trouble if you do it directly.

Bernd
Last edited by infratec on Mon Feb 15, 2016 7:52 am, edited 4 times in total.
europa81
User
User
Posts: 24
Joined: Tue Oct 20, 2015 11:42 pm
Location: Southern Germany

Re: RS-232 receive data

Post by europa81 »

infratec wrote:A Thread example:


Bernd
Bernd, Guten Morgen !
and thank you. I am still working on that thread part, but one question which is bugging me since: how does the @byte know which position within the receive-buffer is the actual one ? I would expect something like:

Code: Select all

buffer_length = available_bytes_in_buffer
for x=0 to buffer_length-1
  receive$=receive$+byte(x)
next x
with then receive$ containing the entire buffer.

cheers
Thomas

__________________________________________________
Code tags added
14.02.2016
RSBasic
europa81
User
User
Posts: 24
Joined: Tue Oct 20, 2015 11:42 pm
Location: Southern Germany

Re: RS-232 receive data

Post by europa81 »

Have been doing some more work on the programme - at my limited intellectual level and am proud to have a moving bar alongside a working programme:

Code: Select all

#WindowColor=$FAFAFA

Define flags = #PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget
OpenWindow(0,0,0,250,60,"RS-232",flags)
WindowBounds(0,150,150, #PB_Ignore, #PB_Ignore)
SetWindowColor(0,#WindowColor)
TextGadget(0,80,10,35,20, "Data:")
TextGadget(1,120,10,45,20,"Nrs")
TrackBarGadget (2, 5, 40, 240, 30, 0, 100, #PB_TrackBar_Ticks)
OpenSerialPort(0,"COM9",1200,#PB_SerialPort_NoParity,8,1,#PB_SerialPort_NoHandshake,512,512)
AddWindowTimer(0,0,20)
Repeat
Select WaitWindowEvent()
    Case #PB_Event_Timer:Gosub rx
    Case #PB_Event_CloseWindow:CloseSerialPort(0):End
EndSelect
ForEver

rx:; Subroutine Receive
b.l=AvailableSerialPortInput(0)
If ReadSerialPortData(0,@Puffer,b)
  p$=Str(puffer)
  SetGadgetText (1,RSet(p$,8))
  SetGadgetState (2,Puffer)
  EndIf
Return
I shall now modify from Subroutine to Procedure. That Thread-thing is still spanish/latin/greek to me as well as the above question as to the pointer knowing which byte of the buffer is to be read. It is a pitty that the serial port cannot trigger an interrupt but that instead a timer wastes plenty of time checking for available data.
Thomas
europa81
User
User
Posts: 24
Joined: Tue Oct 20, 2015 11:42 pm
Location: Southern Germany

Re: RS-232 receive data

Post by europa81 »

here is the Bascom-code for completeness sake:

Code: Select all

$regfile = "m2560def.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 16000000
$baud = 1200
Dim X As Byte
Dim Y As Byte
Do
For X = 0 To 100
Printbin X;
Waitms 100
Next X
For X = 100 To 0 Step -2
Printbin X
Waitms 40
Next X
For X = 0 To 40
Y = Rnd(100)
Printbin Y
Waitms 150
Next X
Loop
End
I notice a fragile behavior of the PB-Programme though: if alone I wish to reposition the running programme on the screen it starts receiving garbage. Could probably be helped by lowering the timer-nr, but that is a lot of wasted time. Guess, I need to learn more about the RS-232 buffer.

Thomas

PS: Forum-question - how can I include an image without the need of hosting it on another server first ?
Post Reply