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

详解UART通信协议以及FPGA实现

文章目录

  • 一、UART概述
  • 二、UART协议帧格式
    • 2.1 波特率
    • 2.2 奇校验ODD
    • 2.3 偶校验EVEN
  • 三、UART接收器设计
    • 3.1 接收时序图
    • 3.2 Verilog代码
    • 3.3 仿真文件测试
    • 3.4 仿真结果
    • 3.5 上版测试
  • 四、UART发送器设计
    • 4.1 发送时序图
    • 4.2 Verilog代码
    • 4.3 仿真文件测试
    • 4.4 仿真结果
    • 4.5 上板测试
  • 五、UART回环测试
    • 5.1 系统框图
    • 5.2 Verilog代码
    • 5.3 仿真文件测试
    • 5.4 仿真结果
    • 5.5 上板测试
  • 六、参考


一、UART概述

  从《浅谈UART,TTL,RS-232,RS-485的区别》这篇文章,我们知道了UART是一种串行、异步、全双工的通信协议,属于协议层;传输过程一般采用RS-232,RS-485电平标准,将所需传输的数据一位接一位地传输;整体传输框架如下:

在这里插入图片描述
  串口通信由发送端和接收端构成,两根信号线实现,一根数据发送,一根数据接收。

二、UART协议帧格式

  在串口通信过程中,数据接收与发送双方没有共享时钟,因此,双方必须协商好数据传输波特率。根据双方协议好的波特率,接收端即可对发送端的数据进行采样。整个传输流程如下:

  1. 传输线空闲时为高电平,然后拉低一个码元时间表示起始位
  2. 接着传输 8 个数据位,先传输低位,再传输高位
  3. 然后传输一个校验位,用来检测本次传输的数据是否正确
  4. 最后输出高电平表示停止位,可以是 1 位、1.5 位、2 位的高电平,并且进入空闲状态,等待下一次的数据传输

协议帧格式如下:
在这里插入图片描述

2.1 波特率

  根据双方协议好的传输速率,接收端即可对发送端的数据进行采样。如果波特率为 9600也就是相当于每秒中划分成了 9600 等份的码元时间。常见的波特率标准为 300bps,600bps,800bps,9600bps,19200bps,38400bps,115200bps 等。通常对串口进行数据采样,采用更高频的时钟。
  一个码元的计算方法:例如我们采样时钟为 50M ,所使用的波特率为 115200,传输 1个码元需要的时间( 1 / 115200 ) = 8680ns

2.2 奇校验ODD

  使完整编码(有效位和校验位)中的 “1” 的个数为奇数个。如果原来信息中 1 的个数为奇数个,则校验位为 0,这样所有信息中1的个数还是奇数 ;如果原来信息中 1 的个数为偶数个,则校验位为 1,这样所有信息中1的个数还是奇数。
  常见的串口通信格式是(8 位数据位+1 位奇数校验位)。以发送字符:10010101和11010101 为例

数据第0位数据第1位数据第2位数据第3位数据第4位数据第5位数据第6位数据第7位校验位
101010011
101010110

2.3 偶校验EVEN

  使完整编码(有效位和校验位)中的 “1” 的个数为偶数个。如果原来信息中 1 的个数为奇数个,则校验位为 1,这样所有信息中1的个数还是偶数 ;如果原来信息中 1 的个数为偶数个,则校验位为 0,这样所有信息中1的个数还是偶数。
  常见的串口通信格式是(8 位数据位+1 位奇数校验位)。以发送字符:10010101和11010101 为例

数据第0位数据第1位数据第2位数据第3位数据第4位数据第5位数据第6位数据第7位校验位
101010010
101010111

三、UART接收器设计

开发平台:vivado2021.1
开发芯片:xc7a100tfgg484-2

3.1 接收时序图

  本次实现11500波特率,无奇偶校验位,时钟频率为50M,则每个码元计数次数为50000000/115200=434。时序图如下:
在这里插入图片描述

3.2 Verilog代码

`timescale 1ns/1ns
module uart_rx#
(parameter CLK_FREQ = 'd50_000_000,  //时钟频率parameter UART_BPS = 'd115200       //波特率
) 
(input                                               clk ,       input                                               rst_n   ,   input                                               rx  ,       //uart_rxoutput  reg     [7:0]                               rx_data ,   //uart_rx_dataoutput  reg                                         rx_data_valid  //uart_rx_data_valid    
);localparam                                          BAUD_CNT_MAX    = CLK_FREQ/UART_BPS ;//一个码元的长度localparam                                          BAUD_CNT_MAX_div2   = BAUD_CNT_MAX/2 ;  reg                                                 rx_reg1 ;reg                                                 rx_reg2 ;reg                                                 rx_reg3 ;reg                                                 rx_flag ;reg             [23:0]                              baud_cnt    ;reg             [3:0]                               bit_cnt ;reg                                                 bit_flag    ;//打两拍,消除亚稳态
always @(posedge clk, negedge rst_n) beginif(rst_n == 1'b0)beginrx_reg1 <= 1'b1;rx_reg2 <= 1'b1;endelse beginrx_reg1 <= rx;rx_reg2 <= rx_reg1;end
end//再打一拍用于判断RX下降沿
always @(posedge clk, negedge rst_n) beginif(rst_n == 1'b0)rx_reg3 <= 1'b1;elserx_reg3 <= rx_reg2;end//接收范围
always @(posedge clk, negedge rst_n) beginif(rst_n == 1'b0)rx_flag <= 1'b0;else if (rx_reg3 == 1'b1 && rx_reg2 == 1'b0)rx_flag <= 1'b1;else if(bit_cnt == 'd8 && bit_flag ==1'b1)rx_flag <= 1'b0;elserx_flag <= rx_flag;
end//baud_cnt:波特率计数器计数,从 0 计数到 BAUD_CNT_MAX
always @(posedge clk, negedge rst_n) beginif(rst_n == 1'b0)baud_cnt <= 'd0;else if(baud_cnt == BAUD_CNT_MAX || rx_flag == 1'b0)baud_cnt <= 'd0;else if(rx_flag == 1'b1)baud_cnt <= baud_cnt + 1'b1;elsebaud_cnt <= baud_cnt;
end//bit_flag: baud_cnt 计数器计数到码元中间,时采样的数据最稳定
always @(posedge clk, negedge rst_n) beginif(rst_n == 1'b0)bit_flag <= 1'b0;else if(baud_cnt == BAUD_CNT_MAX_div2)bit_flag <= 1'b1;elsebit_flag <= 1'b0;end//bit_cnt:有效数据计数器, 8 个有效数据(不含起始位和停止位)
always @(posedge clk, negedge rst_n) beginif(rst_n == 1'b0)bit_cnt <= 'd0;else if(bit_cnt == 'd8 && bit_flag == 1'b1)bit_cnt <= 'd0;else if(bit_flag == 1'b1)bit_cnt <= bit_cnt + 1'b1;elsebit_cnt <= bit_cnt;
end//输出数据
always @(posedge clk, negedge rst_n) beginif(rst_n == 1'b0)rx_data <= 'd0;else if(bit_cnt >= 'd1 && bit_flag == 1'b1)rx_data <= {rx_reg3,rx_data [7:1]};elserx_data <= rx_data ;
end//输出数据有效信号,当接受完8个数据位后拉高
always @(posedge clk, negedge rst_n) beginif(rst_n == 1'b0)rx_data_valid  <= 1'b0;else if(bit_cnt == 'd8 && bit_flag == 1'b1)rx_data_valid  <= 1'b1;elserx_data_valid  <= 1'b0;
endendmodule

3.3 仿真文件测试

这次仿真文件使用task任务来模拟uart发送数据

`timescale 1ns/1ns
module tb_uart_rx();reg                                                 clk ;reg                                                 rst_n   ;reg                                                 rx  ;wire            [7:0]                               rx_data ;wire                                                rx_data_valid  ;initial beginclk = 0;rst_n = 0;rx = 1;#100rst_n = 1;end//调用task函数,连续发送八个数据initial begin#300tx_data(8'h6);tx_data(8'h6);tx_data(8'h1);tx_data(8'hA);tx_data(8'hB);tx_data(8'hC);tx_data(8'hD);tx_data(8'hE);tx_data(8'hF);end//定义task函数task tx_data(input   [7:0] tx_data);integer  i;for (i=0; i<10; i=i+1 ) begincase(i)0:  rx <= 1'b0;1:  rx <= tx_data[0];2:  rx <= tx_data[1];3:  rx <= tx_data[2];4:  rx <= tx_data[3];5:  rx <= tx_data[4];6:  rx <= tx_data[5];7:  rx <= tx_data[6];8:  rx <= tx_data[7];9:  rx <= 1'b1;endcase#(434*20);//每发送完一个bit数据后,延迟一个码元的时间endendtaskalways #10 clk = ~ clk;
uart_rx#(.CLK_FREQ ( 'd50_000_000 	),.UART_BPS ( 'd115200 		)
)u1_uart_rx
(.clk      		( clk      			),.rst_n    		( rst_n    			),.rx       		( rx       			),.rx_data		( rx_data			),.rx_data_valid  ( rx_data_valid  	)
);endmodule

3.4 仿真结果

在这里插入图片描述

  由仿真结果可以看出,我们接收到的依次是(661ABCDEF)8个数据,和仿真文件给的一致。

3.5 上版测试

  调用ila核,准备抓取rx_data,rx_data_valid信号。通过上位机发送数据,观察rx_data是否正确
在这里插入图片描述
  上位机没发送数据时候,ila采集不到rx_data_valid信号拉高。
在这里插入图片描述
  上位机发送一个9F时,ila采集到rx_data_valid信号拉高,并且输出rx_data为9F

四、UART发送器设计

4.1 发送时序图

在这里插入图片描述

4.2 Verilog代码

`timescale 1ns / 1ps
module uart_tx#
(parameter CLK_FREQ = 'd50_000_000,  //时钟频率parameter UART_BPS = 'd115200       //波特率
)
(input                                               clk ,input                                               rst_n   ,input           [7:0]                               tx_data ,       //发送数据input                                               tx_data_en  ,   //发送数据有效信号output  reg                                         tx  
);localparam                                          BAUD_CNT_MAX    = CLK_FREQ/UART_BPS;//待计数的码元周期最大值reg             [7:0]                               tx_data_reg ;reg             [23:0]                              baud_cnt    ;reg             [3:0]                               bit_cnt ;reg                                                 bit_flag    ;reg                                                 tx_flag ;//将待发送的数据缓存起来
always @(posedge clk or negedge rst_n) beginif(rst_n == 1'b0)tx_data_reg <= 'd0;else if(tx_data_en == 1'b1)tx_data_reg <= tx_data;elsetx_data_reg <= tx_data_reg;
end//tx_flag拉高时刻
always @(posedge clk or negedge rst_n) beginif(rst_n == 1'b0)tx_flag <= 1'b0;else if(tx_data_en == 1'b1)tx_flag <= 1'b1;else if(bit_cnt == 'd9 && bit_flag == 1'b1)tx_flag <= 1'b0;elsetx_flag <= tx_flag;
end//baud_cnt 计数器
always @(posedge clk or negedge rst_n) beginif(rst_n == 1'b0)baud_cnt <= 'd0;else if(baud_cnt == BAUD_CNT_MAX)baud_cnt <= 'd0;else if(tx_flag == 1'b1)baud_cnt <= baud_cnt + 1'b1;elsebaud_cnt <= 'd0;
end
//bit_flag拉高时刻
always @(posedge clk or negedge rst_n) beginif(rst_n == 1'b0)bit_flag <= 1'b0;else if(baud_cnt == 'd1)bit_flag <= 1'b1;elsebit_flag <= 1'b0;
end//bit_cnt 计数器
always @(posedge clk or negedge rst_n) beginif(rst_n == 1'b0)bit_cnt <= 'd0;else if(bit_cnt == 'd9 && bit_flag == 1'b1)bit_cnt <= 'd0;else if(bit_flag == 1'b1)bit_cnt <= bit_cnt + 1'b1;elsebit_cnt <= bit_cnt;
end//移位data,由低到高发送至tx
always @(posedge clk or negedge rst_n) beginif(rst_n == 1'b0)tx <= 1'b1;else if(bit_flag == 1'b1)case(bit_cnt)0:  tx <= 1'b0;1:  tx <= tx_data_reg[0];2:  tx <= tx_data_reg[1];3:  tx <= tx_data_reg[2];4:  tx <= tx_data_reg[3];5:  tx <= tx_data_reg[4];6:  tx <= tx_data_reg[5];7:  tx <= tx_data_reg[6];8:  tx <= tx_data_reg[7];9:  tx <= 1'b1;default:tx <= 1'b1;endcase
endendmodule

4.3 仿真文件测试

  模拟两个数据(1A,3B)的输入,让tx模块发送

`timescale 1ns / 1ns
module tb_uart_tx();reg                                                 clk ;reg                                                 rst_n   ;wire                                                tx  ;reg             [7:0]                               tx_data ;reg                                                 tx_data_en  ;initial beginclk = 0;rst_n = 0;tx_data = 8'd0;tx_data_en = 0;#100rst_n = 1;#300tx_data = 8'h1a;tx_data_en = 1;#20 tx_data_en = 0;#(434*20*10+100)//等待10个码元周期时间再等待100nstx_data = 8'h3b;tx_data_en = 1;#20 tx_data_en = 0;#(434*20*10+100)$stop;endalways #10 clk = ~clk;uart_tx#
(.CLK_FREQ    ( 'd50_000_000 ),.UART_BPS    ( 'd115200     )
)
u1_uart_tx
(.clk         ( clk         ),.rst_n       ( rst_n       ),.tx_data     ( tx_data     ),.tx_data_en  ( tx_data_en  ),.tx          ( tx          )
);endmodule

4.4 仿真结果

在这里插入图片描述
  因为发送数据是(1A:00011010)uart先发送起始位,再发送数据位从低到高,最后拉高一个停止位。理论上tx发送的顺序就是0_01011000_1
  从仿真结果来看,tx线上的顺序和理论一致,3B数据同理。

4.5 上板测试

  我们创建一个顶层,调用uart_tx模块,在顶层上输入一个数据,让发送模块发出,然后在上位机上接送,观察和我们发送的数据是否一致,代码如下:

`timescale 1ns / 1psmodule uart_top(input                                               clk ,input                                               rst_n   ,output                                              tx  );reg             [7:0]                               tx_data ;reg                                                 tx_data_en  ;reg             [1:0]                               cnt ;always @(posedge clk or negedge rst_n) beginif(rst_n == 1'b0)cnt <= 'd0;else if(cnt == 'd3)cnt <= cnt;else cnt <= cnt +1'b1;endalways @(posedge clk or negedge rst_n) beginif(rst_n == 1'b0)begintx_data     <= 'd0;tx_data_en  <= 1'b0;endelse if (cnt == 'd2)begintx_data     <= 8'h6D;tx_data_en  <= 1'b1;endelse begintx_data     <= 'd0;tx_data_en  <= 1'b0;endenduart_tx#
(.CLK_FREQ    ( 'd50_000_000 ),.UART_BPS    ( 'd115200 	)
)
u_uart_tx
(.clk         ( clk         ),.rst_n       ( rst_n       ),.tx_data     ( tx_data     ),.tx_data_en  ( tx_data_en  ),.tx          ( tx          )
);endmodule

  我们在顶层模块发送了一个 6D数据。

在这里插入图片描述
上板后,上位机收到了 6D数据

五、UART回环测试

5.1 系统框图

  上面我们测试了UART发送和接收模块都正常,接下来我们将接收模块的输出信号接到发送模块的输入信号,在上位机上面发送数据和接收数据,看是否一致,系统框图如下:
在这里插入图片描述

5.2 Verilog代码

`timescale 1ns / 1psmodule uart_top(input                                               clk ,input                                               rst_n   ,input                                               rx  ,output                                              tx  );wire             [7:0]                               rx_data ;wire                                                 rx_data_valid  ;uart_rx#
(.CLK_FREQ ( 'd50_000_000    ),.UART_BPS ( 'd115200        )    
)
u_uart_rx(.clk            ( clk               ),.rst_n          ( rst_n             ),.rx             ( rx                ),.rx_data        ( rx_data           ),.rx_data_valid  ( rx_data_valid     )
);uart_tx#
(.CLK_FREQ    ( 'd50_000_000 ),.UART_BPS    ( 'd115200     )
)
u_uart_tx
(.clk         ( clk              ),.rst_n       ( rst_n            ),.tx_data     ( rx_data          ),.tx_data_en  ( rx_data_valid    ),.tx          ( tx               )
);endmodule

5.3 仿真文件测试

  我们依然用uart_rx里的测试代码,调用task函数,发送661abcdef

`timescale 1ns / 1ps
module tb_uart_top();reg                                                 clk ;reg                                                 rst_n   ;reg                                                 rx  ;wire                                                tx  ;initial beginclk = 0;rst_n = 0;rx = 1;#100rst_n = 1;end//调用task函数,连续发送八个数据initial begin#300tx_data(8'h6);tx_data(8'h6);tx_data(8'h1);tx_data(8'hA);tx_data(8'hB);tx_data(8'hC);tx_data(8'hD);tx_data(8'hE);tx_data(8'hF);end//定义task函数task tx_data(input   [7:0] tx_data);integer  i;for (i=0; i<10; i=i+1 ) begincase(i)0:  rx <= 1'b0;1:  rx <= tx_data[0];2:  rx <= tx_data[1];3:  rx <= tx_data[2];4:  rx <= tx_data[3];5:  rx <= tx_data[4];6:  rx <= tx_data[5];7:  rx <= tx_data[6];8:  rx <= tx_data[7];9:  rx <= 1'b1;endcase#(434*20);//每发送完一个bit数据后,延迟一个码元的时间endendtaskalways #10 clk  =~clk;
uart_top u_uart_top(.clk    ( clk    ),.rst_n  ( rst_n  ),.rx     ( rx     ),.tx     ( tx     )
);endmodule

5.4 仿真结果

在这里插入图片描述
可以看出接收后的数据和发送的数据没问题

5.5 上板测试

在这里插入图片描述
可以看到发送和接收都正常

六、参考


UART介绍

相关文章:

详解UART通信协议以及FPGA实现

文章目录 一、UART概述二、UART协议帧格式2.1 波特率2.2 奇校验ODD2.3 偶校验EVEN 三、UART接收器设计3.1 接收时序图3.2 Verilog代码3.3 仿真文件测试3.4 仿真结果3.5 上版测试 四、UART发送器设计4.1 发送时序图4.2 Verilog代码4.3 仿真文件测试4.4 仿真结果4.5 上板测试 五、…...

【算法】删除链表中重复元素

本题来源---《删除链表中重复元素》。 题目描述 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2]示例 2&#xff1a; 输入…...

mysql防坑指南

1. MySQL连接数问题 MySQL里的max_connections参数代表mysql数据库的最大连接数&#xff0c;参数默认是151&#xff0c;显然不适用于生产&#xff0c;如果请求大于默认连接数&#xff0c;就会出现无法连接数据库的错误&#xff0c;会遇到too many connections的报错信息。 Mys…...

偏微分方程算法之混合边界差分

目录 一、研究对象 二、差分格式 2.1 向前欧拉格式 1. 中心差商 1.1.1 理论推导 1.1.2 算例实现 2. x0处向前差商&#xff0c;x1处向后差商 1.2.1 理论推导 1.2.2 算例实现 2.2 Crank-Nicolson格式 2.2.1 理论推导 2.2.2 算例实现 一、研究对象 这里我们以混合边界…...

中国八大古都,分别是哪8个?

中国历史上统一王朝或者在全局范围内看呈鼎立之势的大的政权的首都&#xff0c;称古都&#xff0c;又称都城、国都等&#xff0c;是古代王朝的政治中心&#xff0c;也是经济和文化中心。 1、西安 西安&#xff0c;古称长安&#xff0c;是中国历史上建都时间最长、建都朝代最多…...

财务信息化与财务软件有何区别与联系?

财务产品与财务信息化&#xff0c;两者究竟有何不同&#xff0c;又有何相通之处&#xff1f;或许&#xff0c;你心中也充满了这样的疑惑。那么&#xff0c;让我用一则小故事&#xff0c;为你揭晓其中的秘密。 想象这样一个场景&#xff0c;长尾狐狸&#xff0c;作为饭团公司的…...

ssm052游戏攻略网站的设计与实现+vue

游戏攻略网站设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本游戏攻略网站就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处…...

SAP Credit Memo 到期日设置技巧

当我们用FB60, MIRO或者FB70 记账vendor或者customer 的Credit Memo的时候&#xff0c;我们发现Credit Memo的Due Date不受付款条款的影响&#xff0c;默认为跟baseline date是同一天&#xff0c;并且无法手工更改&#xff0c;那么如果要设置到期日怎么操作呢&#xff1f; 首先…...

软件开发安全设计方案

2.1.应用系统架构安全设计要求 2.2.应用系统软件功能安全设计要求 2.3.应用系统存储安全设计要求 2.4.应用系统通讯安全设计要求 2.5.应用系统数据库安全设计要求 2.6.应用系统数据安全设计要求 软件开发全资料获取&#xff1a;软件开发全套资料_软件开发资料-CSDN博客https://…...

【Zabbix】zabbix 软件监控

使用zabbix监控系统查看服务器状态以及网站流量指标&#xff0c;利用监控系统的数据去了解上线发布的结果&#xff0c;和网站的健康状态 利用一个优秀的监控软件&#xff0c;我们可以: ●通过一个友好的界面进行浏览整个网站所有的服务器状态 ●可以在 Web 前端方便的查看监控…...

Vue Router 路由动态缓存组件

文章目录 一、简介基本用法生命周期钩子 二、定义是否缓存组件三、缓存组件1. 通过 :include 属性实现vue2.x中vue3.x中 2. 通过 v-slot 功能实现3. 通过 v-if 来实现 四、注意事项 一、简介 Vue Router 允许你缓存路由组件&#xff0c;这样在用户导航回之前的页面时&#xff…...

数据结构:线性表————单链表专题

&#x1f308;个人主页&#xff1a;小新_- &#x1f388;个人座右铭&#xff1a;“成功者不是从不失败的人&#xff0c;而是从不放弃的人&#xff01;”&#x1f388; &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f3c6;所属专栏&#xff1…...

多线程(54)JMM中的内存屏障

Java内存模型&#xff08;JMM&#xff09;中的内存屏障是一种保证内存可见性、顺序性的底层机制。它们是一组指令&#xff0c;用于在多线程环境中确保内存操作的有序性和可见性。内存屏障主要分为四类&#xff1a;LoadLoad、StoreStore、LoadStore和StoreLoad。 内存屏障的类型…...

什么是流量清洗?

随着网络企业的迅速发展&#xff0c;越来越多的用户都开始关注关于网络流量的问题&#xff0c;同时&#xff0c;随着网络流量的增多&#xff0c;网络上也出现了大量的垃圾信息和恶意攻击&#xff0c;给网络带来了很大的困扰&#xff0c;而流量清洗则能够解决这个问题。 流量清洗…...

淘宝API(通过商品详情接口采集商品页面数据)请求说明文档|可接入测试key

淘宝商品详情数据接口&#xff08;taobao.item_get&#xff09;是天猫开放平台提供的一种API接口&#xff0c;旨在帮助开发者获取天猫平台上的商品详情信息。通过调用这个接口&#xff0c;开发者可以获取包括商品ID、标题、价格、库存量、图片等在内的详细数据&#xff0c;从而…...

示例说明闭包函数

示例说明闭包函数 闭包函数是指在一个函数内部定义另一个函数&#xff0c;并且内部函数可以访问外部函数的局部变量&#xff0c;即使外部函数已经执行完毕。 这种功能使得闭包函数可以捕获外部函数的状态&#xff0c;提供了一种保留局部变量值的方式。闭包函数在编程中常用于…...

【自媒体创作利器】AI白日梦+ChatGPT 三分钟生成爆款短视频

AI白日梦https://brmgo.com/signup?codey5no6idev 引言 随着人工智能&#xff08;AI&#xff09;技术的快速发展&#xff0c;AI在各个领域都展现出了强大的应用潜力。其中&#xff0c;自然语言处理技术的进步使得智能对话系统得以实现&#xff0c;而ChatGPT作为其中的代表之一…...

把握零碎时间,开启长期副业兼职之旅!在家也能轻松赚钱!

转眼间&#xff0c;2024年已悄然走过三分之一。这一年&#xff0c;外界环境似乎并不那么友好&#xff0c;但对我而言&#xff0c;我的月收入仍然相对稳定。我找到的副业让我每月能赚到3000元以上&#xff0c;这让我深感庆幸。 现实中&#xff0c;只依赖主业工资的日子确实艰辛…...

HarmonyOS开发实例:【数字管家app】

样例简介 数字管家场景需要手机端、设备端和服务端三方协同完成&#xff0c;本文档介绍的demo是数字管家大场景中的手机端应用&#xff1b;用户注册登录后可创建我的家庭并管理家庭成员&#xff1b;可以添加设备&#xff08;包括智能台灯&#xff0c;智能窗帘&#xff0c;智能…...

人工智能_大模型033_LangChain003_记忆封装Memory上下文控制机制_LCEL表达式语言---人工智能工作笔记0168

## 三、记忆封装:Memory ### 3.1、对话上下文:ConversationBufferMemory from langchain.memory import ConversationBufferMemory, ConversationBufferWindowMemoryhistory = ConversationBufferMemory() history.save_context({"input": "你好啊"}…...

TSMaster与珠海创芯CAN卡的集成指南

1. 珠海创芯CAN卡与TSMaster的基础认知 第一次接触珠海创芯CAN卡时&#xff0c;我和很多工程师一样好奇&#xff1a;这个硬件到底有什么特别之处&#xff1f;实测下来发现&#xff0c;它最大的优势在于高性价比和兼容性。珠海创芯的CAN卡采用标准USB接口&#xff0c;支持CAN2.0…...

RMBG-1.4动态演示:AI净界处理长发人物的流畅抠图过程

RMBG-1.4动态演示&#xff1a;AI净界处理长发人物的流畅抠图过程 1. 引言&#xff1a;当抠图遇上飘逸长发 你有没有遇到过这样的烦恼&#xff1f;想给一张长发飘飘的人像照片换个背景&#xff0c;结果发现发丝边缘怎么都处理不干净&#xff0c;要么像被狗啃过一样参差不齐&am…...

Maxwell16.0实战:如何用实验电流数据搞定电机仿真(附.tab文件制作技巧)

Maxwell16.0实战&#xff1a;实验电流数据驱动电机仿真的全流程解析 电机仿真作为现代工业设计的重要环节&#xff0c;其准确性直接影响产品性能评估。而将实测电流数据融入仿真流程&#xff0c;往往是工程师突破"理想模型"局限的关键一步。本文将系统性地拆解从实验…...

如何去选择品质优秀的段码屏厂家

在现代电子产品中&#xff0c;LCD液晶段码屏的应用越来越广泛。选择一家优质的厂家不仅能保证产品质量&#xff0c;还能提供高效的服务。本文将为您推荐十家在LCD液晶段码屏领域表现突出的厂家&#xff0c;帮助您做出明智的选择。1. 杭州斡能电子有限公司杭州斡能电子有限公司&…...

ArcGIS Desktop许可证被占满?别慌,这3个方法帮你快速释放Advanced许可(附详细步骤)

ArcGIS Desktop高级许可被占用&#xff1f;3种高效解决方案与实战技巧 当你正在赶制项目报告或处理关键地理数据时&#xff0c;突然弹出的"All ArcGIS for Desktop Advanced licenses are in use"错误提示足以让任何GIS专业人士心跳加速。这种情况往往发生在团队共享…...

Rock3A开发板实战:OpenBMC移植全记录(附避坑指南)

Rock3A开发板OpenBMC移植实战&#xff1a;从硬件适配到性能调优 当RK3568处理器遇上OpenBMC&#xff0c;会碰撞出怎样的火花&#xff1f;作为瑞芯微旗下性能与功耗平衡的明星芯片&#xff0c;RK3568在边缘计算领域已证明其价值。而将其应用于BMC&#xff08;基板管理控制器&…...

LIN总线测试避坑指南:为什么你的校验和测试总通不过?从经典型到增强型的实战解析

LIN总线校验和测试全攻略&#xff1a;从算法原理到故障排查的深度实践 在汽车电子系统的开发与测试中&#xff0c;LIN总线作为CAN总线的补充&#xff0c;广泛应用于车门模块、座椅控制、空调系统等对带宽要求不高的场景。而校验和作为LIN报文数据完整性的重要保障&#xff0c;其…...

神经高利贷:预支未来技能导致认知崩溃

在软件测试领域&#xff0c;从业者常面临一个隐形威胁&#xff1a;过度追求新技能而忽视认知极限&#xff0c;最终引发崩溃。这种现象被称为“神经高利贷”&#xff0c;即通过预支未来学习能力来应对当前挑战&#xff0c;结果导致认知资源枯竭、错误率飙升&#xff0c;甚至职业…...

SDMatte效果对比图谱:SDMatte/RemBG/BackgroundMattingV2在玻璃场景PK

SDMatte效果对比图谱&#xff1a;SDMatte/RemBG/BackgroundMattingV2在玻璃场景PK 1. 引言&#xff1a;玻璃抠图的特殊挑战 玻璃材质因其透明和反光特性&#xff0c;一直是图像抠图领域最具挑战性的对象之一。传统抠图工具在处理玻璃制品时&#xff0c;往往会出现边缘断裂、透…...

C++ 静态成员的生命周期管理

C静态成员的生命周期管理是面向对象编程中一个既基础又关键的话题。静态成员作为类的特殊成员&#xff0c;其生命周期与普通成员变量截然不同&#xff0c;理解它们的初始化、销毁时机以及线程安全等问题&#xff0c;对于编写健壮高效的C代码至关重要。本文将深入探讨静态成员的…...