中科亿海微UART协议

引言


        在现代数字系统设计中,通信是一个至关重要的方面。而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) beginuart_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;endelse begintx_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;elseclk_cnt <= 16'd0;               //对系统时钟计数达一个波特率周期后清零endelse                             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;		//此时发送数据计数器加1elsetx_cnt <= tx_cnt;       endelse                              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: ;endcaseelse uart_txd <= 1'b1;                   //空闲时发送端口为高电平
endendmodule	          
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;          endelse beginuart_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 beginif(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拉低elserx_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;elseclk_cnt <= 16'd0;             //对系统时钟计数达一个波特率周期后清零endelse                              				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;			//此时接收数据计数器加1elserx_cnt <= rx_cnt;       endelserx_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:;                                    endcaseendelse rxdata <= rxdata;elserxdata <= 8'd0;
end//数据接收完毕后给出标志信号并寄存输出接收到的数据
always @(posedge sys_clk or negedge sys_rst_n) begin        if (!sys_rst_n) beginuart_data <= 8'd0;                               uart_done <= 1'b0;endelse if(rx_cnt == 4'd9) begin               //接收数据计数器计数到停止位时           uart_data <= rxdata;                    //寄存输出接收到的数据uart_done <= 1'b1;                      //并将接收完成标志位拉高endelse beginuart_data <= 8'd0;                                   uart_done <= 1'b0; end    
endendmodule	


结论


        设计了发送模块,将数据转换为符合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.rhkb.cn/news/228706.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

王道考研计算机网络——应用层

如何为用户提供服务&#xff1f; CS/P2P 提高域名解析的速度&#xff1a;local name server高速缓存&#xff1a;直接地址映射/低级的域名服务器的地址 本机也有告诉缓存&#xff1a;本机开机的时候从本地域名服务器当中下载域名和地址的对应数据库&#xff0c;放到本地的高…

Python编程新技能:如何优雅地实现水仙花数?

水仙花数&#xff08;Narcissistic number&#xff09;也被称为阿姆斯特朗数&#xff08;Armstrong number&#xff09;或自恋数等&#xff0c;它是一个非负整数&#xff0c;其特性是该数的每个位上的数字的n次幂之和等于它本身&#xff0c;其中n是该数的位数。简单来说&#x…

【HarmonyOS开发】案例-记账本开发

OpenHarmony最近一段时间&#xff0c;简直火的一塌糊度&#xff0c;学习OpenHarmony相关的技术栈也有一段时间了&#xff0c;做个记账本小应用&#xff0c;将所学知识点融合记录一下。 1、记账本涉及知识点 基础组件&#xff08;Button、Select、Text、Span、Divider、Image&am…

SpringCloud(H版alibaba)框架开发教程,使用eureka,zookeeper,consul,nacos做注册中心——附源码(1)

源码地址&#xff1a;https://gitee.com/jackXUYY/springboot-example 创建订单服务&#xff0c;支付服务&#xff0c;公共api服务&#xff08;共用的实体&#xff09;&#xff0c;eureka服务 1.cloud-consumer-order80 2.cloud-provider-payment8001 3.cloud-api-commons 4.…

数据结构:队列(链表和数组模拟实现)

目录 1.何为队列 2.链表模拟实现 2.1 节点和队列创建 2.2 初始化队列 2.3 入队操作 2.4 出队操作 2.5 遍历队列 2.6 获取队首和队尾元素 2.7 判断队列是否为空 2.8 完整实现 3. 数组模拟实现 3.1 创建队列 3.2 入队和出队操作 3.3 遍历队列 3.4 获取队首和队尾元…

构建安全的SSH服务体系

1、配置OpenSSH服务端 在CentOS7.3系统中&#xff0c;OpenSSH服务由openssh、openssh-server等软件包提供&#xff08;默认已安装&#xff09;&#xff0c;并已将sshd添加为标准的系统服务。执行"systemctl start sshd"命令即可启动sshd服务。ssh服务的配置文件默认位…

初识SpringBoot(2023最后一篇文章)

初识SpringBoot 1、SpringBoot概述 Spring是什么&#xff1f; Spring是一个于2003 年兴起的一个轻量级开源Java开发框架&#xff0c;由Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》。Spring是为了解决企业级应用开发的复杂性而创建的&#xff0c;使…

探索工业智能检测,基于轻量级YOLOv8开发构建焊接缺陷检测识别系统

焊接缺陷相关的开发实践在前面的博文中已经有所涉及了&#xff0c;感兴趣的话可以自行移步阅读即可&#xff1a;《探索工业智能检测&#xff0c;基于轻量级YOLOv5s开发构建焊接缺陷检测识别系统》 将智能模型应用和工业等领域结合起来是有不错市场前景的&#xff0c;比如&…

001、安装 Rust

目录 1. 安装 Rust 2. 安装编译器 Visual Studio Code 3. 更新、卸载、文档命令 4. 结语 1. 安装 Rust 安装 Rust 非常简单&#xff0c;首先进入 Rust官网 &#xff0c;然后点击右上角的 Install 。 进入 Install 界面&#xff0c; 它会自动识别你当前的操作系统并给你推荐…

SASS循环

<template><div><button class"btn type-1">默认按钮</button><button class"type-2">主要按钮</button><button class"type-3">成功按钮</button><button class"type-4">信息…

Linux:apache优化(6)—— apache的ab压力测试

要对所购买的物理机(二手)进行烧机在产品上线之前&#xff0c;对应用的一个压力测试对产品本身的压力测试 作用&#xff1a;Apache 附带了压力测试工具 ab&#xff0c;非常容易使用&#xff0c;并且完全可以模拟各种条件对 Web 服务器发起测试请求。在进行性能调整优化过程中&a…

docker学习笔记01-安装docker

1.Docker的概述 用Go语言实现的开源应用项目&#xff08;container&#xff09;&#xff1b;克服操作系统的笨重&#xff1b;快速部署&#xff1b;只隔离应用程序的运行时环境但容器之间可以共享同一个操作系统&#xff1b;Docker通过隔离机制&#xff0c;每个容器间是互相隔离…

Linux:apache优化(7)—— 访问控制

作用&#xff1a;为apache服务提供的页面设置客户端访问权限&#xff0c;为某个组或者某个用户加密访问&#xff1b; /usr/local/httpd/bin/htpasswd -c /usr/local/httpd/conf/htpasswd tarro1 #添加admin用户&#xff0c;可以在两个路径中间添加-c是新建文件删除原文件&#…

MS2358:96KHz、24bit 音频 ADC

产品简述 MS2358 是带有采样速率 8kHz-96kHz 的立体声音频模数 转换器&#xff0c;适合于面向消费者的专业音频系统。 MS2358 通过使用增强型双位 Δ - ∑ 技术来实现其高精度 的特点。 MS2358 支持单端的模拟输入&#xff0c;所以不需要外部器 件&#xff0c;非常适…

RabbitMQ 和 Kafka 对比

本文对RabbitMQ 和 Kafka 进行下比较 文章目录 前言RabbitMQ架构队列消费队列生产 Kafka本文小结 前言 开源社区有好多优秀的队列中间件&#xff0c;比如RabbitMQ和Kafka&#xff0c;每个队列都貌似有其特性&#xff0c;在进行工程选择时&#xff0c;往往眼花缭乱&#xff0c;不…

2023第三届中国高校大数据挑战赛B题代码

任务已完成&#xff0c;聚类效果很好&#xff08;主要在于数据的处理以及特征工程&#xff09;, 需代码si&#xff0c;yuer有限先到先得。

LeetCode每日一题.05(N皇后)

按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的解决方案。 每一种…

Ubuntu 18.04搭建RISCV和QEMU环境

前言 因为公司项目代码需要在RISCV环境下测试&#xff0c;因为没有硬件实体&#xff0c;所以在Ubuntu 18.04上搭建了riscv-gnu-toolchain QEMU模拟器环境。 安装riscv-gnu-toolchain riscv-gnu-toolchain可以从GitHub上下载源码编译&#xff0c;地址为&#xff1a;https://…

pycharm找回误删的文件和目录

昨天不知道做了什么鬼操作&#xff0c;可能是运行了几个git命令&#xff0c;将项目里面的几个文件删除了&#xff0c;有点懵。 我知道pycharm可以找回文件的历史修改记录&#xff0c;但是对于删除的文件能否恢复&#xff0c;一直没试过。 找到删除文件的目录&#xff0c;点击右…

3D换肤在服装行业的应用

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 通过采用高质量的 3D 模型&#xff0c;企业可以提供更加身临其境的体…