【FPGA零基础学习之旅#13】串口发送模块设计与验证

news2025/1/24 22:36:36

🎉欢迎来到FPGA专栏~串口发送模块


  • ☆* o(≧▽≦)o *☆~我是小夏与酒🍹
  • 博客主页:小夏与酒的博客
  • 🎈该系列文章专栏:FPGA学习之旅
  • 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
  • 📜 欢迎大家关注! ❤️
    FPGQ2

CSDN

🎉 目录-串口发送模块

  • 一、效果演示
    • 1.1 演示
    • 1.2 串口发送模块完整代码(可直接使用)
  • 二、串口发送时序
  • 三、模块设计与代码详解
  • 四、按键控制串口发送数据

遇见未来

一、效果演示

1.1 演示

🥝发送测试:
发送测试

🥝issp调试测试:
数据调试:
更改数据
调试数据发送:
issp测试

1.2 串口发送模块完整代码(可直接使用)

模块

🥝模块端口介绍:

信号名称功能描述
Clk系统时钟50MHz
Rst_n系统复位信号
data_byte待传输的8bit数据
send_en发送使能信号
baud_set波特率设置信号
uart_tx串口信号输出
Tx_Done发送结束信号,输出一个时钟周期高电平
uart_state发送状态,处于发送状态时为1

🥝baud_set值与波特率对应关系:

baud_set波特率
0009600
00119200
01038400
01157600
100115200

uart_byte_tx.v:

//
//模块名称:串口发送模块
//
module uart_byte_tx(
	input 		Clk,
	input 		Rst_n,
	input [7:0]	data_byte,
	input 		send_en,
	input [2:0]	baud_set,
	
	output reg uart_tx,
	output reg Tx_Done,
	output reg uart_state
);

	reg bps_clk;//波特率时钟
	
	reg [15:0]div_cnt;//分频计数器
		
	reg [15:0]bps_DR;//分频计数最大值
	
	reg [3:0]bps_cnt;//波特率计数时钟
		
	//定义数据的起始位和停止位
	localparam START_BIT = 1'b0;
	localparam STOP_BIT  = 1'b1;
	
	reg [7:0]r_data_byte;//数据寄存器
	
//--------<uart状态模块>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			uart_state <= 1'b0;
		else if(send_en)
			uart_state <= 1'b1;
		else if(bps_cnt == 4'd11)//bps_cnt计数达到11次,即发送结束
			uart_state <= 1'b0;
		else
			uart_state <= uart_state;
	end

//--------<使能分频计数模块>-------	
	assign en_cnt = uart_state;
	
//--------<寄存待发送的数据,使数据保持稳定>--------
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			r_data_byte <= 8'd0;
		else if(send_en)
			r_data_byte <= data_byte;
		else
			r_data_byte <= r_data_byte;
	end
	
//--------<波特率查找表>--------		
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			bps_DR <= 16'd5207;
		else begin
			case(baud_set)
				0:bps_DR <= 16'd5207;
				1:bps_DR <= 16'd2603;
				2:bps_DR <= 16'd1301;
				3:bps_DR <= 16'd867;
				4:bps_DR <= 16'd433;
				default:bps_DR <= 16'd5207;
			endcase
		end	
	end
	
//--------<Div_Cnt模块>--------	
//得到不同计数周期的计数器
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			div_cnt <= 16'd0;
		else if(en_cnt)begin
			if(div_cnt == bps_DR)
				div_cnt <= 16'd0;
			else
				div_cnt <= div_cnt + 1'b1;
		end
		else
			div_cnt <= 16'd0;
	end
//--------<bps_clk信号的产生>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			bps_clk <= 1'b0;
		else if(div_cnt == 16'd1)
			bps_clk <= 1'b1;
		else
			bps_clk <= 1'b0;
	end
	
//--------<bps_cnt计数模块>--------		
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			bps_cnt <= 4'd0;
		else if(bps_cnt == 4'd11)//clr信号
			bps_cnt <= 4'd0;
		else if(bps_clk)
			bps_cnt <= bps_cnt + 1'b1;
		else
			bps_cnt <= bps_cnt;
	end

//--------<Tx_Done模块>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			Tx_Done <= 1'b0;
		else if(bps_cnt == 4'd11)
			Tx_Done <= 1'b1;
		else
			Tx_Done <= 1'b0;
	end
	
//--------<数据位输出模块-10选1多路器>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			uart_tx <= 1'b1;
		else begin
			case(bps_cnt)
				0:uart_tx <= 1'b1;
				1:uart_tx <= START_BIT;
				2:uart_tx <= r_data_byte[0];
				3:uart_tx <= r_data_byte[1];
				4:uart_tx <= r_data_byte[2];
				5:uart_tx <= r_data_byte[3];
				6:uart_tx <= r_data_byte[4];
				7:uart_tx <= r_data_byte[5];
				8:uart_tx <= r_data_byte[6];
				9:uart_tx <= r_data_byte[7];
				10:uart_tx <= STOP_BIT;
				default:uart_tx <= 1'b1;
			endcase
		end
	end
	
endmodule

二、串口发送时序

串口发送一个字节数据的时序图参考如下:
时序图

根据上图,一个字节想要成功发送完成,需要计数11次波特率时钟的高电平;而且一个完整的字节发送需要10位数据位,包括1个起始位8个数据位1个停止位

需要注意,在串口未发送数据时(波特率时钟未使能时),串口输出高电平;在第一个波特率时钟高电平到来时,开始发送起始位。

🥝波特率计算:

baud_set波特率bps周期分频计数值50M系统时钟计数值
09600104167ns104167/System_clk_period5208-1
11920052083ns52083/System_clk_period2604-1
23840026041ns26041/System_clk_period1302-1
35760017361ns17361/System_clk_period868-1
41152008680ns8680/System_clk_period434-1

三、模块设计与代码详解

根据小梅哥FPGA设计的电路图进行代码编写:
电路设计
代码理解主要参考前文中代码的模块注释串口发送时序图

在此展示简单的测试激励文件:

uart_byte_tx_tb.v:

`timescale 1ns/1ns
`define clock_period 20

module uart_byte_tx_tb;

	reg Clk;
	reg Rst_n;
	reg [7:0]data_byte;
	reg send_en;
	reg [2:0]baud_set;
	
	wire uart_tx;
	wire Tx_Done;
	wire uart_state;
	
	uart_byte_tx Uuart_byte_tx(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.data_byte(data_byte),
		.send_en(send_en),
		.baud_set(baud_set),	
		.uart_tx(uart_tx),
		.Tx_Done(Tx_Done),
		.uart_state(uart_state)
	);
	
	initial Clk = 1;
	always#(`clock_period / 2) Clk = ~Clk;
	
	initial begin
		Rst_n = 1'b0;
		data_byte = 8'd0;
		send_en = 1'b0;
		baud_set = 3'd4;
		#(`clock_period * 20 + 1);
		Rst_n = 1'b1;
		#(`clock_period * 50);
		data_byte = 8'haa;
		send_en = 1'b1;
		#(`clock_period * 1);
		send_en = 1'b0;
		
		@(posedge Tx_Done)
		
		#(`clock_period * 5000);
		data_byte = 8'hff;
		send_en = 1'b1;
		#(`clock_period * 1);
		send_en = 1'b0;
		
		@(posedge Tx_Done)
		#(`clock_period * 5000);
		
		$stop;
	end

endmodule

仿真结果:

仿真结果

Tx_Done信号的正确输出:

txdone信号

四、按键控制串口发送数据

先看整体的RTL视图来理解设计思路:
RTL
按键信号经过KeyFilter按键消抖模块之后的有效信号用来控制串口发送模块的发送使能;HEX8模块74HC595模块用来驱动三线制数码管显示数据;issp模块用来从电脑端调试数据;uart_byte_tx模块用来将调试数据通过串口发送给电脑。

🔸按键消抖模块的详细讲解:【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现)。

🔸HEX8模块的详细讲解:【FPGA零基础学习之旅#11】数码管动态扫描。

🔸74HC595模块的详细讲解:【FPGA零基础学习之旅#12】三线制数码管驱动(74HC595)串行移位寄存器驱动。

🔸issp ip核的创建和使用包含在文章【FPGA零基础学习之旅#11】数码管动态扫描中。

在此给出顶层模块,其余模块见文末:

uart_byte_tx_top.v:

module uart_byte_tx_top(
	input 			Clk,		//50M
	input 			Rst_n,
	input 			key_in,
	output 			SH_CP,		//shift clock
	output 			ST_CP,		//latch data clock
	output 			DS,			//shift serial data
	output 			uart_tx,
	output			led
);

	wire [7:0] sel;//数码管位选(选择当前要显示的数码管)
	wire [7:0] seg;//数码管段选(当前要显示的内容)	

	wire  [7:0] data_byte;
	
	wire key_flag;
	wire key_state;
	
	issp issp(
		.probe(),
		.source(data_byte)
	);
	
	KeyFilter KeyFilter(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_in(key_in),
		.key_flag(key_flag),
		.key_state(key_state)
	);
	
	//通过按键状态使能串口发送模块,按键按下时,串口发送模块使能
	assign send_en = key_flag & (!key_state);
	
	uart_byte_tx uart_byte_tx(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.data_byte(data_byte),
		.send_en(send_en),
		.baud_set(3'd0),
		.uart_tx(uart_tx),
		.Tx_Done(),
		.uart_state(led)
	);

	//由于串口目前只发送一个字节数据,只占用2个数码管,所以其余数码管显示0
	HEX8 HEX8(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.En(1'b1),
		.disp_data({24'h0,data_byte}),
		.sel(sel),
		.seg(seg)
	);

	m74HC595_Driver m74HC595_Driver(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.Data({seg,sel}),
		.S_EN(1'b1),
		.SH_CP(SH_CP),
		.ST_CP(ST_CP),
		.DS(DS)
	);

endmodule

程序配置完成之后的数码管显示和led的点亮:
程序配置完成

使用issp更改数据,数码管显示数据并通过按键发送:
🥝修改为11:
11
发送

🥝修改为AF:
af
afff

本案例的其余模块在此部分列出:

KeyFilter.v:

//
//模块:按键消抖模块
//key_state:输出消抖之后按键的状态
//key_flag:按键消抖结束时产生一个时钟周期的高电平脉冲
//
module KeyFilter(
	input 		Clk,
	input	 	Rst_n,
	input 		key_in,
	output reg 	key_flag,
	output reg 	key_state
);

	//按键的四个状态
	localparam
		IDLE 		= 4'b0001,
		FILTER1 	= 4'b0010,
		DOWN 		= 4'b0100,
		FILTER2 	= 4'b1000;

	//状态寄存器
	reg [3:0] curr_st;
	
	//边沿检测输出上升沿或下降沿
	wire pedge;
	wire nedge;
	
	//计数寄存器
	reg [19:0]cnt;
	
	//使能计数寄存器
	reg en_cnt;
	
	//计数满标志信号
	reg cnt_full;//计数满寄存器
	
//------<边沿检测电路的实现>------
	//边沿检测电路寄存器
	reg key_tmp0;
	reg key_tmp1;
	
	//边沿检测
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin
			key_tmp0 <= 1'b0;
			key_tmp1 <= 1'b0;
		end
		else begin
			key_tmp0 <= key_in;
			key_tmp1 <= key_tmp0;
		end	
	end
		
	assign nedge = (!key_tmp0) & (key_tmp1);
	assign pedge = (key_tmp0)  & (!key_tmp1);

//------<状态机主程序>------	
	//状态机主程序
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin
			curr_st <= IDLE;
			en_cnt <= 1'b0;
			key_flag <= 1'b0;
			key_state <= 1'b1;
		end
		else begin
			case(curr_st)
				IDLE:begin
					key_flag <= 1'b0;
					if(nedge)begin
						curr_st <= FILTER1;
						en_cnt <= 1'b1;
					end
					else
						curr_st <= IDLE;
				end
				
				FILTER1:begin
					if(cnt_full)begin
						key_flag <= 1'b1;
						key_state <= 1'b0;
						curr_st <= DOWN;
						en_cnt <= 1'b0;
					end	
					else if(pedge)begin
						curr_st <= IDLE;
						en_cnt <= 1'b0;
					end
					else
						curr_st <= FILTER1;
				end
				
				DOWN:begin
					key_flag <= 1'b0;
					if(pedge)begin
						curr_st <= FILTER2;
						en_cnt <= 1'b1;
					end
					else
						curr_st <= DOWN;
				end
				
				FILTER2:begin
					if(cnt_full)begin
						key_flag <= 1'b1;
						key_state <= 1'b1;
						curr_st <= IDLE;
						en_cnt <= 1'b0;
					end	
					else if(nedge)begin
						curr_st <= DOWN;
						en_cnt <= 1'b0;
					end
					else
						curr_st <= FILTER2;
				end
				
				default:begin
					curr_st <= IDLE;
					en_cnt <= 1'b0;
					key_flag <= 1'b0;
					key_state <= 1'b1;
				end
			endcase
		end
	end
	
//------<20ms计数器>------		
	//20ms计数器
	//Clk 50_000_000Hz
	//一个时钟周期为20ns
	//需要计数20_000_000 / 20 = 1_000_000次
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			cnt <= 20'd0;
		else if(en_cnt)
			cnt <= cnt + 1'b1;
		else
			cnt <= 20'd0;
	end
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			cnt_full <= 1'b0;
		else if(cnt == 999_999)
			cnt_full <= 1'b1;
		else
			cnt_full <= 1'b0;
	end
	
endmodule

HEX8.v:

module HEX8(
		input 					Clk,			//50M
		input 					Rst_n,			//复位
		input 					En,				//数码管显示使能
		input 		[31:0]		disp_data,		//8 × 4 = 32(8个数码管,数据格式为hex,总共输32位)
		output reg 	[7:0]		seg, 			//数码管段选
		output 		[7:0]		sel	 			//数码管位选(数码管选择)
);
	reg [7:0]sel_r;

//----------<分频器>----------
	reg [14:0]divider_cnt;//25000-1
	
	reg clk_1K;
	
	reg [3:0]data_tmp;//待显示数据缓存
	
	//1KHz分频计数器
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			divider_cnt <= 15'd0;
		else if(!En)
			divider_cnt <= 15'd0;
		else if(divider_cnt == 24999)
			divider_cnt <= 15'd0;
		else
			divider_cnt <= divider_cnt + 1'b1;
	end
	
	//1KHz扫描时钟
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			clk_1K <= 1'b0;
		else if(divider_cnt == 24999)
			clk_1K <= ~clk_1K;
		else
			clk_1K <= clk_1K;
	end
	
//----------<6位循环移位寄存器>-----------	
	always@(posedge clk_1K or negedge Rst_n)begin
		if(!Rst_n)
			sel_r <= 8'b0000_0001;
		else if(sel_r == 8'b1000_0000)
			sel_r <= 8'b0000_0001;
		else
			sel_r <= sel_r << 1;
	end	

//----------<6选1多路器>----------		
	always@(*)begin
		case(sel_r)
			8'b0000_0001:data_tmp = disp_data[3:0];
			8'b0000_0010:data_tmp = disp_data[7:4];
			8'b0000_0100:data_tmp = disp_data[11:8];
			8'b0000_1000:data_tmp = disp_data[15:12];
			8'b0001_0000:data_tmp = disp_data[19:16];
			8'b0010_0000:data_tmp = disp_data[23:20];
			8'b0100_0000:data_tmp = disp_data[27:24];
			8'b1000_0000:data_tmp = disp_data[31:28];
			default:data_tmp = 4'b0000;
		endcase
	end

//----------<LUT>----------		
	always@(*)begin
		case(data_tmp)
			4'h0:seg = 8'hc0;
			4'h1:seg = 8'hf9;
			4'h2:seg = 8'ha4;
			4'h3:seg = 8'hb0;
			4'h4:seg = 8'h99;
			4'h5:seg = 8'h92;
			4'h6:seg = 8'h82;
			4'h7:seg = 8'hf8;
			4'h8:seg = 8'h80;
			4'h9:seg = 8'h90;
			4'ha:seg = 8'h88;
			4'hb:seg = 8'h83;
			4'hc:seg = 8'hc6;
			4'hd:seg = 8'ha1;
			4'he:seg = 8'h86;
			4'hf:seg = 8'h8e;
		endcase
	end
		
//----------<2选1多路器>----------		
	assign sel = (En)?(sel_r):8'b1111_1111;
		
endmodule

m74HC595_Driver.v:

module m74HC595_Driver(
		Clk,
		Rst_n,
		Data,
		S_EN,
		SH_CP,
		ST_CP,
		DS
	);

	parameter DATA_WIDTH = 16;

	input 		Clk;
	input 		Rst_n;
	input 		[DATA_WIDTH-1 : 0] Data;	//data to send
	input 		S_EN;						//send en
	output reg 	SH_CP;						//shift clock
	output reg 	ST_CP;						//latch data clock
	output reg 	DS;							//shift serial data
	
	parameter CNT_MAX = 4;
		
	reg [15:0] divider_cnt;//分频计数器
	wire sck_pluse;
	
	reg [4:0]SHCP_EDGE_CNT;//SH_CP EDGE counter
	
	reg [15:0]r_data;
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			r_data <= 16'd0;
		else if(S_EN)
			r_data <= Data;
		else
			r_data <= r_data;
	end
		
	//clock divide
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			divider_cnt <= 16'd0;
		else if(divider_cnt == CNT_MAX)
			divider_cnt <= 16'd0;
		else
			divider_cnt <= divider_cnt + 1'b1;
	end
	
	assign sck_pluse = (divider_cnt == CNT_MAX);
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			SHCP_EDGE_CNT <= 5'd0;
		else if(sck_pluse)begin
			if(SHCP_EDGE_CNT ==  5'd31)
				SHCP_EDGE_CNT <= 5'd0;
			else
				SHCP_EDGE_CNT <= SHCP_EDGE_CNT + 1'b1;
		end
		else
			SHCP_EDGE_CNT <= SHCP_EDGE_CNT;
	end	
		
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin
			SH_CP <= 1'b0;
			ST_CP <= 1'b0;
			DS <= 1'b0;	
		end
		else begin
			case(SHCP_EDGE_CNT)
				5'd0: begin SH_CP <= 1'b0; ST_CP <= 1'b1; DS <= r_data[15]; end
				5'd1: begin SH_CP <= 1'b1; ST_CP <= 1'b0;end
				5'd2: begin SH_CP <= 1'b0; DS <= r_data[14];end
				5'd3: begin SH_CP <= 1'b1; end
				5'd4: begin SH_CP <= 1'b0; DS <= r_data[13];end
				5'd5: begin SH_CP <= 1'b1; end
				5'd6: begin SH_CP <= 1'b0; DS <= r_data[12];end
				5'd7: begin SH_CP <= 1'b1; end
				5'd8: begin SH_CP <= 1'b0; DS <= r_data[11];end
				5'd9: begin SH_CP <= 1'b1; end
				5'd10:begin SH_CP <= 1'b0; DS <= r_data[10];end
				5'd11:begin SH_CP <= 1'b1; end
				5'd12:begin SH_CP <= 1'b0; DS <= r_data[9];end
				5'd13:begin SH_CP <= 1'b1; end
				5'd14:begin SH_CP <= 1'b0; DS <= r_data[8];end
				5'd15:begin SH_CP <= 1'b1; end
				5'd16:begin SH_CP <= 1'b0; DS <= r_data[7];end
				5'd17:begin SH_CP <= 1'b1; end
				5'd18:begin SH_CP <= 1'b0; DS <= r_data[6];end
				5'd19:begin SH_CP <= 1'b1; end
				5'd20:begin SH_CP <= 1'b0; DS <= r_data[5];end
				5'd21:begin SH_CP <= 1'b1; end
				5'd22:begin SH_CP <= 1'b0; DS <= r_data[4];end
				5'd23:begin SH_CP <= 1'b1; end
				5'd24:begin SH_CP <= 1'b0; DS <= r_data[3];end
				5'd25:begin SH_CP <= 1'b1; end
				5'd26:begin SH_CP <= 1'b0; DS <= r_data[2];end
				5'd27:begin SH_CP <= 1'b1; end
				5'd28:begin SH_CP <= 1'b0; DS <= r_data[1];end
				5'd29:begin SH_CP <= 1'b1; end
				5'd30:begin SH_CP <= 1'b0; DS <= r_data[0];end
				5'd31:begin SH_CP <= 1'b1; end
				default:begin SH_CP <= 1'b0;ST_CP <= 1'b0;DS <= 1'b0;	end
			endcase	
		end
	end

endmodule

csdn

🧸结尾


  • ❤️ 感谢您的支持和鼓励! 😊🙏
  • 📜您可能感兴趣的内容:
  • 【FPGA零基础学习之旅#11】数码管动态扫描
  • 【Python】串口通信-与FPGA、蓝牙模块实现串口通信(Python+FPGA)
  • 【Arduino TinyGo】【最新】使用Go语言编写Arduino-环境搭建和点亮LED灯
  • 【全网首发开源教程】【Labview机器人仿真与控制】Labview与Solidworks多路支配关系-四足爬行机器人仿真与控制
    遇见未来

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

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

相关文章

Redis 十大核心数据类型解析

一、Redis 简述 redis是一个开源的使用C语言编写的一个kv存储系统&#xff0c;是一个速度非常快的非关系远程内存数据库。它支持包括String、List、Set、Zset、hash五种数据结构。 除此之外&#xff0c;通过复制、持久化和客户端分片等特性&#xff0c;用户可以很方便地将red…

基于Yolov8的NEU-DET钢材表面缺陷检测,优化组合新颖程度较高:CVPR2023 PConv和BiLevelRoutingAttention,涨点明显

1.钢铁缺陷数据集介绍 NEU-DET钢材表面缺陷共有六大类,分别为:crazing,inclusion,patches,pitted_surface,rolled-in_scale,scratches 每个类别分布为: 2.基于yolov8的训练 原始网络如下: map@0.5为0.733

博客系统(升级(Spring))(三)登录功能,注册功能,注销功能

博客系统 (三&#xff09; 博客系统登录用户前端后端数据查询&#xff08;在mapper上添加mapper接口&#xff09; 注册用户前端后端插入数据 注销 博客系统 博客系统是干什么的&#xff1f; CSDN就是一个典型的博客系统。而我在这里就是通过模拟实现一个博客系统&#xff0c;这…

Spring Boot 中使用 Poi-tl 渲染数据并生成 Word 文档

本文 Demo 已收录到 demo-for-all-in-java 项目中&#xff0c;欢迎大家 star 支持&#xff01;后续将持续更新&#xff01; 前言 产品经理急冲冲地走了过来。「现在需要将按这些数据生成一个 Word 报告文档&#xff0c;你来安排下」 项目中有这么一个需求&#xff0c;需要将用户…

Linux平台如何实现采集音视频数据并注入轻量级RTSP服务?

技术背景 好多开发者&#xff0c;问我们最多的问题是&#xff0c;为什么要设计轻量级RTSP服务&#xff1f;轻量级RTSP服务&#xff0c;和RTSP服务有什么区别&#xff1f; 针对这个问题&#xff0c;我们的回答是&#xff1a;轻量级RTSP服务解决的核心痛点是避免用户或者开发者…

59、SpringBoot 自定义JSON的序列化器和反序列化器

Serialization(序列化)&#xff1a; 将java对象以一连串的字节码保存在磁盘文件中的过程&#xff0c;也可以说是保存java对象状态的过程。序列化可以将数据永久保存在磁盘上(通常保存在文件中)。 deserialization(反序列化)&#xff1a; 将保存在磁盘文件中的java字节码重新转…

关于µC/OS-III 多任务的基本理解

关于C/OS-III 多任务的基本理解 任务和任务管理是 RTOS 的核心&#xff0c;且大多数项目使用 RTOS 的目的就是为了使用 RTOS 的多任务管理能力。 C/OS-III作为经典的RTOS&#xff0c;了解并学习其任务管理机制&#xff0c;是非常有必要的。 文章目录 关于C/OS-III 多任务的基本…

进阶C语言-指针的进阶(中)

指针的进阶 &#x1f4d6;5.函数指针&#x1f4d6;6.函数指针数组&#x1f4d6;7.指向函数指针数组的指针&#x1f4d6;8.回调函数 &#x1f4d6;5.函数指针 数组指针 - 指向数组的指针 - 存放的是数组的地址 - &数组名就是数组的地址。 函数指针 - 指向函数的指针 - 存放的…

【Java】session的工作原理

文章目录 一、session的概念及特点session概念session主要有以下的这些特点 二、为什么要使用session三、session的工作原理四、session的生命周期Session何时生效Session何时失效 五、session的性能瓶颈六、session实现登录状态的控制 一、session的概念及特点 session概念 …

无涯教程-JavaScript - COUPDAYSNC函数

描述 COUPDAYSNC函数返回从结算日期到下一个息票日期的天数。 语法 COUPDAYSNC (settlement, maturity, frequency, [basis])争论 Argument描述Required/OptionalSettlement 证券的结算日期。 证券结算日期是指在发行日期之后将证券交易给买方的日期。 RequiredMaturity 证…

基于第二代 ChatGLM2-6B P-Tuning v2 微调训练医疗问答任务

今天是教师节&#xff0c;恭祝全体老师们节日快乐&#xff01;&#x1f60a; 一、ChatGLM2-6B 在本专栏前面文章中实验了使用 ChatYuan-large-v2 Freeze 微调训练医疗问答任务&#xff0c;训练后效果整体还可以&#xff0c;这篇文章继续探索使用最近比较火的 ChatGLM 官方推出…

docker镜像详解

目录 什么是docker镜像镜像相关命令docker pulldocker imagesdocker searchdocker rmi导出 / 导入镜像 镜像分层镜像摘要镜像摘要的作用分发散列值 什么是docker镜像 Docker镜像是Docker容器的基础组件&#xff0c;它包含了运行一个应用程序所需的一切&#xff0c;包括代码、运…

Sharding-Jdbc(2):Sharding-Jdbc入门案例

1 前置条件 搭建读写分离的数据库环境,搭建方法如下文,目标数据库test Mysql性能优化(5):主从同步原理与实现_mysql主从配置优化_不死鸟.亚历山大.狼崽子的博客-CSDN博客 2 新建maven项目 3 pom引入依赖 <?xml version="1.0" encoding="UTF-8"…

《protobuf》基础语法2

文章目录 枚举类型ANY 类型oneof 类型map 类型改进通讯录实例 枚举类型 protobuf里有枚举类型&#xff0c;定义如下 enum PhoneType {string home_addr 0;string work_addr 1; }同message一样&#xff0c;可分为 嵌套定义&#xff0c;文件内定义&#xff0c;文件外定义。不…

二维码智慧门牌管理系统:智能化地址管理,提升社会治理效率

文章目录 前言一、地址管理挑战二、二维码智慧门牌管理系统解决方案 前言 随着科技的飞速发展&#xff0c;我们的生活正经历前所未有的变革。尤其是智能化技术&#xff0c;已经深刻影响了我们的日常生活和工作环境。然而&#xff0c;在某些领域&#xff0c;如地址管理和社会治…

十大免费好用的视频软件推荐,新手小白必备

很多人都在使用视频软件进行编辑&#xff0c;那么你们知道哪些视频软件是免费的而且还好用&#xff1f; 现在很多小伙伴比较喜欢用手机编辑视频&#xff0c;而这些剪辑软件具有领先的智能化AI技术&#xff0c;让你不用绿幕就能一键挖出图像&#xff0c;不仅可以一键挖出三维人…

获取板块分类并展示

板块分类也会变动&#xff0c;偶尔看下&#xff0c;利于总体分析大盘 https:dapanyuntu.com/ 该网站含有板块信息 分析接口 搜素关键字 拷贝curl到curl解析工具&#xff0c;去掉无用的参数&#xff0c;生成requests代码 尝试nginx反代接口 server {listen 443;loca…

汇率失守7.3关口

号外&#xff1a;9.8教链内参《被判入狱1万年》。 拉锯多时的离岸人民币汇率USDCNH失守7.3关口&#xff0c;隔夜冲破7.36的高位。 为什么7.3是一个关键关口&#xff1f;因为这里是2022年10月底、11月初时曾经测试过的支撑位&#xff08;从CNH的角度说&#xff09;。 如果支撑位…

微信视频号挂公众号文章链接新方法:不限次数,不限号

当看到自己身边的人&#xff0c;通过我分享的方法绑定成功&#xff0c;那是开心到起飞了。 因为我知道&#xff1a;外面不靠谱的人很多&#xff01;分享不靠谱方法的人&#xff0c;可谓是更多。 为什么我要主动分享视频号评论区挂公众号文章链接&#xff1f;总有人伸张正义&a…

java中log使用总结

目录 一、概述1.1. 核心日志框架1.2 门面日志框架 二、最佳实践2.1 核心日志框架API包2.2 门面日志框架依赖2.3 集成使用2.3.1 集成jcl2.3.2 集成slf4j2.3.2.1 slf4j集成单一框架2.3.2.2 slf4j整合混合框架 三、总结3.1 所有相关包3.1.1 核心日志框架包3.1.2 门面日志框架3.1.3…