当前位置: 首页 > news >正文

Linux 串口编程

目录

  • 前言
  • 一、tty体系
  • 二、串口硬件基础知识
  • 三、Linux下的串口编程
    • 3.1 打开串口
    • 3.2 从串口读写数据,问题1、2的诞生
    • 3.3 关闭串口
    • 3.4 串口配置
      • 3.4.1 获取/设置串口的参数
      • 3.4.2 设置波特率
      • 3.4.3 设置控制模式标志
      • 3.4.4 设置本地模式标志
      • 3.4.5 设置输入模式标志
      • 3.4.6 设置输出模式标志
      • 3.4.7 设置控制字符
      • 3.4.8 清空发送/接收缓冲区
  • 四、解决问题 1、2
    • 4.1 cfmakeraw() RAW模式
    • 4.2 改进串口数据读取
  • 五、完整的示例代码
  • 六、参考链接:


前言

在嵌入式Linux中,串口是一个字设备,访问具体的串行端口的编程与读/写文件的操作类似,只需打开相应的设备文件即可操作。串口编程特殊在于串口通信时相关参数与属性的设置。嵌入式Linux的串口编程时应注意,若在根文件中没有串口设备文件,应使用mknod命令创建,这这里假设串口设备是/dev/ttyS0,介绍一下串口的编程过程。
#mknod /dev/ttyS0 c 4 64

一、tty体系

tty是teletype的缩写,在上世纪计算机还很昂贵的时候,多人可以通过这种终端来连接并共用一台计算机,发展到今日,tty已经成为了字符类设备的统称,这类设备包括:控制台、UART等物理串行接口以及伪终端。也就是说,开发板物理串口一般对应linux中/dev目录下的tty*设备文件,访问这些文件,就访问硬件串口了。

二、串口硬件基础知识

串口是一类以串行方式传输数据的接口(每次1bit)这类接口常用于网络设备、键盘、鼠标、调制解调器、以及终端设备(teletype,上世纪电脑还是大块头时,大家通过这种设备远程共用一台电脑)等。

常用bps(每秒传输的位数)或称为波特率来表示串口的通讯速度,常见的有9600bps、38400bps、115200bps等。

对于常用的RS232接口,除了常见的TXD、RXD、GND这三个必须的通讯信号线外,还有一些用于控制的信号线:

名称方向用途
DCD(Data Carrier Detect)输入如果读到低电平(逻辑1),说明线缆对面的设备已经正确连接。
DTR(Data Terminal Ready)输出输出低电平(逻辑1)表明我方已经准备好数据传输,一般软件打开串行端口时,此信号会自动拉低。
CTS(Clear To Send)输入如果读到低电平(逻辑1),说明线缆对面的设备允许我们此时发送数据。
RTS(Request To Send)输出输出低电平(逻辑1)以请求线缆对面的设备传输数据,大多数时候,此信号线总是输出低电平。

一般在连接时,我方的DTR连接对方的DCD,我方的RTS连接对方的CTS,反之亦然。**DCD和DTR信号用于设备检测,CTS和RTS信号用于进行信号流控制(除此之外还有一种软件信号流控制方法,当然我在工作中很少用到这些)。


三、Linux下的串口编程

既然Linux下串口设备是以文件的形式存在,我们当然可以用通用的文件I/O函数访问它们,不过访问设备文件一般需要超级管理员权限,在开发板上我们一般以root身份登录系统,这当然也就不存在问题。除此之外,为了对串口进行设置,Linux系统提供了一个名为 termios.h 的文件,里面包含串口设置相关的数据结构以及函数接口,这些函数接口,归根结底其实也是调用了文件I/O函数中的ioctl函数。

下面的示例代码中,均默认包含以下头文件:

#include <stdio.h>
#include <string.h>
#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 */

3.1 打开串口

以下代码演示如何正确打开一个串口设备文件

打开串口设备文件的操作与普通文件的操作类似,都采用标准的I/O操作函数open()。

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

open()函数有两个参数,第一个参数是要打开的文件名(此处为串口设备文件/dev/ttyS0);第二个参数设置打开的方式,O_RDWR表示打开的文件可读/写,O_NDELAY表示以非阻塞方式打开,O_NOCTTY表示若打开的文件为终端设备,则不会将终端作为进程控制终端。

3.2 从串口读写数据,问题1、2的诞生

串口的数据读/写与普通文件的读/写一样,都是使用read()/write()函数实现。

n = write( fd, buf, len ); //将buf中len个字节的数据从串口输出,返回输出的字节数
n = read( fd, buf, len ); //从串口读入len个字节的数据并放入buf, 返回读取的字节数

示例如下:
写数据

/** write data to serial port* return the length of bytes actually written on success, or -1 on error*/
ssize_t write_port(int fd, void *buf,size_t len)
{ssize_t actual_write;actual_write = write(fd, buf, len);if (actual_write == -1){/* write failure */perror("write_port: Unable to write port - ");}return actual_write;
}

读数据

/** read data from serial port* return the length of bytes actually read on success, or -1 on error*/
ssize_t read_port(int fd, void *buf, size_t len)
{ssize_t actual_read;actual_read = read(fd, buf, len);if (actual_read == -1){/* read failure */perror("read_port: Unable to read port - ");}return actual_read;
}

函数实现了读取功能,但是存在两个问题:

1.只有在读完一行才会退出,也就是读到’\r’或’\n’,否则进程会一直堵塞到read函数上;
2.如果串口没有收到数据,函数会一直堵塞直到超时或接收到数据,最小接收长度以及超时时间可以通过后面提到的配置函数进行配置;

问题1可以通过设置串口终端工作在RAW模式解决,问题2可以通过设置串口的最小接收字节数和超时时间解决,具体见 3.4 小节的串口配置内容。

3.3 关闭串口

关闭串口的操作很简单,将打开的串口设备文件句柄关闭即可。

close(fd);

3.4 串口配置

Linux提供了一组用于配置串口终端的数据结构以及对应的函数接口,称为 “POSIX termios interface”。要使用它们,只需要包含此头文件:

#include <termios.h> /* POSIX terminal control definitions */

它的参数设置需要使用struct termios结构体,这个结构体在termio.h文件中定义,且应在程序中包含这个头文件。

typedef unsigned char    cc_t ;
typedef unsigned int     speed_t ;
typedef unsigned int     tcflag_t ;
struct termios{tcflag_t      c_iflag ;          /*输入模式标志*/tcflag_t      c_oflag ;         /*输出模式标志*/tcflag_t      c_cflag ;            /*控制模式标志*/tcflag_t      c_lflag ;            /*本地模式标志*/tcflag_t      c_line ;            /*行规程类型,一般应用程序不使用*/cc_t         c_cc[NCC];      /*控制字符*/speed_t      c_ispeed ;      /*输入数据波特率*/speed_t      c_ospeed ;      /*输出数据波特率*/};

串口的设置主要是设置这个结构体的各成员值,然后利用该结构体将参数传给硬件驱动程序。在Linux中,串口以串行终端的方式进行处理,因而,可以使用tcgetattr()/tcsetattr()函数获取/设置串口的参数。

3.4.1 获取/设置串口的参数

通过系统提供的如下两个接口,我们可以获取当前串口的状态或设置新的状态:

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

这两个参数都有一个批向termios结构体的指针作为参数,用于返回当前终端的属性或设置该终端的属性。参数fd就是用open()函数打开的终端文件句柄,而串口就是用open()打开的串口设备文件句柄。tcsetattr()函数的optional_action参数用于指定新设定的参数起作用的时间,其设定值可以为:

  • TCSANOW 改变立即生效
  • TCSADRAIN 在所有的输出都被传输后改变生效,适用于更改影响输出参数的情况。
  • TCSAFLUSH 在所有输出都被传输后改变生效,丢弃所有末读入的输入(清空输入缓 存)。

3.4.2 设置波特率

使用cfsetospeed()/cfsetispeed()函数设置波特率,它们分别用于在termios结构体中设置输出和输入的波特率。设置波特率可以使用波特率常数,其定义为字母“B+速率”,如B19200就是波特率为19200bps,B115200就是波特率为115200bps。

int cfsetispeed( struct termios *termios_p, speed_t speed );     //speed为波特率常数
int cfsetospeed( struct termios *termios_p, speed_t speed );

例 :

cfsetispeed( ttys0_opt, B115200 );
cfsetospeed( ttys0_opt, B115200 );

3.4.3 设置控制模式标志

控制模式标志c_cflag主要用于设置串口对DCD信号状态检测、硬件流控制、字符位宽、停止位和奇偶校验等,常用标志位如下:

CLOCAL 忽略DCD信号,若不使用MODEM,或没有串口没有CD脚就设置此标志
CREAD 启用接收装置,可以接收字符
CRTSCTS 启用硬件流控制,对于许多三线制的串不应使用,需设置~CRTCTS
CSIZE 字符位数掩码,常用CS8
CSTOPB 使用两个停止位,若用一位应设置~CSTOPB
PARENB 启用奇偶校验

例如,下面的代码将串口设置为忽略DCD信号,启用接收装置,关闭硬件流控制,传输数据时使用8位数据位和一位停止位(8N1),不使用奇偶校验。

 struct temios ttys0ttyso_opt.c_cflag |= CLOCAL | CREAD ;      //将CLOCAL与CREAD位设置为1ttys0_opt.c_cflag &= ~CRTSCTS ;            //将硬件流控制位CRTSCTS清0,其他位不变ttys0_opt.c_cflag &= ~CSIZE ;           //清除数据位掩码ttys0_opt.c_cflag |= CS8 ;                //设置8位数据位标志CS8ttys0_opt.c_cflag &= ~(PARENB|CSTOPB);    //使用1位停止位,停用奇偶校验

3.4.4 设置本地模式标志

本地模式标志c_lflag主要用于设置终端与用户的交互方式,常见的设置标志位有ICAN-ON,ECHO和ECHOE等。其中,ICANON标志位用于实现规范输入,即read()读到行结束符后返回,常用于终端的处理;若串口用于发送/接收数据,则应清除此标志,使用非规范模式(raw mode)。非规范模式中,输入数据不组成行,不处规范模式中的特殊字符。在规范模式中,当设置ECHO标志位时,用户向终端输入的字符将被回传给用户;当设置ECHOE标志位时,用户输入退格键时,则回传“退格-空格-退格”序列给用户,使得退格键覆盖的字符从显示中消失,这样更符合用户的习惯(若未设置此标志,输入退格键时,则光标回退一个字符,但原有的字符未从显示中消失)。

3.4.5 设置输入模式标志

输入模式标志c_iflag主要用于控制串口的输入特性,常用的设置有IXOFF和IXON,分别用于软件流控制。其中,IXOFF用于防止输入缓冲区溢出;IXON则是在输入数据中识别软件流控制标志。由于许多嵌入式系统无法使用硬件流控制,因此,只能使用软件流控制数据传输的速度,但是,它可能降低串口数据传输效率。启用软件流控制的代码如下:

 ttys0_opt.c_iflag |= IXOFF|IXON ;

3.4.6 设置输出模式标志

输出模式标志c_oflag主要用于对串口在规范模式时输出的特殊字符处理,而对非规范模式无效。

3.4.7 设置控制字符

在非规范模式中,控制字符数组c_cc[]中的变量c_cc[VMIN]和c_cc[VTIME]用于设置read()返回前读到的最少字节数和读超时时间,其值分为四种情况:

  • 1.c_cc[VMIN]>0,c_cc[VTIME]>0
    读到一个字节后,启动定时器,其超时时间为c_cc[VTIME],read()返回的条件为至少读到c_cc[VMIN]个字符或定时器超期。
  • 2.c_cc[VMIN]>0, c_cc[VTIME] ==0
    只要读到数据的字节数大于等于c_cc[VMIN],则read()返回;否则,将无限期阻塞等待。
  • 3.c_cc[VMIN] == 0, c_cc[VTIME]>0
    只要读到数据,则read()返回;若定时器超期(定时时间c_cc[VTIME])却未读到数据,则read()返回0;
  • 4.c_cc[VMIN] == 0, c_cc[VTIME] == 0
    若有数据,则read()读取指定数量的数据后返回;若没有数据,则read()返回0;

在termios结构体中填写完这些参数后,接下来就可以使用tcsetattr()函数设置串口的属性。

tcsetattr( fd, &old_opt );         //将原有的设置保存到old_opt,以便程序结束后恢复
tcsetattr( fd, TCSANOW, &ttsy0_opt );

3.4.8 清空发送/接收缓冲区

为保证读/写操作不被串口缓冲区中原有的数据干拢,可以在读/写数据前用tcflush()函数清空串口发送/接收缓冲区。tcflush()函数的参数可为:

TCIFLUSH      清空输入队列
TCOFLUSH   	  清空输出队列
TCIOFLUSH     同时清空输入和输出队列

四、解决问题 1、2

4.1 cfmakeraw() RAW模式

示例为一个串口配置函数,其将串口配置为传入的波特率,8位数据位,无校验位,RAW格式:

/** config serial port baud * and set data format to 8N1(8bits data, no parity bit, 1 stop bit)* return 0 on success, or -1 on error*/
int config_port(int fd, speed_t baud)
{struct termios term;/* read serial port configure */if (tcgetattr(fd, &term) != 0){perror("config_port: Unable to read configure - ");return -1;}/* set baudrate */cfsetspeed(&term, baud);/* 8N1 mode */term.c_cflag &= ~PARENB;term.c_cflag &= ~CSTOPB;term.c_cflag &= ~CSIZE;term.c_cflag |= CS8;/* enbale raw mode */cfmakeraw(&term);/* write serial port configure */if (tcsetattr(fd, TCSADRAIN, &term) != 0){perror("config_port: Unable to write configure - ");return -1;}
}

cfmakeraw() 函数使得串口工作于RAW模式,在此模式下,tty子系统会将从串口收到的所有字节数据直接递交给应用层,而不进行额外处理,此时read()函数会在读取完缓冲区的所有数据后立刻退出并返回实际读到的数值,而不是等到\r或\n的到来,这便解决了上面读取函数的问题1。

4.2 改进串口数据读取

可以在开启串口的RAW模式后,通过配置termios结构体中的成员:

.c_cc[VTIME]; /* 指定超时时间 */
.c_cc[VMIN];  /* 指定最少读取的字节 */

来指定read读取时至少需要读到多少字节才返回(这个需要配合串口的RAW格式),也可以对接收的超时时间进行设置,如果将这 两者都设为0,则不管是否读到数据,read函数都会立刻退出,这就解决了前面提到的问题2。

五、完整的示例代码

仅供参考

#include <errno.h> /* Error number definitions */
#include <fcntl.h> /* File control definitions */
#include <stdio.h>
#include <string.h>
#include <termios.h> /* POSIX terminal control definitions */
#include <unistd.h>  /* UNIX standard function definitions *//** open serial port* return file descriptor on success or -1 on error.*/
int open_port(char *path)
{int fd;fd = open(path, O_RDWR | O_NOCTTY | O_NDELAY);if (fd == -1){/* open failure, print system error msg. */perror("open_port: Unable to open port - ");}else{/* clear file descriptor flags */fcntl(fd, F_SETFL, 0);return fd;}
}/** write data to serial port* return the length of bytes actually written on success, or -1 on error*/
ssize_t write_port(int fd, void *buf, size_t len)
{ssize_t actual_write;actual_write = write(fd, buf, len);if (actual_write == -1){/* write failure */perror("write_port: Unable to write port - ");}return actual_write;
}/* set timeout and minimum number of bytes to read */
int read_port_setup(int fd, cc_t timeout_sec, cc_t min_bytes)
{struct termios term;/* read serial port configure */if (tcgetattr(fd, &term) != 0){perror("config_port: Unable to read configure - ");return -1;}/* set timeout in deciseconds for noncanonical read */term.c_cc[VTIME] = timeout_sec * 10;/* set minimum number of bytes to read */term.c_cc[VMIN] = min_bytes;/* write serial port configure */if (tcsetattr(fd, TCSADRAIN, &term) != 0){perror("config_port: Unable to write configure - ");return -1;}
}/** read data from serial port* return the length of bytes actually read on success, or -1 on error** fd - file descriptor* buf - pointer of buffer to receive bytes* len - buffer* sec - timeout second* min - minimum bytes to read*/
ssize_t read_port(int fd, void *buf, size_t len, cc_t sec, cc_t min)
{ssize_t actual_read;/* setup serial port */if (read_port_setup(fd, sec, min) == -1){return -1;}/* read bytes from serial port */actual_read = read(fd, buf, len);if (actual_read == -1){/* read failure */perror("read_port: Unable to read port - ");}return actual_read;
}/** config serial port baud and set data format to 8N1* (8bits data, no parity bit, 1 stop bit)* return 0 on success, or -1 on error*/
int config_port(int fd, speed_t baud)
{struct termios term;/* read serial port configure */if (tcgetattr(fd, &term) != 0){perror("config_port: Unable to read configure - ");return -1;}/* set baudrate */cfsetspeed(&term, baud);/* 8N1 mode */term.c_cflag &= ~PARENB;term.c_cflag &= ~CSTOPB;term.c_cflag &= ~CSIZE;term.c_cflag |= CS8;/* enbale raw mode */cfmakeraw(&term);/* write serial port configure */if (tcsetattr(fd, TCSADRAIN, &term) != 0){perror("config_port: Unable to write configure - ");return -1;}
}/** close serial port */
int close_port(int fd)
{if (close(fd) == -1){perror("close_port: Unable to close port - ");return -1;}return 0;
}int main(int argc, char *argv[])
{char *path = "/dev/ttyS0";int fd;char send_string[] = "hello world!\n";char read_string[20] = "";ssize_t length;/* open port */fd = open_port(path);if (fd > 0){printf("open %s success, fd = %d.\n", path, fd);}/* config port */config_port(fd, B9600);/* write data to port */length = write_port(fd, send_string, sizeof(send_string));if (length >= 0){printf("%ld bytes written.\n", length);}/* read data from port */length = read_port(fd, read_string, 20, 5, 5);if (length >= 0){printf("%ld bytes read : ", length);for (ssize_t i = 0; i < length; i++){printf("%02X ", (int)(read_string[i]));}printf("\n");}/* close port */close_port(fd);return 0;
}

六、参考链接:

linux 串口编程
嵌入式linux入门3-2-串口

相关文章:

Linux 串口编程

目录 前言一、tty体系二、串口硬件基础知识三、Linux下的串口编程3.1 打开串口3.2 从串口读写数据,问题1、2的诞生3.3 关闭串口3.4 串口配置3.4.1 获取/设置串口的参数3.4.2 设置波特率3.4.3 设置控制模式标志3.4.4 设置本地模式标志3.4.5 设置输入模式标志3.4.6 设置输出模式标…...

Adminer源码编译 精简语言中英文和基本使用方法

Adminer是一个小而强悍的基于web的数据库管理工具&#xff0c; 官方默认支持几十种语言&#xff0c;但是对于中国的用户而言只需要有中文和英文就够了&#xff0c;其他语言基本无用。这就需要我们下载Adminer源码自己编译 Adminer.php , 如下图所示 adminer 中英文语言精简版本…...

go 中线程安全map

在 Go 语言中&#xff0c;官方包 sync.Map 确实提供了线程安全的映射数据结构。然而&#xff0c;正如你所提到的&#xff0c;使用 sync.Map 时&#xff0c;有时需要进行类型断言&#xff0c;这可能会让代码显得冗长或不直观。 如果你希望使用一个更加易用的线程安全映射&#…...

eslint 安装与使用-基础教程

中文官网 官方规则解析 规则参考 - ESLint - 插件化的 JavaScript 代码检查工具 eslint ESlint 是一个检查 JS,TS 语法的工具.能够与常用开发工具&#xff0c;例如 VS Code&#xff0c;进行集成并提供错误提示&#xff0c;和可能的修正方法 安装 安装eslint npm init esli…...

自然语言处理的未来愿景

自然语言处理的未来愿景 在这个信息爆炸的时代,计算机如何理解和生成我们日常使用的语言,已经成为一个引人注目的问题。你有没有想过,为什么智能助手能理解你的指令?又或者,为什么社交媒体上的推荐引擎能够精准地推荐你喜爱的内容?这背后,正是自然语言处理(NLP)在发挥…...

等保2.0三级测评华为华三交换机路由器

在使用本博客提供的学习笔记及相关内容时,请注意以下免责声明: 信息准确性:本博客的内容是基于作者的个人理解和经验,尽力确保信息的准确性和时效性,但不保证所有信息都完全正确或最新。 非专业建议:博客中的内容仅供参考,不能替代专业人士的意见和建议。在做出任何重要…...

BA和CS算法中的Levy飞行策略

Levy飞行策略通过模拟自然界中动物的长距离迁徙行为&#xff0c;指导粒子进行更大范围的搜索&#xff0c;有助于算法快速找到全局最优解。它是一种具有独特优势的随机行为策略&#xff0c;模拟随机游走或搜索过程中的步长和方向&#xff0c;其步长的概率分布为重尾分布&#xf…...

PHP:实现两张无关联表数据的联合分页处理方案

前言 在现代软件开发中&#xff0c;高效地处理数据是至关重要的环节。尤其是在使用 PHP 进行开发时&#xff0c;常常会遇到各种复杂的数据处理需求。其中&#xff0c;实现两张无关联表数据的联合分页处理就是一个具有挑战性的任务。这种需求在很多实际应用场景中都可能出现&am…...

【单元测试】单元测试介绍

1 单元测试基础 1.单元测试&#xff1a;单元测试又称模块测试&#xff0c;属于白盒测试&#xff0c;是最小单位的测试。模块分为程序模块和功能模块。功能模块指实现了一个完整功能的模块&#xff08;单元&#xff09;&#xff0c;一个完整的程序单元具备输入、加工和输出三个…...

PyQt事件机制及其应用

一、实例前置 一个小闹钟应用 创建主窗口类 首先我们创建了一个名为AlarmClock的类&#xff0c;它继承自QMainWindow。这个类将包含我们的GUI组件和逻辑。 from Alarm_clock import Ui_MainWindowclass AlarmClock(QMainWindow):def __init__(self):super().__init__()# 初始化…...

厦门凯酷全科技有限公司抖音电商服务的卓越典范

在短视频和直播带货迅速崛起的时代&#xff0c;厦门凯酷全科技有限公司&#xff08;以下简称“凯酷全科技”&#xff09;以其专业的服务、创新的精神以及对市场的深刻理解&#xff0c;在抖音电商领域中脱颖而出&#xff0c;成为众多品牌商家信赖的选择。本文将深入探讨凯酷全科…...

vue3水波柱状图 ,实现

效果图 //引用页面 <div style"height: 60px;background-color: #fff;border-radius: 5px;width: 40px;"><WavePercentage:percentage"progress"primary-color"#ffcb7c"secondary-color"#ffcb7c"/></div>import Wa…...

如何在两台 PostgreSQL 服务器之间使用逻辑复制槽进行数据复制

如何在两台 PostgreSQL 服务器之间使用逻辑复制槽进行数据复制 如何在两台 PostgreSQL 服务器之间使用逻辑复制槽进行数据复制环境准备1. 配置主服务器&#xff08;Publisher&#xff09;1.1 修改 postgresql.conf1.2 修改 pg_hba.conf1.3 重启 PostgreSQL 服务1.4 创建逻辑复制…...

System.Data.OracleClient 需要 Oracle 客户端软件 version 8.1.7 或更高版本

问题1&#xff1a;“/”应用程序中的服务器错误。 System.Data.OracleClient 需要 Oracle 客户端软件 version 8.1.7 或更高版本。 说明: 执行当前 Web 请求期间&#xff0c;出现未经处理的异常。请检查堆栈跟踪信息&#xff0c;以了解有关该错误以及代码中导致错误的出处的详细…...

【机器人】振动分析和控制工具之Bode图

Bode 图完整介绍 Bode 图由两个部分组成&#xff1a; 幅值图 (Magnitude Plot)&#xff1a;描述系统对不同频率输入信号的增益大小&#xff08;幅值响应&#xff09;。相位图 (Phase Plot)&#xff1a;描述系统输出信号相对于输入信号的相位差。 Bode 图的横轴是频率&#x…...

生成:安卓证书uniapp

地址&#xff1a; https://ask.dcloud.net.cn/article/35777 // 使用keytool -genkey命令生成证书&#xff1a; 官网&#xff1a; keytool -genkey -alias testalias -keyalg RSA -keysize 2048 -validity 36500 -keystore test.keystore ----------------------------------…...

酒店/电影推荐系统里面如何应用深度学习如CNN?

【1】酒店推荐系统里面如何应用CNN&#xff1f;具体过程是什么 在酒店推荐系统中应用卷积神经网络&#xff08;CNN&#xff09;并不是一个常见的选择&#xff0c;因为 CNN 主要用于处理具有空间结构的数据&#xff0c;如图像、音频和某些类型的序列数据。然而&#xff0c;在某…...

【CSS in Depth 2 精译_069】11.3 利用 OKLCH 颜色值来处理 CSS 中的颜色问题(上)

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第四部分 视觉增强技术 ✔️【第 11 章 颜色与对比】 ✔️ 11.1 通过对比进行交流 11.1.1 模式的建立11.1.2 还原设计稿 11.2 颜色的定义 11.2.1 色域与色彩空间11.2.2 CSS 颜色表示法 11.2.2.1 RGB…...

Redis篇-6--原理篇5--单线程模型

1、概述 Redis 采用单线程模型来处理客户端请求&#xff0c;这意味着在任意时刻只有一个命令被执行。这种设计简化了 Redis 的实现&#xff0c;并确保了高并发环境下的数据一致性。尽管 Redis 是单线程的&#xff0c;但它通过高效的内存管理和网络 I/O 操作&#xff0c;仍然能…...

Java版-图论-最小生成树-Prim算法

实现描述 如图&#xff1a; Prim算法的基本思想是从一个顶点开始&#xff0c;逐步构建最小生成树。具体步骤如下&#xff1a; 随机选取一个顶点作为起始点&#xff0c;并将其加入最小生成树的集合中。从该顶点出发&#xff0c;选择一条边连接到其他未被访问的顶点中的最小权…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...

在树莓派上添加音频输入设备的几种方法

在树莓派上添加音频输入设备可以通过以下步骤完成&#xff0c;具体方法取决于设备类型&#xff08;如USB麦克风、3.5mm接口麦克风或HDMI音频输入&#xff09;。以下是详细指南&#xff1a; 1. 连接音频输入设备 USB麦克风/声卡&#xff1a;直接插入树莓派的USB接口。3.5mm麦克…...

API网关Kong的鉴权与限流:高并发场景下的核心实践

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中&#xff0c;API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关&#xff0c;Kong凭借其插件化架构…...

实战设计模式之模板方法模式

概述 模板方法模式定义了一个操作中的算法骨架&#xff0c;并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下&#xff0c;重新定义算法中的某些步骤。简单来说&#xff0c;就是在一个方法中定义了要执行的步骤顺序或算法框架&#xff0c;但允许子类…...