1. 串口编程
串口编程的一般步骤为:
- 打开串口设备(一般为/dev/ttyS[n])
- 设置串口参数(包括波特率、数据位、停止位、校验位等)
- 监听接口,当有数据时通知CPU
- 读取串口(写入数据到串口)
- 关闭串口设备
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产生一个坐标点(循环产生)。/************************************************************************ * 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#include #include #include #include #include #include #include #include #include #include #include #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;}