Linux串口应用编程

news2024/10/7 12:23:48

在Linux系统中,操作设备的统一接口就是:open/ioctl/read/write
对于UART,又在ioctl之上封装了很多函数,主要是用来设置行规程。
所以对于UART,编程的套路就是:

  • 使用open函数打开串口
  • 设置行规程,比如波特率、数据位、停止位、检验位、RAW模式、一有数据就返回
  • read/write数据
    在这里插入图片描述

1. 打开串口

由于串行端口是一个文件,因此使用open(2)函数来访问它。C语言代码示例如下。

1.1 示例

#include <stdio.h>   /* 标准输入/输出定义 */
#include <string.h>  /* 字符串函数定义 */
#include <unistd.h>  /* UNIX标准函数定义 */
#include <fcntl.h>   /* 文件控制定义 */
#include <errno.h>   /* 错误号定义 */
#include <termios.h> /* POSIX终端控制定义 */

// 成功时返回文件描述符,错误时返回-1。
int open_port(void){
  int fd; /* 端口的文件描述符 */
  fd = open("/dev/ttyf1", O_RDWR | O_NOCTTY | O_NDELAY);
  if (fd == -1){// 打开端口失败
    perror("open_port: Unable to open /dev/ttyf1 - ");
  }
  else
    fcntl(fd, F_SETFL, 0);
  return (fd);
}

其他系统可能需要相应的设备文件名,但除此之外代码是相同的。

1.2 open函数的标志位

当我们打开设备文件时,我们使用了另外两个标志以及读+写模式:

fd = open("/dev/ttyf1", O_RDWR | O_NOCTTY | O_NDELAY);

其中,

  • O_NOCTTY :表示告诉操作系统,应用程序(进程)打开串口之后,不要把程序当作控制终端。如果指定这一点,那么任何输入(如键盘中止信号等)都将影响进程。
  • O_NDELAY:表示告诉操作系统,应用程序(进程)不关心DCD信号线的状态,即不关心端口的另一端是否启动并运行。如果没有指定这个标志,进程将被置于休眠状态,直到DCD信号线是空间电压。

2. 配置串口

配置串口也就是设置行规程,行规程的参数用结构体struct termios来表示。设置行规程就是设置该结构体中成员的值。

2.1 结构体struct termios

结构体struct termios定义如下:
在这里插入图片描述

struct termios{
	unsigned short c_iflag;   /* 输入模式标志*/
	unsigned short c_oflag;   /* 输出模式标志*/
	unsigned short c_cflag;   /* 控制模式标志*/
	unsigned short c_lflag;   /* 区域模式标志或本地模式标志或局部模式*/
	unsigned char c_line;     /* 行控制line discipline */
	unsigned char c_cc[NCC];  /* 控制字符特性*/
};

2.2 struct termios作用

struct termios被用来提供一个健全的线路设置集合, 如果这个端口在被用户初始化前使用. 驱动初始化这个变量使用一个标准的数值集, 它拷贝自 tty_std_termios 变量. tty_std_termostty 核心被定义为:

struct termios tty_std_termios = {
	.c_iflag = ICRNL | IXON;
	.c_oflag = OPOST | ONLCR;
	.c_cflag = B38400 | CS8 | CREAD | HUPCL;
	.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
	.c_cc = INIT_C_CC;
};

这个 struct termios 结构用来持有所有的当前线路设置,给这个 tty 设备的一个特定端口。这些线路设置控制当前波特率。数据大小。数据流控设置。以及许多其他值。

2.3 struct termios成员介绍

2.3.1 c_iflag标志常量:Input mode ( 输入模式)

输入模式成员c_iflag控制对端口上接收到的字符所做的任何输入处理。c_iflag中存储的最终值由下表中选项的按位或。

常量描述
INPCK启用奇偶校验
IGNPAR忽略奇偶校验错误
PARMRK标记奇偶校验错误
ISTRIP去掉奇偶校验位
IXON启用输出的 XON/XOFF 流控制
IXOFF启用输入的 XON/XOFF 流控制
IXANY(不属于 POSIX.1;XSI) 允许任何字符来重新开始输出
IGNBRK忽略输入中的 BREAK 状态。 (忽略命令行中的中断)
BRKINT当检测到中断条件时发送SIGINT
INLCR将输入中的 NL 翻译为 CR。(将收到的换行符号转换为Return)
IGNCR忽略输入中的回车
ICRNL将输入中的回车翻译为新行 (除非设置了 IGNCR)(否则当输入信号有 CR 时不会终止输入)
IUCLC(不属于 POSIX) 将输入中的大写字母映射为小写字母
IMAXBEL(不属于 POSIX) 当输入队列满时响零。Linux 没有实现这一位,总是将它视为已设置

2.3.2 c_oflag 标志常量: Output mode ( 输出模式)

c_oflag成员包含输出过滤选项。与输入模式一样,您可以选择已处理原始数据输出。c_oflag 中存储的最终值由下表中选项的按位或。

常量描述
OPOST启用具体实现自行定义的输出处理(未设置=原始输出)
OLCUC(不属于 POSIX) 将输出中的小写字母映射为大写字母
ONLCR(XSI) 将输出中的新行符映射为回车-换行
OCRNL将输出中的回车映射为新行符
ONOCR不在第 0 列输出回车
ONLRET不输出回车
OFILL发送填充字符作为延时,而不是使用定时来延时
OFDEL(不属于 POSIX) 填充字符是 ASCII DEL (0177)。如果不设置,填充字符则是 ASCII NUL
NLDLY新行延时掩码。取值为 NL0 和 NL1
CRDLY回车延时掩码。取值为 CR0, CR1, CR2, 或 CR3
BSDLY回退延时掩码。取值为 BS0 或 BS1。(从来没有被实现过)
VTDLY竖直跳格延时掩码。取值为 VT0 或 VT1
IUCLC(不属于 POSIX) 将输入中的大写字母映射为小写字母
FFDLY进表延时掩码。取值为 FF0 或 FF1

更多选项如下图所示:
在这里插入图片描述
一般有两种输出模式可供选择:
(1)选择已处理输出
通过在c_oflag成员中设置OPOST选项来选择处理后的输出:

options.c_oflag |= OPOST;

在所有不同的选项中,目前只能使用ONLCR选项,它将换行符映射为CR-LF对。其余的输出选项主要是历史上的,可以追溯到行打印机和终端无法跟上串行数据流的时候。
(2)选择原始输出
通过重置c_oflag成员中的OPOST选项来选择原始输出:

options.c_oflag &= ~OPOST;

OPOST选项被禁用时,c_oflag中的所有其他选项位都会被忽略。

2.3.3 c_cflag 标志常量: Control mode ( 控制模式)

c_cflag成员控制波特率、数据位数、奇偶校验、停止位和硬件流控制。所有支持的配置都有常量。

c_cflag中存储的最终值由下表中选项确定。

常量描述
CBAUD(不属于 POSIX) 波特率掩码 (4+1 位)
OLCUC(不属于 POSIX) 扩展的波特率掩码 (1 位),包含在 CBAUD 中
CSIZE字符长度掩码(传送或接收字元时用的位数)。取值为 CS5(传送或接收字元时用5bits), CS6, CS7, 或 CS8
CSTOPB设置两个停止位,而不是一个
CREAD打开接受者
PARENB允许输出产生奇偶信息以及输入的奇偶校验(启用同位产生与侦测)
PARODD输入和输出是奇校验(使用奇同位而非偶同位)
HUPCL在最后一个进程关闭设备后,降低 modem 控制线 (挂断)
CLOCAL忽略 modem 控制线
LOBLK(不属于 POSIX) 从非当前 shell 层阻塞输出(用于 shl )
CIBAUD(不属于 POSIX) 输入速度的掩码。CIBAUD 各位的值与 CBAUD 各位相同,左移了 IBSHIFT 位
CRTSCTS(不属于 POSIX) 启用 RTS/CTS (硬件) 流控制

在这里插入图片描述
c_cflag成员包含两个应该始终启用的选项,CLOCALCREAD。这将确保您的程序不会成为端口的“所有者”,受到零星的作业控制和挂起信号的影响,并且串行接口驱动程序将读取传入的数据字节。

不要直接初始化c_cflag(或任何其他标志)成员。应该始终使用按位的ANDORNOT操作符来设置或清除成员中的位。不同的操作系统版本可以以不同的方式使用位,因此使用位操作符将防止破坏新串行驱动程序中所需的位标志。

2.3.4 c_lflag 标志常量: Local mode ( 局部模式)

本地模式成员c_lflag控制串口驱动程序如何管理输入字符。通常,将为规范或原始输入配置c_lflag成员。c_cflag中存储的最终值由下表中选项确定。

常量描述
ISIG使能SIGINTR、SIGSUSP、SIGDSUSP和SIGQUIT信号
ICANON启用规范化输入(否则为raw)
XCASE(不属于 POSIX; Linux 下不被支持) 如果同时设置了 ICANON,终端只有大写。输入被转换为小写,除了有前缀的字符。输出时,大写字符被前缀(某些系统指定的特定字符) ,小写字符被转换成大写。
ECHO启用输入字符的回显
ECHOE如果同时设置了 ICANON,字符 ERASE 擦除前一个输入字符,WERASE 擦除前一个词
ECHOK如果同时设置了 ICANON,字符 KILL 删除当前行
ECHONL如果同时设置了 ICANON,回显字符 NL,即使没有设置 ECHO
NOFLSH禁止在产生 SIGINT, SIGQUIT 和 SIGSUSP 信号时刷新输入和输出队列,即关闭queue中的flush
IEXTEN启用扩展功能
ECHOCTL如果同时设置了 ECHO,除了 TAB, NL, START, 和 STOP 之外的 ASCII 控制信号被回显为 ^X, 这里 X 是比控制信号大 0x40 的 ASCII 码。例如,字符 0x08 (BS) 被回显为 ^H
ECHOPRT如果同时设置了 ICANON 和 IECHO,字符在删除的同时被打印
CRTSCTS(不属于 POSIX) 启用 RTS/CTS (硬件) 流控制

一般有两种输入模式可供选择:
(1)选择规范输入
规范输入是面向行的。输入字符被放入缓冲区,用户可以交互地编辑缓冲区,直到收到CR(回车)或LF(换行)字符。
当选择此模式时,通常选择ICANONECHOECHO选项:

options.c_lflag |= (ICANON | ECHO | ECHOE);

(2)选择原始输入
原始输入未经处理。当接收到输入字符时,它们将完全按照接收到的方式传递。通常,当使用原始输入时,您将取消选择ICANON, ECHO, ECHOEISIG选项:

options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

2.3.5 c_cc 数组:特殊控制字元

UNIX串行接口驱动程序提供了指定字符和数据包超时的能力。c_cc数组中的两个元素用于超时:VMINVTIME。在规范输入模式下或通过openfcntl在文件上设置NDELAY选项时,会忽略超时。

VMIN指定要读取的最小字符数。如果设置为0,则VTIME值指定等待读取每个字符的时间。请注意,这并不意味着对N个字节的读取调用将等待N个字符进入。相反,超时将应用于第一个字符,read调用将返回立即可用的字符数(最多可达您请求的字符数)。

如果VMIN不为零,则VTIME指定等待读取第一个字符的时间。如果在给定的时间内读取一个字符,则任何读取将阻塞(等待),直到读取所有VMIN字符。也就是说,一旦读取了第一个字符,串行接口驱动程序期望接收整个字符包(VMIN字节总数)。如果在允许的时间内没有读取任何字符,则调用read返回0。此方法允许您告诉串行驱动程序您需要恰好N个字节,并且任何读调用将返回0或N个字节。然而,超时只适用于第一个字符读取,所以如果由于某种原因驱动程序错过了N字节包中的一个字符,那么read调用可能会永远阻塞,等待额外的输入字符。

VTIME指定等待传入字符的时间,以十分之一秒为单位。如果VTIME设置为0(默认值),读取将无限期阻塞(等待),除非在端口上设置NDELAY选项openfcntl

VMINVTIME的组合方式如下:
(1)VMIN = 0 , VTIME =0
read立即回传,否则传回 0 ,不读取任何字元
(2)VMIN = 0 , VTIME >0
read传回读到的字元,或在十分之一秒后传回VTIME
(3)VMIN > 0 , VTIME =0
read会等待,直到VMIN字元可读
(4)VMIN > 0 , VTIME > 0
每一格字元之间计时器即会被启动
read会在读到VMIN字元,传回值或VTIME的字元计时(1/10秒)超过时将值传回

2.4 与结构体struct termios相关的函数

函数命名解释:

  • tc:terminal contorl
  • cf:control flag

2.4.1 tcgetattr()与tcsetattr()

(1)tcgetattr()函数:get terminal attributes,获得终端的属性
原型:

#include <termios.h>
#include <unistd.h>

int tcgetattr(int fd, struct termios *termios_p);

作用:取得终端介质(fd)初始值,并把其值 赋给temios_p; 函数可以从后台进程中调用;但是,终端属性可能被后来的前台进程所改变。

(2)tcsetattr() 函数:set terminal attributes,修改终端参数
原型:

#include <termios.h>
#include <unistd.h>

int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);

作用:设置与终端相关的参数 ,使用 termios_p 引用的 termios 结构。optional_actionstcsetattr函数的第二个参数)指定了什么时候改变会起作用,可以使用的值如下:

  • TCSANOW:改变立即发生
  • TCSADRAIN:改变在所有写入 fd 的输出都被传输后生效。这个函数应当用于修改影响输出的参数时使用。(当前输出完成时将值改变)
  • TCSAFLUSH :改变在所有写入 fd 引用的对象的输出都被传输后生效,所有已接受但未读入的输入都在改变发生前丢弃(同TCSADRAIN,但会舍弃当前所有值)。

2.4.2 tcflush()

原型:

int tcflush(int fd, int queue_selector);

作用:丢弃要写入 引用的对象,但是尚未传输的数据,或者收到但是尚未读取的数据,取决于 queue_selector 的值。 queue_selector的取值有:

  • TCIFLUSH :刷新收到的数据但是不读
  • TCOFLUSH :刷新写入的数据但是不传送
  • TCIOFLUSH :同时刷新收到的数据但是不读,并且刷新写入的数据但是不传送

2.4.3 tcflow()

原型:

int tcflow(int fd, int action);

作用:挂起 fd 引用的对象上的数据传输或接收,取决于 action 的值。 action 取值有:

  • TCOOFF :挂起输出
  • TCOON :重新开始被挂起的输出
  • TCIOFF :发送一个 STOP 字符,停止终端设备向系统传送数据
  • TCION :发送一个 START 字符,使终端设备向系统传输数据

打开一个终端设备时的默认设置是输入和输出都没有挂起。

2.4.4 波特率函数

波特率函数被用来获取和设置 termios结构体中输入和输出波特率的值。新值不会马上生效,直到成功调用了 tcsetattr() 函数。
(1)cfgetospeed()函数
原型:

speed_t cfgetispeed(const struct termios *termios_p);

作用:返回 termios_p 指向的 termios 结构中存储的输出波特率。返回存储在终端结构中的输入波特率。
(2)cfsetispeed()函数:sets the input baud rate,设置输入波特率
原型:

int cfsetispeed(struct termios *termios_p, speed_t speed);

作用:设置 termios 结构中存储的输入波特率为 speed。如果输入波特率被设为0,实际输入波特率将等于输出波特率。
(3)cfsetospeed()函数:sets the output baud rate,设置输出波特率
原型:

int cfsetospeed(struct termios *termios_p, speed_t speed);

作用:设置 termios 结构中存储的输出波特率为 speed

(4)cfsetspeed()函数:同时设置输入、输出波特率
原型:

int cfsetspeed(struct termios *termios_p, speed_t speed);

作用:cfsetspeed()是一个4.4BSD扩展。它接受与cfsetispeed()相同的参数,并设置输入和输出速度。
(5)波特率大小设置选择
如图:
在这里插入图片描述

3. Linux串口应用编程实例

下面给出了串口配置的完整的函数。通常,为了函数的通用性,通常将常用的选项都在函数中列出,这样可以大大方便以后用户的调试使用。该设置函数如下所示:

3.1 串口配置的函数

// fd:设备文件描述符;nSpeed:需要设置的波特率;nBits:需要设置的数据位数;nEvent:奇偶校验位;nStop:停止位
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop){
	struct termios newtio,oldtio;

	/*保存测试现有串口参数设置,在这里如果串口号等出错,会有相关的出错信息*/
	if  ( tcgetattr( fd,&oldtio)  !=  0) { 
		perror("SetupSerial 1");
		return -1;
	}
	
	//将 newtio 清零
	bzero( &newtio, sizeof( newtio ) );

	/*步骤一,设置字符大小*/
	newtio.c_cflag  |=  CLOCAL | CREAD; 
	newtio.c_cflag &= ~CSIZE; 

	/*设置数据位*/
	switch( nBits ){
		case 7:
			newtio.c_cflag |= CS7;
			break;
		case 8:
			newtio.c_cflag |= CS8;
			break;
	}

	/*设置奇偶校验位*/
	switch( nEvent ){
		case 'O': //奇数
			newtio.c_cflag |= PARENB;
			newtio.c_cflag |= PARODD;
			newtio.c_iflag |= (INPCK | ISTRIP);
			break;

		case 'E': //偶数
			newtio.c_iflag |= (INPCK | ISTRIP);
			newtio.c_cflag |= PARENB;
			newtio.c_cflag &= ~PARODD;
			break;
		case 'N':  //无奇偶校验位
			newtio.c_cflag &= ~PARENB;
			break;
	}

	/*设置波特率*/
	switch( nSpeed ){
		case 2400:
			cfsetispeed(&newtio, B2400);
			cfsetospeed(&newtio, B2400);
			break;
		case 4800:
			cfsetispeed(&newtio, B4800);
			cfsetospeed(&newtio, B4800);
			break;
		case 9600:
			cfsetispeed(&newtio, B9600);
			cfsetospeed(&newtio, B9600);
			break;
		case 115200:
			cfsetispeed(&newtio, B115200);
			cfsetospeed(&newtio, B115200);
			break;
		case 460800:
			cfsetispeed(&newtio, B460800);
			cfsetospeed(&newtio, B460800);
			break;
		default:
			cfsetispeed(&newtio, B9600);
			cfsetospeed(&newtio, B9600);
			break;
	}

	/*设置停止位*/
	if( nStop == 1 )
		newtio.c_cflag &=  ~CSTOPB;
	else if ( nStop == 2 )
		newtio.c_cflag |=  CSTOPB;

	/*设置等待时间和最小接收字符*/
	newtio.c_cc[VTIME]  = 0;
	newtio.c_cc[VMIN] = 0;

	/*处理未接收字符*/
	tcflush(fd,TCIFLUSH);

	/*激活新配置*/
	if((tcsetattr(fd,TCSANOW,&newtio))!=0){
		perror("com set error");
		return -1;
	}
	printf("set done!\n");
	return 0;
}

3.2 打开串口的函数

下面给出了一个完整的打开串口的函数,同样写考虑到了各种不同的情况。程序如下所示:

/*打开串口函数*/
int open_port(int fd,int comport){
	char *dev[]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2"};

	//串口 1
	if (comport==1){
		fd = open( "/dev/ttyS0", O_RDWR|O_NOCTTY|O_NDELAY);
		if (-1 == fd){
			perror("Can't Open Serial Port");
			return(-1);
		}
	}
	else if(comport==2){//串口 2
		fd = open( "/dev/ttyS1", O_RDWR|O_NOCTTY|O_NDELAY);
		if (-1 == fd){
			perror("Can't Open Serial Port");
			return(-1);
		}
	}
	else if (comport==3){//串口 3
		fd = open( "/dev/ttyS2", O_RDWR|O_NOCTTY|O_NDELAY);
		if (-1 == fd){
			perror("Can't Open Serial Port");
			return(-1);
		}
	}

	/*恢复串口为阻塞状态*/
	if(fcntl(fd, F_SETFL, 0)<0)
		printf("fcntl failed!\n");
	else
		printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));

	/*测试是否为终端设备*/
	if(isatty(STDIN_FILENO)==0)
		printf("standard input is not a terminal device\n");
	else
		printf("isatty success!\n");
		
	printf("fd-open=%d\n",fd);

	return fd;
}

3.3 从串口中读取数据

//
int read_datas(int fd, char *rcv_buf,int rcv_wait){
	int retval;

	fd_set rfds;

	struct timeval tv;

	int ret,pos;

	tv.tv_sec = rcv_wait;      // wait 2.5s
	tv.tv_usec = 0;

	pos = 0; // point to rceeive buf

	while (1){
		FD_ZERO(&rfds);

		FD_SET(fd, &rfds);

		retval = select(fd+1 , &rfds, NULL, NULL, &tv);

		if (retval == -1){
			perror("select()");
			break;
		}
		else if (retval){// pan duan shi fou hai you shu ju
			ret = read(fd, rcv_buf+pos, 2048);
			pos += ret;
	
			if (rcv_buf[pos-2] == '\r' && rcv_buf[pos-1] == '\n'){
				FD_ZERO(&rfds);
				FD_SET(fd, &rfds);
	
				retval = select(fd+1 , &rfds, NULL, NULL, &tv);
	
				if (!retval) break;// no datas, break
		
			}
		}
		else{
			printf("No data\n");
			break;
		}

	}
	return 1;
}

3.4 向串口传数据

int send_data(int fd, char *send_buf){
	ssize_t ret;
	ret = write(fd,send_buf,strlen(send_buf));

    if (ret == -1){
		printf ("write device %s error\n", DEVICE_TTYS);
		return -1;
	}
    return 1;
}

参考

[1] https://digilander.libero.it/robang/rubrica/serial.htm
[2] https://blog.csdn.net/yemingzhu163/article/details/5897156
[3] https://www.cnblogs.com/feisky/archive/2010/05/21/1740893.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/444862.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue---自定义指令

目录 1、为什么使用自定义指令&#xff1f; 2、自定义指令 3、自定义指令使用 1、为什么使用自定义指令&#xff1f; 什么时候我们需要去自定义一个指令呢&#xff1f; 事件修饰符&#xff0c;很大的程度上我们是为了让我们的代码更加显得是数据驱动的以及可测试的&#x…

姿态识别、手势识别(附代码)

姿态识别技术是一种基于计算机视觉的人体姿态分析方法&#xff0c;可以通过分析人体的姿态&#xff0c;提取出人体的关键点和骨架信息&#xff0c;并对人体的姿态进行建模和识别。随着深度学习技术的发展&#xff0c;近年来姿态识别技术得到了广泛的应用和研究&#xff0c;其中…

React框架的介绍、特点、安装及基本使用流程

一、react介绍 官网&#xff1a;React (docschina.org) react是由facebook前端开发团队开发和维护的js框架 react的实现功能类似VUE&#xff0c;但是由于国外的开发风格&#xff0c;导致在react上&#xff0c;并没有对数据渲染的步骤进行封装&#xff0c;需要开发者更多的使…

【计算几何】点在几何图形中定位问题

一、说明 点的定位属于几何查找&#xff0c;是计算几何中的一个重要的问题。其包括点在三角形内外&#xff0c;多边形内外判断&#xff0c;平面剖分中的位置等。 二、点和几何区域的关系 2.1 点和线的位置关系 两个平行向量的叉乘等于0。如果两个向量的叉乘等于0&#xff0c…

Kali下开启远程管理-ssh

1、使用管理员root修改/etc/ssh/sshd_config 配置文件 ┌──(kali㉿kali)-[~] └─# sudo -i //切换管理root ┌──(root㉿kali)-[~] └─# vim /etc/ssh/sshd_config PermitRootLogin prohibit-password > yes PasswordAuthentication 去掉#号 2、重启ssh.serv…

大数据项目之数仓相关知识

第1章 数据仓库概念 数据仓库&#xff08;DW&#xff09;: 为企业指定决策&#xff0c;提供数据支持的&#xff0c;帮助企业&#xff0c;改进业务流程&#xff0c;提高产品质量等。 DW的输入数据通常包括&#xff1a;业务数据&#xff0c;用户行为数据和爬虫数据等 ODS: 数据…

基于计算机视觉手势识别控制系统YoLoGesture (利用YOLO实现) 有详细代码+部署+在线服务器尝试+开源可复现

基于计算机视觉手势识别控制系统YoLoGesture (利用YOLO实现) 在线服务器体验网址&#xff1a; https://kedreamix-yologesture.streamlit.app/ 文章目录 基于计算机视觉手势识别控制系统YoLoGesture (利用YOLO实现)1. 项目已完成的部分2. 部分尝试结果3. 项目整体框架3.1. 数据…

如何实现多个窗口同步操作?技术层面?借助工具?

朋友们&#xff01;你们是否曾经遇到过需要在多个窗口之间进行同步操作的情况&#xff1f;例如&#xff0c;你想在不同的浏览器窗口中同时滚动或者放大缩小网页。如果你有这样的需求&#xff0c;东哥今天就从技术和借助专业工具两方面给大家讲解如何实现对多个相同布局的窗口进…

【C++入门必备知识:|引用| +|auto关键字| + |范围for|】

【C入门必备知识&#xff1a;|引用| |auto关键字| |范围for|】 ①.引用Ⅰ.引用概念Ⅱ.引用使用Ⅲ.引用特性Ⅳ.使用场景1.做函数参数意义&#xff1a; 2.做函数返回值意义&#xff1a; Ⅵ.常引用Ⅶ.引用与指针区别 ②.auto关键字1.使用规则 ③.基于范围的for循环1.使用规则 在这…

如何在你的云服务器/云主机上更新并使用最新版本的python(python3.11)

更新并使用最新版本的python3.11 第一步&#xff0c;登录云服务器&#xff0c;并更新系统包 打开您的终端&#xff08;Terminal&#xff09;或使用任意SSH客户端&#xff0c;输入如下命令来登录云主机&#xff1a; ssh 用户名IP地址 在输入密码后&#xff0c;您将成功登录到云…

【软考备战·希赛网每日一练】2023年4月21日

文章目录 一、今日成绩二、错题总结第一题第二题第三题第四题 三、知识查缺 题目及解析来源&#xff1a;2023年04月21日软件设计师每日一练 一、今日成绩 二、错题总结 第一题 解析&#xff1a; 第二题 解析&#xff1a; 活动图 是一种特殊的状态图&#xff0c;它展现了在系统…

【谷歌扩展程序入门】简单制作一个查看网页结构的扩展程序

简言 在想看网页结构的时候一般会F12查看元素内容。 太麻烦了 还不简单方便。 扩展程序 扩展建立在诸如 HTML、JavaScript 和 CSS 之类的 Web 技术之上。它们在单独的沙盒执行环境中运行并与 Chrome 浏览器交互。 扩展允许您通过使用 API 修改浏览器行为和访问 Web 内容来“扩…

wsl2-ubuntu20编译Lineage17(Android10)

WSL2安装Ubuntu20 wsl2安装 略 安装Ubuntu20 wsl.exe --list --online 列出当前支持的所有系统&#xff0c;不过这个命令是从https://raw.githubusercontent.com/microsoft/WSL/master/distributions/DistributionInfo.json来获取&#xff0c;所以有很大概率会失败。失败就…

解忧杂货铺(三):工作相关资源搜集

1、概述 此文档记录一些对自己很有用的小工具或者其他资源的链接 2、资源 2.1 Hightec生成HEX的方法 Hightec生成HEX的方式https://blog.csdn.net/qq_31225611/article/details/113696362 2.2 UML各个图解析 UML图https://blog.csdn.net/qq_35423190/article/details/1250…

ChatGPT: 深入解读OpenAI的语言模型技术

ChatGPT: 深入解读OpenAI的语言模型技术 引言 引言部分旨在介绍ChatGPT是什么&#xff0c;为什么它是近年来最受欢迎的语言模型之一&#xff0c;并概述本文的主要内容。 1.1 简介 ChatGPT是由OpenAI开发的一种基于深度学习技术的对话生成模型。它采用了最先进的自然语言处理技…

python之流程控制练习题(二)

1、计算1~100的和&#xff08;包含1和100&#xff09;2、计算1~6的乘积&#xff08;包含1和6&#xff09;3、计算1~100之间偶数的和&#xff08;包含1和100&#xff09;4、计算1~100之间可以被3又能被5整数的数的个数&#xff08;包含1和100&#xff09;5、使用循环&#xff0c…

Uboot、Linux BSP定制,最小系统移植

目录 一、linux操作系统支持哪些处理器 二、linux支持哪些版本 三、linux支持哪些外设IP 四、 现有操作系统举例 一、linux操作系统支持哪些处理器 目前已经linux SOC有Cortex-A5x2 Cortex-A9x4,Cortex-A53x4&#xff0c;Riscv-v 二、linux支持哪些版本 已经支持的linux版…

氧气与肠道菌群失调

谷禾健康 健康的肠道微生物群特点是氧气含量低&#xff0c;并且存在大型专性厌氧菌细菌群落&#xff0c;这些共生菌通过限制肠道病原体的扩张为宿主提供益处。 那么是什么导致肠道健康走下坡路&#xff0c;是什么原因引起肠道菌群失调&#xff0c;在科学界一直有2种观点&#x…

转化率暴增的秘密,如何使用营销自动化?

我们生活在自动化时代&#xff0c;聪明的公司正在利用技术将手动流程转变为自动流程。营销自动化是指使用软件、插件、人工智能和分析工具来执行常见和重复的营销流程&#xff0c;例如发送电子邮件和为网站访问者部署应用内消息。 而SaleSmartly&#xff08;ss客服&#xff09…

Linux用户的分类与家目录,ls、pwd、cd、mkdir、touch、rmdir、rm指令与选项等

Linux中用户的分类与用户的家目录 在Linux当中&#xff0c;用户的分类只分为两类&#xff0c;一类叫做超级用户root&#xff0c;还有就是其他也就是传说中的普通用户。我们刚刚登进去时&#xff0c;默认所处的目录是***/root或者/home/用户名***&#xff0c;比如说/root, /hom…