Avatar billede ferrari_brian Nybegynder
16. november 2005 - 00:17 Der er 49 kommentarer og
1 løsning

serial port i Linux

Hej...

jeg har siddet og kigget på diverse ting der skulle kunne skrive til serielporten i linux, men jeg har ikke rigtig fundet noget der virkede (som jeg kunne compile)

Er der en der har et virkende eksempel på hvordan C/C++ kan håndtere serielporten i Linux?

lige nu kører jeg på en Fedora.

med venlig hilsen
Brian
Avatar billede bertelbrander Novice
16. november 2005 - 00:47 #1
Jeg har ikke linux ved hånden, men man åbner blot "dev/com1" med open og læser med read og skriver med write.

Hvad har du prøvet og hvad er det du ikke kan få til at virke?
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 00:53 #2
http://www.faqs.org/docs/Linux-HOWTO/Serial-Programming-HOWTO.html#AEN56 <-- jeg var ved at prøve på det der ... men kunne simpelthen ikke få den til at compile ...

canonical ting...

Jeg skal som sådan bare have en stump kode der kan åbne, læse, skrive og lukke com1
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 00:54 #3
er temmelig ny til linux ... men det er linux der skal bruges.

jeg skal bare kunne skrive 4 HEX
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 00:56 #4
altså som sådan skulle man vel lave det sådan at man kan skrive til com porten som til en fil ... eller noget lignende. så jeg fx kan skrive på porten og så modtager en hyperterminal (eller samme program på en anden maskine) det jeg skriver. ?
Avatar billede bertelbrander Novice
16. november 2005 - 01:05 #5
Jeg prøvede at klippe det væk der ikke kan kompilere på windows, og lavede læsning om til skrivning:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

/* baudrate settings are defined in <asm/termbits.h>, which is
included by <termios.h> */
#define BAUDRATE B38400
/* change this definition for the correct port */
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 /* POSIX compliant source */

#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE;

int main()
{
  int fd, res;
  char buf[255];
  /*
    Open modem device for reading and writing and not as controlling tty
    because we don't want to get killed if linenoise sends CTRL-C.
  */
  fd = open(MODEMDEVICE, O_RDWR);
  if (fd < 0)
  {
      perror(MODEMDEVICE);
      exit(-1);
  }
  buf[0] = 0x04;
  write(fd, buf, 1);
  close(fd);
}
Avatar billede strych9 Praktikant
16. november 2005 - 01:06 #6
echo "blah" | /dev/com1

Alt i Linux er en fil ja. Alle programmerings og scripting sprog kan læse og skrive til filer hvilket gør at linux arkitekturmæssigt er ufatteligt kraftfuldt for selv det mindste scripting sprog.

Men du skal skrive til den rigtige fil. Dine devices er i /dev folderen. Kig efter om du har et com1 device der, eller om det hedder ttyS0 osv.
Avatar billede bertelbrander Novice
16. november 2005 - 01:09 #7
Alt er også en fil (stream) på windows...
Avatar billede strych9 Praktikant
16. november 2005 - 01:10 #8
ok, men så vil jeg gerne se dig skrive råt output til seriel port, harddisk, lydkort, printer, osv med bare een linje i en kommandoprompt på Windows =)
Avatar billede bertelbrander Novice
16. november 2005 - 01:12 #9
echo "blah" >com1:
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 01:17 #10
ja men hvis du gør sådan så får du vel ikke sat porten op til at skrive til den ? altså med baud osv ? Det skal man jo i hvert tilfælde i hyperterminalen i windows
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 01:19 #11
hvis jeg bruger: echo "blah" | /dev/ttyS0

så skriver den adgang nægtet (jeg er logget på som root). og den hedder ttyS0 og ikke com1

jeg kan heller ikke se at jeg modtaget noget i den anden ende ..
Avatar billede bertelbrander Novice
16. november 2005 - 01:21 #12
Koden var mest tænkt som et eksempel, vi kan altid få sat baud op senere.

Kan det kompileres? Kan du se om du får sendt noget? (det er måske en idé at sende andet end 0x04 for at teste).
Avatar billede strych9 Praktikant
16. november 2005 - 01:22 #13
Kan lige så godt være ttyS1 eller ttyS2. Jeg kan egentlig ikke huske kommandoen til at se hvilken terminal er logget på. Måske er det bare så simpelt som at skrive "who". Jeg har ikke min linux kasse tændt ligenu.
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 01:24 #14
jeg får en fejl med at write og close ikke er declared
Avatar billede bertelbrander Novice
16. november 2005 - 01:26 #15
Jeg gætter lidt, prøv at tilføje:
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 01:26 #16
der står 'write' was not declared in this scope
Avatar billede bertelbrander Novice
16. november 2005 - 01:28 #17
Hvad kompilerer du med når ikke du har Linux box'en tændt?
Avatar billede strych9 Praktikant
16. november 2005 - 01:29 #18
Du må ikke blande os sammen bertel =)

brian, du kan se navn til I/O adresse mapping med setserial kommandoen.

jeg skal sove nu.
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 01:31 #19
den siger nu: /tmp/ccvcoMip.o(.eh_frame+0x11): undefined reference to ' __gxx_personality_v0' collect2: ld returnerede afslutningskoden 1
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 01:32 #20
jeg har min linuxmaskine tændt
Avatar billede bertelbrander Novice
16. november 2005 - 01:34 #21
>strych9, undskyld.

>Brian, det ligner en fejl i den kommando du bruger til at kompilere.
Hvordan kompilerer du?
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 01:39 #22
med gcc
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 01:39 #23
kan godt være jeg skriver fejl
hvis du kan skrive hvordan du ville gøre så kan jeg måske finde ud af det
Avatar billede bertelbrander Novice
16. november 2005 - 01:40 #24
Er din fil en .c eller en .cpp fil?
Hvordan ser kommandolinien ud?
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 01:41 #25
hvis jeg bruger g++ så kører den bare og så færdig ...?
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 01:44 #26
jeg kom til at se at det var en .cpp så det er g++ ./serialtest.cpp
Avatar billede bertelbrander Novice
16. november 2005 - 01:44 #27
Hvis den kompilerer unden at skrive noget, tyder det på at det virker.
Har den lavet et program?
Programmet hedder måske a.out hvis ikke du har fortalt den hvad det skal hedde. Du kan bruge -omyprogram hvis du vil have programmet til at hedde myprogram
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 01:49 #28
hvis jeg bruger g++ -o serial ./serialtest.cpp så laver den en fil (serial) og jeg bruger så chmod 0x serial til at gøre den eksekverbar og den kører også men der sker intet
Avatar billede bertelbrander Novice
16. november 2005 - 01:51 #29
Hvordan ser du at der ikke sker noget?
Hvis programmet kan åbne porten skriver det ikke noget.
Du skal måske sætte noget til at læse det du skriver.
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 01:54 #30
jeg har åbnet en HyperTerminal på en windows-maskine ... det burde den vel kunne finde ud af at læse ?

jeg har includeret <iostream.h> og skrevet cout << "test";

og når jeg compiler det og kører serial så skriver den 'test' på skærmen så den kan altså godt gøre noget... ved bare ikke hvad der kommer ud
Avatar billede bertelbrander Novice
16. november 2005 - 02:00 #31
Ja, hyperterminal på Windows burde kunne læse det du skriver fra Linux.
Det kræver kun et NULL-modem kabel og at hyperterminal er sat rigtigt op, f.ex. med baud-rate.
Kan du få andre programmer på linux til at sende til windows maskinen?
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 02:01 #32
jeg ved ikke hvad jeg skulle bruge på linux ? et forslag ?

jeg kan godt sende fra den ene win-maskine til den anden og vice versa
Avatar billede bertelbrander Novice
16. november 2005 - 02:07 #33
Jeg har ikke prøvet det, men lidt søgning på linux ledte til:
http://cutecom.sourceforge.net/

Jeg siger godnat.
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 02:09 #34
okai tak for hjælpen so far .. godnat
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 12:28 #35
Jeg har nu fået forbindelse via minicom
med:
baud: 115800
databit: 8
Paritet: none
Stopbit: 1

og derefter har jeg også fået forbindelse til den via:

echo "b" > /dev/ttyS0
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 12:44 #36
Jeg har nu også fået den til at sende via det lille C++ program ... dog sender den bare et mærkeligt tegn hver gang.

Det bedste er at der nu er forbindelse:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>

/* baudrate settings are defined in <asm/termbits.h>, which is
included by <termios.h> */
#define BAUDRATE B115800
/* change this definition for the correct port */
#define MODEMDEVICE "/dev/ttyS0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */

#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE;

int main()
{
  int fd, res;
  char buf[255];
  /*
    Open modem device for reading and writing and not as controlling tty
    because we don't want to get killed if linenoise sends CTRL-C.
  */
  fd = open(MODEMDEVICE, O_RDWR);
  if (fd < 0)
  {
      perror(MODEMDEVICE);
      exit(-1);
  }
  buf[0] = 0x04;
  write(fd, buf, 1);
  close(fd);
}
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 15:09 #37
hmm... nu har jeg fundet ud af at det "kun" virker når jeg har været inde i minicom først, idet der elelrs ikke er åbnet for porten (den skal vel initialiseres på en eller anden måde ?)
Avatar billede strych9 Praktikant
16. november 2005 - 15:39 #38
Jeg mener bestemt at du bruger setserial til at sætte hastighed, paritet osv på porten. "man setserial". Dette altså forudsagt at jeg forstår dit spørgsmål helt rigtigt.
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 17:16 #39
altså jeg vil have porten åbnet gennem programmet ?

man kan selvfølgelig vel også åbne den i opstarten med setserial eller hvad der nu skal bruges. men det andet ville være smartere ?
Avatar billede bertelbrander Novice
16. november 2005 - 19:43 #40
Dit program sender 0x04, det er ikke underligt at hyperterminal viser det som et sjovt tegn.

Du kunne erstatte write med:
  strcpy(buf, "\r\nHello World\r\n");
  write(fd, buf, strlen(buf));
For at se om du kan modtage noget fornuftigt.

Med hensyn til opsætning: Prøv at kompilere koden fra eksemplet igen og fortæl hvilke fejl du får.
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 19:46 #41
Jeg har lige fået opsætningen til at virke poster koden om lidt ... skal lige rydde det jeg har fjernet og sat ind som ikke bliver brugt
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 19:49 #42
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>

#include <sys/uio.h>
#include <unistd.h>
#include <stdlib.h>



/* baudrate settings are defined in <asm/termbits.h>,
which is included by <termios.h> */
#define BAUDRATE B115200         
/* change this definition for the correct port */
#define MODEMDEVICE "/dev/ttyS0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */

#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE;

/*
  Name:      Main
  Function:  Opens and Initializes the SerialPort. And then writes to it.
*/

main() {
      int fd,c, res;
      struct termios oldtio,newtio;
      char buf[255];
      /*
        Open modem device for reading and writing and not as controlling tty
        because we don't want to get killed if linenoise sends CTRL-C.
      */

      fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
      if (fd <0) {perror(MODEMDEVICE); exit(-1); }

      /*
        BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
        CRTSCTS : output hardware flow control (only used if the cable has
                  all necessary lines. See sect. 7 of Serial-HOWTO)
        CS8    : 8n1 (8bit,no parity,1 stopbit)
        CLOCAL  : local connection, no modem contol
        CREAD  : enable receiving characters
      */
      newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
       
      /*
        IGNPAR  : ignore bytes with parity errors
        ICRNL  : map CR to NL (otherwise a CR input on the other computer
                  will not terminate input)
        otherwise make device raw (no other input processing)
      */
      newtio.c_iflag = IGNPAR | ICRNL;

      /*
        Raw output.
      */
      newtio.c_oflag = 0;
     
      /*
        ICANON  : enable canonical input
        disable all echo functionality, and don't send signals to calling program
      */
      newtio.c_lflag = ICANON;
       
      /*
        initialize all control characters
        default values can be found in /usr/include/termios.h, and are given
        in the comments, but we don't need them here
      */
      newtio.c_cc[VINTR]    = 0;    /* Ctrl-c */
      newtio.c_cc[VQUIT]    = 0;    /* Ctrl-\ */
      newtio.c_cc[VERASE]  = 0;    /* del */
      newtio.c_cc[VKILL]    = 0;    /* @ */
      newtio.c_cc[VEOF]    = 4;    /* Ctrl-d */
      newtio.c_cc[VTIME]    = 0;    /* inter-character timer unused */
      newtio.c_cc[VMIN]    = 1;    /* blocking read until 1 character arrives */
      newtio.c_cc[VSWTC]    = 0;    /* '\0' */
      newtio.c_cc[VSTART]  = 0;    /* Ctrl-q */
      newtio.c_cc[VSTOP]    = 0;    /* Ctrl-s */
      newtio.c_cc[VSUSP]    = 0;    /* Ctrl-z */
      newtio.c_cc[VEOL]    = 0;    /* '\0' */
      newtio.c_cc[VREPRINT] = 0;    /* Ctrl-r */
      newtio.c_cc[VDISCARD] = 0;    /* Ctrl-u */
      newtio.c_cc[VWERASE]  = 0;    /* Ctrl-w */
      newtio.c_cc[VLNEXT]  = 0;    /* Ctrl-v */
      newtio.c_cc[VEOL2]    = 0;    /* '\0' */
     
      /*
        now clean the modem line and activate the settings for the port
      */
      tcflush(fd, TCIFLUSH);
      tcsetattr(fd,TCSANOW,&newtio);
     
      /*
        Nu skriver jeg et tegn på porten og lukker den igen.
      */

    buf[0] = '5';
    write(fd, buf, 1);
    close(fd);
}
Avatar billede bertelbrander Novice
16. november 2005 - 19:51 #43
Så problemet er løst?
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 19:57 #44
BertelBrander >> og en virkende kode der kan skrive en string:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <string.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdlib.h>



/* baudrate settings are defined in <asm/termbits.h>,
which is included by <termios.h> */
#define BAUDRATE B115200         
/* change this definition for the correct port */
#define MODEMDEVICE "/dev/ttyS0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */

#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE;

/*
  Name:      Main
  Function:  Opens and Initializes the SerialPort. And then writes to it.
*/

main() {
      int fd,c, res;
      struct termios oldtio,newtio;
      char buf[255];
      /*
        Open modem device for reading and writing and not as controlling tty
        because we don't want to get killed if linenoise sends CTRL-C.
      */

      fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
      if (fd <0) {perror(MODEMDEVICE); exit(-1); }

      /*
        BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
        CRTSCTS : output hardware flow control (only used if the cable has
                  all necessary lines. See sect. 7 of Serial-HOWTO)
        CS8    : 8n1 (8bit,no parity,1 stopbit)
        CLOCAL  : local connection, no modem contol
        CREAD  : enable receiving characters
      */
      newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
       
      /*
        IGNPAR  : ignore bytes with parity errors
        ICRNL  : map CR to NL (otherwise a CR input on the other computer
                  will not terminate input)
        otherwise make device raw (no other input processing)
      */
      newtio.c_iflag = IGNPAR | ICRNL;

      /*
        Raw output.
      */
      newtio.c_oflag = 0;
     
      /*
        ICANON  : enable canonical input
        disable all echo functionality, and don't send signals to calling program
      */
      newtio.c_lflag = ICANON;
       
      /*
        initialize all control characters
        default values can be found in /usr/include/termios.h, and are given
        in the comments, but we don't need them here
      */
      newtio.c_cc[VINTR]    = 0;    /* Ctrl-c */
      newtio.c_cc[VQUIT]    = 0;    /* Ctrl-\ */
      newtio.c_cc[VERASE]  = 0;    /* del */
      newtio.c_cc[VKILL]    = 0;    /* @ */
      newtio.c_cc[VEOF]    = 4;    /* Ctrl-d */
      newtio.c_cc[VTIME]    = 0;    /* inter-character timer unused */
      newtio.c_cc[VMIN]    = 1;    /* blocking read until 1 character arrives */
      newtio.c_cc[VSWTC]    = 0;    /* '\0' */
      newtio.c_cc[VSTART]  = 0;    /* Ctrl-q */
      newtio.c_cc[VSTOP]    = 0;    /* Ctrl-s */
      newtio.c_cc[VSUSP]    = 0;    /* Ctrl-z */
      newtio.c_cc[VEOL]    = 0;    /* '\0' */
      newtio.c_cc[VREPRINT] = 0;    /* Ctrl-r */
      newtio.c_cc[VDISCARD] = 0;    /* Ctrl-u */
      newtio.c_cc[VWERASE]  = 0;    /* Ctrl-w */
      newtio.c_cc[VLNEXT]  = 0;    /* Ctrl-v */
      newtio.c_cc[VEOL2]    = 0;    /* '\0' */
     
      /*
        now clean the modem line and activate the settings for the port
      */
      tcflush(fd, TCIFLUSH);
      tcsetattr(fd,TCSANOW,&newtio);
     
      /*
        Nu skriver jeg et tegn på porten og lukker den igen.
      */

    strcpy(buf, "\r\nHello World\r\n";
    write(fd, buf, strlen(buf));
    close(fd);
}
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 20:00 #45
ja, det må jeg nok indrømme nu. Jeg ved endnu ikke om jeg skal have den til at læse fra serielporten. men det burde kunne lade sig gøre.

Jeg vil godt give points til BertelBrander, da jeg nu har fået løst det som spørgsmålet gik ud på
Avatar billede bertelbrander Novice
16. november 2005 - 20:03 #46
Du burde kunne læse med read. Du skal nok sætte den op til om du vil vente på at der bliver modtaget noget eller den skal returnere med det samme. De steder jeg har brugt det har jeg brugt ioctl til det.

Jeg samler ikke på point.
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 20:08 #47
ioctl ? how virker den ?

Jeg siger i hvert tilfælde tak

men mht read så vil det være sådan at den får en string eller lignende hver gang der bliver skrevet til den hvis det er. I så fald skal den bare tage det og smække det i en fil (istedet for skrive det på skærmen)
Avatar billede bertelbrander Novice
16. november 2005 - 20:15 #48
Prøv at skrive man ioctl på din Linux box.
Lidt søgning på google giver f.ex:
    o  If the object the descriptor is associated with is marked
        for  4.2BSD-style  non-blocking  I/O  (with  the  FIONBIO
        ioctl() request or a call to fcntl(2V) using the  FNDELAY
        flag  from  <sys/file.h>  or  the  O_NDELAY  flag  from
        <fcntl.h> in  the  4.2BSD  environment),  the  read  will
        return -1 and errno will be set to EWOULDBLOCK.
Avatar billede ferrari_brian Nybegynder
16. november 2005 - 20:25 #49
ok, kan være jeg lige kigger på det senere. lige nu skal jeg vist koncentrere mig om at få den til at kommunikere med mit php. Det burde dog være tilgængeligt under linux.

Tak for hjælpen. Jeg vender tilbage hvis jeg får brug for hjælp til read.
Avatar billede ferrari_brian Nybegynder
19. december 2005 - 14:42 #50
Lukketid
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester