串口编程(二) - 代码实现

1. 串口编程

串口编程的一般步骤为:

    1. 打开串口设备(一般为/dev/ttyS[n])
    1. 设置串口参数(包括波特率、数据位、停止位、校验位等)
    1. 监听接口,当有数据时通知CPU
    1. 读取串口(写入数据到串口)
    1. 关闭串口设备

mark

2. 代码示例

1). 串口的基本配置

/************************************************************************
 * Function_name: serial_open
 * Description: Open the /dev/ttyS[n] serial device
 * Input: 
 *		1. int port_num: the serial device port number
 * Output: None
 * Return: the device description
 *
 * Autor		Time			Content
 * Jimmy	2018-04-05			Create	
 *
 ************************************************************************/

int serial_open(int port_num)
{
    int fd = -1;
    char device[16];
    memset(device, '\0', sizeof(device));
    sprintf(device, "/dev/ttyS%d", port_num);

    fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);

    if(-1 == fd)
    {
        printf("Open the %s failed! [%d:%s]\n", device, errno, strerror(errno));
        return -1;
    }

    fcntl(fd, F_SETFL, 0);      //Use the block mode

    return fd;
}

/************************************************************************
 * Function_name: set_parm
 * Description: set the serial device paramters
 * Input: 
 *		1. int fd: the device description
		2. int speed: the band speed
		3. int data_bits: the data bits(7bit or 8bit)
		4. int stop_bits: stop  bits(1bit or 2bit)
		5. char parity: the parity(odd/even/none)
 * Output: None
 * Return: 
		0:	succeed
		-1:	error
 *
 * Autor		Time			Content
 * Jimmy	2018-04-05			Create	
 *
 ************************************************************************/
int set_parm(int fd, int speed, int data_bits, int stop_bits, char parity)
{
    struct termios old_opt;
    struct termios new_opt;

    int rtn = 0;

    //1. get the old termios options
    rtn = tcgetattr(fd, &old_opt);
    if(rtn != 0)
    {
        printf("tcgetattr failed! [%d:%s]\n", errno, strerror(errno));
        rtn = -1;
    }

    if(0 == rtn)
    {
        //2. set the io speed
        tcflush(fd, TCIOFLUSH);     //flush the io data

        //3. set the io speed
        switch(speed)
        {
            case 2400:
                cfsetispeed(&new_opt, B2400);
                cfsetospeed(&new_opt, B2400);
                break;
            case 4800:
                cfsetispeed(&new_opt, B4800);
                cfsetospeed(&new_opt, B4800);
                break;
            case 9600:
                cfsetispeed(&new_opt, B9600);
                cfsetospeed(&new_opt, B9600);
                break;
            case 19200:
                cfsetispeed(&new_opt, B19200);
                cfsetospeed(&new_opt, B19200);
                break;
            case 38400:
                cfsetispeed(&new_opt, B38400);
                cfsetospeed(&new_opt, B38400);
                break;
            case 57600:
                cfsetispeed(&new_opt, B57600);
                cfsetospeed(&new_opt,  B57600);
                break;
            case 115200:
                cfsetispeed(&new_opt, B115200);
                cfsetospeed(&new_opt, B115200);
                break;
            case 230400:
                cfsetispeed(&new_opt, B230400);
                cfsetospeed(&new_opt, B230400);
                break;
            default:
                cfsetispeed(&new_opt, B115200);
                cfsetospeed(&new_opt, B115200);
                break;
        }

        //4. set the data bits 
        new_opt.c_cflag &= ~CSIZE;
        switch(data_bits)
        {
            case 7:
                new_opt.c_cflag |= CS7;
                break;
            case 8:
                new_opt.c_cflag |= CS8;
                break;

            default:
                printf("Error on set the data bits\n");
                break;
        }

        //5. set the stop bits
        switch(stop_bits)
        {
            case 1: //set the stop 1 bit
                new_opt.c_cflag &= ~CSTOPB;
                break;

            case 2:
                new_opt.c_cflag |= CSTOPB;
                break;

            default:
                printf("Error on set the stop bits\n");
                break;
        }

        //6. set the parity
        switch(parity)
        {
            case 'N':
            case 'n':
                new_opt.c_cflag &= ~PARENB; //clear parity enable 
                break;

            case 'E':
            case 'e':
                new_opt.c_cflag |= PARENB; //clear parity enable 
                new_opt.c_cflag &= ~PARODD;
                new_opt.c_cflag |= (INPCK | ISTRIP);
                break;

            case 'O':
            case 'o':
                new_opt.c_cflag |= PARENB;
                new_opt.c_cflag |= PARODD;
                new_opt.c_cflag |= (INPCK | ISTRIP);   //Enable the input parity checking, and strip the eigth bit
                break;

            default:
                printf("Error on set the parity!\n");
                break;
        }

        //7. set the wait time and mix received characters
        new_opt.c_cc[VTIME] = 0;
        new_opt.c_cc[VMIN] = 0;

        //8. set the attribute and valid now
        tcflush(fd, TCIOFLUSH);
        if(tcsetattr(fd, TCSANOW, &new_opt) != 0)
        {
            printf("Error on tcsetattr! [%d:%s]!\n", errno, strerror(errno));
            rtn = -1;
        }
    }

    printf("set the parameter ok!\n");
    return rtn;
}

/************************************************************************
 * Function_name: serial_send
 * Description: send data to the serial device
 * Input: 
 		1. int fd: device description
		2. char *p_buf: the send data buffer
		3. int len: the data length
 * Output: None
 * Return: 
		>=0: 	on succeed
		-1:		input argument illegal
		-2:		write data error
 *
 * Autor		Time			Content
 * Jimmy	2018-04-05			Create	
 *
 ************************************************************************/
int serial_send(int fd, char *p_buf, int len)
{

    int wr_len = -1;

    if((fd < 0) || (NULL == p_buf) || (len < 0))
    {
        printf("Input arguments are illegal!\n");
        return -1;
    }

    wr_len = write(fd, p_buf, len);

    if(wr_len < 0)
    {
        printf("write %d bytes failed!\n", len);
        return -1;
    }

    return wr_len;
}

/************************************************************************
 * Function_name: serial_recv
 * Description: recv the data from serial device
 * Input: 
 		1. int fd: device description
		2. char *p_buf: the recv data buffer
		3. int len: the data length
 * Output: None
 * Return: 
 		>=0: 	on succeed
		-1:		input argument illegal
		-2:		write data error
 *
 * Autor		Time			Content
 * Jimmy	2018-04-05			Create	
 *
 ************************************************************************/
int serial_recv(int fd, char *p_buf, int len)
{
    int rd_len = 0;

    if((fd < 0) || (NULL == p_buf) || (len <= 0))
    {
        printf("Input arguments are illegal!\n");
        return -1;
    }

    rd_len = read(fd, p_buf, len);

    if(rd_len < 0)
    {
        printf("write %d bytes failed!\n", len);
        return -2;
    }

    return rd_len;
}

/************************************************************************
 * Function_name: serial_recv_pthread
 * Description: read data thread, used to read the serial device port
 * Input: 
 		1. void *data: the data that transfer to the thread 
 * Output: None
 * Return: None
 *
 * Autor		Time			Content
 * Jimmy	2018-04-05			Create	
 *
 ************************************************************************/
void * serial_recv_pthread(void *p_data)
{
    char recv_buf[RECV_LEN];
    int rtn_val = 0;
    int len = 0;
    int recv_len = 0; //total received data length

    fd_set rdfs;
    struct timeval tv;


    while(FALSE == THREAD_EXIT)
    {
        //1. set the read fd set
        FD_ZERO(&rdfs);
        FD_SET(*(int *)p_data, &rdfs);
        
        tv.tv_sec = 5;  //Delay time is 5 seconds
        tv.tv_usec = 0;

        //2. wait the serial port data comming
        rtn_val = select(*(int *)p_data+1, &rdfs, NULL, NULL, &tv);

        if(rtn_val == -1)
        {
            printf("select failed!\n");
            continue;
        }
        else if(0 == rtn_val)
        {
            printf("Time out[5 seconds]\n");
            continue;
        }
        else
        {
            //3. read the port data to buffer
            do{
                len = serial_recv(*(int *)p_data, &recv_buf[recv_len], 128);
                recv_len += len;
            }while(len > 0);

            printf("Received total length is %d\n", recv_len);
        }
    }
	
	return (void *)0;
}

2). 发送数据
数据有三个自由度(x,y,yaw),我们设计了一个如上图所示的轨迹,没200mm产生一个坐标点(循环产生)。

mark

mark

/************************************************************************
 * Function_name: calc_checksum 
 * Description: calc the data crc 
 * Input: 
 		1. char *buf: data buffer
		2. int data_len: the buffer data length
 * Output: None
 * Return:  crc number
 *
 * Autor		Time			Content
 * Jimmy	2018-04-05			Create	
 *
 ************************************************************************/
char calc_crc(char *buf,int data_len)
{
    int i = 0;
    char sum;
    unsigned short tmp = 0;
	
    while (i < data_len)
    {
        tmp += ((unsigned char)buf[i]);
        i++;
    }
    tmp = tmp & 0x00ff;
    sum = tmp ;
	
    return sum;
}

/************************************************************************
 * Function_name: send_data
 * Description: send the data to device[data is eaggle, 4*4 sq.m]
 * Input: 
 		1. void *data: the data that transfer to the thread 
 * Output: None
 * Return: None
 *
 * Autor		Time			Content
 * Jimmy	2018-04-05			Create	
 *
 ************************************************************************/
int send_data(int fd)
{
    int rtn = 0;
	int i=0;

    int y_dir = 1;
    int x_dir = 1;
    int x=0; 
    int y=0;
    int yaw = 0;

    map_coor_t t_map_coor;
    memset(&t_map_coor, 0, sizeof(map_coor_t));

    t_map_coor.head[0] = 0xEE;
    t_map_coor.head[1] = 0xFF;
    t_map_coor.cmd_type = 0x01;
    t_map_coor.type = 0x00;
    
    while(FALSE == THREAD_EXIT)
    {
        x += 200*x_dir;

        if(x >= 20000)
        {
            x = 20000;
            x_dir = -1;
            yaw = 31416;

            goto FLAG_1;
        }

        if(x <= -20000)
        {
            x = -20000;
            x_dir = 1;
            yaw = 0;

            goto FLAG_1;
        }

        if(y >= 20000)
        {
            y = 20000;
            y_dir = -1;
            yaw = 15708;
        }

        if(y <= -20000)
        {
            y = -20000;
            y_dir = 1;
            yaw = -15708;
        }

        goto FLAG_2;

        FLAG_1:
        for(i=1; i<=10; i++)
        {
            y += 200*y_dir;
            {
                t_map_coor.x = x;
                t_map_coor.y = y;
                t_map_coor.yaw = (y_dir==1)? 15708:-15708; 
                t_map_coor.crc = calc_crc((char *)&t_map_coor, sizeof(map_coor_t)-1); 

                printf("x=%d, y=%d, yaw=%d\n", x, y, t_map_coor.yaw);

                sleep(1);
                serial_send(fd, (char *)&t_map_coor, sizeof(t_map_coor));
            }
        }

        FLAG_2:
        {
            t_map_coor.x = x;
            t_map_coor.y = y;
            t_map_coor.yaw = yaw;
            t_map_coor.crc = calc_crc((char *)&t_map_coor, sizeof(map_coor_t)-1); 

            printf("x=%d, y=%d, yaw=%d\n", x, y, yaw);

            sleep(1);
            serial_send(fd, (char *)&t_map_coor, sizeof(t_map_coor));
        }
    }

    return rtn;
}

**3). main函数

/*************************************************************************************
 * Filename: 
 * Autor: Jimmy  2018-04-05
 *
 ************************************************************************************/
 
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <sys/time.h>
#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
#include <pthread.h>
#include <signal.h>

#define SERIAL_PORT 1
#define RECV_LEN    1024
#define	TRUE		0
#define FALSE		1
#define	PACKED __attribute__ ((packed))	//Cancel byte alignmen

/************************************************************************
 * Function_name: installsig
 * Description: install the SIGINT and SIGTERM signal
 * Input: 
 		1. 
 * Output: None
 * Return: None
 *
 * Autor		Time			Content
 * Jimmy	2018-04-05			Create	
 *
 ************************************************************************/
void sigroutine(int signo)
{
	if(g_serial_fd == -1)
	{
		printf("g_serial_fd was not init !!\n");
	}
	else
	{
		close(g_serial_fd);
	}
	THREAD_EXIT = TRUE;
}
 
void installsig() 
{
	struct sigaction act;

	sigemptyset(&act.sa_mask);

	act.sa_flags = SA_RESETHAND;
	act.sa_handler = sigroutine;

	if (sigaction(SIGINT,&act,NULL) < 0)
	{
		printf("install sigal error\n");
		
	}
	else
	{
		printf("install for sigTERM \n");
	}

	if (sigaction(SIGTERM,&act,NULL) < 0)
	{
		printf("install sigal error\n");
	}
	else
	{
		printf("install for sigTERM \n");
	}
}

/************************************************************************
 * Function_name: main
 * Description: 
 * Input: 
 		1. 
 * Output: None
 * Return: None
 *
 * Autor		Time			Content
 * Jimmy	2018-04-05			Create	
 *
 ************************************************************************/
int main(int argc, char *argv[])
{
    int fd = -1;
	int rtn = 0;
    pthread_attr_t thread_attr;
	pthread_t	serial_id;
	
    if(argc != 2)
    {
	    printf("argc error!  argc=%d\n", argc);
	    return -1;
    }
	
	//0. install the sigaction
	installsig();
	
    int serial_port = atoi(argv[1]); 
    printf("serial_port=%d\n", serial_port);
    
    //1. open the serial port
    //fd = open_port(SERIAL_PORT); 
    fd = serial_open(serial_port); 

    if(fd == -1)
    {
        exit(EXIT_FAILURE);
    }
	
	g_serial_fd = fd;
	
    //2. set the serial port parameters
    rtn = set_parm(fd, 115200, 8, 1,'N' );    
    if(rtn != 0)
    {
        exit(EXIT_FAILURE);
    }
	
    //3. start the read thread
	pthread_attr_init(&thread_attr);
	pthread_attr_setdetachstate(&thread_attr,PTHREAD_CREATE_DETACHED);		//detached the thread, with mian thread wait
	
	pthread_create(&serial_id,&thread_attr, serial_recv_pthread, NULL);

    //4. send the data to serail port_
    send_data(fd);  
	
    return 0;
}

posted @ 2018-04-05 14:15  Jimmy_Nie  阅读(993)  评论(0编辑  收藏  举报