News:

;) This forum is the property of Proton software developers

Main Menu

UART with troubles

Started by midali, Nov 24, 2021, 12:49 PM

Previous topic - Next topic

david

SBUS (horrible protocol) was initially introduced by Futaba and later adopted by Frysky who then added SPort to allow telemetry (requiring a second UART channel) and more recently came up with FPort which does control data and telemetry over a single UART -just like Flysky's iBus protocol which has been around for some years.
Unless you're building something using existing hardware I would seriously consider looking at FPort as this will be the standard going forward.
The compiler makes short work of decoding iBus-
 HRSIn Wait($20,$40),Ch1,Ch2,Ch3,Ch4,Ch5,Ch6,Ch7,Ch8,Ch9,Ch10  (Ch1 - Ch10 defined as Word variables) but I gave up on SBUS because it seemed to be splitting channels across bytes and was getting messy.
Good luck with your project.

Cheers,
David

midali

   Right David , Sbus is a horrible , but I made quicky the protocol to decode the first 6channels . I didn't think I would have a trouble with receiving a some 25 bytes . The really is that I'm begginer and too old , my processing is slow ...

Here is a code to decode first 6ch ( not tested if its right )
Dim rx_buffer[25] As Byte
Dim i             As Byte = 0
Dim ch[7]         As Word
Dim A             As Word
Dim B             As Word

main:

        i = 0
   Do   
       HSerIn 5,timeout ,[rx_buffer[i]]
        i = i +1
    Loop
   
timeout:
    A = rx_buffer[1]             
    B = rx_buffer[2] & %00000111
        ch[1] = A + (B << 8)
    A = rx_buffer[2] >> 3       
    B = rx_buffer[3] & %00111111
        ch[2] = A + (B << 8)
    A = rx_buffer[3] >> 6 '           
    B = rx_buffer[4]   
        A = A + (B << 8)               
        B = rx_buffer[5] >> %00000001
        ch[3] = A + (B << 8)
    A = rx_buffer[5] >> 1
    B = rx_buffer[6] & %00001111
        ch[4] = A + (B << 8)
    A = rx_buffer[6] >> 4
    B = rx_buffer[7] & %01111111
        ch[5] = A + (B << 8)
    A = rx_buffer[7] >> 7 
    B = rx_buffer[8]       
         A = A + (B << 8)
         B = rx_buffer[9] & %00000011
         ch[6] = A + (B << 8)
                   
GoTo main

david

Hi,
It's great to hear you have made good progress on your project.
Now that you can decode the channel variables inside the micro what do you intend to do with them?   Will you convert the 6 variables to PWM outputs?   6 channels or even 8 can be done sequentially but if you're looking to go to 12 or 14 channels it would impact the frame fate and you may want to consider simultaneous outputs as some of the multichannel rxs do.
Good luck and keep up the good work.

Cheers,
David

midali

Hi,

For the moment I still haven't been able to read the 25 bytes correctly. After I manage to do it right, for my application, there is no need to convert to pwm signal.

Quote from: david on Nov 27, 2021, 08:59 PMGood luck and keep up the good work.
Thank you David

tumbleweed

#24
I think one thing you'll have to do (once you have it properly receiving data) is to not only sync on the $0F byte, but after that verify that 25 bytes later you get the $00 end of frame.
It's possible that $0F is part of the data and not a 'real' start of frame byte. Since $0F and $00 can be data bytes this isn't foolproof, but it's better than nothing.

If you increase your buffer size to 2x25 bytes you should be guaranteed to get an entire valid frame in there somewhere.

joesaliba

Today I had a look again at SBus. I can synchronise with $0F and I am receiving data, at least I can see it on the PC terminal.

Now I am trying to assemble the data bytes. I might use Midali method but I want to make sure that when I change something on the Tx, data is being changed.

@tumbleweed I have seen an example to check for header and footer. If I get around it I post my findings.

Joe

midali

#26
   Its first time when I try interrupts . About Trastikata post #9 I have some questions :
1.  GIE must be enable ?
2. "Ready to receive" bit , UsartRx which bit is, from which register ?
3. If data is 8E2 , I its necessary to set 9bit receiving ?
4. I setup right the interrupt variables acording with datasheet?

Declare  Xtal = 32
OSCCON  = %11110100 'set to 8 x 4PLL MHz

RCSTA.6=1

Declare Hserial_Clear  = On
Declare Hserial_Baud   = 100000
Declare Hserial_Parity = Even

Include "lcd.bas"

PORTC  = %10000000

Dim rx_buffer[25] As Byte
Dim rx            As Byte
Dim i             As Byte =0
Dim ch[7]         As Word
Dim A             As Word
Dim B             As Word

Dim Tempbyte      As Byte
Dim y             As Byte
Dim UsartRxReady  As Bit = 0
Dim OERR          As RCSTA.1
Dim CREN          As RCSTA.4
Dim RC1IF         As PIR1.5


On_Interrupt GoTo Isr
GoTo Main

Isr:
    Context Save
   
    If OERR = 1 Then                                'Clear Overrun Error bit
        CREN = 0
        CREN = 1
    EndIf

    If RC1IF = 1 Then                               'Interrupt when a byte is received - USART RX Interrupt flag is set
        Tempbyte = RCREG                            'Read the USART buffer to TempByte

        If Tempbyte = $0F Or y > 25 Then            'If the end of message "$0" is found or the message exceeds the InBuffer size of 25 bytes
            If UsartRx = 1 Then                     'If "Ready to receive" bit is set           
                UsartRx = 0                         'Clear "Ready To Receive" Bit
                UsartRxReady = 1                    'And Set "Message Received/Message Read" bit
            EndIf
        EndIf

        If UsartRx = 1 Then                         'If "Ready To Receive" Bit is set
            rx_buffer[y] = Tempbyte                  'Place the value of the received byte in the corresponding InBuffer position
            Inc y                                   'Increment the buffer position
        EndIf

        If Tempbyte = 25 And UsartRxReady = 0 Then  'If the preamble 36 is found and "Message Received/Message Read" Bit is cleared
            Clear rx_buffer : y = 0                  'Reset InBuffer and buffer counter
            rx_buffer[y] = Tempbyte                  'Start refilling the InBuffer
            UsartRx = 1                             'And "Ready to receive" Bit
            Inc y                                   'Increment the buffer counter from the first position
        EndIf

        RC1IF = 0                                   'Clear the USART RX interrupt flag
    EndIf

    Context Restore

I know my questions are unpleasant for members with experience, but you are the only ones who can help me. Even though I spent 2 weeks with this program, I am willing to lose another 2, but I can't do more!

Thank you all !

tumbleweed

QuoteGIE must be enable ?
Yes, INTCON.GIE must be set to enable interrupts along with INTCON.PEIE and PIE1.RCIE (usart rx)

Quote3. If data is 8E2 , I its necessary to set 9bit receiving ?
Yes. You should remove the 'Declare Hserial_Parity = Even' since it's not used

You can get rid of setting 'RC1IF = 0' in the ISR too since that bit is read-only (RCIF clears when you read RCREG)

I'll let others comment on your other questions since that's not how I'd handle the RX ISR.

trastikata

Quote from: midali on Nov 29, 2021, 02:42 PM1.  GIE must be enable ?
2. "Ready to receive" bit , UsartRx which bit is, from which register ?
3. If data is 8E2 , I its necessary to set 9bit receiving ?
4. I setup right the interrupt variables acording with datasheet?

1 - Yes
2 - "Ready to receive" bit is not a hardware bit, but an ordinary software bit variable. I am using it as a marker when the routine in the interrupt has finished receiving.
3 - Take a look here: https://forum.pjrc.com/threads/23956-Teensy-3-UART-settings?p=63136&viewfull=1#post63136
4 - Here's a list of registers you should be aware, those were taken from my program, so you'll have to check it for your device.
    TRISC.7 = 1 'PORTC.7 (Or other) as input
    TRISC.6 = 0 'PORTC.6 (Or other) as output
    RCSTA1.7 = 1 'SPEN: Serial port Enable bit
    RCSTA1.2 = 0 'FERR: Framing Error bit clear
    RCSTA1.1 = 0 'OERR: Overrun Error bit clear
    BAUDCON1.1 = 1 'WUE: Wake-up Enable bit
    BAUDCON1.3 = 1 '16-Bit Baud Rate Register Enable bit
    TXSTA1.2 = 0   'BRGH: High Baud Rate Select bit
    SPBRGH1 = 0   'EUSARTx Baud Rate Generator Register High Byte
    SPBRG1 = 25   'EUSARTx Baud Rate Generator Register Low Byte
    PEIE = 1      'Peripheral/Low-Priority Interrupt Enable bit
    RCON.7 = 0      'IPEN: Interrupt Priority Enable bit
    PIE1.5 = 1      'RC1IE: EUSART1 Receive Interrupt Enable bit
    RC1IF = 0    'Clear EUSART1 Receive Interrupt Flag bit
    RCSTA1.4 = 1  'Continuous Receive Enable bit - Enables receiver
    GIE = 1    'Enable Global Interrupts

joesaliba

I managed to decode the S-Bus. I cannot take credit for this one as I found some code on the internet and converted to PDS. Will post it once at my PC.

Regards

Joe

midali

I'm still working on S-bus decoding but I haven't succeeded yet, so a functional code would be welcome .

joesaliba

If you have SBus2 it might not work as the footer is different. If I find some spare time I will try to make it for SBus2, although I do not have Sbus2.

Here is the working code I have. Hope this will get you started: -

Device = 18F26K22

Xtal = 16

OSCCON = %01110010

'===================================================================================================

Dim Num_Ch          As 17           ' Constant used to assign number of channels

' Communication
Dim Buf_Len         As 25           ' Constant used for array buffer length
Dim TimeOut         As 5000         ' Constant used for serial timeout
Dim Header          As $0F          ' Constant used for header of message
Dim Footer          As $00          ' Constant used for footer of message; SBus
Dim Footer2         As $04          ' Constant used for footer of message; SBus2
Dim State           As Byte = 0     ' Variable used
Dim Ch17_Mask       As Byte = $01   ' Variable used to mask channel 17
Dim Ch18_Mask       As Byte = $02   ' Variable used to mask channel 18
Dim Lost_Frame_M    As Byte = $04   ' Variable used to mask lost frame
Dim Failsafe_M      As Byte = $08   ' Variable used to mask failsafe

' Parsing state tracking
Dim Prev_Byte       As Byte = Footer
Dim Cur_Byte        As Byte

' Buffer for storing messages
Dim Buff[Buf_Len]   As Word

' Data
Dim Ch[Num_Ch]      As Word = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Dim DG1             As Word
Dim DG2             As Word
Dim Temp1           As Word
Dim Temp2           As Word

Dim New_Data        As Bit = 0
Dim Failsafe        As Bit = 0
Dim Lost_Frame      As Bit = 0


Dim InData[25]  As Byte = 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
Dim Rx_byte     As Byte

Dim bIndex      As Byte

Dim bMyArray[10] As Byte = "Hello"      ' Load the first 5 bytes of the array

'===================================================================================================

Declare TRIS_REVERSE = On           ' Handle the Read, Modify, Write differently
Declare Dead_Code_Remove = 1        ' Remove dead code
Declare Optimiser_Level  = 2

Declare Hserial1_Baud = 100000
Declare Hserial2_Baud = 19200

Declare Hserial1_Clear   = On        ' Clear overflow automatically
Declare Hserial1_Parity Even

Declare Hserial2_Clear   = On        ' Clear overflow automatically

'===================================================================================================
'*********************
'* Set Pic registers *
'*********************
'>>>Analog, comparators etc..<<<

PMD0   = %00111111      '
PMD1   = %10011111      '
PMD2   = %00001110      ' Enable / disable peripheral modules
                        ' Bit 0 = ADC module
                        ' Bit 1 = Comparator 1 module
                        ' Bit 2 = Comparator 2 module
                        ' Bit 3 = CTMU module
                        ' Bit 4 - 7 = Unimplemented

VREFCON0 = %00000000    ' Turn OFF VREF
CTMUCONH = %00000000    ' Turn OFF CTMU

HLVDCON = %00000000     ' Turn OFF HLVD
CM1CON0 = %00000000     ' Turn OFF comparators
CM2CON0 = %00000000     ' Turn OFF comparators

ADCON0  = %00000000     ' Disable analog on startup and select analog pins
ADCON1  = %00000000     ' Select VREF; Connected to internal signal AVDD / AVSS
ADCON2  = %10000011     ' Select FRC and right justify analog result

TRISA   = %00000000     ' Configure PORTB I/O
TRISB   = %10000000     ' Configure PORTB I/O
TRISC   = %10000001     ' Configure PORTB I/O

WPUB    = %00000000     ' Disable PORTB pull-up

ANSELA  = %00000000     ' Set analog / digital ports
ANSELB  = %00000000     ' Set analog / digital ports
ANSELC  = %00000000     ' Set analog / digital ports

INTCON  = %00000000
INTCON2 = %10000000     ' Disable all PORTB pull-ups; Bit 7 = 1
IOCB    = %00000000     ' Turn OFF all Interrupt On Change on PORTB

LATA = 0                ' Turn OFF PORTA
PORTB = 0
PORTC = 0

PIR1 = %00000000
PIE1 = %00000000
PIE2 = %00000000

               '76543210
  RCSTA1     = %10010000 '%11010000 = 208; %10010000 = 144 ; Enable continuous receive
               '76543210
  RCSTA2     = %10010000 '%11010000 = 208; %10010000 = 144 ; Enable continuous receive

               '76543210
  TXSTA1     = %00100100
               '76543210
  TXSTA2     = %00100100

           '76543210
BAUDCON1 = %00100000 '(BAUDCON.5 = 1 is inverted; BAUDCON.5 = 0 is non-inverted)
           '76543210
BAUDCON2 = %00100000 '(BAUDCON.5 = 1 is inverted; BAUDCON.5 = 0 is non-inverted)

'===================================================================================================
'****************
'* Main routine *
'****************
'>>>Main routine<<<

Main:

RCSTA1.4 = 0
DelayMS 1
RCSTA1.4 = 1

Cur_Byte = 0
Prev_Byte = 0

Do

    HRSIn1 Cur_Byte

    If State = 0 Then
        If Cur_Byte = Header And Prev_Byte = Footer Then
            Buff[State] = Cur_Byte
            Inc State
        Else State = 0
        EndIf

    Else If State < Buf_Len Then
            Buff[State] = Cur_Byte
            Inc State
            Else State = 0
    EndIf

    Prev_Byte = Cur_Byte

Loop Until State = Buf_Len

' Goto data_1

parsedata()

DelayMS 1000

GoTo Main

'--------------------------------------------------------------------------------------------------

HRSOut2 " -- OK!... "

DelayMS 1000

GoTo Main

'===================================================================================================
'**************
'* Parse data *
'**************

Sub ParseData()                 ' Parse received data

' Parse received data

Ch[1] = Buff[1] | ((Buff[2] << 8) & $07FF)                          ' Channel 1

Ch[2] = (Buff[2] >> 3) | ((Buff[3] << 5) & $07FF)                   ' Channel 2

Ch[3] = (Buff[3] >> 6) | (Buff[4] << 2) | ((Buff[5] << 10) & $07FF) ' Channel 3

Ch[4] = (Buff[5] >> 1) | ((Buff[6] << 7) & $07FF)                   ' Channel 4

Ch[5] = (Buff[6] >> 4) | ((Buff[7] << 4) & $07FF)                   ' Channel 5

Ch[6] = (Buff[7] >> 7) | (Buff[8] << 1) | ((Buff[9] << 9) & $07FF)  ' Channel 6

Ch[7] = (Buff[9] >> 2) | ((Buff[10] << 6) & $07FF)                  ' Channel 7

Ch[8] = (Buff[10] >> 5) | ((Buff[11] << 3) & $07FF)                 ' Channel 8

'-----------------------------------------------------------------------------------

Ch[9] = Buff[12] | ((Buff[13] << 8) & $07FF)                        ' Channel 9

Ch[10] = (Buff[13] >> 3) | ((Buff[14] << 5) & $07FF)                ' Channel 10

Ch[11] = (Buff[14] >> 6) | (Buff[15] << 2) | ((Buff[16] << 10) & $07FF) ' Channel 11

Ch[12] = (Buff[16] >> 1) | ((Buff[17] << 7) & $07FF)                ' Channel 12

Ch[13] = (Buff[17] >> 4) | ((Buff[18] << 4) & $07FF)                ' Channel 13

Ch[14] = (Buff[18] >> 7) | (Buff[19] << 1) | ((Buff[20] << 9) & $07FF)  ' Channel 14

Ch[15] = (Buff[20] >> 2) | ((Buff[21] << 6) & $07FF)                ' Channel 15

Ch[16] = (Buff[21] >> 5) | ((Buff[22] << 3) & $07FF)                ' Channel 16

DG1 = 0
DG2 = 0

DG1 = Buff[23] & %0000001 * 2047
DG2 = (Buff[23] >> 1) & %0000001 * 2047



HRSOut2 "DG1 = " , Dec4 DG1 , " "
HRSOut2 "DG2 = " , Dec4 DG2

HRSOut2 " -- OK!... "
DelayMS 1000
EndSub

'===================================================================================================
'===================================================================================================
'**********************
'* Fuse Configuration *
'**********************

'---------------------------------------------------------------------------------------------------
'**** Added by Fuse Configurator ****
' Use the Fuses Tab to change these settings

Config_Start
  FOSC = INTIO67     ;Internal oscillator bloc
  PLLCFG = OFF       ;Oscillator used directl
  PRICLKEN = On      ;Primary clock enable
  FCMEN = OFF        ;Fail-Safe Clock Monitor disable
  IESO = OFF         ;Oscillator Switchover mode disable
  PWRTEN = On        ;Power up timer enable
  BOREN = OFF        ;Brown-out Reset disabled in hardware and softwar
  BORV = 190         ;VBOR set to 1.90 V nomina
  WDTEN = OFF        ;Watch dog timer is always disabled. SWDTEN has no effect
  WDTPS = 32768      ;1:3276
  CCP2MX = PORTC1    ;CCP2 input/output is multiplexed with RC
  PBADEN = OFF       ;PORTB<5:0> pins are configured as digital I/O on Rese
  CCP3MX = PORTB5    ;P3A/CCP3 input/output is multiplexed with RB
  HFOFST = OFF       ;HFINTOSC output and ready status are delayed by the oscillator stable statu
  T3CMX = PORTC0     ;T3CKI is on RC
  P2BMX = PORTB5     ;P2B is on RB
  MCLRE = INTMCLR    ;RE3 input pin enabled; MCLR disable
  STVREN = On        ;Stack full/underflow will cause Rese
  LVP = OFF          ;Single-Supply ICSP disable
  XINST = OFF        ;Instruction set extension and Indexed Addressing mode disabled (Legacy mode
  Debug = OFF        ;Disable
  Cp0 = OFF          ;Block 0 (000800-003FFFh) not code-protecte
  CP1 = OFF          ;Block 1 (004000-007FFFh) not code-protecte
  CP2 = OFF          ;Block 2 (008000-00BFFFh) not code-protecte
  CP3 = OFF          ;Block 3 (00C000-00FFFFh) not code-protecte
  CPB = OFF          ;Boot block (000000-0007FFh) not code-protecte
  CPD = OFF          ;Data EEPROM not code-protecte
  WRT0 = OFF         ;Block 0 (000800-003FFFh) not write-protecte
  WRT1 = OFF         ;Block 1 (004000-007FFFh) not write-protecte
  WRT2 = OFF         ;Block 2 (008000-00BFFFh) not write-protecte
  WRT3 = OFF         ;Block 3 (00C000-00FFFFh) not write-protecte
  WRTC = OFF         ;Configuration registers (300000-3000FFh) not write-protecte
  WRTB = OFF         ;Boot Block (000000-0007FFh) not write-protecte
  WRTD = OFF         ;Data EEPROM not write-protecte
  EBTR0 = OFF        ;Block 0 (000800-003FFFh) not protected from table reads executed in other block
  EBTR1 = OFF        ;Block 1 (004000-007FFFh) not protected from table reads executed in other block
  EBTR2 = OFF        ;Block 2 (008000-00BFFFh) not protected from table reads executed in other block
  EBTR3 = OFF        ;Block 3 (00C000-00FFFFh) not protected from table reads executed in other block
  EBTRB = OFF        ;Boot Block (000000-0007FFh) not protected from table reads executed in other block
Config_End

'**** End of Fuse Configurator Settings ****
'---------------------------------------------------------------------------------------------------
'===================================================================================================

tumbleweed

Note that Joe's code sets the UART to 8-bit mode with no parity ('Declare Hserial1_Parity Even' doesn't do anything).
so you're getting N81, not E82 format.

That will work for receiving chars, but since the receive parity bit (bit 9) is where the UART now expects the STOP bit,
you'll get framing errors if the SBUS transmitter sends a byte with the parity bit = 0.

A framing error won't stop you from receiving bytes (unlike what happens if the overrun error gets set), but it's something to be aware of.

If you try to transmit a byte using that format, the SBUS receiver on the other end might likely fail.

joesaliba

Tumbleweed,

Help me please. I changed the  RCSTA1.6 to 1, enabling the 9th bit receive.

To confirm my understanding using the 18F26K22, changing this bit, will it make the receiver 8E2?

If yes, I changed this bit and I continued receiving the data as it should.

Joe

tumbleweed

#34
Quotechanging this bit, will it make the receiver 8E2?
Not entirely, Joe, but when you set RX9 it'll add space for 8 data bits + receive parity bit (the ninth bit)
so you won't get framing errors on receive anymore.

The 8-bit pics don't really have a hardware parity function, so it ends up like this...
S = START bit
E = Even parity
P = STOP bit(s)

8E2 would look like:
S 12345678 E P P  (12 bit times)

8N1 looks like this:
S 12345678 P    (10 bit times)

When you set it to 9-bit mode, the state of the 9th (parity) bit can be read in the RCSTA.RX9D bit,
which you would have to read before reading RCREG.

You would then have to add code to compute the even/odd parity of the received data byte and compare that to the RX9D bit.
Or, you can just ignore the bit on receive if you don't care about trying to detect parity errors.

As far as the 2 STOP bits go, the pic UART will stop on the first one. Since a STOP bit looks just like the state of an idle line (typically HIGH unless you start inverting everything), the second STOP bit will just look like one bit time of extra delay between receiving the next byte... no harm, no foul.

This gets a little more complicated when trying to transmit 8E2, but I don't think you need to worry about that in this case.

joesaliba

Quote from: tumbleweed on Dec 10, 2021, 06:36 PMThis gets a little more complicated when trying to transmit 8E2, but I don't think you need to worry about that in this case.

Thanks tumbleweed for the detailed explanation.

In this case, no, I don't need to transmit in this case.

But as a general rule for 8-bit devices, because I intend to use some smaller 8-pin PIC's, it looks that it will be near impossible to send 8E2 if needs be.

For now I am ok receiving data to switch on the gadgets I do.

Regards

Joe

tumbleweed

#36
Quoteit looks that it will be near impossible to send 8E2 if needs be
It's not that bad, you just have to do things manually.

Here are the steps to transmit 8E2:

1. In the uart init routine set the uart to transmit 9 bits (TXSTA.TX9 = 1)

2. When you go to transmit a byte you must compute the desired parity on the data byte
prior to loading it into the TXREG. Write a routine to compute the parity (even or odd)
and set bit TXSTA.TX9D to 0/1 as appropriate, then load TXREG.

3. After loading TXREG, wait for the byte to finish transmitting ('while TXSTA.TRMT=0').
TRMT will go high half-way into the STOP bit. To 'generate' the remaining 1.5 STOP bits
you must wait at least an additional 1.5 bit times. At 100000 baud one bit time is
1/100000 = 10us, so you need at least 15us.
 During transmit additional stop bit times don't normally cause any issues, so you might just add a 20us delay

In psuedo-code it would look something like this:
sub SendByte(b as byte)
    ' wait for room in the TXREG (just to be safe)
    while PIRx.TXIF = 0: wend
   
    ' compute even parity and load TX9D
    TXSTA.TX9D = compute_even_parity(b)
   
    ' load data byte into TXREG
    TXREG = b
   
    ' allow time for the TSR to load
    NOP
   
    ' wait for byte to transmit
    while TXSTA.TRMT = 0: wend
   
    ' wait addtl 2 bit times (20us @ 100000)
    DelayUs 20
end sub

joesaliba

Thanks a lot tumbleweed. Certainly it would come handy when I need it.

Joe

tumbleweed

I corrected the bit timing in the post above... 100000 baud is 10us/bit, not 1us!

That's what I get for posting before the morning coffee kicks in.

midali

Hi to all !

Joesaliba , the code is working right for you ?
The reading data from serial is stable, not random , but the values readed are not right . For example , ch1=1062 , ch2 = 1035 , ch3 = 473 , ch4 = 936 . Values should be around 1500 .

Thanks a lot !