LINUX多线程读写串口实例-鑫天视景虚拟现实数据手套
  • 联系我们   Contact
    您的位置:首页 > 新闻动态 > 技术文章

    LINUX多线程读写串口实例

    2020/4/24      点击:

    LINUX环境下,使用多线程读写串口: 

    普通串口 MODEMDEVICE "/dev/ttyS0" 

    USB转串口MODEMDEVICE "/dev/ttyUSB0" 

    获取串口控制权限, sudo chmod 666 /dev/ttyUSB0 

    使用特殊设定,实现任意自定义波特率,例如B256000 B460800等等。

    // 设置为特殊波特率,比如200000, 这个设置方法在虚拟机环境下不能通过,需要在真正的UBUNTU环境下才可以^_^
    int set_anybaud(int fd, int baud)
    {
    	int   status;
    	struct termios   Opt;
    	struct serial_struct Serial;
    	tcgetattr(fd, &Opt);
    	tcflush(fd, TCIOFLUSH);
    	printf("\ncfsetispeed(&Opt,B38400)\n");
    	cfsetispeed(&Opt, B38400);
    	cfsetospeed(&Opt, B38400);
    	tcflush(fd, TCIOFLUSH);
    	status = tcsetattr(fd, TCSANOW, &Opt);
    	if (status != 0)
    	{
    		perror("tcsetattr fd1");
    		return -1;
    	}
    
    	if ((ioctl(fd, TIOCGSERIAL, &Serial)) < 0) 
    	{
    		printf("Fail to get Serial!\n");
    		return -2;
    	}
    	Serial.flags = ASYNC_SPD_CUST;
    	Serial.custom_divisor = Serial.baud_base / baud;
    	printf("分频系数 %x\n", Serial.custom_divisor);
    	if ((ioctl(fd, TIOCSSERIAL, &Serial)) < 0)
    	{
    		printf("分频设置: ERROR\n");
    		return -3;
    	}
    	printf("分频设置: OK.\n");
    
    	ioctl(fd, TIOCGSERIAL, &Serial);
    	printf("\nBAUD: success set baud to %d,custom_divisor=%d,baud_base=%d\n", baud
    		, Serial.custom_divisor, Serial.baud_base);
    	return 0;
    }

    测试源文件代码如下:

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include#include 
    #include 
    #include 
    #include "Wiseglove.h" 
    
    #define BAUDRATE B115200
    #define MODEMDEVICE "/dev/ttyS0"
    #define R_BUF_LEN (256)
    void printtid(void);
    void* com_read(void* pstatu)
    {
    	printtid();
    	int i=0;
    	int fd,c=0,num;
    	struct termios oldtio,newtio;
    	char buf[R_BUF_LEN];
    	printf("start.../n");
    	/*打开PC机的COM1通信端口*/
    	fd=open(MODEMDEVICE,O_RDWR | O_NOCTTY | O_NONBLOCK /*| O_NDELAY*/); //非阻塞式
    	if(fd<0)
    	{
    		perror(MODEMDEVICE);
    		exit(1);
    	}
    	printf("open .../n");
    	/*将目前终端机的结构保存至oldtio结构*/
    	tcgetattr(fd,&oldtio);
    	/*清除newtio结构,重新设置通信协议*/
    	bzero(&newtio,sizeof(newtio));
    	/*通信协议设为8N1,8位数据位,N没有效验,1位结束位*/
    	newtio.c_cflag = BAUDRATE |CS8|CLOCAL|CREAD;
    	newtio.c_iflag = IGNPAR;
    	newtio.c_oflag = 0;
    	/*设置为正规模式*/
    	newtio.c_lflag=ICANON;
    	/*清除所有队列在串口的输入*/
    	tcflush(fd,TCIFLUSH);	/*新的termios的结构作为通信端口的参数*/
    	tcsetattr(fd,TCSANOW,&newtio);
    	printf("reading.../n");
    	while(*(int*)pstatu)
    	{
    		num = read(fd,buf, R_BUF_LEN);
    		buf[R_BUF_LEN-1] = 0;
    		if(num > 0 && num <= R_BUF_LEN)
    		{ 
    			buf[num]=0;
    			printf("%s", buf);
    			fflush(stdout);
    		}
    	}
    	printf("close.../n");
    	close(fd);
    	/*恢复*/
    	tcsetattr(fd,TCSANOW,&oldtio);
    }
    void* com_send(void* p)
    {
    	printtid();
    	int fd,c=0;
    	struct termios oldtio,newtio;
    	char ch;
    	static char s1[20];
    	printf("Start.../n ");
    	/*打开arm平台的COM1通信端口*/
    	fd=open(MODEMDEVICE,O_RDWR | O_NOCTTY);
    	if(fd<0)
    	{
    		perror(MODEMDEVICE);
    		exit(1);
    	}
    	printf(" Open.../n ");
    	 /*将目前终端机的结构保存至oldtio结构*/
           tcgetattr(fd,&oldtio);
    	/*清除newtio结构,重新设置通信协议*/
    	bzero(&newtio,sizeof(newtio));
    	/*通信协议设为8N1*/
    	newtio.c_cflag =BAUDRATE |CS8|CLOCAL|CREAD; //波特率 8个数据位 本地连接 接受使能
    	newtio.c_iflag=IGNPAR;                      //忽略奇偶校验错误
    	newtio.c_oflag=0;
    	/*设置为正规模式*/
    	newtio.c_lflag=ICANON;                     //规范输入
    	/*清除所有队列在串口的输出*/
    	tcflush(fd,TCOFLUSH);
    	/*新的termios的结构作为通信端口的参数*/
    	tcsetattr(fd,TCSANOW,&newtio);
    	printf("Writing.../n ");
    	///*
    	while(*(char*)p != 0)
    	{
    		int res = 0;
    		res = write(fd,(char*)p, 1);
    		if(res != 1) printf("send %c error/n", *(char*)p);
    		else printf("send %c ok/n", *(char*)p);
    		++p;
    	}
    	printf("Close.../n");
    	close(fd);
    	/*还原旧的通信端口参数*/
    	tcsetattr(fd,TCSANOW,&oldtio);
    	printf("leave send thread/n");
    }
    /*
    	开始线程
    	thread_fun	线程函数
    	pthread		线程函数所在pthread变量
    	par		线程函数参数
    	COM_STATU	线程函数状态控制变量 1:运行 0:退出
    */
    int start_thread_func(void*(*func)(void*), pthread_t* pthread, void* par, int* COM_STATU)
    {
    	*COM_STATU = 1;
    	memset(pthread, 0, sizeof(pthread_t));
    	int temp;
            /*创建线程*/
            if((temp = pthread_create(pthread, NULL, func, par)) != 0)
    		printf("线程创建失败!/n");
            else
    	{
    		int id = pthread_self();
                    printf("线程%u被创建/n", *pthread);
    	}
    	return temp;
    }
    /*
    	结束线程
    	pthread		线程函数所在pthread变量
    	COM_STATU	线程函数状态控制变量 1:运行 0:退出
    */
    int stop_thread_func(pthread_t* pthread, int* COM_STATU)
    {
    	printf("prepare stop thread %u/n", *pthread);
    	*COM_STATU = 0;
     	if(*pthread !=0) 
    	{
                    pthread_join(*pthread, NULL);
    	}
    	printf("线程%d退出!/n", *COM_STATU);
    }
    void printtid(void)
    {
    	int id = pthread_self();
            printf("in thread %u/n", id);
    }
    int main()
    {
    	pthread_t thread[2];
    	printtid();
    	const int READ_THREAD_ID = 0;
    	const int SEND_THREAD_ID = 1;
    	int COM_READ_STATU = 0;
    	int COM_SEND_STATU = 0;
    	if(start_thread_func(com_read, &thread[READ_THREAD_ID],  &COM_READ_STATU, &COM_READ_STATU) != 0)
    	{
    		printf("error to leave/n");
    		return -1;
    	}
    	printf("wait 3 sec/n");
    	sleep(3);
    	printf("wake after 3 sec/n");
    	if(start_thread_func(com_send, &thread[SEND_THREAD_ID], "ABCDEFGHIJKLMNOPQRST", &COM_SEND_STATU) != 0)
    	{
    		printf("error to leave/n");
    		return -1;
    	}
    	printtid();
    	printf("wait 10 sec/n");
    	sleep(10);
    	printf("wake after 10 sec/n");
    	stop_thread_func(&thread[READ_THREAD_ID], &COM_READ_STATU);
    	stop_thread_func(&thread[SEND_THREAD_ID], &COM_SEND_STATU);
    	return 0;
    }
  • 上一篇:没有啦
  • 下一篇:motionbuilder动作数据文件的导入 2020/3/15