Some playing with ucontroller (arduino)

Share your advanced PureBasic knowledge/code with the community.
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Some playing with ucontroller (arduino)

Post by Psychophanta »

I am proud to share my first steps with RS232 communication with arduino via USB.
I will need to send and to receive data between pc and arduino in order to perform real time variable corrections, etc. to reach some bigger projects.
So, here it is the runnable code; the ucontroller part and the pc part.
(NOTICE: There is not mandatory to take a look to the microcontroller C code here, in order to test it, but it would be convenient:)

Code: Select all

CompilerIf 0
struct VectorInt16{int16_t x,y,z;};
struct DVectorInt16{VectorInt16 a,w;};
uint16_t disponible;
uint32_t baudios=115200;
struct recibido{byte ini[2];union {DVectorInt16 dato;float flotante[3];int32_t bit32[3];int16_t bit16[6];uint32_t ubit32[3];uint16_t ubit16[6];};}recibo;
void setup()
{
  // inicializar comunicacion serial
  Serial.begin(baudios);
  while (!Serial); // espera para la enumeracion en el Leonardo, en los demas continua de inmediato
}
void loop()
{
if (disponible=Serial.available()>0 && Serial.readBytes(recibo.ini,14)>=14)
  {
    if ('o'==recibo.ini[0] && 'k'==recibo.ini[1]) // <- verificar si llegó bloque completo de dato
    {
      digitalWrite(7,1);
      // enviar datos via RS232:
      Serial.write("ok");
      Serial.write((byte*)&recibo.dato,12);
      delay(10); // <- ajustar este valor de la espera es crítico para poder enviar y recibir valores
      digitalWrite(7,0);
    }
    else if ('b'==recibo.ini[0] && 'a'==recibo.ini[1]) // <- verificar si llegó baudios
    {
      while (Serial.available()&&Serial.read());Serial.flush(); // <- vaciar buffer
      Serial.end();
      baudios=recibo.ubit32[0];
      delay(60);
      setup();
    }
  }
  else if ('r'==recibo.ini[0] && 'e'==recibo.ini[1]) // <- reset
  {
    digitalWrite(13,1);
    while (Serial.available()&&Serial.read());Serial.flush(); // <- vaciar buffer
    Serial.end();
    delay(200)  ;
    recibo.ini[0]=0;
    digitalWrite(13,0);
    asm volatile ("  jmp 0");
  }
}
CompilerEndIf

Procedure.d EscalarRango(V.d,InputRangeL.d,InputRangeR.d,OutputRangeL.d,OutputRangeR.d)
  ;Interpola una variable V contenida dentro del rango no exponencial [InputRangeL,InputRangeR] hacia otro rango no exponencial [OutputRangeL,OutputRangeR]
  ;Util por ejemplo para barra de desplazamiento: TrackBarGadget()
  If V<InputRangeL:V=InputRangeL:EndIf
  If V>InputRangeR:V=InputRangeR:EndIf
  ProcedureReturn OutputRangeL+(V-InputRangeL)*((OutputRangeR-OutputRangeL)/(InputRangeR-InputRangeL))
EndProcedure

Structure VectorInt16
  x.w:y.w:z.w
EndStructure
Structure dVectorInt16
  a.VectorInt16
  w.VectorInt16
EndStructure

Enumeration gadgets
  #ventanagadgets
  #Menu
  #contenedor
  #cuadro
  #puerto
  #textosbarras
  #botonenviar1
  #botonenviar2
  #botonenviar3
  #s1
  #s1fino
  #s2
  #s2fino
  #s3
  #s3fino
  #e1
  #e2
  #e3
  #e4
  #e5
  #e6
  #s1min
  #s1texto
  #s1max
  #s2min
  #s2texto
  #s2max
  #s3min
  #s3texto
  #s3max
  #e1texto
  #e2texto
  #e3texto
  #e4texto
  #e5texto
  #e6texto
  #trackbarmax=10000
  #WindowWidth=800
  #WindowHeight=600
EndEnumeration
Global s1.d,s1min.d=-#trackbarmax/2,s1max.d=#trackbarmax/2,s2.d,s2min.d=-#trackbarmax/2,s2max.d=#trackbarmax/2,s3.d,s3min.d=-#trackbarmax/2,s3max.d=#trackbarmax/2
Global e1.d,e2.d,e3.d,e4.d,e5.d,e6.d,e1min.d=-32768,e1max.d=32767,e2min.d=-32768,e2max.d=32767,e3min.d=-32768,e3max.d=32767,e4min.d=-32768,e4max.d=32767,e5min.d=-32768,e5max.d=32767,e6min.d=-32768,e6max.d=32767

;/ **************** serial ****************
Enumeration RS232
  #serie
  #puertosCOM
  #baudios
EndEnumeration
Structure datosMPU6050
  asci.a[2]
  StructureUnion
    dato.DVectorInt16
    flotante.f[3]
    bit32.l[3]
    bit16.w[6]
    ubit32.l[3]
    ubit16.u[6]
  EndStructureUnion
EndStructure
Procedure.a EnumSerial(Array puertos.a(1))
  Protected i.a,c.a
  For i=1 To 255
    If QueryDosDevice_("COM"+Str(i),Space(128),128)
      Redim puertos(c):puertos(c)=i:c+1
    EndIf
  Next
  ProcedureReturn c
EndProcedure
Global Dim puertosRS232.a(0),npuertosserie.a=EnumSerial(puertosRS232())
If npuertosserie=0:MessageRequester("Error","No existen puertos RS232 disponibles"):End:EndIf
Global PuertoCOM$="",baudios.l
Global cantidad.q,leido.q; <- número de bytes reportados como disponibles para leer; número de bytes efectivamente leidos
#Nmuestra=79; <- número de muestras total (maximo 255)
Global nova.a
Global bloque.u=SizeOf(datosMPU6050); <- el bloque de datos recibidos desde el controlador por cada ciclo de programa de este
Global *baseserie.datosMPU6050=AllocateMemory(bloque*#Nmuestra,#PB_Memory_NoClear); la base de memoria donde se almacena una ristra de '#Nmuestra' bloques 
Global *lecturavalida.datosMPU6050; <- puntero usado para gestionar la llegada de bloques leidos
DataSection
  valoresbaudios:
  Data.l 300,1200,2400,4800,9600,19200,38400,57600,74880,115200,230400,250000,500000,1000000,2000000
EndDatasection
Procedure vaciarserial(puerto.a=0)
  Protected *nserie.byte,*serie.byte=AllocateMemory(10,#PB_Memory_NoClear)
  cantidad=AvailableSerialPortInput(puerto)
  While cantidad
    *nserie.byte=ReAllocateMemory(*serie.byte,cantidad,#PB_Memory_NoClear):*serie=*nserie
    ReadSerialPortData(puerto,*serie,cantidad)
    cantidad=AvailableSerialPortInput(puerto)
  Wend
  FreeMemory(*serie.byte)
  cantidad=0
EndProcedure
Procedure enviarserial(prefijo$="ok")
  If PuertoCOM$
    PokeS(*baseserie,prefijo$,2,#PB_Ascii)
                            if prefijo$="ok"
                            *baseserie\dato\a\x=2*s1:*baseserie\dato\a\y=2*s2:*baseserie\dato\a\z=2*s3
                            *baseserie\dato\w\x=4*s1:*baseserie\dato\w\y=4*s2:*baseserie\dato\w\z=4*s3
                            endif
    WriteSerialPortData(#serie,*baseserie,bloque)
    Delay(10)
  EndIf
EndProcedure
Procedure.l recibirserial()
  *lecturavalida=0
  cantidad=AvailableSerialPortInput(#serie)
  If cantidad=0
    ;sonido(39,99997)
    nova+1
    If nova>200:nova=0:CloseSerialPort(#serie):delay(100)
      OpenSerialPort(#serie,PuertoCOM$,baudios,#PB_SerialPort_NoParity,8,0,#PB_SerialPort_NoHandshake,1024,8)
    EndIf
    ;WriteSerialPortData(#serie,@"0",1)
    ProcedureReturn 0
  ElseIf cantidad>bloque*#Nmuestra; <- buffer rebosado: sin lectura
    ;sonido(89,10000)
    vaciarserial(#serie):ProcedureReturn -2
  ElseIf cantidad<>ReadSerialPortData(#serie,*baseserie,cantidad); <- error leyendo buffer
    ;sonido(229,77777)
    vaciarserial(#serie):ProcedureReturn -1
  Else
    *lecturavalida=*baseserie
    While *lecturavalida+bloque<=*baseserie+cantidad
      If PeekS(*lecturavalida,2,#PB_Ascii)="ok"
        ProcedureReturn cantidad
      EndIf
      *lecturavalida+1
    Wend 
    *lecturavalida=0
    ;sonido(219,1077)
    ;WriteSerialPortData(#serie,@"+",1)
    ProcedureReturn -3; <- sin lectura
  EndIf
EndProcedure
;\ *******************************************
Procedure gachetos(x.u=20,y.u=20)
  Protected gx.u=x+20,gy.u=y,sx.u,an.u=#WindowWidth*3/80,al.u=#WindowHeight*3/4
  OpenWindow(#ventanagadgets,x,y,#WindowWidth,#WindowHeight,"",#PB_Window_SystemMenu|#PB_Window_BorderLess|#PB_Window_SizeGadget|#PB_Window_ScreenCentered)
  CreateMenu(#Menu,WindowID(#ventanagadgets))
  MenuTitle("Comportamiento botones de envio")
  MenuItem(1,"Mantener enviando valor 1")
  MenuItem(2,"Mantener enviando valor 2")
  MenuItem(3,"Mantener enviando valor 3")
  MenuItem(4,"Resetear uControlador")
  FrameGadget(#cuadro,10,4,#WindowWidth-20,#WindowHeight-10,"Ajustar calibrado de motor")
  ;ScrollAreaGadget(#contenedor,gx+20,gy+40,#WindowWidth,#WindowHeight,#WindowWidth,#WindowHeight,10,#PB_ScrollArea_Flat)
  TextGadget(#puerto,x,gy+4,80,20,"Puerto RS232:")
  TextGadget(#textosbarras,gx+20,gy+36,#WindowWidth-20,20,"  s1     s1f                           s2     s2f                           s3    s3f                                 e1            e2             e3             e4             e5            e6")
  ComboBoxGadget(#puertosCOM,gx+60,gy,80,25):GadgetToolTip(#puertosCOM,"Puertos RS232 disponibles"); puerto COM
  For s.a=0 To npuertosserie-1:AddGadgetItem(#puertosCOM,s,"COM"+Str(puertosRS232(s))):Next
  ComboBoxGadget(#baudios,gx+140,gy,90,25); baudios
  baudios.l=PeekL(?valoresbaudios+GetGadgetState(#baudios)*SizeOf(Long))
  For s=1 To 15:Read.l a.l:AddGadgetItem(#baudios,-1,Str(a)+" baudio"):Next
  TrackBarGadget(#s1,gx+20,gy+50,an,al,0,#trackbarmax,#PB_TrackBar_Ticks|#PB_TrackBar_Vertical):GadgetToolTip(#s1,"dato 1 de salida")
  StringGadget(#s1texto,gx,gy+500,90,20,Str(GetGadgetState(#s1)),#PB_String_UpperCase|#PB_Text_Center):GadgetToolTip(#s1texto,"dato 1 de salida")
  ButtonGadget(#botonenviar1,gx,gy+540,90,20,"enviar 1",#PB_Button_Toggle):GadgetToolTip(#botonenviar1,"Pulsar para enviar dato 1")
  StringGadget(#s1min,gx-10,gy+520,54,20,Str(0),#PB_String_UpperCase|#PB_String_BorderLess|#PB_Text_Center):SetGadgetColor(#s1min,#PB_Gadget_BackColor,$456789):GadgetToolTip(#s1min,"Valor mínimo")
  StringGadget(#s1max,gx+48,gy+520,54,20,Str(#trackbarmax),#PB_String_UpperCase|#PB_String_BorderLess|#PB_Text_Center):SetGadgetColor(#s1max,#PB_Gadget_BackColor,$456789):GadgetToolTip(#s1max,"Valor máximo")
  TrackBarGadget(#s1fino,gx+50,gy+50,an*2/3,al,0,#trackbarmax,#PB_TrackBar_Ticks|#PB_TrackBar_Vertical):SetGadgetState(#s1fino,(#trackbarmax-0)/2):GadgetToolTip(#s1fino,"salida 1 ajuste fino")
  TrackBarGadget(#s2,gx+140,gy+50,an,al,0,#trackbarmax,#PB_TrackBar_Ticks|#PB_TrackBar_Vertical):GadgetToolTip(#s2,"dato 2 de salida")
  StringGadget(#s2texto,gx+120,gy+500,90,20,Str(GetGadgetState(#s2)),#PB_String_UpperCase|#PB_Text_Center):GadgetToolTip(#s2texto,"dato 2 de salida")
  ButtonGadget(#botonenviar2,gx+120,gy+540,90,20,"enviar 2",#PB_Button_Toggle):GadgetToolTip(#botonenviar2,"Pulsar para enviar")
  StringGadget(#s2min,gx+110,gy+520,54,20,Str(0),#PB_String_UpperCase|#PB_String_BorderLess|#PB_Text_Center):SetGadgetColor(#s2min,#PB_Gadget_BackColor,$456789):GadgetToolTip(#s2min,"Valor mínimo")
  StringGadget(#s2max,gx+168,gy+520,54,20,Str(#trackbarmax),#PB_String_UpperCase|#PB_String_BorderLess|#PB_Text_Center):SetGadgetColor(#s2max,#PB_Gadget_BackColor,$456789):GadgetToolTip(#s2max,"Valor máximo")
  TrackBarGadget(#s2fino,gx+170,gy+50,an*2/3,al,0,#trackbarmax,#PB_TrackBar_Ticks|#PB_TrackBar_Vertical):SetGadgetState(#s2fino,(#trackbarmax-0)/2):GadgetToolTip(#s2fino,"salida 2 ajuste fino")
  TrackBarGadget(#s3,gx+260,gy+50,an,al,0,#trackbarmax,#PB_TrackBar_Ticks|#PB_TrackBar_Vertical):GadgetToolTip(#s3,"dato 3 de salida")
  StringGadget(#s3texto,gx+240,gy+500,90,20,Str(GetGadgetState(#s3)),#PB_String_UpperCase|#PB_Text_Center):GadgetToolTip(#s3texto,"dato 3 de salida")
  ButtonGadget(#botonenviar3,gx+240,gy+540,90,20,"enviar 3",#PB_Button_Toggle):GadgetToolTip(#botonenviar3,"Pulsar para enviar")
  StringGadget(#s3min,gx+230,gy+520,54,20,Str(0),#PB_String_UpperCase|#PB_String_BorderLess|#PB_Text_Center):SetGadgetColor(#s3min,#PB_Gadget_BackColor,$456789):GadgetToolTip(#s3min,"Valor mínimo")
  StringGadget(#s3max,gx+288,gy+520,54,20,Str(#trackbarmax),#PB_String_UpperCase|#PB_String_BorderLess|#PB_Text_Center):SetGadgetColor(#s3max,#PB_Gadget_BackColor,$456789):GadgetToolTip(#s3max,"Valor máximo")
  TrackBarGadget(#s3fino,gx+290,gy+50,an*2/3,al,0,#trackbarmax,#PB_TrackBar_Ticks|#PB_TrackBar_Vertical):SetGadgetState(#s3fino,(#trackbarmax-0)/2):GadgetToolTip(#s3fino,"salida 3 ajuste fino")
  TrackBarGadget(#e1,gx+400,gy+50,an,al,0,#trackbarmax,#PB_TrackBar_Ticks|#PB_TrackBar_Vertical):GadgetToolTip(#e1,"entrada 1")
  StringGadget(#e1texto,gx+380,gy+500,64,20,Str(GetGadgetState(#e1)),#PB_String_UpperCase|#PB_String_BorderLess|#PB_Text_Center)
  TrackBarGadget(#e2,gx+450,gy+50,an,al,0,#trackbarmax,#PB_TrackBar_Ticks|#PB_TrackBar_Vertical):GadgetToolTip(#e2,"entrada 2")
  StringGadget(#e2texto,gx+430,gy+500,64,20,Str(GetGadgetState(#e2)),#PB_String_UpperCase|#PB_String_BorderLess|#PB_Text_Center)
  TrackBarGadget(#e3,gx+500,gy+50,an,al,0,#trackbarmax,#PB_TrackBar_Ticks|#PB_TrackBar_Vertical):GadgetToolTip(#e3,"entrada 3")
  StringGadget(#e3texto,gx+480,gy+500,64,20,Str(GetGadgetState(#e3)),#PB_String_UpperCase|#PB_String_BorderLess|#PB_Text_Center)
  TrackBarGadget(#e4,gx+550,gy+50,an,al,0,#trackbarmax,#PB_TrackBar_Ticks|#PB_TrackBar_Vertical):GadgetToolTip(#e4,"entrada 4")
  StringGadget(#e4texto,gx+530,gy+500,64,20,Str(GetGadgetState(#e4)),#PB_String_UpperCase|#PB_String_BorderLess|#PB_Text_Center)
  TrackBarGadget(#e5,gx+600,gy+50,an,al,0,#trackbarmax,#PB_TrackBar_Ticks|#PB_TrackBar_Vertical):GadgetToolTip(#e5,"entrada 5")
  StringGadget(#e5texto,gx+580,gy+500,64,20,Str(GetGadgetState(#e5)),#PB_String_UpperCase|#PB_String_BorderLess|#PB_Text_Center)
  TrackBarGadget(#e6,gx+650,gy+50,an,al,0,#trackbarmax,#PB_TrackBar_Ticks|#PB_TrackBar_Vertical):GadgetToolTip(#e6,"entrada 6")
  StringGadget(#e6texto,gx+630,gy+500,64,20,Str(GetGadgetState(#e6)),#PB_String_UpperCase|#PB_String_BorderLess|#PB_Text_Center)
  SetGadgetState(#s1,EscalarRango(s1,s1min,s1max,0,#trackbarmax)):SetGadgetText(#s1texto,StrD(s1,6)):SetGadgetText(#s1min,StrD(s1min,4)):SetGadgetText(#s1max,StrD(s1max,4))
  SetGadgetState(#s2,EscalarRango(s2,s2min,s2max,0,#trackbarmax)):SetGadgetText(#s2texto,StrD(s2,6)):SetGadgetText(#s2min,StrD(s2min,4)):SetGadgetText(#s2max,StrD(s2max,4))
  SetGadgetState(#s3,EscalarRango(s3,s3min,s3max,0,#trackbarmax)):SetGadgetText(#s3texto,StrD(s3,6)):SetGadgetText(#s3min,StrD(s3min,4)):SetGadgetText(#s3max,StrD(s3max,4))
  SetGadgetState(#e1,EscalarRango(e1,e1min,e1max,0,#trackbarmax)):SetGadgetText(#e1texto,StrD(e1,4))
  SetGadgetState(#e2,EscalarRango(e2,e2min,e2max,0,#trackbarmax)):SetGadgetText(#e2texto,StrD(e2,4))
  SetGadgetState(#e3,EscalarRango(e3,e3min,e3max,0,#trackbarmax)):SetGadgetText(#e3texto,StrD(e3,4))
  SetGadgetState(#e4,EscalarRango(e4,e4min,e4max,0,#trackbarmax)):SetGadgetText(#e4texto,StrD(e4,4))
  SetGadgetState(#e5,EscalarRango(e5,e5min,e5max,0,#trackbarmax)):SetGadgetText(#e5texto,StrD(e5,4))
  SetGadgetState(#e6,EscalarRango(e6,e6min,e6max,0,#trackbarmax)):SetGadgetText(#e6texto,StrD(e6,4))
  DisableGadget(#e1,1):DisableGadget(#e2,1):DisableGadget(#e3,1):DisableGadget(#e4,1):DisableGadget(#e5,1):DisableGadget(#e6,1)
  DisableGadget(#e1texto,1):DisableGadget(#e2texto,1):DisableGadget(#e3texto,1):DisableGadget(#e4texto,1):DisableGadget(#e5texto,1):DisableGadget(#e6texto,1)
EndProcedure
gachetos()
baudios=115200:SetGadgetState(#baudios,9); <- 115200 baudios
Repeat
  If #ventanagadgets=EventWindow()
    evento=WaitWindowEvent()
    et.i=EventType()
    Select evento
    Case #PB_Event_CloseWindow:End
    Case #PB_Event_Menu
      Select EventMenu()
      Case 1:SetMenuItemState(#Menu,1,GetMenuItemState(#Menu,1)!1):SetGadgetState(#botonenviar1,GetMenuItemState(#Menu,1))
      Case 2:SetMenuItemState(#Menu,2,GetMenuItemState(#Menu,2)!1):SetGadgetState(#botonenviar2,GetMenuItemState(#Menu,2))
      Case 3:SetMenuItemState(#Menu,3,GetMenuItemState(#Menu,3)!1):SetGadgetState(#botonenviar3,GetMenuItemState(#Menu,3))
      Case 4
        baudios=115200:SetGadgetState(#baudios,9); <- 115200 baudios
        PuertoCOM$=GetGadgetText(#puertosCOM)
        If PuertoCOM$
          If IsSerialPort(#serie)
            enviarserial("re")
            Delay(140)
            ; enviar dato de baudios nuevos
            *baseserie\ubit32[0]=baudios
            enviarserial("ba")
            While IsSerialPort(#serie)
              vaciarserial(#serie)
              CloseSerialPort(#serie)
            Wend
            Delay(10)
          EndIf
          Delay(50)
          If OpenSerialPort(#serie,PuertoCOM$,baudios,#PB_SerialPort_NoParity,8,0,#PB_SerialPort_NoHandshake,1024,8)
            SetGadgetText(#cuadro,"Probando a través del puerto "+PuertoCOM$+" a "+Str(baudios)+" baudios")
            vaciarserial(#serie)
          Else
            SetGadgetText(#cuadro,"No puede abrirse el puerto "+PuertoCOM$)
          EndIf
        EndIf
      EndSelect
    Case #PB_Event_Gadget
      eg.i=EventGadget()
      Select eg
      Case #baudios,#puertosCOM
        baudios.l=PeekL(?valoresbaudios+GetGadgetState(#baudios)*SizeOf(Long))
        PuertoCOM$=GetGadgetText(#puertosCOM)
        If PuertoCOM$
          If IsSerialPort(#serie)
            Delay(40)
            ; enviar dato de baudios nuevos
            *baseserie\ubit32[0]=baudios
            enviarserial("ba")
            While IsSerialPort(#serie)
              vaciarserial(#serie)
              CloseSerialPort(#serie)
            Wend
            Delay(10)
          EndIf
          Delay(50)
          If OpenSerialPort(#serie,PuertoCOM$,baudios,#PB_SerialPort_NoParity,8,0,#PB_SerialPort_NoHandshake,1024,8)
            SetGadgetText(#cuadro,"Ajustar calibrado de motor a través del puerto "+PuertoCOM$+" a "+Str(baudios)+" baudios")
            vaciarserial(#serie)
          Else
            SetGadgetText(#cuadro,"No puede abrirse el puerto "+PuertoCOM$)
          EndIf
        EndIf
      Case #s1
        s1=EscalarRango(GetGadgetState(#s1),0,#trackbarmax,s1min,s1max)
        GadgetToolTip(#s1,StrD(s1,6)):SetGadgetText(#s1texto,StrD(s1,4))
      Case #s1fino
        Repeat
          evento=WaitWindowEvent(100)
          ; usar aqui #WM_LBUTTONDOWN y #WM_LBUTTONUP
          valor.d=GetGadgetState(#s1fino)/#trackbarmax-0.5
          GadgetToolTip(#s1fino,StrD(valor,6))
          s1+valor*(s1max-s1min)/#trackbarmax/3
          If s1>s1max:s1=s1max:ElseIf s1<s1min:s1=s1min:EndIf
          SetGadgetText(#s1texto,StrD(s1,4))
          SetGadgetState(#s1,EscalarRango(s1,s1min,s1max,0,#trackbarmax))
          GadgetToolTip(#s1,StrD(s1,6))
        Until evento<>#PB_Event_GadgetDrop Or evento<>#PB_Event_LeftClick Or evento<>#PB_Event_Gadget Or evento<>#PB_Event_WindowDrop
        evento=WaitWindowEvent()
        If evento<>#PB_Event_Gadget:SetGadgetState(#s1fino,#trackbarmax/2):EndIf
      Case #botonenviar1
        If GetGadgetState(#botonenviar1):enviarserial():EndIf
        If GetMenuItemState(#Menu,1)=0
          SetGadgetState(#botonenviar1,0)
        EndIf
      Case #s2
        s2=EscalarRango(GetGadgetState(#s2),0,#trackbarmax,s2min,s2max)
        GadgetToolTip(#s2,StrD(s2,6)):SetGadgetText(#s2texto,StrD(s2,4))
      Case #s2fino
        Repeat
          evento=WaitWindowEvent(100)
          valor.d=GetGadgetState(#s2fino)/#trackbarmax-0.5
          GadgetToolTip(#s2fino,StrD(valor,6))
          s2+valor*(s2max-s2min)/#trackbarmax/3
          If s2>s2max:s2=s2max:ElseIf s2<s2min:s2=s2min:EndIf
          SetGadgetText(#s2texto,StrD(s2,4))
          SetGadgetState(#s2,EscalarRango(s2,s2min,s2max,0,#trackbarmax))
          GadgetToolTip(#s2,StrD(s2,6))
        Until evento<>#PB_Event_GadgetDrop Or evento<>#PB_Event_LeftClick Or evento<>#PB_Event_Gadget Or evento<>#PB_Event_WindowDrop
        evento=WaitWindowEvent()
        If evento<>#PB_Event_Gadget:SetGadgetState(#s2fino,#trackbarmax/2):EndIf
      Case #botonenviar2
        If GetGadgetState(#botonenviar2):enviarserial():EndIf
        If GetMenuItemState(#Menu,2)=0
          SetGadgetState(#botonenviar2,0)
        EndIf
      Case #s3
        s3=EscalarRango(GetGadgetState(#s3),0,#trackbarmax,s3min,s3max)
        GadgetToolTip(#s3,StrD(s3,6)):SetGadgetText(#s3texto,StrD(s3,4))
      Case #s3fino
        Repeat
          evento=WaitWindowEvent(100)
          valor.d=GetGadgetState(#s3fino)/#trackbarmax-0.5
          GadgetToolTip(#s3fino,StrD(valor,6))
          s3+valor*(s3max-s3min)/#trackbarmax/3
          If s3>s3max:s3=s3max:ElseIf s3<s3min:s3=s3min:EndIf
          SetGadgetText(#s3texto,StrD(s3,4))
          SetGadgetState(#s3,EscalarRango(s3,s3min,s3max,0,#trackbarmax))
          GadgetToolTip(#s3,StrD(s3,6))
        Until evento<>#PB_Event_GadgetDrop Or evento<>#PB_Event_LeftClick Or evento<>#PB_Event_Gadget Or evento<>#PB_Event_WindowDrop
        evento=WaitWindowEvent()
        If evento<>#PB_Event_Gadget:SetGadgetState(#s3fino,#trackbarmax/2):EndIf
      Case #botonenviar3
        If GetGadgetState(#botonenviar3):enviarserial():EndIf
        If GetMenuItemState(#Menu,3)=0
          SetGadgetState(#botonenviar3,0)
        EndIf
      Case #s1min
        s1min=ValD(GetGadgetText(#s1min))
        If s1min>s1max:s1min=s1max:SetGadgetText(#s1min,StrD(s1min,4)):EndIf
        If s1min>s1:s1=s1min:EndIf
        SetGadgetState(#s1,EscalarRango(s1,s1min,s1max,0,#trackbarmax))
        SetGadgetText(#s1texto,StrD(s1,4))
      Case #s1texto
;                               valor$=UCase(GetGadgetText(#s1texto))
;                               s.a=1
;                               While s<=Len(valor$)
;                                 v.a=Asc(Mid(valor$,s,1))
;                                 While v='.' Or v='E' Or v='-' Or (v>='0' And v<='9')
;                                   s.a+1
;                                   v.a=Asc(Mid(valor$,s,1))
;                                 Wend
;                                 valor$=RemoveString(valor$,Mid(valor$,s,1))
;                               Wend
;                               SetGadgetText(#s1texto,valor$)
        s1=ValD(GetGadgetText(#s1texto))
        If s1>s1max:s1=s1max:SetGadgetText(#s1texto,StrD(s1,4))
        ElseIf s1<s1min:s1=s1min:SetGadgetText(#s1texto,StrD(s1,4))
        EndIf
        SetGadgetState(#s1,EscalarRango(s1,s1min,s1max,0,#trackbarmax))
      Case #s1max
        s1max=ValD(GetGadgetText(#s1max))
        If s1max<s1min:s1max=s1min:SetGadgetText(#s1max,StrD(s1max,4)):EndIf
        If s1max<s1:s1=s1max:EndIf
        SetGadgetState(#s1,EscalarRango(s1,s1min,s1max,0,#trackbarmax))
        SetGadgetText(#s1texto,StrD(s1,4))
      Case #s2min
        s2min=ValD(GetGadgetText(#s2min))
        If s2min>s2max:s2min=s2max:SetGadgetText(#s2min,StrD(s2min,4)):EndIf
        If s2min>s2:s2=s2min:EndIf
        SetGadgetState(#s2,EscalarRango(s2,s2min,s2max,0,#trackbarmax))
        SetGadgetText(#s2texto,StrD(s2,4))
      Case #s2texto
        s2=ValD(GetGadgetText(#s2texto))
        If s2>s2max:s2=s2max:SetGadgetText(#s2texto,StrD(s2,4))
        ElseIf s2<s2min:s2=s2min:SetGadgetText(#s2texto,StrD(s2,4))
        EndIf
        SetGadgetState(#s2,EscalarRango(s2,s2min,s2max,0,#trackbarmax))
      Case #s2max
        s2max=ValD(GetGadgetText(#s2max))
        If s2max<s2min:s2max=s2min:SetGadgetText(#s2max,StrD(s2max,4)):EndIf
        If s2max<s2:s2=s2max:EndIf
        SetGadgetState(#s2,EscalarRango(s2,s2min,s2max,0,#trackbarmax))
        SetGadgetText(#s2texto,StrD(s2,4))
      Case #s3min
        s3min=ValD(GetGadgetText(#s3min))
        If s3min>s3max:s3min=s3max:SetGadgetText(#s3min,StrD(s3min,4)):EndIf
        If s3min>s3:s3=s3min:EndIf
        SetGadgetState(#s3,EscalarRango(s3,s3min,s3max,0,#trackbarmax))
        SetGadgetText(#s3texto,StrD(s3,4))
      Case #s3texto
        s3=ValD(GetGadgetText(#s3texto))
        If s3>s3max:s3=s3max:SetGadgetText(#s3texto,StrD(s3,4))
        ElseIf s3<s3min:s3=s3min:SetGadgetText(#s3texto,StrD(s3,4))
        EndIf
        SetGadgetState(#s3,EscalarRango(s3,s3min,s3max,0,#trackbarmax))
      Case #s3max
        s3max=ValD(GetGadgetText(#s3max))
        If s3max<s3min:s3max=s3min:SetGadgetText(#s3max,StrD(s3max,4)):EndIf
        If s3max<s3:s3=s3max:EndIf
        SetGadgetState(#s3,EscalarRango(s3,s3min,s3max,0,#trackbarmax))
        SetGadgetText(#s3texto,StrD(s3,4))
      Case #contenedor
        ;If et=#PB_EventType_Resize:EndIf
      EndSelect
      If GetGadgetState(#botonenviar1) Or GetGadgetState(#botonenviar2) Or GetGadgetState(#botonenviar3)
        enviarserial()
      EndIf
      ;
      If PuertoCOM$
        recibirserial()
        If *lecturavalida
          e1=*lecturavalida\dato\a\x:e2=*lecturavalida\dato\a\y:e3=*lecturavalida\dato\a\z:e4=*lecturavalida\dato\w\x:e5=*lecturavalida\dato\w\y:e6=*lecturavalida\dato\w\z
          SetGadgetState(#e1,EscalarRango(e1,e1min,e1max,0,#trackbarmax)):GadgetToolTip(#e1,StrD(e1,6)):SetGadgetText(#e1texto,StrD(e1,4))
          SetGadgetState(#e2,EscalarRango(e2,e2min,e2max,0,#trackbarmax)):GadgetToolTip(#e2,StrD(e2,6)):SetGadgetText(#e2texto,StrD(e2,4))
          SetGadgetState(#e3,EscalarRango(e3,e3min,e3max,0,#trackbarmax)):GadgetToolTip(#e3,StrD(e3,6)):SetGadgetText(#e3texto,StrD(e3,4))
          SetGadgetState(#e4,EscalarRango(e4,e4min,e4max,0,#trackbarmax)):GadgetToolTip(#e4,StrD(e4,6)):SetGadgetText(#e4texto,StrD(e4,4))
          SetGadgetState(#e5,EscalarRango(e5,e5min,e5max,0,#trackbarmax)):GadgetToolTip(#e5,StrD(e5,6)):SetGadgetText(#e5texto,StrD(e5,4))
          SetGadgetState(#e6,EscalarRango(e6,e6min,e6max,0,#trackbarmax)):GadgetToolTip(#e6,StrD(e6,6)):SetGadgetText(#e6texto,StrD(e6,4))
        EndIf
      EndIf
    EndSelect
  EndIf
ForEver
Last edited by Psychophanta on Sat Apr 16, 2022 7:56 pm, edited 1 time in total.
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
User avatar
HeX0R
Addict
Addict
Posts: 1187
Joined: Mon Sep 20, 2004 7:12 am
Location: Hell

Re: Some playing with ucontroller (arduino)

Post by HeX0R »

Com Ports doesn't necessarily start with "COM", e.g. virtual com ports, or com port bridges do have usually different names.
You might better use this to retrieve all available ports.

I might take a deeper look at this, when I finally re-find my arduino :shock:
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Re: Some playing with ucontroller (arduino)

Post by Psychophanta »

HeX0R wrote: Sat Apr 16, 2022 6:29 pm Com Ports doesn't necessarily start with "COM", e.g. virtual com ports, or com port bridges do have usually different names.
You might better use this to retrieve all available ports.

I might take a deeper look at this, when I finally re-find my arduino :shock:
Thank you.
I am improving. and I what also it to be crossplatform :)
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Some playing with ucontroller (arduino)

Post by infratec »

After a short look and a search after the word Thread,
I can say:

A serial communication window program without Thread can not be reliable.

You should definately create a communication thread which handles the complete communication.
Else you can run in lost bytes or timeouts or no realtime.
Especially if you use higher baudrates.
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Some playing with ucontroller (arduino)

Post by infratec »

If you want to be crossplatform you need an extended routine to set baudrates higher then the old standard 115200.

This works in linux and macOS:

https://www.purebasic.fr/english/viewto ... 03#p581103
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Re: Some playing with ucontroller (arduino)

Post by Psychophanta »

Thanks @infratec
To me, the serial communication is a hard pain, :|
will take a look to improve...
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Re: Some playing with ucontroller (arduino)

Post by Psychophanta »

Another one.
This one is for testing motors which work in a RC style, this is, those kind of motors are controlled via some microseconds pulses separated by 20 milliseconds (look at the 'servo' library in the arduino reference and/or RC motors specification).
This tip runs directly (no modification needs at all) after you connect motor/s correctly and after loading the program to the microcontroller.

Code: Select all

; _____*  Programa para arduino para probar motores mediante el protocolo de control clásico RC *_____
CompilerIf 0
#include <Servo.h>
Servo servo0,servo1;
int datuno,dat0uno; // <- entero para contener el dato de interes que entra
float datdos,dat0dos; // <- flotante para contener el dato de interes que entra
uint32_t datbau=115200,dat0bau=115200; // <- se pone 115200, pero depende del proyecto en cuestion
#define cadenalen 100
String cadena=""; // <- cadena para contener los datos que entran
String ini="ini"; // <- cadena para identificar el inicio de los datos que entran
String fin="fin"; // <- cadena para identificar el final de los datos que entran
String bau="bau"; // <- cadena para identificar baudios
String uno="uno"; // <- cadena para identificar variable uno
String dos="dos"; // <- cadena para identificar variable dos

bool cadenacompleta=false;  // whether the string is complete
void setup()
{
  cadena.reserve(cadenalen);
  // inicializar comunicacion serial
  Serial.begin(datbau);
  while (!Serial); // espera para la enumeracion en el Leonardo, en los demas continua de inmediato
  while (Serial.available()&&Serial.read());Serial.flush(); // <- vaciar buffer
  delay(40);
  servo0.attach(10); // <- enganchar Servo0: marrón o negro -> masa, rojo -> 5v, amarillo o naranja o blanco -> D10, D5, D6... elige el que quieras
  servo1.attach(11); // <- enganchar Servo1: marrón o negro -> masa, rojo -> 5v, amarillo o naranja o blanco -> D10, D5, D6... elige el que quieras
  servo0.write(90) ;
  servo1.write(90);
}
void loop()
{
  if (Serial.available()>0)
  {
    char inChar=(char)Serial.read();
    (cadena.length()>=cadenalen)?cadena=(String)inChar:cadena+=(String)inChar;
    if (cadena.indexOf(ini,0)>=0 && cadena.endsWith(fin))
    {
      cadena.remove(cadena.indexOf(fin,0),fin.length());
      cadena.remove(0,cadena.indexOf(ini,0)+ini.length());
      if (cadena.indexOf(uno,0)==0)
      {
        cadena.remove(0,cadena.indexOf(uno,0)+uno.length());
        dat0uno=cadena.toInt();
        if (dat0uno!=datuno)
        {
          datuno=dat0uno;
          servo0.writeMicroseconds(datuno);
          Serial.print(datuno);Serial.println(" microsegundos");
          Serial.flush();
        }
      }
      else if (cadena.indexOf(dos,0)==0)
      {
        cadena.remove(0,cadena.indexOf(dos,0)+dos.length());
        dat0dos=cadena.toFloat();
        if (dat0dos!=datdos)
        {
          datdos=dat0dos;
          servo1.write(datdos);
          Serial.print(datdos);Serial.println(" grados");
          Serial.flush();
        }
      }
      else if (cadena.indexOf(bau,0)==0)
      {
        cadena.remove(0,cadena.indexOf(bau,0)+bau.length());
        dat0bau=cadena.toInt();
        if (dat0bau!=datbau)
        {
          datbau=dat0bau;
          while (Serial.available()&&Serial.read());Serial.flush(); // <- vaciar buffer
          Serial.end();
          delay(40);
          Serial.begin(datbau);
          while (!Serial); // espera para la enumeracion en el Leonardo, en los demas continua de inmediato
          Serial.print("baudios: ");Serial.println(datbau);
          delay(40);
          Serial.flush();
        }
      }
      cadena="";
    }
  }
  //delay(10);
}
CompilerEndIf

Procedure.a EnumSerial(List puertos$())
  Protected i.a
  For i=1 To 255
    If QueryDosDevice_("COM"+Str(i),Space(128),128)
      AddElement(puertos$()):puertos$()="COM"+Str(i)
    EndIf
  Next
  ProcedureReturn ListSize(puertos$())
EndProcedure
Procedure vaciarserial(puerto.a=0)
  Protected *nserie.byte,*serie.byte=AllocateMemory(10,#PB_Memory_NoClear)
  cantidad=AvailableSerialPortInput(puerto)
  While cantidad
    *nserie.byte=ReAllocateMemory(*serie.byte,cantidad,#PB_Memory_NoClear):*serie=*nserie
    ReadSerialPortData(puerto,*serie,cantidad)
    cantidad=AvailableSerialPortInput(puerto)
  Wend
  FreeMemory(*serie.byte)
  cantidad=0
EndProcedure

Global NewList puertosRS232$()
If EnumSerial(puertosRS232$())=0:MessageRequester("Error","No existen puertos RS232 disponibles"):End:EndIf
Global PuertoCOM$="",baudios.l
Global cantidad.q; <- número de bytes reportados como disponibles para leer
DataSection
  valoresbaudios:
  Data.l 300,1200,2400,4800,9600,19200,38400,57600,74880,115200,230400,250000,500000,1000000,2000000
EndDatasection

Enumeration
  #ventana
  #cuadro
  #valor
  #valor2
  #botonmotor1
  #botonmotor2
  #puertosCOM
  #baudios
  #deslizador
  #deslizador2
  #serie=0
  #WindowWidth=390
  #WindowHeight=130
EndEnumeration
Global bloque.u=1,leido.q,cantidad.q,faltaba.u,ini.l,fin.l,uno.l,dos.l,valor.l,var.u,var2.f,*baseserie.byte=AllocateMemory(80)
OpenWindow(#ventana,400,300,#WindowWidth,#WindowHeight,"Ajustar calibrado de motor",#PB_Window_MinimizeGadget)
Top=5
GadgetHeight=24
FrameGadget(#cuadro,5,Top,380,120,"Ajustar calibrado de motor"):Top+20
ButtonGadget(#botonmotor1,10,Top,50,GadgetHeight,"motor 1",#PB_Button_Toggle)
StringGadget(#valor,60,Top,50,GadgetHeight,"")
ButtonGadget(#botonmotor2,110,Top,50,GadgetHeight,"motor 2",#PB_Button_Toggle)
StringGadget(#valor2,160,Top,50,GadgetHeight,"")
ComboBoxGadget(#puertosCOM,220,Top,60,GadgetHeight); puerto COM
ForEach puertosRS232$():AddGadgetItem(#puertosCOM,-1,puertosRS232$()):Next
ComboBoxGadget(#baudios,280,Top,100,GadgetHeight)
For s.a=1 To 15:Read.l a.l:AddGadgetItem(#baudios,-1,Str(a)+" baudio"):Next
SetGadgetState(#baudios,9):baudios.l=115200; <- 115200 baudios
TrackBarGadget(#deslizador,10,60,370,25,700,2300):SetGadgetState(#deslizador,1590):var.u=GetGadgetState(#deslizador):SetGadgetText(#valor,Str(var.u)+"us")
TrackBarGadget(#deslizador2,10,90,370,25,0,1800):SetGadgetState(#deslizador2,900):var2.f=GetGadgetState(#deslizador2)/10:SetGadgetText(#valor2,StrF(var2)+"º")
DisableGadget(#valor,GetGadgetState(#botonmotor1)!1):DisableGadget(#deslizador,GetGadgetState(#botonmotor1)!1)
DisableGadget(#valor2,GetGadgetState(#botonmotor2)!1):DisableGadget(#deslizador2,GetGadgetState(#botonmotor2)!1)
PokeS(@ini,"ini",3,#PB_Ascii):PokeS(@fin,"fin",3,#PB_Ascii)
PokeS(@uno,"uno",3,#PB_Ascii):PokeS(@dos,"dos",3,#PB_Ascii)
PokeS(@bau,"bau",3,#PB_Ascii)
Macro enviaryrecibirdato(gad,dato,cual,signo)
  If PuertoCOM$
    i.a=StringByteLength(StrF(dato#),#PB_Ascii)
    Copymemory(@ini,*baseserie,3):Copymemory(@cual#,*baseserie+3,3)
    PokeS(*baseserie+6,StrF(dato#),i,#PB_Ascii)
    Copymemory(@fin,*baseserie+6+i,3)
    WriteSerialPortData(#serie,*baseserie,9+i)
    Delay(10)
    cantidad=AvailableSerialPortInput(#serie)
    If cantidad
      leido=ReadSerialPortData(#serie,*baseserie,cantidad)
      dato#=ValF(PeekS(*baseserie,4,#PB_Ascii))
      SetGadgetText(gad#,StrF(dato#)+signo#)
    EndIf
  EndIf
EndMacro
Repeat
  evento=WaitWindowEvent()
  If evento=#PB_Event_Gadget
    Select EventGadget()
    Case #baudios,#puertosCOM
      baudios.l=PeekL(?valoresbaudios+GetGadgetState(#baudios)*SizeOf(Long))
      PuertoCOM$=GetGadgetText(#puertosCOM)
      If PuertoCOM$
        While IsSerialPort(#serie)
          vaciarserial(#serie)
          CloseSerialPort(#serie)
        Wend
        ;Delay(1)
        If OpenSerialPort(#serie,PuertoCOM$,baudios,#PB_SerialPort_NoParity,8,0,#PB_SerialPort_NoHandshake,1024,8)
          SetGadgetText(#cuadro,"Ajustar calibrado de motor a través del puerto "+PuertoCOM$)
          vaciarserial(#serie)
          Delay(200)
          WriteSerialPortData(#serie,@ini,3)
          WriteSerialPortData(#serie,@bau,3)
          i.a=StringByteLength(StrF(baudios),#PB_Ascii):PokeS(@bau,StrF(baudios),i,#PB_Ascii):WriteSerialPortData(#serie,@bau,i)
          WriteSerialPortData(#serie,@fin,3)
        Else
          SetGadgetText(#cuadro,"No puede abrirse el puerto "+PuertoCOM$)
        EndIf
      EndIf
    Case #botonmotor1
      DisableGadget(#valor,GetGadgetState(#botonmotor1)!1):DisableGadget(#deslizador,GetGadgetState(#botonmotor1)!1)
    Case #botonmotor2
      DisableGadget(#valor2,GetGadgetState(#botonmotor2)!1):DisableGadget(#deslizador2,GetGadgetState(#botonmotor2)!1)
    Case #deslizador
      var.u=GetGadgetState(#deslizador)
      enviaryrecibirdato(#valor,var,uno,"us")
    Case #valor
      var.u=Val(GetGadgetText(#valor))
      SetGadgetState(#deslizador,var)
      enviaryrecibirdato(#valor,var,uno,"us")
    Case #deslizador2
      var2.f=GetGadgetState(#deslizador2)/10
      enviaryrecibirdato(#valor2,var2,dos,"º")
    Case #valor2
      var2.f=ValF(GetGadgetText(#valor2))
      SetGadgetState(#deslizador2,var2.f*10)
      enviaryrecibirdato(#valor2,var2,dos,"º")
    EndSelect
  EndIf
Until evento=#PB_Event_CloseWindow
While IsSerialPort(#serie)
  vaciarserial(#serie)
  CloseSerialPort(#serie)
Wend
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
Post Reply