串口编程(二) - 代码实现
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 <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;
}