FreeBasic communication with Arduino logic error?

For issues with communication ports, protocols, etc.
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

FreeBasic communication with Arduino logic error?

Post by BasicCoder2 »

Recently I renewed my interest in Arduino and RPi projects and hoped to use FreeBasic for high level control.
In this first test I have 4 LEDS as output and 4 button switches as input.
Image
The idea is for the PC to send the Arduino commands and the Arduino to act on them.
The command to toggle a LED is a character "1","2","3" or "4". This works as expected.
The command to return the state of the buttons as a four character string is the character "9".
When I hold down a button and press the [9] key I expected the Arduino to return a string holding the button current values. Instead it returns the previous button values.
While still holding down button1 I enter the command 9 again and this time it returns 0111 showing I am holding down button1
I release the button1 and again enter the command 9 and it still returns 0111
If I again press the command 9 it now returns the expected 1111
In other words I have to send the command twice. The first time it returns the previous state and the second time it returns the actual state.

Code: Select all

screenres 640,480,32

Open Com "COM3:9600,n,8,1,cs0,ds0,cd0,rs" As #1
If Err <> 0 Then
    Print "Error opening COM3"
    Sleep 2000,1
    Cls
    end
End If

function readButtons() as string
    dim inpData as string
    inpData = ":"
    while Loc(1) > 0
        inpData = inpData + Input(1,#1)
    wend
    return inpData
end function

dim as string key
dim as string buttons

do
    input "Enter command";key  'enter command

    if key >= "1" and key <= "4" then 'command to toggle a LED
        print #1,key;  'send toggle command
    end if

    'before pressing [9] key hold down one of the buttons
    if key="9" then   'command to read the button values
        print #1,key  'send command to put button values in buffer
        buttons = readButtons()  'read buffer
        print buttons;           'show button values
    end if

    Sleep 2
loop until key="q"

Close #1
Arduino Code

Code: Select all

int serialData = 0;

void setup(){
  pinMode(22,INPUT);  // button switches
  pinMode(23,INPUT);
  pinMode(24,INPUT);
  pinMode(25,INPUT); 
  
  pinMode(30,OUTPUT);  // output to LEDS
  pinMode(31,OUTPUT);
  pinMode(32,OUTPUT);
  pinMode(33,OUTPUT); 

  Serial.begin(9600);
  
}

const int LED1 = 30;
const int LED2 = 31;
const int LED3 = 32;
const int LED4 = 33;

int LEDS[5];

int const btn1 = 22;
int const btn2 = 23;
int const btn3 = 24;
int const btn4 = 25;

String buttons;

void readButtons(){

  buttons = "";
  
  if  (digitalRead(btn1)==HIGH){
    buttons = buttons + '1';
  }else{
    buttons = buttons + '0';
  }

  if  (digitalRead(btn2)==HIGH){
    buttons = buttons + '1';
  }else{
    buttons = buttons + '0';
  }

  if  (digitalRead(btn3)==HIGH){
    buttons = buttons + '1';
  }else{
    buttons = buttons + '0';
  }

  if  (digitalRead(btn4)==HIGH){
    buttons = buttons + '1';
  }else{
    buttons = buttons + '0';
  }

  Serial.println(buttons);  // place result on buffer
  
}

void loop(){

  if (Serial.available() > 0){

    serialData = Serial.read();
    
    if (serialData == '1'){  // command to toggle LED1
      if (LEDS[1]==0){
        digitalWrite(LED1,HIGH);
        LEDS[1]=1;
      }else{
        digitalWrite(LED1,LOW);
        LEDS[1]=0;
      }
    }

    if (serialData == '2'){  // command to toggle LED2
      if (LEDS[2]==0){
        digitalWrite(LED2,HIGH);
        LEDS[2]=1;
      }else{
        digitalWrite(LED2,LOW);
        LEDS[2]=0;
      }
    }

    if (serialData == '3'){  // command to toggle LED3
      if (LEDS[3]==0){
        digitalWrite(LED3,HIGH);
        LEDS[3]=1;
      }else{
        digitalWrite(LED3,LOW);
        LEDS[3]=0;
      }
    }

    if (serialData == '4'){  // command to toggle LED4
      if (LEDS[4]==0){
        digitalWrite(LED4,HIGH);
        LEDS[4]=1;
      }else{
        digitalWrite(LED4,LOW);
        LEDS[4]=0;
      }
    }
    
    if (serialData == '9'){
        readButtons();
    }
  }

}
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: FreeBasic communication with Arduino logic error?

Post by MrSwiss »

I've not checked the FB code ...

Arduino code (reviewed, adapted):

Code: Select all

int serialData = 0;

void setup(){
  pinMode(22,INPUT);  // button switches
  pinMode(23,INPUT);
  pinMode(24,INPUT);
  pinMode(25,INPUT);
 
  pinMode(30,OUTPUT);  // output to LEDS
  pinMode(31,OUTPUT);
  pinMode(32,OUTPUT);
  pinMode(33,OUTPUT);

  Serial.begin(9600);
}

const byte LED1 = 30;       // byte instead of int (1 byte instead of 2)
const byte LED2 = 31;
const byte LED3 = 32;
const byte LED4 = 33;

byte LEDS[4];               // corrected 4 elements (0 To 3)

const byte btn1 = 22;
const byte btn2 = 23;
const byte btn3 = 24;
const byte btn4 = 25;

String buttons;

String readButtons(){       // FUNCTION: returning a string (void = Sub)

  buttons = "";
 
  if  (digitalRead(btn1)==HIGH){
    buttons += '1';
  }else{
    buttons += '0';
  }

  if  (digitalRead(btn2)==HIGH){
    buttons += '1';
  }else{
    buttons += '0';
  }

  if  (digitalRead(btn3)==HIGH){
    buttons += '1';
  }else{
    buttons += '0';
  }

  if  (digitalRead(btn4)==HIGH){
    buttons += '1';
  }else{
    buttons += '0';
  }

  return buttons;              // return result to loop() aka: MAIN-LOOP
  //Serial.println(buttons);  // place result on buffer
}

void loop(){

  if (Serial.available() > 0){

    serialData = Serial.read();
   
    if (serialData == '1'){  // command to toggle LED1
      if (LEDS[0]==0){
        digitalWrite(LED1,HIGH);
        LEDS[0]=1;
      }else{
        digitalWrite(LED1,LOW);
        LEDS[0]=0;
      }
    }
    
    if (serialData == '2'){  // command to toggle LED2
      if (LEDS[1]==0){
        digitalWrite(LED2,HIGH);
        LEDS[1]=1;
      }else{
        digitalWrite(LED2,LOW);
        LEDS[1]=0;
      }
    }

    if (serialData == '3'){  // command to toggle LED3
      if (LEDS[2]==0){
        digitalWrite(LED3,HIGH);
        LEDS[2]=1;
      }else{
        digitalWrite(LED3,LOW);
        LEDS[2]=0;
      }
    }

    if (serialData == '4'){  // command to toggle LED4
      if (LEDS[3]==0){
        digitalWrite(LED4,HIGH);
        LEDS[3]=1;
      }else{
        digitalWrite(LED4,LOW);
        LEDS[3]=0;
      }
    }
   
    if (serialData=='9'){
      Serial.println(readButtons());   // returns button (String)
    }
  }

}
(code compiled successfully, but can't run on my ARDU (less Pin's, than yours!))
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: FreeBasic communication with Arduino logic error?

Post by BasicCoder2 »

With your version the LEDs still work correctly but there is no change in the behavior reading the button states.
An Arduino Uno could be used just change the pins used and their label in the setup()
Of course you would need the LEDs and Buttons circuit to connect to test the code.
In my case I happen to have already used most of those pins to control two motors and read their encoders.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: FreeBasic communication with Arduino logic error?

Post by MrSwiss »

hmmm, move the String buttons; (declaration) into void loop(){.
Use it as parameter in readButtons(String buttons){ and also in the call:
Serial.println(readButtons(buttons)); then check, if it makes a
difference.
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: FreeBasic communication with Arduino logic error?

Post by coderJeff »

Seeing the pic makes me want to dig out my arduino board...

If I had to guess, I'd say right here:

Code: Select all

    print #1,key  'send command to put button values in buffer
    buttons = readButtons()  'read buffer
Seems like there should be a delay or handshake between sending the command and reading the response. No handshaking looking at OPEN COM statement. So, have to give some time to allow the command to get to the arduino and a response sent back, like with a SLEEP command. Or change the the readButtons() to idle for some maximum amount of milliseconds before either returning the result, or timing out.
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: FreeBasic communication with Arduino logic error?

Post by BasicCoder2 »

coderJeff wrote: "Seeing the pic makes me want to dig out my arduino board..."

Well dig it out then :)

Here is a shorter version which still shows the same behavior.
Enter command? 1 'this turns on the LED as expected
'but doesn't return the command sent
Enter command? 2 'this turns off the LED as expected
49 'and returns these three byes, a '1'
13 ' CR
10 ' LF

Enter command? 9 'command to read switch
50
13
10

Enter command? 9 'try again with the switch down
1
57
13
10

Enter command? 9 'keeping the switch down and now it returns the correct value
0
57
13
10

Code: Select all

screenres 640,480,32

Open Com "COM3:9600,n,8,1,cs0,ds0,cd0,rs" As #1
If Err <> 0 Then
    Print "Error opening COM3"
    Sleep 2000,1
    Cls
    end
End If
    
dim as string outData
dim as string inData

do

    input "Enter command";outData
    print #1,outData      ' SEND DATA

    inData = ""
    while Loc(1) > 0
        inData = inData + Input(1,#1)
    wend
    print inData
    
    Sleep 2
loop until multikey(&H01)

Close #1
Arduino

Code: Select all

int serialData = 0;
const byte LED1 = 30;  // pin number
const byte BTN1 = 22;  // pin number

void setup()
{
  pinMode(LED1,OUTPUT);   // LED
  pinMode(BTN1,INPUT);    // BUTTON
  Serial.begin(9600);  
}


void loop()
{
  if (Serial.available() > 0)
  {
    serialData = Serial.read();  //get command

    // command to turn on LED
    if (serialData == '1'){
      digitalWrite(LED1,HIGH);
    }

    // command to turn off LED
    if (serialData == '2'){
      digitalWrite(LED1,LOW);
    }

    // command to read button value and return to PC
    if (serialData == '9'){
      Serial.println(digitalRead(BTN1));
    }

    // returns command sent
    Serial.println(serialData);  //return command

  }  
}
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: FreeBasic communication with Arduino logic error?

Post by MrSwiss »

BasicCoder2,

you obviously didn't understand the gist, of coderJeff's post ...
(the by you criticized behaviour is in your FB code, not on the ARDU)
In the FB code, you have to give the ARDU a break, to respond to watever re-
quest you've sent to it (transmit, accept it, act on it, send data back).

Therefore a minimum of flow control is needed, that lets you switch, between
send and receive (a simple Boolean does the trick).

Note: plse. get into the healthy habit of using variables, instead of literals.
(makes code shorter and simpler to read, as well as easier modifiable)

Minimalistic FB-code:

Code: Select all

screenres 640,480,32

Dim As Long     fn = FreeFile
Dim As String   com_cmd = "COM3:9600,n,8,1,cs0,ds0,cd0,rs"

If Open Com(com_cmd As #fn) <> 0 Then
    Print "Error opening COM3"
    Sleep 2000, 1
    Cls
    End 1
End If
   
dim as string   outData, inData
Dim As boolean  state = TRUE            ' send (if FALSE receive)

do
    If state Then
        outData = ""
        Input "Enter command"; outData
        print #fn, outData              ' SEND DATA
        state = FALSE
    Else
        While LOC(fn) = 0               ' wait until ARDU responds
            Sleep 20                    ' (forever, if no answer!)
        Wend
        inData = ""
        while Loc(fn) > 0
            inData += Input(1,#fn)
        Wend
        print inData
        state = TRUE
    End If
   
    Sleep 20
loop until multikey(&H01)

Close #fn
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: FreeBasic communication with Arduino logic error?

Post by BasicCoder2 »

Thank you for your code it seems to work well. I wasn't sure how or where to include a delay simply because I didn't really understand what was going on with the code. I did handshaking back in my MSDOS Assembler days using the parallel ports. No LOC or COM statements or a multitasking OS to understand.

Of course I don't want the pc waiting for ever until ARDU responds. I need it to be doing other things including informing the human that ARDU is not responding within some time limit.

The problem for me now with FreeBASIC is that without a MrSwiss I might never get things working.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: FreeBasic communication with Arduino logic error?

Post by MrSwiss »

BasicCoder2 wrote:Of course I don't want the pc waiting for ever until ARDU responds. I need it to be doing other things including informing the human that ARDU is not responding within some time limit.
Well, you just have to add a bit of code that quit's waiting, after a time limit has expired ...

Code: Select all

' additionally required stuff: 1 x variable + 1 x const
' dim as double tl	' to hold value for comparison with Timer
' const as single timeout = 0.5	 ' timeout in seconds

	 Else
	     tl = Timer + timeout
        While LOC(fn) = 0               ' wait until ARDU responds
            If Timer > tl then Exit While, Do	' quit wait and main-loop
            Sleep 20
        Wend
        inData = ""
You'd still need LOC() and LPTn, because that's FreeBASIC code ...
Dr_D
Posts: 2451
Joined: May 27, 2005 4:59
Contact:

Re: FreeBasic communication with Arduino logic error?

Post by Dr_D »

Interesting... I've been toying a bit with Arduino again as well. I've never attempted to use it in conjunction with FB before, though. It looks like this gives me the perfect excuse! lol
Anyway, I have extremely modest goals, to be quite honest. It's all just for fun, and to keep my mind active after work. I'm thinking like a mechanical binary clock... Christmas lights that the kids can control with an interface written in FB would be really cool... stuff like that. :)
Razgriz_101
Posts: 5
Joined: Jul 27, 2019 10:23

Re: FreeBasic communication with Arduino logic error?

Post by Razgriz_101 »

It's one hell of a great idea in my eyes as well, I've already assembled a small home automation set for my flat using off-the-counter systems, and was wondering whether I could come up by myself with a bigger, Arduino and FB-based one, when I buy one of these house in Larnaca for the holidays.
Last edited by Razgriz_101 on Aug 06, 2019 13:33, edited 2 times in total.
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

FreeBasic and Arduino projects

Post by BasicCoder2 »

There are lots of cool electronic projects these days that you can do using the RPi and/or Arduino.
FreeBasic will run on the Rpi although most projects use Python.
This is the setup I intend to buy soon.
https://www.altronics.com.au/p/z6309-ra ... n-display/
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: FreeBasic communication with Arduino logic error?

Post by coderJeff »

BasicCoder2 wrote:Of course I don't want the pc waiting for ever until ARDU responds. I need it to be doing other things including informing the human that ARDU is not responding within some time limit.
To have this happen, can't use fbc's INPUT. The INPUT command will block execution until it completes, so on the fbc (host) side, nothing else can happen while INPUT statement is working. Similar on the arduino side if you were using delay() statement. The warnings on the arduino reference for delay() are pretty much same for INPUT on fbc side.
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: FreeBasic communication with Arduino logic error?

Post by coderJeff »

OK, I found my arduino and some parts:
Image

I don't have the micro-push-buttons, but I do have a keypad that can do the same thing, using it as multiple push buttons. FYI, the DIN connector is for a PS2 keyboard I was working with last, and writing my own PS2 keyboard driver for arduino; it only uses 2 inputs (clock & data) so, it won't interfere with using 4 inputs for push buttons, and 4 outputs for LED's.

I will post some demo code for serial communication, soon-ish. :)
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Arduino Serial Communication Demo #1

Post by coderJeff »

Arduino Serial Communication Demo #1

Image

In this first demo, we are using a simple arduino sketch to echo back what it gets on the serial communication port.

Arduino sketch:

Code: Select all

void setup()
{
  Serial.begin( 9600 );
  Serial.print( "Arduino is online\n" );
}

void loop()
{
  if( Serial.available() > 0 )
  {
    int8_t ch = Serial.read();
    if( ch != -1 )
    {
      Serial.write( ch );
    }
  }
}
Then on the fbc (host) side, we aren't doing anything too fancy. Just taking input from the keyboard, displaying it on the terminal, and sending it to the arduino. Finally, what ever the arduino sends us, we display on the terminal. I've added code to display control characters, like CR and LF so we know exactly what's going back and forth. I'll have to test on Linux next, but TERMINAL_EOL probably only needs to be CHR(10) on Linux.

Code: Select all

const DEVICE_COM = "COM7"
const DEVICE_FILE_NO = 1

const KEYBOARD_ESCAPE = chr(27)
const KEYBOARD_EOL = chr(13)

const TERMINAL_EOL = chr(13, 10)

const DEVICE_EOL = chr(10)

const COLOR_KEYBOARD = 7
const COLOR_TERMINAL = 12
const COLOR_OUTPUT   = 10
const COLOR_INPUT    = 13

dim shared code(0 to 31) as zstring * 4 = _
	 { _
		"NUL", "SOH", "STX", "ETX", _
		"EOT", "ENQ", "ACK", "BEL", _
		"BS ", "HT ", "LF ", "VT ", _
		"FF ", "CR ", "SO ", "SI ", _
		"DLE", "DC1", "DC2", "DC3", _
		"DC4", "NAK", "SYN", "ETB", _
		"CAN", "EM" , "SUB", "ESC", _
		"FS ", "GS ", "RS ", "US "  _
	}

function keyboard_read_key() as string
	function = inkey
end function

sub terminal_write_string( byval clr as integer, byref s as const string )
	static last_ch as integer = 0
	color clr
	for i as integer = 1 to len(s)
		dim ch as integer = asc(mid(s,i,1))
		select case ch
		case 0 to 31
			if( ch <> 10 and last_ch = 13 ) then
				print
			end if
			print "<" & rtrim(code(ch)) & ">";
			if( ch = 10 ) then
				print
			end if
		case else
			print chr(ch);
		end select
		last_ch = ch
	next
	color 7
end sub

function arduino_open() as boolean
	dim s as string
	s = DEVICE_COM & ":9600,n,8,1,cs0,ds0,cd0,rs"
	function = not cbool( open com(s As #DEVICE_FILE_NO ) )
end function

sub arduino_close()
	close #DEVICE_FILE_NO
end sub

function arduino_read_byte() as string
	if loc(DEVICE_FILE_NO) > 0 THEN
		function = input( 1, #DEVICE_FILE_NO )
	end if
end function

sub arduino_write_string( byref s as string )
	print #DEVICE_FILE_NO, s;
end sub

'' ----------------
'' MAIN
'' ----------------

if arduino_open() = false then
	print "error connecting to arduino"
	end 1
end if

const COLOR_KEYBOARD = 7
const COLOR_TERMINAL = 12
const COLOR_INPUT    = 13
const COLOR_OUTPUT   = 10


terminal_write_string( COLOR_KEYBOARD, "keyboard" & TERMINAL_EOL )
terminal_write_string( COLOR_TERMINAL, "terminal" & TERMINAL_EOL )
terminal_write_string( COLOR_OUTPUT, "output" & TERMINAL_EOL )
terminal_write_string( COLOR_INPUT, "input" & TERMINAL_EOL )

terminal_write_string( COLOR_TERMINAL, TERMINAL_EOL )
terminal_write_string( COLOR_TERMINAL, TERMINAL_EOL )

terminal_write_string( COLOR_TERMINAL, "connected" & TERMINAL_EOL )


dim as string k, r

do
	k = keyboard_read_key()

	'' write keyboard input to terminal and arduino
	select case k
	case KEYBOARD_ESCAPE
		exit do
	case KEYBOARD_EOL
		terminal_write_string( COLOR_KEYBOARD, k )
		terminal_write_string( COLOR_TERMINAL, TERMINAL_EOL )
		terminal_write_string( COLOR_OUTPUT, DEVICE_EOL )
		arduino_write_string( DEVICE_EOL )
	case else
		terminal_write_string( COLOR_KEYBOARD, k )
		terminal_write_string( COLOR_TERMINAL, k )
		terminal_write_string( COLOR_OUTPUT, k )
		arduino_write_string( k )
	end select

	'' read any response from arduino
	do
		r = arduino_read_byte()
		terminal_write_string( COLOR_INPUT, r )
	loop until r = ""

	sleep 20

loop

arduino_close()

terminal_write_string( COLOR_TERMINAL, "disconnected" & TERMINAL_EOL )
Each colour displayed on the terminal represents a different part of the communication between keyboard (white), terminal(red), output (green), input (magenta).

I ran this demo on a windows pc, so you should notice a few things:
1) keyboard end of line (EOL), aka RETURN, has value of CR or CHR(13)
2) terminal (on windows) expects end of line to have CR+LF or CHR(13,10) to display correctly
3) we translate the keyboard input EOL or CHR(13) to what the arduino expects, which is LF or CHR(10)
4) arduino's 'print("\n")' command sends us an EOL of LF or CHR(10) only.

Also to note, is we are not blocking execution on either the arduino side or the fbc side.

This communication is rather simple, and to add the concept of "commands" and "responses" we will need to add some buffering on both sides to achieve this.
Post Reply