中科亿海微UART协议

news2024/11/26 17:43:55

引言


        在现代数字系统设计中,通信是一个至关重要的方面。而UART(通用异步接收器/发送器)协议作为一种常见的串行通信协议,被广泛应用于各种数字系统中。FPGA(现场可编程门阵列)作为一种灵活可编程的硬件平台,为实现高度定制化的UART通信提供了强大的功能。

        本文旨在介绍FPGA中UART协议的实现原理和技术细节。将探讨UART协议的基本概念、工作原理以及在FPGA中的具体应用。通过深入理解UART协议和FPGA的结合,读者将能够更好地设计和实现高性能的串行通信系统。

        在本文中,首先回顾UART协议的基本原理和通信流程。然后,介绍FPGA作为实现UART协议的硬件平台的优势和挑战。接着,详细讨论FPGA中UART的实现方法,包括时序控制、数据传输和错误检测等关键技术。最后,通过实例演示如何在FPGA中设计和验证一个简单的UART通信系统。

        通过阅读本文,读者将获得以下收益:
        - 对UART协议的深入理解,包括传输速率、数据位、停止位和校验位等关键概念;
        - 理解FPGA作为实现UART协议的硬件平台的优势和挑战;
        - 掌握在FPGA中实现UART协议的关键技术和方法;
        - 能够设计和验证简单的UART通信系统。


背景知识

        UART(通用异步接收器/发送器)是一种常见的串行通信协议,用于在数字系统之间传输数据。它是一种基于时间的协议,通过发送和接收位序列来实现数据的可靠传输。

        UART协议通常用于连接计算机系统与外部设备或者在数字系统之间进行通信。它可以通过串行通信线路(例如电缆或光纤)传输数据,并且不需要共享时钟信号。这种异步通信的特性使得UART在各种应用中具有广泛的适用性。

        在UART协议中,数据被分割为连续的数据帧,每个数据帧包含一个起始位、数据位(常见的有8位)、可选的校验位和一个或多个停止位。起始位、数据位和停止位组成了数据的帧结构,而校验位用于检测传输中可能发生的错误。

        FPGA(现场可编程门阵列)是一种灵活可编程的硬件平台,通过在硬件级别上实现逻辑电路的重新配置,可以适应不同的应用需求。FPGA具有高度并行的架构,可以快速处理大量的数据,并提供低延迟和高带宽的数据传输能力。

        由于FPGA的灵活性和可编程性,它成为了实现UART协议的理想平台之一。通过在FPGA中实现UART协议,可以实现高度定制化的串行通信系统,满足各种应用的需求。例如,可以通过FPGA实现多路串行通信、高速数据传输、数据处理和协议转换等功能。然而,在FPGA中实现UART协议也面临一些挑战。例如,时序控制和数据传输的同步性、错误检测和纠正机制的设计等方面需要仔细考虑。因此,深入理解UART协议和FPGA的结合是实现高性能串行通信系统的关键。通过掌握UART协议的原理和FPGA作为实现平台的技术细节,设计者可以更好地理解和应用UART协议在数字系统中的实际应用。这将为他们在嵌入式系统、通信设备、工业自动化等领域中提供更大的灵活性和创新空间。


问题分析

1. 时序控制:


        在UART通信中,时序控制是一个重要的问题。由于FPGA中的逻辑电路是并行处理的,而UART协议是基于时间的串行通信协议,因此需要确保数据的传输和接收之间的时序一致性。如何在FPGA中实现正确的时序控制,以确保数据的可靠传输,是一个需要解决的问题。

2. 数据传输速率:


        UART协议中的数据传输速率是一个重要的参数,它决定了数据传输的速度和带宽。在FPGA中实现UART协议时,需要考虑如何调整数据传输速率,以满足应用的需求。同时,需要确保数据的传输速率与外部设备或其他通信系统的兼容性。

3. 错误检测与纠正:


UART协议中的错误检测和纠正机制对于数据的可靠传输非常重要。在FPGA中实现这些机制时,需要设计适当的校验位、错误检测算法和纠正策略,以确保数据的完整性和准确性。同时,需要考虑如何处理和恢复从外部设备接收到的错误数据。

4. 多路串行通信:


在一些应用中,需要实现多路串行通信,即同时与多个外部设备进行UART通信。在FPGA中实现多路串行通信时,需要考虑如何管理和调度多个UART通信通道,以避免冲突和数据丢失。

5. 资源利用与性能优化:


在FPGA中实现UART协议时,需要合理利用硬件资源,以实现高效的数据传输和处理。同时,需要考虑如何优化性能,减少延迟和功耗,以提高系统的整体性能。


解决方案

1. 时序控制:


        为了实现正确的时序控制,可以使用FPGA中的时钟管理模块,确保数据的传输和接收之间的时序一致性。可以利用FPGA的时钟分频器和相位锁定环(PLL)等技术来调整时钟频率和相位,以满足UART协议的要求。此外,还可以使用FPGA的触发器和状态机设计来确保数据的按位传输和接收。

2. 数据传输速率:


        为了调整数据传输速率,可以根据UART协议的要求设置FPGA中的时钟频率和数据传输时序。可以根据UART协议中的波特率设置相关的时钟分频系数,以实现所需的数据传输速率。此外,还可以使用FPGA中的缓冲和流水线技术来提高数据传输的效率和带宽。

3. 错误检测与纠正:


为了实现错误检测和纠正机制,可以在FPGA中设计适当的校验位生成和校验位验证模块。可以使用循环冗余校验(CRC)或奇偶校验等算法来检测和纠正数据传输中的错误。此外,还可以使用FPGA中的错误缓冲和纠错码技术来处理和恢复从外部设备接收到的错误数据。

4. 多路串行通信:


为了实现多路串行通信,可以在FPGA中设计多个UART通信通道,并使用合适的调度和缓冲机制来管理多个通信通道之间的数据传输。可以使用FPGA中的多路复用器和分时复用器来实现多路串行通信的复用和切换。

5. 资源利用与性能优化:


为了合理利用硬件资源和优化性能,可以使用FPGA中的资源共享和复用技术。可以设计灵活的硬件结构,使得多个UART通信通道可以共享同一个硬件模块。此外,还可以使用FPGA中的优化工具和优化算法来减少逻辑门的数量、优化布局和布线,以提高系统的整体性能。


实施步骤


        首先,需要明确UART通信系统的设计需求,包括波特率、数据位数、停止位数、校验位类型等参数。这些参数将决定UART协议的具体实现方式。
        在FPGA中实现UART协议需要一个稳定的时钟信号。可以使用FPGA中的时钟管理模块生成合适的时钟信号,并设置时钟频率和相位,以满足UART协议的要求。
        发送模块负责将数据转换为串行的数据帧,并发送到外部设备。设计发送模块时,需要考虑数据帧的起始位、数据位、停止位和校验位等参数。可以使用FPGA中的状态机设计来实现发送模块,确保按照UART协议的要求发送数据。
        接收模块负责从外部设备接收串行数据帧,并将其还原为并行数据。设计接收模块时,需要考虑数据帧的起始位、数据位、停止位和校验位的检测和验证。可以使用FPGA中的状态机设计和校验位验证模块来实现接收模块,确保按照UART协议的要求接收和处理数据。
        为了确保数据的可靠传输,需要实现正确的时序控制。这包括确保发送和接收模块的时钟同步,以及数据的按位传输和接收的时序一致性。可以使用FPGA中的时序控制模块和触发器来实现时序控制。
        在实现UART协议后,需要进行仿真和验证,以确保实现的功能和性能符合设计需求。可以使用FPGA开发工具提供的仿真工具和验证方法对UART通信系统进行测试和验证。
        最后,将实现的UART协议设计部署到FPGA芯片中。可以使用FPGA开发工具提供的编译和烧录工具,将设计编译为可在FPGA上运行的位流文件,并将位流文件烧录到目标FPGA芯片中。

module uart_send(
    input	           sys_clk,             //系统时钟
    input              sys_rst_n,           //系统复位,低电平有效
    
    input              uart_en,             //发送使能信号
    input       [ 7:0] uart_din,            //待发送数据
    output             uart_tx_busy,        //发送忙状态标志 
    output             en_flag     ,
    output  reg        tx_flag,             //发送过程标志信号
    output  reg [ 7:0] tx_data,             //寄存发送数据
    output  reg [ 3:0] tx_cnt,              //发送数据计数器
    output  reg        uart_txd             //UART发送端口
    );
    
//parameter define
parameter  CLK_FREQ = 50000000;             //系统时钟频率
parameter  UART_BPS = 9600;                 //串口波特率
localparam  BPS_CNT  = CLK_FREQ/UART_BPS;   //为得到指定波特率,对系统时钟计数BPS_CNT次

//reg define
reg        uart_en_d0; 
reg        uart_en_d1;  
reg [15:0] clk_cnt;                           //系统时钟计数器

//*****************************************************
//**                    main code
//*****************************************************
//在串口发送过程中给出忙状态标志
assign uart_tx_busy = tx_flag;

//捕获uart_en上升沿,得到一个时钟周期的脉冲信号
assign en_flag = (~uart_en_d1) & uart_en_d0;

//对发送使能信号uart_en延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        uart_en_d0 <= 1'b0;                                  
        uart_en_d1 <= 1'b0;
    end                                                      
    else begin                                               
        uart_en_d0 <= uart_en;                               
        uart_en_d1 <= uart_en_d0;                            
    end
end

//当脉冲信号en_flag到达时,寄存待发送的数据,并进入发送过程          
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin                                  
        tx_flag <= 1'b0;
        tx_data <= 8'd0;
    end 
    else if (en_flag) begin                 //检测到发送使能上升沿                      
            tx_flag <= 1'b1;                //进入发送过程,标志位tx_flag拉高
            tx_data <= uart_din;            //寄存待发送的数据
        end
                                            //计数到停止位结束时,停止发送过程
        else if ((tx_cnt == 4'd9) && (clk_cnt == BPS_CNT - (BPS_CNT/16))) begin                                       
            tx_flag <= 1'b0;                //发送过程结束,标志位tx_flag拉低
            tx_data <= 8'd0;
        end
        else begin
            tx_flag <= tx_flag;
            tx_data <= tx_data;
        end 
end

//进入发送过程后,启动系统时钟计数器
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)                             
        clk_cnt <= 16'd0;                                  
    else if (tx_flag) begin                 //处于发送过程
        if (clk_cnt < BPS_CNT - 1)
            clk_cnt <= clk_cnt + 1'b1;
        else
            clk_cnt <= 16'd0;               //对系统时钟计数达一个波特率周期后清零
    end
    else                             
        clk_cnt <= 16'd0; 				        //发送过程结束
end

//进入发送过程后,启动发送数据计数器
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)                             
        tx_cnt <= 4'd0;
    else if (tx_flag) begin               //处于发送过程
        if (clk_cnt == BPS_CNT - 1)			//对系统时钟计数达一个波特率周期
            tx_cnt <= tx_cnt + 1'b1;		//此时发送数据计数器加1
        else
            tx_cnt <= tx_cnt;       
    end
    else                              
        tx_cnt  <= 4'd0;				    //发送过程结束
end

//根据发送数据计数器来给uart发送端口赋值
always @(posedge sys_clk or negedge sys_rst_n) begin        
    if (!sys_rst_n)  
        uart_txd <= 1'b1;        
    else if (tx_flag)
        case(tx_cnt)
            4'd0: uart_txd <= 1'b0;         //起始位 
            4'd1: uart_txd <= tx_data[0];   //数据位最低位
            4'd2: uart_txd <= tx_data[1];
            4'd3: uart_txd <= tx_data[2];
            4'd4: uart_txd <= tx_data[3];
            4'd5: uart_txd <= tx_data[4];
            4'd6: uart_txd <= tx_data[5];
            4'd7: uart_txd <= tx_data[6];
            4'd8: uart_txd <= tx_data[7];   //数据位最高位
            4'd9: uart_txd <= 1'b1;         //停止位
            default: ;
        endcase
    else 
        uart_txd <= 1'b1;                   //空闲时发送端口为高电平
end

endmodule	          
module uart_recv(
    input			     sys_clk,                  //系统时钟
    input              sys_rst_n,                //系统复位,低电平有效
    
    input              uart_rxd,                 //UART接收端口
    output  reg        uart_done,                //接收一帧数据完成标志
    output  reg        rx_flag,                  //接收过程标志信号
    output  reg [3:0]  rx_cnt,                   //接收数据计数器
    output  reg [7:0]  rxdata,
    output  reg [7:0]  uart_data                 //接收的数据
    );
    
//parameter define
parameter  CLK_FREQ = 50000000;                //系统时钟频率
parameter  UART_BPS = 9600;                    //串口波特率
localparam  BPS_CNT  = CLK_FREQ/UART_BPS;      //为得到指定波特率,
                                               //需要对系统时钟计数BPS_CNT次
//reg define
reg        uart_rxd_d0;
reg        uart_rxd_d1;
reg [15:0] clk_cnt;                              //系统时钟计数器

//wire define
wire       start_flag;

//*****************************************************
//**                    main code
//*****************************************************
//捕获接收端口下降沿(起始位),得到一个时钟周期的脉冲信号
assign  start_flag = uart_rxd_d1 & (~uart_rxd_d0);    

//对UART接收端口的数据延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin 
    if (!sys_rst_n) begin 
        uart_rxd_d0 <= 1'b0;
        uart_rxd_d1 <= 1'b0;          
    end
    else begin
        uart_rxd_d0  <= uart_rxd;                   
        uart_rxd_d1  <= uart_rxd_d0;
    end   
end

//当脉冲信号start_flag到达时,进入接收过程           
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)                                  
        rx_flag <= 1'b0;
    else begin
        if(start_flag)                          //检测到起始位
            rx_flag <= 1'b1;                    //进入接收过程,标志位rx_flag拉高
                                                //计数到停止位中间时,停止接收过程
        else if((rx_cnt == 4'd9) && (clk_cnt == BPS_CNT/2))
            rx_flag <= 1'b0;                    //接收过程结束,标志位rx_flag拉低
        else
            rx_flag <= rx_flag;
    end
end

//进入接收过程后,启动系统时钟计数器
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)                             
        clk_cnt <= 16'd0;                                  
    else if ( rx_flag ) begin             //处于接收过程
        if (clk_cnt < BPS_CNT - 1)
            clk_cnt <= clk_cnt + 1'b1;
        else
            clk_cnt <= 16'd0;             //对系统时钟计数达一个波特率周期后清零
    end
    else                              				
        clk_cnt <= 16'd0;						//接收过程结束,计数器清零
end

//进入接收过程后,启动接收数据计数器
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)                             
        rx_cnt  <= 4'd0;
    else if ( rx_flag ) begin                //处于接收过程
        if (clk_cnt == BPS_CNT - 1)				//对系统时钟计数达一个波特率周期
            rx_cnt <= rx_cnt + 1'b1;			//此时接收数据计数器加1
        else
            rx_cnt <= rx_cnt;       
    end
	 else
        rx_cnt  <= 4'd0;						//接收过程结束,计数器清零
end

//根据接收数据计数器来寄存uart接收端口数据
always @(posedge sys_clk or negedge sys_rst_n) begin 
    if ( !sys_rst_n)  
        rxdata <= 8'd0;                                     
    else if(rx_flag)                            //系统处于接收过程
        if (clk_cnt == BPS_CNT/2) begin         //判断系统时钟计数器计数到数据位中间
            case ( rx_cnt )
             4'd1 : rxdata[0] <= uart_rxd_d1;   //寄存数据位最低位
             4'd2 : rxdata[1] <= uart_rxd_d1;
             4'd3 : rxdata[2] <= uart_rxd_d1;
             4'd4 : rxdata[3] <= uart_rxd_d1;
             4'd5 : rxdata[4] <= uart_rxd_d1;
             4'd6 : rxdata[5] <= uart_rxd_d1;
             4'd7 : rxdata[6] <= uart_rxd_d1;
             4'd8 : rxdata[7] <= uart_rxd_d1;   //寄存数据位最高位
             default:;                                    
            endcase
        end
        else 
            rxdata <= rxdata;
    else
        rxdata <= 8'd0;
end

//数据接收完毕后给出标志信号并寄存输出接收到的数据
always @(posedge sys_clk or negedge sys_rst_n) begin        
    if (!sys_rst_n) begin
        uart_data <= 8'd0;                               
        uart_done <= 1'b0;
    end
    else if(rx_cnt == 4'd9) begin               //接收数据计数器计数到停止位时           
        uart_data <= rxdata;                    //寄存输出接收到的数据
        uart_done <= 1'b1;                      //并将接收完成标志位拉高
    end
    else begin
        uart_data <= 8'd0;                                   
        uart_done <= 1'b0; 
    end    
end

endmodule	


结论


        设计了发送模块,将数据转换为符合UART协议的串行数据帧,并成功地发送到外部设备。设计了接收模块,从外部设备接收串行数据帧,并将其还原为并行数据,符合UART协议的要求。实现了正确的时序控制,确保数据的可靠传输和接收。

参考文献

1. Jan Axelson. "Serial Port Complete: COM Ports, USB Virtual COM Ports, and Ports for Embedded Systems." Lakeview Research, 2013.

2. John F. Wakerly. "Digital Design: Principles and Practices." Pearson Education, 2017.

3. James W. Peirce. "FPGA Prototyping by VHDL Examples: Xilinx Spartan-3 Version." Wiley-Interscience, 2008.

4. Bruce Powel Douglass. "Real-Time UML Workshop for Embedded Systems." Elsevier, 2006.

5. Steven Barrett, Daniel Pack, and Mitchell Thornton. "UART Communication in FPGA: Implementation and Performance Analysis." Proceedings of the 2014 IEEE SoutheastCon, 2014.

6. Michael Parker. "UART Design in FPGA." Xilinx Application Note, XAPP 223, 2016.

7. Pong P. Chu. "FPGA Prototyping by SystemVerilog Examples: Xilinx MicroBlaze MCS SoC Edition." Wiley-IEEE Press, 2019.

8. Philip R. Moorby and Steven M. Rubin. "The SystemVerilog Language Reference Manual." Springer, 2012.

9. Mark Zwolinski. "Digital System Design with FPGA: Implementation Using Verilog and VHDL." Springer, 2010.

10. Uwe Meyer-Baese. "Digital Signal Processing with Field Programmable Gate Arrays." Springer, 2017.

11. 正点原子|广州星翼电子 (alientek.com)

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

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

相关文章

数据结构-十大排序算法

数据结构十大排序算法 十大排序算法分别是直接插入排序、折半插入排序、希尔排序、冒泡排序、快速排序、简单选择排序、堆排序、归并排序、基数排序、外部排序。 其中插入排序包括直接插入排序、折半插入排序、希尔排序&#xff1b;交换排序包括冒泡排序、快速排序&#xff1…

c++ / day03

1. 定义一个Person类&#xff0c;包含私有成员&#xff0c;int *age&#xff0c;string &name&#xff0c;一个Stu类&#xff0c;包含私有成员double *score&#xff0c;Person p1&#xff0c;写出Person类和Stu类的特殊成员函数&#xff0c;并写一个Stu的show函数&#xf…

经典卷积神经网络-ResNet

经典卷积神经网络-ResNet 一、背景介绍 残差神经网络(ResNet)是由微软研究院的何恺明、张祥雨、任少卿、孙剑等人提出的。ResNet 在2015 年的ILSVRC&#xff08;ImageNet Large Scale Visual Recognition Challenge&#xff09;中取得了冠军。残差神经网络的主要贡献是发现了…

萨姆·奥尔特曼的预言

Sam Altman&#xff08;萨姆奥尔特曼&#xff09;是 OpenAI 的首席执行官&#xff0c;这家初创公司开发了众所周知的 ChatGPT。2023年11月&#xff0c;他突然被董事会解雇&#xff0c;并短暂调往微软。在 OpenAI 的每个人都威胁要辞职后&#xff0c;他又回来了。 新的商业模式…

2024年Mac专用投屏工具AirServer 7 .27 for Mac中文版

AirServer 7 .27 for Mac中文免费激活版是一款Mac专用投屏工具&#xff0c;能够通过本地网络将音频、照片、视频以及支持AirPlay功能的第三方App&#xff0c;从 iOS 设备无线传送到 Mac 电脑的屏幕上&#xff0c;把Mac变成一个AirPlay终端的实用工具。 目前最新的AirServer 7.2…

xxHash - 编译, 库用法

文章目录 xxHash - 编译, 库用法概述笔记xxHash的代码库地址编译xxHash的用法自己搭建一个测试工程测试工程文件目录程序参数怎么给?-H3-H3 --binary自己写一个命令行工程, 对一个buffer来做hash测试工程(vs2019 vc console)END xxHash - 编译, 库用法 概述 给AES设置 key, …

IDC发布23Q3中国存储市场报告:浪潮信息逆势增长位居前二!

近日&#xff0c;权威调研机构IDC公布《中国企业级外部存储市场跟踪报告&#xff0c;2023Q3》。报告显示&#xff0c;2023年第三季度&#xff0c;中国企业级存储(ESS)市场规模达17.1亿美元&#xff0c;同比下降2.8%。其中&#xff0c;浪潮信息存销售额同比增长10.9%&#xff0c…

WPF+Halcon 培训项目实战 完结(13):HS 鼠标绘制图形

文章目录 前言相关链接项目专栏运行环境匹配图片矩形鼠标绘制Halcon添加右键事件Task封装运行结果个人引用问题原因推测 圆形鼠标绘制代码运行结果 课程完结&#xff1a; 前言 为了更好地去学习WPFHalcon&#xff0c;我决定去报个班学一下。原因无非是想换个工作。相关的教学视…

2023全新返佣商城分销商城理财商城系统源码 全开源PHP+VUE源码

2023全新返佣商城分销商城理财商城系统源码 全开源PHPVUE源码 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/88657863

【C语言】Windows上用GTK写GUI程序

要使用GTK开发一个Windows图形用户界面程序&#xff0c;需要首先设置GTK开发环境。这通常包括安装GTK库和它的依赖&#xff0c;以及配置编译器和工具链。可以选择使用纯C语言和GTK库或者使用支持GTK绑定的其他语言&#xff0c;如Python、C或Rust。 1. 安装GTK开发库 在Window…

Access数据库C#读写验证

1、数据库简介 Access数据库是一个相当古老的文件型数据库&#xff0c;主打一个简单方便&#xff0c;没有复杂的安装过程&#xff0c;没有庞大的后端管理&#xff0c;整个数据库就是一个文件。可以像普通文件一样复制和修改&#xff0c;可以同时读写。 在小型系统中&#xff0c…

Rasa初始化聊天机器人的配置

本文详细介绍了使用 rasa init 初始化聊天机器人项目的配置&#xff0c;包括 nlu.yml、rules.yml、stories.yml、test_stories.yml、config.yml、credentials.yml、domain.yml、endpoints.yml 等文件。如下所示&#xff1a; │ config.yml │ credentials.yml │ domain.ym…

simulink代码生成(六)——多级中断的配置

假如系统中存在多个中断&#xff0c;需要合理的配置中断的优先级与中断向量表&#xff1b;在代码生成中&#xff0c;要与中断向量表对应&#xff1b;中断相关的知识参照博客&#xff1a; DSP28335学习——中断向量表的初始化_中断向量表什么时候初始化-CSDN博客 F28335中断系…

算法——字符串

这里结合的是之前一些算法&#xff0c;比如模拟、KMP等&#xff0c;题型比较丰富 最长公共前缀 最长公共前缀 题目解析 查找字符串数组中的最长公共前缀。如果不存在公共前缀&#xff0c;返回空字符串 “” 算法原理 解法一&#xff1a;两两比较&#xff1a;定义一个指…

基于图论的图像分割 python + PyQt5

数据结构大作业&#xff0c;基于图论中的最小生成树的图像分割。一个很古老的算法&#xff0c;精度远远不如深度学习算法&#xff0c;但是对于代码能力是一个很好的锻炼。 课设要求&#xff1a; &#xff08; 1 &#xff09;输入&#xff1a;图像&#xff08;例如教室场景图&a…

poi操作Excel给列设置下拉菜单(数据验证)

效果图&#xff1a; pom.xml文件增加依赖&#xff1a; <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.0.1</version></dependency> 12345Workbook实现类有三个&#xff1a;HSSFWork…

Python算法例33 删除数字

1. 问题描述 给出一个字符串A&#xff0c;表示一个n位的正整数&#xff0c;删除其中k位数字&#xff0c;使得剩余的数字仍然按照原来的顺序排列产生一个新的正整数&#xff0c;本例将找到删除k个数字之后的最小正整数&#xff0c;其中n≤240&#xff0c;k≤n。 2. 问题示例 …

计算机专业个人简历范文(8篇)

HR浏览一份简历也就25秒左右&#xff0c;如果你连「好简历」都没有&#xff0c;怎么能找到好工作呢&#xff1f; 如果你不懂得如何在简历上展示自己&#xff0c;或者觉得怎么改简历都不出彩&#xff0c;那请你一定仔细读完。 互联网运营个人简历范文> 男 22 本科 AI简历…

测试开发工具推荐(含自动化、性能、稳定性、抓包)

今天将给大家推荐14款日常工作中经常用到的测试开发工具神器&#xff0c;涵盖了自动化测试、APP性能测试、稳定性测试、抓包工具等。 一、UI自动化测试工具 1. uiautomator2 Github地址 https://github.com/openatx/uiautomator2 介绍&#xff1a; openatx开源的ui自动化…

k8s陈述式资源管理(命令行)

1、资源管理 &#xff08;1&#xff09;陈述式资源管理&#xff08;常用——查、增&#xff09; 使用kubectl工具进行命令行管理 ①特点&#xff1a;对资源的增删查比较方便&#xff0c;对改不友好 ②优点&#xff1a;90%以上的场景都可以满足 ③缺点&#xff1a;命令冗长…