Android Question How to send command to PIC16F876A

Alvsky

Member
Licensed User
Longtime User
Hi
My friend made some kind of timer with PIC16F876A and asked me to make an app to control that timer.
Timer has 256 bytes where I have to write some values. He programmed a timer in a way that data is written/read into/from registers by sending letter W/R and corresponding bytes after that.
There are also 4 servos that are controlled by a slider which can have values from 0 to 1023 (Short - 2 bytes).
To control e.g. first servo I have to send letter A and a slider value (3 bytes in total: one for A and 2 for Short Slider value). Moving slider should move servo in real time.

I have to point out that I am quite new with using B4A and that I am not a "born" programmer so if I ask some "stupid" questions I apologize in advance.

To make that app I took UsbToSerial Example so I managed to make a connection to the timer and when I move slider, sometimes servo moves but not all the time as it should.
The code I use to move servo is this:

B4X:
Sub SeekBar1_ValueChanged (Value As Int, UserChanged As Boolean)

    Dim comm1 As String
 
    comm1 = "A"&BC.ShortsToBytes(Array As Short(Value))
...     
    astreams1.Write(comm1.GetBytes("UTF8"))
   
End Sub

My question is, of course, What am I doing wrong?

Tnanks
 

ac9ts

Active Member
Licensed User
Longtime User
The way I would debug this situation is to first verify what you are sending is in the correct format (#bytes, baud rate, etc.). Connect the PIC board to a terminal program and get the exact command sequence to do the various moves. Document what those commands are. Next, disconnect the PIC board from the terminal program and connect your B4A app to the terminal program and have it send the commands. Verify that what you entered in the first phase matches what your app sends.

You may also be sending the command too quickly. I believe the ValueChanged sub is called continually while the slider is dragged on the screen. You may be sending the next command before the first one completes on the PIC board. Create a small test app that just has 2-3 buttons. Each button would be programmed to send a different move command. Tap one and verify the move is made. Tap the next and verify the next move is made. If these work correctly, you will need to figure a different way to interpret the value to send so you are not sending multiple commands.
 
Last edited:
Upvote 0

Alvsky

Member
Licensed User
Longtime User
thanks for suggestion.
I created a simple app which only few buttons as you suggested. I have now 2 situations and two ways of sending a command to PIC.
Firs one is this: I use 3 different buttons, 1 button = 1 byte and it works every time. In Log I always get back what I send.
So when I send a command C12 I do it this way:

B4X:
Sub Astreams1_NewData (Buffer() As Byte)
    Log("Data:")
    Log(bc.HexFromBytes(Buffer))
End Sub

Sub ButtonC_Click
    astreams1.write(Array As Byte(99)) 'letter C
End Sub
Sub Button3_Click
    astreams1.write(Array As Byte(0x1)) '1
End Sub
Sub Button3_Click
    astreams1.write(Array As Byte(0x2)) '2
End Sub


BUT...

when I send a command like this:

B4X:
Sub Button2_Click 'C
    astreams1.write(Array As Byte(99)) 'c=99
    astreams1.write(Array As Byte(0x1,0x1))
End Sub

or like this:

B4X:
Sub Button2_Click 'C
    astreams1.write(Array As Byte(99)) 'c=99 
    astreams1.write(Array As Byte(0x1))
    astreams1.write(Array As Byte(0x1))
End Sub

I don't always get back what I have sent (somethimes I get back C11, and somethimes C05 or only 15 or...) and that's what confuses me: what is the difference? Speed? If it is the speed, how can I send bytes slowly, one at the time?
In other words, I have to always read every single byte I send and I don't know how to do that so any halp would be appreciated.

And yes, It all works perfect when I connect timer to a PC and send commands over the terminal.
 
Upvote 0

Arf

Well-Known Member
Licensed User
Longtime User
Hi,
Try write each block of data in on go, something like this:

B4X:
Sub Button2_Click 'C
    astreams1.write(Array As Byte(99, 1, 1))
End Sub

asynchstreams is then more likely to deliver the data in one USB packet rather than possibly spread over 2 or 3 packets.
 
Upvote 0

Alvsky

Member
Licensed User
Longtime User
I just tried your suggestion and same happens. I also tried with individual bytes and it works again.
Is there a way to verify every returned byte and then send the next one?
 
Upvote 0

Arf

Well-Known Member
Licensed User
Longtime User
Mmmmm, if I were you I'd look at the data arriving at the PIC end, the timing, and when the PIC responds with sending back the received bytes in relation to the time the rest of the transmitted bytes arrive. Ideally if it's expecting 3byte commands, it would wait to receive all 3 bytes, action them, then respond with 3 bytes.

If you want to try send 1byte, get 1 byte, send another byte type approach, best thing is to buffer the incoming data and perhaps use a timer to examine the received data.

With asynchstreams I founf that data doesn't usually arrive together, if I expect 6 bytes I usually get a New_Data event for one byte, then another for 5 bytes. So it is best to buffer the receved data up and work with the buffered data.

I wrote a little class to work as a fifo, I've attached it. No claims from me as to how good the programming is, but it works for me. Include it in your project and initialise it and use it like this:
B4X:
Sub Process_Globals
    Dim rxfifo As cFIFO
B4X:
Sub Activity_Create(FirstTime As Boolean)
   rxfifo.Initialize
B4X:
Sub AStream_NewData (Buffer() As Byte)
    rxfifo.PutManyByte(Buffer)
End Sub

you can check how many bytes there are in the fifo by checking rxfifo.Cnt, and grab them out the fifo one by one with rxfifo.GetByte.

Also be aware that if you have any modal dialog boxes, any code that calls DoEvents, or use the inputList or inputMap functions (which are modal), then these block asynchstreams while they are being displayed.
 

Attachments

  • cFIFO.bas
    1.8 KB · Views: 219
Upvote 0

Alvsky

Member
Licensed User
Longtime User
thanks for your effort. I will try this and post back result.
Another thing I noticed is another command. It is the Write command. I have to write 256 bytes to PIC. Syntax is letter "w" followed by the bytes.
I tried to write first 9 bytes for test like this:

B4X:
Sub Button1_Click 'B
        astreams1.write(Array As Byte(0x77,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0xF)) 'w=0x77
End Sub

but similar thing happened: I received only first few bytes as an answer like this:
Data:
77
Data:
09
Data:
08
Data:
FF

when I read PIC memory (command "r") I can see that only first 3 bytes (9,8,7) are written.
This command also works from Terminal.
 
Upvote 0

Arf

Well-Known Member
Licensed User
Longtime User
I'd really try to access the serial data at the PIC rx pin, it may arrive in chunks some amount time apart, and you need to know how the PIC expects to receive the data - in a constant stream, or how long does it wait before it decides the full serial stream has arrived?

If you had a DATALENGTH field after the W command or something like that, it would know to wait for x amount of data.
 
Upvote 0

ac9ts

Active Member
Licensed User
Longtime User
If all your commands are working when you type them in to a terminal yet fail when they are sent from a program, there may be an issue in how the PIC is receiving the data. When you type them, there is a built in inter-character delay as you type, no matter how fast you are. Is the receiver interrupt driven or polled? How big is the buffer? How are the commands interpreted on the PIC side?
 
Upvote 0

Mark Read

Well-Known Member
Licensed User
Longtime User
Just a suggestion. What happens if you send the command?

B4X:
astream1.Write("C12".GetBytes("UTF8"))

or

B4X:
astream1.Write("C 12".GetBytes("UTF8"))
 
Upvote 0

Alvsky

Member
Licensed User
Longtime User
I just talked to PIC program designer and he programmed the PIC in a following way:
Every byte that is sent to PIC is read and returned to 1 byte buffer. When buffer is read by application, PIC is ready to receive another byte.

So the principle is quite simple: I have to send send a byte, then read it (preferably verify) and THEN send second byte and so on for third and every other byte...

The only thing is that I don't know how to control it so I need your help
 
Upvote 0

Tayfur

Well-Known Member
Licensed User
Longtime User

Maybe check serial port on app and chip. is it same?

The basic PIC Serial port configuration for the TX software is:

Bits per second (BAUD)2400
Number of bits8
ParityNone
Stop bits1
Flow controlNone
 
Upvote 0

Alvsky

Member
Licensed User
Longtime User
I managed to find a way to Write and read and check read value but I'm quite sure it could be done in more optimized way so I would appreciate if someone would comment my code.
Also, I have a problem with slider because it always gets me Error. I guess it's because it writes too fast. So is there a way to, let's say, pause a slider until it gets to wanted position?

Here is the relevant code:

B4X:
...
Dim conf(256) As Byte
Dim sent() As Byte
Dim w As String
Dim bite() As Byte
Dim n,m As Int
...
Sub Astreams1_NewData (Buffer() As Byte)
    ' You must check for DeviceInfo or analyze Buffer data to know what is connected to the USB
    ' The order of the USB could change as you plug them and could change when changing the hub port they are connected to
    Log(n&":    "&BC.HexFromBytes(Buffer))

If w="W" Then 'Write command
        If BC.HexFromBytes(Buffer) = BC.HexFromBytes(Array As Byte(0x77)) Then
            n=n+1
            m=77
            Log("Write: "&BC.HexFromBytes(Buffer))
            Send_Click
        Else
             If BC.HexFromBytes(Buffer) = BC.HexFromBytes(sent) Then
            Label2.Text = "s"&n&"-"&BC.HexFromBytes(Buffer)
            n=n+1
            Send_Click
            Else
                Msgbox(" sent: "&BC.HexFromBytes(sent)&" - rcvd: "&BC.HexFromBytes(Buffer),"Error")
                w=0
                n=0
                m=0

            End If
        End If
End If   

If w="A" Then 'servo A
        If BC.HexFromBytes(Buffer) = BC.HexFromBytes(Array As Byte(0x61)) Then
            n=n+1
            m=61
            Log("servoA")
            ServoA
        Else
             If BC.HexFromBytes(Buffer) = BC.HexFromBytes(sent) Then
                Log("Rcvd: "&BC.HexFromBytes(Buffer))
            n=n+1
            ServoA
            Else
                Msgbox(" sent: "&BC.HexFromBytes(sent)&" - rcvd: "&BC.HexFromBytes(Buffer),"Error")
                w=0
                n=0
                m=0
            End If
        End If
End If
End Sub

Sub Send_Click
If m<>77 Then
    n=-1
    w="W"
    astreams1.write(Array As Byte(0x77)) ' write
    Else
        astreams1.write(Array As Byte(conf(n)))
        sent = Array As Byte(conf(n))
        w="W"
        If n=255 Then
            w=0
            n=0
            m=0
        End If
End If

End Sub

Sub SeekBar1_ValueChanged (Value As Int, UserChanged As Boolean)
    Dim gx1() As Byte = BC.ShortsToBytes(Array As Short(Value))

    EditText1.Text = Value-512'   
    Label2.Text = "A"&BC.HexFromBytes(BC.ShortsToBytes(Array As Short(Value)))
    conf(spnIndex*10+0) = gx1(1)   
    servoAH(spnIndex) = gx1(0)
   
servoAll = Bit.Or(Bit.Or(servoAH(spnIndex),Bit.ShiftLeft(servoBH(spnIndex),2)),Bit.Or(Bit.ShiftLeft(servoCH(spnIndex),4),Bit.ShiftLeft(servoDH(spnIndex),6)))
conf(spnIndex*10+8) = ToUnsigned(servoAll)

bite = Array As Byte(gx1(1),gx1(0))

ServoA

End Sub

Sub ServoA
If m<>61 Then
    n=-1
    w="A"
    astreams1.write(Array As Byte(0x61)) ' send a
    Else
        astreams1.write(Array As Byte(bite(n)))
        sent = Array As Byte(bite(n))
        w="A"
        If n=1 Then
            w=0
            n=0
            m=0
        End If
        Log("sent="&BC.HexFromBytes(sent))
'        Loop
       
End If       
End Sub

For all those that have time and will to help, thanks in advance
 
Upvote 0
Cookies are required to use this site. You must accept them to continue using the site. Learn more…