QQ登录

只需一步,快速开始

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 701|回复: 0

请教串口编程!

[复制链接]
发表于 2003-8-31 20:44:47 | 显示全部楼层 |阅读模式
由于实验需要编写了一个串口操作程序(当然是写得满头大汗),操作系统环境是
redhat 9.0,编译器是自带的gcc-3.2.2-5。下面是代码清单,贴出来共享:
file1: serial_port.h
[code:1]
#ifndef __SERIAL_PORT_H__
#define __SERIAL_PORT_H__

#include <termios.h>            // POSIX terminal control definitions
#include <unistd.h>             // UNIX standard function definitions
#include <fcntl.h>              // File control definitions

class serial_port
{
  public:
        serial_port() {fd = -1;}
        virtual ~serial_port() {};

        bool open_port();
        bool close_port();
        bool write_to(char *pin, int buffer_length);
        bool read_from(char *pout, int &buffer_length);

        inline bool query();    // return true if already open
        int getfile() {return fd;}

        char port[80];          // serial port name
        long BAUD;              // baud rate                                 
        long DATA;              // data bits                                 
        long STOP;              // stop bits
        long PARITYON;
        long PARITY;

  private:
        int fd;                 // file descriptor for the port
        // place for old and new port setting for serial port
        struct termios oldtio, newtio;
};

#endif
[/code:1]

file2: serial_port.cpp
[code:1]
#include <assert.h>
using namespace std;

#include "serial_port.h"

bool serial_port::open_port()
{
        assert(query() == false);
        // open the serial port to be non-blocking (read will return immediately
)
        fd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK);
        if (fd < 0) {
                fd = -1;
                return false;
        }

        assert(query() == true);

        tcgetattr(fd, &oldtio);         // save current port setting
        // set new port settings for canonical input processing
        newtio.c_cflag = BAUD | CRTSCTS | DATA | STOP | PARITYON | PARITY | CLOC
AL | CREAD;
        newtio.c_iflag = IGNPAR;
        newtio.c_oflag = 0;
        newtio.c_lflag = 0;             // ICANON
        newtio.c_cc[VMIN] = 1;
        newtio.c_cc[VTIME] = 0;
        tcflush(fd, TCIFLUSH);
        tcsetattr(fd, TCSANOW, &newtio);

        return true;
}

bool serial_port::close_port()
{
        assert(query() == true);

        // restore old port setting
        tcsetattr(fd, TCSANOW, &oldtio);
        close(fd);
        fd = -1;

        assert(query() == false);
}

bool serial_port::write_to(char *pin, int buffer_length)
{
        assert(query() == true);

        int write_length = write(fd, pin, buffer_length);
        if (write_length != buffer_length) return false;
                return true;
}

bool serial_port::read_from(char *pout, int &buffer_length)
{
        assert(query() == true);

        buffer_length = read(fd, pout, buffer_length);
        if (buffer_length < 0) return false;
                return true;
}

bool serial_port::query()
{
        return fd > 0;
}
[/code:1]

file3: main.cpp
[code:1]
#include <iostream>
#include <string>
#include <sys/signal.h>
using namespace std;

#include "serial_port.h"

char device[80];                        // name of device to open
const char device_def[] = "/dev/ttyS0"; // default device if none specified on c
ommand line
int t_option = 0;                       // set if -t option is used
int r_option = 0;                       // set if -r option is used
const int SIZE = 101;

// print command usage and exit
void usage()               
{
        cerr << "usage:serialhandler [-t | -r] [device]\n";
        cerr << "  -t option sends bits via device specified\n";
        cerr << "  -r option receives bits from device specified\n";
        cerr << "  default device is " << device_def << endl;
        exit(1);
}

// handle command line options
void parse_args(int argc, char *argv[])
{
        const char      *flags = "tr";
        int             c;

        while ((c = getopt(argc, argv, flags)) != EOF) {
                switch (c) {
                case 't':
                        t_option = 1;
                        break;
                case 'r':
                        r_option = 1;
                        break;
                case '?':
                        usage();
                        break;
                }
        }

        if (t_option + r_option > 1) {
                cerr << "serialhandle: options are mutually exclusive\n";
                usage();
        }

        // check for a single additional argument
        if ((argc - optind) > 1)
                usage();                // too many arguments
        if ((argc - optind) == 1)
                strcpy(device, argv[optind]);   // one argument
}

bool wait_flag = false;                 // false while no signal received
void signal_handler_IO(int status)      // definition of signal handler
{
        // cout << "received SIGIO signal\n";
        wait_flag = true;
}

void install_handler(int fd)
{
        struct sigaction saio;          // definition of signal action

        // install the serial handler before making the device asynchronous
        saio.sa_handler = signal_handler_IO;
        sigemptyset(&saio.sa_mask);     // saio.sa_mask = 0;
        saio.sa_flags = 0;
        saio.sa_restorer = NULL;
        sigaction(SIGIO, &saio, NULL);

        // allow the process to receive SIGIO
        fcntl(fd, F_SETOWN, getpid());
        // make the file descriptor asynchronous (the manual page says only
        // O_APPEND and O_NONBLOCK, will work with F_SETFL...)
        fcntl(fd, F_SETFL, FASYNC);
}

int main(int argc, char *argv[])
{
        // parse command line arguments
        strcpy(device, device_def);
        parse_args(argc, argv);

        serial_port *port = new serial_port;
        strcpy(port->port, device);
        port->BAUD = B4800;
        port->DATA = CS8;
        port->STOP = 0;
        port->PARITYON = 0;
        port->PARITY = 0;

        if (port->open_port() != true) {
                cerr << "unable to open device - " << device << endl;
                delete port;
                exit(1);
        } else {
                assert(port->query() == true);
                cout << "device - " << device << " successfully opened\n";
        }

        int fd = port->getfile();       // get the file descriptor
        install_handler(fd);            // install the serial handler

        char *buffer = new char[SIZE];
        if (r_option == 0) {
                while (/*cin.get() != EOF*/ 1) {
                        cin.getline(buffer, SIZE/*, '\n'*/);
                        buffer[strlen(buffer)] = '\n';
                        if (!port->write_to(buffer, strlen(buffer)))
                                cerr << "write failure" << endl;
                        memset(buffer, 0, SIZE);
                        sleep(1);
                }
        } else {
                int buffer_length;
                while (/*cin.get() != EOF*/ 1) {
                        if (wait_flag == true) {
                                // cout << "received SIGIO signal\n";
                                buffer_length = SIZE;
                                if (!port->read_from(buffer, buffer_length))
                                        cerr << "read failure" << endl;
                                if (buffer_length > 0)
                                        cout << buffer/* << endl*/;
                                memset(buffer, 0, SIZE);
                                wait_flag = false;
                        }
                        sleep(1);
                }
        }
        delete [] buffer;

        assert(port->query() == true);
        port->close_port();
        assert(port->query() == false);
        delete port;
}
[/code:1]

干脆连Makefile也贴上吧,呵呵:
[code:1]
INCL =
CFLAGS = -O2 -g
LFLAGS =
LIBS =
CC = g++

serialhandler: main.o serial_port.o
        $(CC) $(LFLAGS) -o serialhandler main.o serial_port.o

main.o: main.cpp serial_port.h

serial_port.o: serial_port.cpp serial_port.h

clean:
        rm -f serialhandler
        rm -f main.o
        rm -f serial_port.o

.SUFFIXES: .cpp

.cpp.o:
        $(CC) -c $(CFLAGS) $(INCL) -o $@ $<
[/code:1]

总算完了,下面我有几个问题想请教

这个程序现在还有一个小小的bug
如果在终端以-t方式运行程序,在命令行中输入字串回车,则发送出该字串,
可是当字串长度等于或超过32时,就会在发出该字串后自动发送回车符,其原因
是getline那一句不起作用了,直接跳过去了,就开始不停的循环
为什么会这样,我怀疑和以下问题相似:
http://mathbits.com/MathBits/CompSci/APstrings/APgetline.htm
可是用同样的方法根本无法修正此bug,况且我在getline之前并没有
调用cin >>呀

还有一个问题我已经避过去了,但是问题的原因还没有想明白
起初的程序输出用的是cout << buffer << endl
这个时候如果向该串口发送字符超过8个,将会以8为单位进行截断
也就是说,我发送的是:
aaaaaaaaaaaaaaaaaaaa
但接收的却是:
aaaaaaaa
aaaaaaaa
aaaa
用gdb调试时却一切正常(难道延时能解决问题?)
这究竟是怎么回事?

我是个新手,还没入门,请多多指点
万分感激!!!!!!!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2024-11-15 00:02 , Processed in 0.080228 second(s), 16 queries .

© 2021 Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表