ARM初学者 https://bbs.21ic.com/?367665 [收藏] [复制] [RSS]

日志

liunx之串口

已有 1563 次阅读2009-6-1 03:48 |系统分类:嵌入式系统

在i386上实现串口收发数据的程序。

/*本程序符合GPL条约
MyCom.c
*/
#include <stdio.h>              // printf
#include <fcntl.h>              // open
#include <string.h>             // bzero
#include <stdlib.h>             // exit
#include <sys/times.h>          // times
#include <sys/types.h>          // pid_t
#include <termios.h>        //termios, tcgetattr(), tcsetattr()
#include <unistd.h>

#include <sys/ioctl.h>          // ioctl
#include "mycom.h"

#define    TTY_DEV    "/dev/ttyS"    //端口路径

//#define U16C550A        //for SBS pc104 serial port(cpu onboard com1\com2) 
//#define U16C954            //for SBS pc104+ serial port(sem/7513,scm/7026 com3-com6 etc.)

#define TIMEOUT_SEC(buflen,baud) (buflen*20/baud+2)  //接收超时
#define TIMEOUT_USEC 0
/*******************************************
 *    获得端口名称
********************************************/
static char *get_ptty(portinfo_t * pportinfo)
{
    char *ptty;

    switch(pportinfo->tty){
        case 0:{
            ptty = TTY_DEV"0";
        }break;
        case 1:{
            ptty = TTY_DEV"1";
        }break;
        case 2:{
            ptty = TTY_DEV"2";
        }break;
        case 3:{
            ptty = TTY_DEV"3";
        }break;
        case 4:{
            ptty = TTY_DEV"4";
        }break;
        case 5:{
            ptty = TTY_DEV"5";
        }break;
        case 6:{
            ptty = TTY_DEV"6";
        }break;
        case 7:{
            ptty = TTY_DEV"7";
        }break;
        case 8:{
            ptty = TTY_DEV"8";
        }break;
        case 9:{
            ptty = TTY_DEV"9";
        }break;
    }
    return(ptty);
}

/*******************************************
 *    波特率转换函数(请确认是否正确)
********************************************/
int convbaud(unsigned long int baudrate)
{
    switch(baudrate){
        case 2400:
            return B2400;
        case 4800:
            return B4800;
        case 9600:
            return B9600;
        case 19200:
            return B19200;
        case 38400:
            return B38400;
        case 57600:
            return B57600;
        case 115200:
            return B115200;
        default:
            return B9600;
    }
}

/*******************************************
 *    Setup comm attr
 *    fdcom: 串口文件描述符,pportinfo: 待设置的端口信息(请确认)
 *
********************************************/
int PortSet(int fdcom, const portinfo_t *pportinfo)
{
    struct termios termios_old, termios_new;
    int     baudrate, tmp;
    char    databit, stopbit, parity, fctl;

    bzero(&termios_old, sizeof(termios_old));
    bzero(&termios_new, sizeof(termios_new));
    cfmakeraw(&termios_new);
    tcgetattr(fdcom, &termios_old);            //get the serial port attributions
    /*------------设置端口属性----------------*/
    //baudrates
    baudrate = convbaud(pportinfo -> baudrate);
    cfsetispeed(&termios_new, baudrate);        //填入串口输入端的波特率
    cfsetospeed(&termios_new, baudrate);        //填入串口输出端的波特率
    termios_new.c_cflag |= CLOCAL;            //控制模式,保证程序不会成为端口的占有者
    termios_new.c_cflag |= CREAD;            //控制模式,使能端口读取输入的数据

    // 控制模式,flow control
    fctl = pportinfo-> fctl;
    switch(fctl)
    {
        case '0':{
            termios_new.c_cflag &= ~CRTSCTS;        //no flow control
        }break;
        case '1':{
            termios_new.c_cflag |= CRTSCTS;            //hardware flow control
        }break;
        case '2':{
            termios_new.c_iflag |= IXON | IXOFF |IXANY;    //software flow control
        }break;
    }

    //控制模式,data bits
    termios_new.c_cflag &= ~CSIZE;        //控制模式,屏蔽字符大小位
    databit = pportinfo -> databit;
    switch(databit)
    {
        case '5':
        {
            termios_new.c_cflag |= CS5;
        }break;   
        case '6':
        {
            termios_new.c_cflag |= CS6;
        }break;
        case '7':
        {
            termios_new.c_cflag |= CS7;
        }break;
        default:
            termios_new.c_cflag |= CS8;
    }

    //控制模式 parity check
    parity = pportinfo -> parity;
    switch(parity)
    {
        case '0':
        {
            termios_new.c_cflag &= ~PARENB;        //no parity check
        }break;
        case '1':
        {
            termios_new.c_cflag |= PARENB;        //odd check
            termios_new.c_cflag &= ~PARODD;
        }break;
        case '2':
        {
            termios_new.c_cflag |= PARENB;        //even check
            termios_new.c_cflag |= PARODD;
        }break;
    }

    //控制模式,stop bits
    stopbit = pportinfo -> stopbit;
    if(stopbit == '2')
    {
        termios_new.c_cflag |= CSTOPB;    //2 stop bits
    }
    else
    {
        termios_new.c_cflag &= ~CSTOPB;    //1 stop bits
    }

    //other attributions default
    termios_new.c_oflag &= ~OPOST;            //输出模式,原始数据输出
    termios_new.c_cc[VMIN]  = 1;            //控制字符, 所要读取字符的最小数量
    termios_new.c_cc[VTIME] = 1;            //控制字符, 读取第一个字符的等待时间    unit: (1/10)second

    tcflush(fdcom, TCIFLUSH);                //溢出的数据可以接收,但不读
    tmp = tcsetattr(fdcom, TCSANOW, &termios_new);    //设置新属性,TCSANOW:所有改变立即生效    tcgetattr(fdcom,&termios_old);
    return(tmp);
}

/*******************************************
 *    Open serial port
 *    tty: 端口号 ttyS0, ttyS1, ....
 *    返回值为串口文件描述符
********************************************/
int PortOpen(portinfo_t *pportinfo)
{
    int fdcom;    //串口文件描述符
    const char *ptty;

    ptty = (const char *)get_ptty(pportinfo);
    //fdcom = open(ptty, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
    fdcom = open(ptty, O_RDWR | O_NOCTTY | O_NONBLOCK);

    return (fdcom);
}

/*******************************************
 *    Close serial port
********************************************/
void PortClose(int fdcom)
{
    close(fdcom);
}

/********************************************
 *    send data
 *    fdcom: 串口描述符,data: 待发送数据,datalen: 数据长度
 *    返回实际发送长度
*********************************************/
int PortSend(int fdcom, char *data, int datalen)
{
    int len = 0;
#ifdef U16C954
    int line =TIOCM_DTR;            //for 16954 chip,use DTR instead of RTS
#else
    int line =TIOCM_RTS;
#endif
    if(ioctl(fdcom,TIOCMBIS,&line))        // 1--send 0--receive
        printf("enter send mode error \n");
    usleep(10);
   
    len = write(fdcom, data, datalen);    //实际写入的长度
    if(len == datalen){
        return (len);
    }
    else{
        tcflush(fdcom, TCOFLUSH);
        return -1;
    }
}

/*******************************************
 *    receive data
 *    返回实际读入的字节数
 *
********************************************/
int PortRecv(int fdcom, char *data, int datalen, int baudrate)
{
    int readlen, fs_sel;
    fd_set    fs_read;
    struct timeval tv_timeout;
#ifdef U16C954
    int line = TIOCM_DTR;
#else
    int line = TIOCM_RTS;
#endif
   
    if (ioctl(fdcom,TIOCMBIC,&line))
        printf("enter receive mode error\n");
    usleep(10);

    FD_ZERO(&fs_read);
    FD_SET(fdcom, &fs_read);
    tv_timeout.tv_sec = TIMEOUT_SEC(datalen, baudrate);
    tv_timeout.tv_usec = TIMEOUT_USEC;

    fs_sel = select(fdcom+1, &fs_read, NULL, NULL, &tv_timeout);
    if(fs_sel){
        readlen = read(fdcom, data, datalen);
        return(readlen);
    }
    else{
        return(-1);
    }

    return (readlen);
}

//*************************Test*********************************
int main(int argc, char *argv[])
{
    int fdcom, i, SendLen, RecvLen,iii,jjj,kkk;
    struct termios termios_cur;
    char RecvBuf[256];
    unsigned long index;
    portinfo_t portinfo ={
        '0',                              // print prompt after receiving
         2400,                          // baudrate: 115200
         '8',                              // databit: 8
         '0',                              // debug: off
         '0',                              // echo: off
         '0',                              // flow control: none
         atoi(argv[2]),                  // 获取第二参数决定使用哪个串口
         '0',                              // parity: none
         '1',                              // stopbit: 1
          0                              // reserved
    };

    if(argc != 3){
        printf("Usage: %s type port\n",argv[0]);
        printf("  type section may be: 0--send,1--receive\n");
        printf("  port section may be: 0~9\n");
        exit(-1);
    }

    fdcom = PortOpen(&portinfo);
    if(fdcom<0){
        printf("Error: open serial port error.\n");
        exit(1);
    }

    PortSet(fdcom, &portinfo);
    if(atoi(argv[1]) == 0)//获取第一个参数选择是发送还是接收
    {
        //send data
        for(i=0; i<100; i++)
        {
//            SendLen = PortSend(fdcom, "0xff", 1);
//            SendLen = PortSend(fdcom, "0x0a", 1);
//            SendLen = PortSend(fdcom, "0x12", 1);
//            SendLen = PortSend(fdcom, "0x34", 1);
//            SendLen = PortSend(fdcom, "0x56", 1);
//            SendLen = PortSend(fdcom, "0x78", 1);
//            SendLen = PortSend(fdcom, "0x11", 1);
//            SendLen = PortSend(fdcom, "0x11", 1);
//            SendLen = PortSend(fdcom, "0x11", 1);
//            SendLen = PortSend(fdcom, "0x19", 1);
//            SendLen = PortSend(fdcom, "0x14", 1);
//            SendLen = PortSend(fdcom, "0x11", 1);
//            SendLen = PortSend(fdcom, "0x11", 1);
//            SendLen = PortSend(fdcom, "0x11", 1);
            SendLen = PortSend(fdcom, "1234567890", 10);
            if(SendLen > 0)
            {
                printf("No %d send %d data 1234567890.\n", i, SendLen);
            }
            else{
                printf("Error: send failed.\n");
            }
            sleep(1);
        }
        PortClose(fdcom);
    }
    else
    {
        index = 1;
        for(;;)
        {
            RecvLen = PortRecv(fdcom, RecvBuf, 256, portinfo.baudrate);
            if (RecvLen > 0)
            {
                for(i = 0; i < RecvLen; i++)
                {
                    printf("0x%02X ", RecvBuf & 0xff);
                }
                printf("                                           Index:%000000000010ld\r\n",index & 0xffffffff);
                index++;
            }
            else
            {
//                printf("Error: receive error.\n");
            }
//            printf("\r\n");
        }
    }
    return 0;
}

路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)