serielle Schnittstelle

Hardware- und Elektronikbasteleien, Ansteuerung von Schnittstellen und Peripherie.
Fragen zu "Consumer"-Problemen kommen in Offtopic.
Benutzeravatar
John Doe
Beiträge: 57
Registriert: 02.01.2006 18:08

serielle Schnittstelle

Beitrag von John Doe »

Hallo an alle,
ich möchte mittels der MVCOM-Befehle mit einem µController kommunizieren. Das Problem ist die Erfassung der vom µC gesendeten Daten.
Normalerweise benutze ich eine Schleife, die ständig die RS232-Schnittstelle abfragt, ob Daten vom µC gesendet wurden.
Gitb es keine Möglichkeit über einen Interrupt, wie z.B. in VisualBasic 'OnComm', auf gesendete Daten vom µC zu reagieren.
andi256
Beiträge: 100
Registriert: 06.11.2004 11:23
Computerausstattung: PB 5.30 (x64) Win7
Wohnort: Österreich

Beitrag von andi256 »

Habe das auf meiner Platte gefunden ... ist für Atmel µController

ist mit api und nicht MVCom .... aber müsste sich einfach umschreiben lassen

PS. war damals nur ein kurzer Versuch also (Quick & Dirty)


vielleicht hilft es

Code: Alles auswählen

#TIMEOUT =   1000

Global handle

Procedure open_port()
 handle = CreateFile_("COM2:", #GENERIC_READ | #GENERIC_WRITE,0, 0, #OPEN_EXISTING, 0, 0)
 If handle = #INVALID_HANDLE_VALUE
  Debug("Couldn't open serial device!")
 Else
  ct.COMMTIMEOUTS 
  ct\ReadIntervalTimeout = 0
  ct\ReadTotalTimeoutMultiplier = 0 
  ct\ReadTotalTimeoutConstant = 0 
  ct\WriteTotalTimeoutMultiplier = 0 
  ct\WriteTotalTimeoutConstant = 0 
  SetCommTimeouts_(handle,@ct)
  DCB.dcb
  dcb\DCBlength=8
  dcb\BaudRate=9600
              ;BPCDD STOIENR AD2345678901234567
  dcb\fbits=  %00000100000001000000000000000000
  dcb\wReserved=0
  dcb\XonLim=2048
  dcb\XoffLim=2048
  dcb\ByteSize=8
  dcb\Parity=0
  dcb\StopBits=0
  dcb\XonChar=$11
  dcb\XoffChar=$13
  dcb\ErrorChar=0
  dcb\EofChar=0
  dcb\EvtChar=0
  dcb\wReserved1=0
  SetCommState_(handle,@dcb)
  PurgeComm_(handle,#PURGE_TXCLEAR|#PURGE_RXCLEAR)
  x.l
  GetCommMask_(handle,@x)
  SetCommMask_(handle, 0)
  ClearCommBreak_(handle)
  SetCommBreak_(handle)
  Delay(100)
 EndIf 
EndProcedure

Procedure setA(bit);Output bit on B channel
If bit; = 1
 EscapeCommFunction_(handle,#SETRTS)
Else 
 EscapeCommFunction_(handle,#CLRRTS)
EndIf
EndProcedure

Procedure setB(bit);Output bit on A channel
If bit; = 1
 EscapeCommFunction_(handle, #SETDTR)
Else
 EscapeCommFunction_(handle, #CLRDTR)
EndIf 
EndProcedure

Procedure getA();Input bit on A channel
 status.l
 GetCommModemStatus_(handle,@status)
 If (#MS_DSR_ON & status) <> 0
  r = #True
 Else
  r = #False
 EndIf
 ProcedureReturn r
EndProcedure

Procedure getB();Input bit on B channel
 status.l
 GetCommModemStatus_(handle,@status)
 If (#MS_CTS_ON & status) <> 0
  ProcedureReturn = #True
 Else
  ProcedureReturn = #False
 EndIf
EndProcedure

Procedure close_port() 
 CloseHandle_(handle)
EndProcedure 

Procedure waitA(bit);Wait For pin To settle
 i = #TIMEOUT
 While (i > 0) And (bit <> getA() )
  i-1
  If i = 0
   Debug("ERROR: Signal A is stuck!")
  EndIf 
 Wend
EndProcedure 

;Define the SPI programming Interface signals
Procedure GETMISO() 
 ProcedureReturn getB()
EndProcedure
 
Procedure SCK(X) 
 setA(X)
EndProcedure

Procedure MOSI(X) 
 setB(X)
EndProcedure

Procedure WAITSCK(X)   
 waitA(X)
EndProcedure

Procedure spiwr(cin)
 For j = 7 To 0 Step -1
   SCK(0)
    If ((cin>>j)&1) 
     MOSI(1)
    Else
     MOSI(0)  
    EndIf 
    WAITSCK(0)
    SCK(1)
    WAITSCK(1)
    cout = (cout<<1)|GETMISO()
  Next j
 ProcedureReturn cout
EndProcedure

Procedure spiwr4(byte1,byte2,byte3,byte4)
 spiwr(byte1)
 spiwr(byte2)
 spiwr(byte3)
 ProcedureReturn spiwr(byte4)
EndProcedure


Procedure eraseprogram()
 spiwr4($AC,$80,0,0)
 Delay(20); // At least 9 ms delay after chip erase
EndProcedure

Procedure readprogram(addr)
ProcedureReturn (spiwr4($28, (addr >> 8), addr & $ff, 0) << 8) +  spiwr4($20, (addr >> 8), addr & $ff,0)
EndProcedure

Procedure loadprogram(addr,hi,lo)
 spiwr4($40, 0, addr & $1f, lo); // load low byte first!
 spiwr4($48, 0, addr & $1f, hi);
EndProcedure

Procedure writeprogram(pageaddr)
 spiwr4($4c, (pageaddr >> 8), pageaddr & $ff, 0);
 Delay(20); // At least 5 ms delay after writing a page
EndProcedure

; -------- MAIN

 open_port()
 MOSI(1)
 SCK(0)

 spiwr($AC)
 spiwr($53)
 If (spiwr($00) <> $53) 
  Debug "ERROR: Programming enable command didn't respond."
 Else 
  Debug "Programming enable command worked fine."
 EndIf  
 
 spiwr($00)
 Debug "Vendor code:                 "+Hex(spiwr4($30,0,0,0))
 Debug "Part family and memory size: "+Hex(spiwr4($30,0,1,0))
 Debug "Part number:                 "+Hex(spiwr4($30,0,2,0))
 Debug "Calibration byte:            "+Hex(spiwr4($38,0,0,0))

 eraseprogram()
 Debug "Address 0: "+ Hex(readprogram(0))
 Debug "Programming first instruction to 0x1234. "
 loadprogram(0,$12,$34)
 writeprogram(0)
 Debug "Address 0: "+Hex(readprogram(0))
 
 close_port() 
Georg
Beiträge: 29
Registriert: 17.06.2005 19:04

Beitrag von Georg »

Du kannst das mit WaitCommEvent machen. So wie ich es in dem
Beispiel machen, blockiert aber die Funktion. Deshalb in einem Thread.
Man kann es auch anderst machen, das ist aber aufwendiger.

Code: Alles auswählen

;PureBasic 3.94

Declare ThreadEmpf()

Global ComPort.s , hCom , ThreadID , ComEvent  ,BufferRx.s , CountBuffer , ComError
Global IDWndMain ,  hWndMain ,StrEmpf 
;Die benötigten Strukturen
Global dcb.DCB ;Einstellungen der Schnittstelle
Global ccf.COMMCONFIG 
Global o.OVERLAPPED ;Damit andere Prozesse Zugriff haben. Vorletzter Parameter bei CreateFile
Global timeouts.COMMTIMEOUTS
BufferRx = Space(255); Hier schreibt ReadFile die empfangenden Daten rein

ComPort = "COM2" ; 
FillMemory_(@ccf\dcb, SizeOf(dcb), 0);DCB-Struktur mit Nullen füllen
dcb\DCBlength = SizeOf(DCB); Größe der Struktur ermitteln
ccf\dwSize = SizeOf(COMMCONFIG) + dcb\DCBlength ; Größe der Struktur ermitteln

;Einstellungen aus dem Gerätemanager verwenden. 
; Man kann die Struktur aber auch selbst füllen. Z.Bsp mit "BuildCommDCB", oder von Hand
GetDefaultCommConfig_(ComPort, @ccf, @ccf\dwSize)
SetDefaultCommConfig_(ComPort, @ccf, @ccf\dwSize)

;Comport öffnen.;z.Bsp  Com2.  Das "\\.\" ist nur für ComPortnummern über 12 erforderlich
hCom = CreateFile_("\\.\"+ComPort, #GENERIC_READ |#GENERIC_WRITE ,0,0, #OPEN_EXISTING ,#FILE_FLAG_OVERLAPPED ,0)
             If hCom <> #INVALID_HANDLE_VALUE
                     SetCommMask_(hCom,#EV_RXCHAR );Event festlegen. Wenn ein Byte emfangen wird, wird ein Event ausgelöst
                     SetCommState_(hCom,@ccf\dcb) ; Einstellungen übernehmen
                     SetupComm_(hCom, 255,255);Empangs- und SendeBuffer einstellen
                    GetCommTimeouts_( hCom,@timeouts)
                                       timeouts\ReadIntervalTimeout = #MAXWORD
                                       timeouts\ReadTotalTimeoutMultiplier = 0
                                       timeouts\ReadTotalTimeoutConstant = 300 ; Wartet 300ms 
                                       timeouts\WriteTotalTimeoutMultiplier = 0
                                       timeouts\WriteTotalTimeoutConstant = 0
                    SetCommTimeouts_( hCom,@timeouts) 
                      ClearCommError_(hCom,@ComError,#NULL); Löscht alle evt. Fehler     
                      PurgeComm_(hCom,#PURGE_TXCLEAR  | #PURGE_RXCLEAR);Leert die Buffer
                    
                      ThreadID = CreateThread(@ThreadEmpf(),0);Thread starten
            Else
                     MessageRequester("","ComPort kann nicht geöffnet werden") 
                     End ;Wenn man will,  Programm beenden
          EndIf         
    
;Jetzt die Threadfunktion. An dieser Stelle im Code muss  sie aber declariert werden!!
Procedure ThreadEmpf()
;So wie   " WaitCommEvent"  hier verwendet wird , blockiert sie den Thread bis das Event eintritt. Man kann es auch anderst machen.
  ;Aber aufwendiger  
  Repeat  
      ClearCommError_(hCom,@ComError,#NULL)
      WaitCommEvent_(hCom, @ComEvent,@o);
        ;Dann mit Readfile den Buffer auslesen. Der dritte Parameter gibt an, wieviele Byte gelesen werden sollen.
        ;ReadFile wartet dann solange bis alle Byte empfangen wurde. Geht ein Byte verloren, dann blockiert ReadFile.
        ;Um das zu verhinder kann man mit "SetCommTimeouts" Timeouts setzen.
        ;Man kann den dritten Parameter auch auf 1 setzen und in einer Schleife solange lesen bis der Speicher leer ist..
        ;"ClearCommError" gibt vorhandene Byte im Buffer zurück.
        ReadFile_(hCom, BufferRx,4,@CountBuffer,0)
        SetGadgetText(StrEmpf , BufferRx)
        
  ForEver   
EndProcedure       
      

                                        
IDWndMain =OpenWindow(#PB_Any,0,0,380,160,  #PB_Window_SystemMenu  | #PB_Window_WindowCentered  ,"USB zu RS232 Konvertertest")
    hWndMain = WindowID(IDWndMain)
    CreateGadgetList(hWndMain)
                  StrEmpf =  StringGadget(#PB_Any,10,10,360,140,"")


Repeat
          Event = WaitWindowEvent()
                    Select Event    
                              Case #PB_Event_CloseWindow
                                         If EventWindowID() = IDWndMain  
                                                        SetCommMask_(hCom,0 )      ;Maske auf Null setzten
                                                        KillThread(hThread) ; Thread beenden
                                                        CloseHandle_(hThread); ThreadHandle schließen. Ob bei PB4.0 noch erforderlich ?
                                                        CloseHandle_(hCom)   ; ComPort schließen.       
                                                        End
                                        EndIf   
                      EndSelect
ForEver                                         
End

Viel Spaß
Georg
Antworten