11.1Linux串口应用程序开发

news2025/2/11 9:15:20

UART简介

UART的全称是Universal Asynchronous Receiver and Transmitter,即异步发送和接收。
串口在嵌入式中用途非常的广泛,主要的用途有:

  • 打印调试信息;
  • 外接各种模块:GPS、蓝牙;
    串口因为结构简单、稳定可靠(通过RXD 、TXD、GND三根线即可完成通信),广受欢迎。
    在这里插入图片描述

串口的参数

  • 波特率:常用的有9600、19200、115200、230400、921600等,其实意思就是每秒传输这么多个比特位数(bit)
  • 起始位:先发出一位或两位逻辑”0”的信号,表示传输数据的开始。
  • 数据位:可以是5~8位逻辑”0”或”1”。如ASCII码(7位),扩展BCD码(8位)。
  • 校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。
  • 停止位:它是一个字符数据的结束标志,通常一位或两位逻辑”1”。

串口传输数据

  • 双方约定好波特率(每一位占据的时间)。
  • 双方约定好传输电平,即高电平是多少v,低电平是但是v。
  • 双方约定好起始位位数。
  • 双方约定好奇偶校验。
  • 双方约定好停止位位数。
    在这里插入图片描述

tty 设备节点命名规则

  • /dev/ttyS0 、 /dev/ttySTM0 :串口终端。
  • /dev/tty1 、 /dev/tty2 、 …… :虚拟终端设备。
  • /dev/tty0 :当前正在使用的虚拟终端的别名。
  • /dev/tty :本进程自己的终端。
  • /dev/console :控制台,由内核的命令行参数确定,可以认为是一个拥有更高权限的终端,不管当前正在使用哪个终端,系统信息都会发送到控制台上。

串口编程

头文件

编写串口应用程序时需要先包含如下头文件:

#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */

打开串口

int open_port(void)
{
	int fd;
	/* 打开串口
	 * "/dev/ttyf1" 串口文件名
	 * O_RDWR 以读写方式打开
	 * O_NOCTTY 不将此端口作为控制终端
	 * O_NDELAY 表示不关心 DCD 信号线的状态,同时它还将串口设置为非阻塞模式,在没有数据时进行读取返回0,
	 *          后面可以通过fcntl(fd, F_SETFL, 0)将其设置为阻塞式
	 **/
	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);
}

读写串口

通过write函数写数据(发送数据),通过read函数都数据(接收数据)

关闭串口

通过close函数关闭串口设备

配置串口

可以通过如下来读取或配置串口参数:

 /* tcgetattr 获取串口配置参数, tcsetattr 设置串口配置参数
 - fd
 - optional_actions 配置模式:
 -                  TCSANOW 改变立即发生 
 -                  TCSADRAIN 改变在写入 fd 的数据都被传输后生效
 -                  TCSAFLUSH 改变在写入 fd 的数据都被传输后生效,且已接收但未读取的数据全部丢弃
 - termios_p 串口配置参数
 **/
 int tcgetattr(int fd, struct termios *termios_p)
 int tcsetattr(int fd, int optional_actions, const struct termios *termios_p)

串口的配置参数保存在struct termios 结构体中,此结构体至少包含以下成员:

	/* 输入控制标志 */
	tcflag_t c_iflag;
	/* 输出控制标志 */
	tcflag_t c_oflag;
	/* 控制模式标志 */
	tcflag_t c_cflag;
	/* 本地模式标志 */
	tcflag_t c_lflag;
	/* 行规程 */
	cc_t c_cc[NCCS];
	/* 输入波特率 */
	int c_ispeed;
	/* 输出波特率 */
	int c_ospeed;
  • 输入控制标志选项(c_iflag)
    INPCK :启用输入奇偶校验
    IGNPAR :忽略奇偶校验错误
    PARMRK :标记奇偶校验错误
    ISTRIP :去掉奇偶校验位
    IXON :启用输出的 XON/XOFF 流控制
    IXOFF :启用输入的 XON/XOFF 流控制
    IXANY :允许任何字符来重新开始输出
    IGNBRK :忽略输入中的 BREAK 状态
    BRKINT :检测到中断条件时发送 SIGINT
    INLCR :将换行映射到回车
    IGNCR :忽略回车
    ICRNL :将回车映射到换行
    IUCLC :将大写映射到小写
    启用输入奇偶校验并剥离奇偶校验位:
	c_iflag |= (INPCK | ISTRIP)
启用软件流控制:
	c_iflag |= (IXON | IXOFF | IXANY);
禁用软件流控:
	c_iflag &= ~(IXON | IXOFF | IXANY);
  • 输出控制标志选项(c_oflag)
    OPOST :启用输出处理(未设置 = 原始输出)
    OLCUC :将小写映射到大写
    ONLCR :将换行映射到回车+换行
    OCRNL :将回车映射到换行
    NOCR :不在第 0 列输出回车
    ONLRET :将换行映射到回车
    OFILL :发送填充字符作为延时,而不是使用定时来延时
    OFDEL :填充字符为 DEL
    NLDLY :新行延时掩码
    NL0 :新行没有延迟
    NL1 :换行后延迟100ms
    CRDLY :回车延时掩码
    CR0 :回车没有延迟
    CR1 :回车后的延迟取决于当前列位置
    CR2 :回车后延迟 100 毫秒
    CR3 :回车后延迟 150 毫秒
    TABDLY :tab延时掩码
    TAB0 :TAB 没有延迟
    TAB1 :TAB 后的延迟取决于当前列位置
    TAB2 :发送 TAB 后延迟 100 毫秒
    TAB3 :将 TAB 字符扩展为空格
    BSDLY :回退延时掩码
    BS0 :回退没有延迟
    BS1 :回退后延迟 50 毫秒
    VTDLY :竖直跳格延时掩码
    VT0 :竖直跳格无延迟
    VT1 :竖直跳格后延迟 2 秒
    FFDLY :进表延时掩码
    FF0 :进表没有延迟
    FF1 :进表后延迟 2 秒
    选择原始输出:
	/* 禁用OPOST选项时,将忽略 c_oflag中的所有其他选项位 */
	c_oflag &= ~OPOST;
  • 控制模式标志(c_cflag)
    CSIZE :字符长度掩码
    CS5 :5 个数据位
    CS6 :6 个数据位
    CS7 :7 个数据位
    CS8 :8 个数据位
    CSTOPB :2 个停止位(否则为 1 个)
    CREAD :启用接收器
    PARENB :启用奇偶校验位
    PARODD :使用奇校验而不是偶校验
    HUPCL :关闭时挂断 moden
    CLOCAL :忽略 modem 控制线
    CRTSCTS :启用硬件流控制
    设置字符大小:
	c_cflag &= ~CSIZE; /* 屏蔽字符大小位 */ 
	c_cflag |= CS8; /* 选择 8 个数据位 */
设置奇偶校验:
	/*无奇偶校验 (8N1) */
	c_cflag &= ~PARENB;
	c_cflag &= ~CSTOPB;
	c_cflag &= ~CSIZE;
	c_cflag |= CS8;
	/* 偶校验(7E1) */
	c_cflag |= PARENB;
	c_cflag &= ~PARODD;
	c_cflag &= ~CSTOPB;
	c_cflag &= ~CSIZE;
	c_cflag |= CS7;
	/* 奇校验(7O1) */
	c_cflag |= PARENB;
	c_cflag |= PARODD;
	c_cflag &= ~CSTOPB;
	c_cflag &= ~CSIZE;
	c_cflag |= CS7;
设置硬件流控制:
c_cflag |= CRTSCTS;
禁用硬件流控制:
	c_cflag &= ~CRTSCTS;
  • 本地模式标志(c_lflag)
    ISIG :启用 SIGINTR、SIGSUSP、SIGDSUSP 和 SIGQUIT 信号
    ICANON :使能规范输入,这使 EOF 、 EOL 、 EOL2 、 ERASE 、 KILL 、 REPRINT 、 STATUS 、 WERASE 字符起作用,输入字符被装配成行
    XCASE :如果同时设置了 ICANON ,则输入被转换为小写(除有前缀 / 的字符以外),输出一个大写字符也在其前加一个 /
    ECHO :回显输入字符
    ECHOE :如果同时设置了 ICANON ,字符 ERASE 擦除前一个输入字符, WERASE 擦除前一个词
    ECHOK :如果同时设置了 ICANON,字符 KILL 删除当前行
    ECHONL :如果同时设置了 ICANON,回显字符 NL,即使没有设置 ECHO
    NOFLSH :禁止在产生 SIGINT, SIGQUIT 和 SIGSUSP 信号时刷新输入和输出队列
    IEXTEN :启用扩展字符处理,这个标志必须与 ICANON 同时使用才能解释特殊字符 EOL2 、 LNEXT 、 REPRINT 、 WERASE, IUCLC 标志才有效
    ECHOCTL :如果同时设置了 ECHO,除了 TAB, NL, START, 和 STOP 之外的 ASCII 控制字符被回显为 ^X (这里 X 是比控制字符加 0x40 的 ASCII 码)
    ECHOPRT :如果同时设置了 ICANON 和 IECHO,字符在删除的同时被打印
    ECHOKE :如果同时设置了 ICANON ,回显 KILL 时将删除一行中的每个字符
    FLUSHO :输出被刷新,这个标志可以通过键入字符 DISCARD 来开关
    PENDIN :在读入下一个字符时,输入队列中所有字符被重新输出
    TOSTOP :向试图写控制终端的后台进程组发送 SIGTTOU 信号
    选择规范输入:
	c_lflag |= (ICANON | ECHO | ECHOE);
选择原始输入:
	c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  • 控制字符(c_cc )
    VINTR :中断字符。发出 SIGINT 信号,当设置 ISIG 时可被识别
    VQUIT :退出字符。发出 SIGQUIT 信号,当设置 ISIG 时可被识别
    VERAS :删除字符。删除上一个还没有删掉的字符,但不删除上一个 EOF 或行首,当设置 ICANON 时可被识别
    VKILL :终止字符。删除自上一个 EOF 或行首以来的输入,当设置 ICANON 时可被识别
    VEOF :文件尾字符。这个字符使得 tty 缓冲中的内容被送到等待输入的用户程序中,而不必等到 EOL,当设置ICANON 时可被识别
    VEOL : 行结束字符,当设置 ICANON 时可被识别
    VEOL2 :替换的行结束,当设置 ICANON 时可被识别
    VMIN :要读取的最小字符数
    VTIME :等待数据的时间(100毫秒)
    MIN与TIME组合有以下四种:
//有数据立即读取,并返回读取的字节数,无数据立即返回0
MIN = 0 , TIME = 0;
//在 TIME 指定的时间内有数据则返回读取的字节数,无数据返回0
MIN = 0 , TIME > 0;
//在最少读取到 MIN 个字节数才返回
MIN > 0 , TIME = 0;
//读取到的一个字节时启动计时,此后每收到一个字符都会重新计时,在最少读取到 MIN 个字节数或超时返回读取的字节数
MIN > 0 , TIME > 0;
  • 波特率(c_ispeed & c_ospeed)
    波特率的设置和读取通过下列函数实现:
	/* 获取输入波特率 */
	speed_t cfgetispeed(const struct termios *termios_p);
	/* 获取输出波特率 */
	speed_t cfgetospeed(const struct termios *termios_p);
	/* 设置输入波特率 */
	int cfsetispeed(struct termios *termios_p, speed_t speed);
	/* 设置输出波特率 */
	int cfsetospeed(struct termios *termios_p, speed_t speed);
	/* 设置输入输出波特率 */
	int cfsetspeed(struct termios *termios_p, speed_t speed);

串口应用程序编写

原理图

在这里插入图片描述

在这里插入图片描述

编写设备树

在设备树stm32mp157d-atk.dtsi中引用uart3和uart4节点,并加入如下内容:

&usart3 {
	pinctrl-names = "default", "sleep";
	pinctrl-0 = <&usart3_pins_mx>;
	pinctrl-1 = <&usart3_sleep_pins_mx>;
	/delete-property/dmas;
	/delete-property/dma-names;
	status = "okay";
};

&uart5 {
	pinctrl-names = "default", "sleep";
	pinctrl-0 = <&uart5_pins_mx>;
	pinctrl-1 = <&uart5_sleep_pins_mx>;
	/delete-property/dmas;
	/delete-property/dma-names;
	status = "okay";
};

在设备树stm32mp15-pinctrl.dtsi中引用的&pinctrl节点中加入如下内容:

	uart5_pins_mx: uart5_mx-0 {
		pins1 {
			pinmux = <STM32_PINMUX('B', 12, AF14)>; /* UART5_RX */
			bias-disable;
		};
		pins2 {
			pinmux = <STM32_PINMUX('B', 13, AF14)>; /* UART5_TX */
			bias-disable;
			drive-push-pull;
			slew-rate = <0>;
		};
	};

	uart5_sleep_pins_mx: uart5_sleep_mx-0 {
		pins {
			pinmux = <STM32_PINMUX('B', 12, ANALOG)>, /* UART5_RX */
					 <STM32_PINMUX('B', 13, ANALOG)>; /* UART5_TX */
		};
	};

	usart3_pins_mx: usart3_mx-0 {
		pins1 {
			pinmux = <STM32_PINMUX('D', 8, AF7)>; /* USART3_TX */
			bias-disable;
			drive-push-pull;
			slew-rate = <0>;
		};
		pins2 {
			pinmux = <STM32_PINMUX('D', 9, AF7)>; /* USART3_RX */
			bias-disable;
		};
	};

	usart3_sleep_pins_mx: usart3_sleep_mx-0 {
		pins {
			pinmux = <STM32_PINMUX('D', 8, ANALOG)>, /* USART3_TX */
					 <STM32_PINMUX('D', 9, ANALOG)>; /* USART3_RX */
		};
	};

在设备树stm32mp157d-atk.dts的aliases节点中增加如下内容:

		//usart3的设备文件名是ttySTM1
		//uart5的设备文件名是ttySTM2
		serial1 = &usart3;
		serial2 = &uart5;

用make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- dtbs -j8编译设备树,然后用新的.dtb文件启动系统

编写应用程序

编写一个应用程序,从串口读取数据,然后显示读取到的字节数,并将读取的数据返回到PC,程序包含以下几个部分:

  1. 打开串口设备
  2. 配置串口设备
  3. 读写串口设备
    完整的应用程序如下:
#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */

int set_port(int fd, int baud_rate, int n_bits, char parity, int n_stop)
{
	struct termios options;

	/* 读取配置 */
	if(tcgetattr(fd, &options) < 0) 
	{ 
		perror("SetupSerial 1");
		return -1;
	}

	options.c_iflag = 0x00;
	options.c_oflag = 0x00;
	options.c_cflag = 0x00;
	options.c_lflag = 0x00;

	/* 禁用软件流控 */
	options.c_iflag &= ~(IXON | IXOFF | IXANY);
	if((parity == 'O') || (parity == 'E')) {
		/* 启用输入奇偶校验并剥离奇偶校验位 */
		options.c_iflag |= (INPCK | ISTRIP);
	}

	/* 选择原始输出 */
	options.c_oflag &= ~OPOST;

	/* 设置字符大小 */
	options.c_cflag &= ~CSIZE;
	switch(n_bits)
	{
		case 7:
			options.c_cflag |= CS7;
			break;
		case 8:
		default:
			options.c_cflag |= CS8;
			break;
	}
	/* 设置奇偶校验 */
	switch(parity)
	{
		case 'O':
			options.c_cflag |= PARENB;
			options.c_cflag |= PARODD;
			break;
		case 'E':
			options.c_cflag |= PARENB;
			options.c_cflag &= ~PARODD;
			break;
		case 'N':
		default:
			options.c_cflag &= ~PARENB;
			break;
	}
	/* 禁用硬件流控制 */
	options.c_cflag &= ~CRTSCTS;
	/* 设置停止位 */
	switch(n_stop)
	{
		case 2:
			options.c_cflag |= CSTOPB;
			break;
		case 1:
		default:
			options.c_cflag &= ~CSTOPB;
			break;
	}
	/* 启用接收器,并忽略 modem 控制线 */
	options.c_cflag |= CLOCAL | CREAD; 

	/* 选择原始输入 */
	options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

	/* 设置波特率 */
	switch(baud_rate)
	{
		case 2400:
			cfsetispeed(&options, B2400);
			cfsetospeed(&options, B2400);
			break;
		case 4800:
			cfsetispeed(&options, B4800);
			cfsetospeed(&options, B4800);
			break;
		case 9600:
			cfsetispeed(&options, B9600);
			cfsetospeed(&options, B9600);
			break;
		case 115200:
		default:
			cfsetispeed(&options, B115200);
			cfsetospeed(&options, B115200);
			break;
	}
	/* 设置读取超时和每次读取的最小字节数 */
	options.c_cc[VMIN] = 1;
	options.c_cc[VTIME] = 1;

	/* 刷新缓冲区 */
	tcflush(fd, TCIFLUSH);

	/* 配置串口 */
	if((tcsetattr(fd, TCSANOW, &options))!=0)
	{
		perror("com set error");
		return -1;
	}

	return 0;
}

int open_port(const char *com)
{
	int fd;

	/* 打开串口 */
	fd = open(com, O_RDWR | O_NOCTTY | O_NDELAY);
	if (fd == -1)
	{
		/* 打开失败 */
		perror("open_port");
	}
	else
	{
		/* 设置为阻塞式读取 */
		fcntl(fd, F_SETFL, 0);
	}

	return (fd);
}

int main(int argc, char **argv)
{
	int fd;
	int result;
	char buffer[64];

	if (argc != 2)
	{
		printf("Usage: \n");
		printf("%s </dev/ttySAC1 or other>\n", argv[0]);
		return -1;
	}

	/* 打开串口设备 */
	fd = open_port(argv[1]);
	if (fd < 0)
	{
		printf("open %s err!\n", argv[1]);
		return -1;
	}

	/* 设置串口设备 */
	result = set_port(fd, 115200, 8, 'N', 1);
	if(result < 0)
	{
		printf("set port err!\n");
		return -1;
	}

	while(1)
	{
		/* 读取串口接收到的数据 */
		result = read(fd, &buffer, sizeof(buffer));
		if(result > 0)
		{
			printf(" read %d bytes\r\n", result);
			/* 通过串口发送数据 */
			result = write(fd, &buffer, result);
		}
		else
			perror(NULL);
	}

	return 0;
}

上机测试

  1. 根据原理图修改设备树,主要是使能需要用到的串口,然后编译设备树,用新的设备树启动串口
  2. 从这里下载代码,并进行编译,然后将编译得到的可执行程序拷贝到目标板的root目录中
  3. 连接串口线到电脑
  4. 在终端运行命令./uart_teat.out /dev/ttySTM2进行串口测试,其中/dev/ttySTM2是串口设备文件名,如下分别是串口测试软件输出和串口调试软件的截图
    串口测试软件输出串口调试助手

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

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

相关文章

Angular 进阶之五: Signals到底用不用?

Angular 在V16的时候推出了Signals&#xff0c;在17正式作为主打功能之一强烈推荐&#xff0c;看过了各种博主的各种科普文章也没说明白&#xff0c;到底这东西值不值得用&#xff1f;毕竟项目大了&#xff0c;重构代码也不是闹着玩儿的。各种科普文章主要在说两点&#xff1a;…

自定义注解 - java文档生成、结合SpringBoot使用

参考资料&#xff1a; 参考视频 拦截器自定义注解 AOP自定义注解 通过AOP获取属性 拦截器、过滤器、AOP的区别和联系 个人学习笔记及源码 注&#xff1a;这里仅讲怎么使用&#xff0c;具体原理请参考个人学习笔记 自定义注解源码介绍&#xff1a; 其中视频例子2为上述参…

智能优化算法应用:基于减法平均算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于减法平均算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于减法平均算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.减法平均算法4.实验参数设定5.算法结果6.…

[C/C++]数据结构 希尔排序

&#x1f966;前言: 希尔排序也称 “缩小增量排序”&#xff0c;它也是一种插入类排序的方法,在学习希尔排序之前我们首先了解一下直接插入排序. 一: &#x1f6a9;直接插入排序 1.1 &#x1f31f;排序思路 直接插入排序的基本原理是将一条记录插入到已排好的有序表中&#x…

微信小程序开发系列-01创建一个最小的小程序项目

本文讲述了通过微信开发者工具&#xff0c;创建一个新的小程序项目&#xff0c;完全从零开始&#xff0c;不依赖开发者工具的模板。目的是为了更好的理解小程序工程项目的构成。 文章目录 创建一个空项目app.json全局配置pagessitemapLocation app.js 创建一个空项目 打开微信…

Android 11.0 系统默认打开OEM解锁开关功能实现

1.前言 在11.0的系统rom定制化开发中,在9.0系统以后为了设备的安装,系统开始启用oem机制,所以在adb push文件就需要先oem解锁,然后才可以 进行相关操作,所以就需要默认打开oem解锁的开关,来方便oem解锁功能的实现 如图: 2.系统默认打开OEM解锁开关功能实现的核心类 pac…

大数据Doris(四十一):物化视图简单介绍

文章目录 物化视图简单介绍 一、适用场景

Apache Commons Math: 面向Java的数学和统计库

第1章&#xff1a;引言 大家好&#xff0c;我是小黑&#xff0c;咱们今天要聊的是Apache Commons Math这个宝藏级的Java库。为啥说它是宝藏呢&#xff1f;因为它简直就是处理数学问题的瑞士军刀&#xff0c;无论你是要搞统计分析、数值计算&#xff0c;还是解决优化问题&#…

微信小程序备案流程整理

一、备案流程 [找备案入口]–[填主体信息]–[填小程序信息]–[初审]–[短信核验]–[通管局审核] 1&#xff0c;在小程序后台找到备案入口 &#xff08;1&#xff09;新的未上架小程序&#xff0c;可以在小程序首页点击【去备案】进入。 &#xff08;2&#xff09;已上架小程…

智能优化算法应用:基于袋獾算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于袋獾算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于袋獾算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.袋獾算法4.实验参数设定5.算法结果6.参考文献7.MA…

【Midjourney】Midjourney提示词格式详解

目录 &#x1f347;&#x1f347;Midjourney是什么&#xff1f; &#x1f349;&#x1f349;Midjourney怎么用&#xff1f; &#x1f514;&#x1f514;Midjourney提示词格式 &#x1f341; 1.模型版本提示词&#x1f341; 参数 参数详解 应用示例 &#x1f343; 2.风格…

小狐狸GPT付费2.4.9 去除授权弹窗版

后台安装步骤&#xff1a; 1、在宝塔新建个站点&#xff0c;php版本使用7.2 、 7.3 或 7.4&#xff0c;把压缩包上传到站点根目录&#xff0c;运行目录设置为/public 2、导入数据库文件&#xff0c;数据库文件是 /db.sql 3、修改数据库连接配置&#xff0c;配置文件是/.env 4、…

三列布局 css

实现如下图的三列布局&#xff1a; .box {width:1400px;margin:0 auto;padding-bottom:40px;> .left {float:left;width:180px;margin-top:100px;text-align:center;}> .center {float:left;margin-top:100px;margin-left:130px;item-box {float:left;text-align:left;…

RPC(6):RMI实现RPC

1RMI简介 RMI(Remote Method Invocation) 远程方法调用。 RMI是从JDK1.2推出的功能&#xff0c;它可以实现在一个Java应用中可以像调用本地方法一样调用另一个服务器中Java应用&#xff08;JVM&#xff09;中的内容。 RMI 是Java语言的远程调用&#xff0c;无法实现跨语言。…

蓝牙物联网通信网络设计方案

随着当前经济的快速发展&#xff0c;社会运行节奏加快&#xff0c;人们更倾向于选择高效的出行方式&#xff0c;而飞机就是其中之一。近年来&#xff0c;全国各地机场的吞吐量不断增长&#xff0c;导致航站楼面积过大&#xff0c;而 GPS全球定位系统在室内感测不到卫星信号无法…

Java开发框架和中间件面试题(5)

44.Tomcat一个请求的处理流程&#xff1f; 假设来自客户的请求为&#xff1a; http&#xff1a;//localhost&#xff1a;8080/test/index.jsp请求被发送到本机端口8080&#xff0c;被在那里侦听Copote HTTP/1.1 Connector,然后 1.Connector把该请求交给它所在的Service的Engi…

(GCC) 库的操作

文章目录 预备静态库生成链接环境区别 动态库生成链接环境区别 END参考ar指令 预备 准备两个文件&#xff0c;以最简单的形式进行展示。 add.c int add(int x, int y) {return x y; }main.c 为了方便直接在头文件中声明函数 #include <stdio.h>extern int add(int,…

Python电能质量扰动信号分类(三)基于Transformer的一维信号分类模型

目录 引言 1 数据集制作与加载 1.1 导入数据 1.2 制作数据集 2 Transformer分类模型和超参数选取 2.1 定义Transformer分类模型 2.2 定义模型参数 3 Transformer模型训练与评估 3.1 模型训练 3.2 模型评估 代码、数据如下&#xff1a; 往期精彩内容&#xff1a; 电…

Leetcode—86.分隔链表【中等】

2023每日刷题&#xff08;六十九&#xff09; Leetcode—86.分隔链表 实现代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode* partition(struct ListNode* head, int x) {struct ListNode…

实验室安全教育考试管理系统v3.0功能介绍

瑞熙贝通实验室安全练习和在线考试系统&#xff0c;采取线上培训学习与安全考试相结合的教学形式&#xff0c;在学生进入开放实验室之前通过系统对实验的安全与规范有一个系统的认识与学习。通过线上考试系统&#xff0c;为评价学生的实验室安全学习效果提供了快速有效的实验平…