通信协议详解(一):UART串口(协议+数据格式+设计实现)

本文详细介绍了UART串口通信协议,包括数据包格式、波特率和整体架构。通过Verilog实现了UART的发送和接收模块,重点展示了如何进行串并转换以完成数据的发送和接收。在发送模块中,利用计数器实现波特率控制,而在接收模块中,通过检测下降沿开始传输并锁定数据。最后,通过仿真验证了模块的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

uart串口通信协议及verilog实现

一、uart串口通信简介

通用异步收发器 UART(Universal Asynchronous Receiver/Transmitter),是一种串行、异步、全双工的通信协议,将所需传输的数据一位接一位地传输,在UART通讯协议中信号线上的状态位高电平代表’1’,低电平代表’0’。其特点是通信线路简单,只要一对传输线就可以实现双向通信,大大降低了成本,但传送速度较慢。

二、串口传输

1、数据协议

在这里插入图片描述
在串口通信中,尤其需要关注的是数据流以及波特率。一个数据流由10个数据位组成,包含1位起始位,7位有效数据位,1位奇偶校验位,1位停止位。uart串口信号线上空闲时常驻高电平,当检测到低电平下降沿时认为数据传输开始,到停止位时数据传输结束,一共10位数据位组成一个数据包。
起始位:通信线路上空闲时为“1”,当检测到“0”即下降沿时,认为数据传输开始
有效数据位:传输开始后传递的需要接收和发送的数据值,可以表示指令或数据
奇偶校验位:奇偶校验,通过来校验传输数据中“1”的个数为奇数个(奇校验)或偶数个(偶校验)来指示传输数据是否正确
停止位:数据传输结束,传输线恢复常“1”状态
此外,还需关注数据传输波特率,波特率表示一秒内传输了多少个码元数量,一般波特率为300,1200,2400,9600,19200,38400,115200等。例如9600 Baud表示一秒内传输了9600个码元信息,当一个码元只含1 bit信息时,波特率=比特率

2、整体架构

串口协议用于与其他模块之间的信息交互,包含接收模块发送模块,信号传输线上根据波特率完成码元的接收与发送,因而接收模块主要完成并串转换,串并转换是接收和发送模块必备的基本功能,发送模块完成并串转换,接收模块完成串并转换。
在这里插入图片描述

波特率与时钟频率关系如下(码元为单bit时):

三、串口传输实现

1、发送模块

代码如下

//===============
//author:LGYSSS
//proj:uart_transimitter
//===============
module uart_tx(
    clk    ,
    rst_n  ,
    data_vld , //有效信号
    data_in,   //输入信号
    data_out,  //并行转串行输出信号
    rdy        //模块有效信号,示意模块准备接收数据
    );


parameter WIDTH	=8;
parameter CLK_CNT= 5208;     //波特率baud=9600下单码元传输 码元宽度为104166  50MHz下一个时钟周期为20ns,传输一个数据位104166/20=5208个clk
parameter  NUM_CNT=10;     //数据位个数


input clk;
input rst_n;
input [WIDTH-1:0]data_in;
input data_vld;
output data_out;
output rdy;
 
reg data_out; 
reg [WIDTH-1:0]data_in_reg;
reg start_tx;
wire [WIDTH-1+2:0] data;

reg   [12:0]     cnt0;
wire             add_cnt0;
wire             end_cnt0;
reg   [3:0]      cnt1;
wire             add_cnt1;
wire             end_cnt1;
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		start_tx<=0;
	else if(start_tx==0&&data_vld==1)
		start_tx<=1;
	else if(end_cnt1)
		start_tx<=0;
end



always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            cnt0 <= 0;
        end
        else if(add_cnt0)begin
            if(end_cnt0)
                cnt0 <= 0;
            else
                cnt0 <= cnt0 + 1;
        end
end

assign add_cnt0 = start_tx;
assign end_cnt0 = add_cnt0 && cnt0== CLK_CNT-1;

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        cnt1 <= 0;
    end
    else if(add_cnt1)begin
        if(end_cnt1)
            cnt1 <= 0;
        else
            cnt1 <= cnt1 + 1;
    end
end

assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1== NUM_CNT-1;

always  @(posedge clk or negedge rst_n)begin  //在数据有vld效时进行数据锁存,进行下一步串并转换
	if(!rst_n)begin
		data_in_reg<=0;
	end
	else if(start_tx==0&&data_vld==1)begin
		data_in_reg<=data_in;
	end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        data_out <= 1'b1;
    end
    else if(add_cnt0 && cnt0==1-1)begin
        data_out <= data[cnt1];
    end
end

assign data={1'b1,data_in_reg,1'b0}; //起始位,停止位拼接

assign rdy=((data_vld==1)||(start_tx==1))?1'b0:1'b1;

endmodule

2、接收模块

代码如下:

//===============
//author:LGYSSS
//proj:uart_receiver
//===============
module uart_rx(
    clk    ,
    rst_n  ,
    data_vld ,
    rx_data_in,
    rx_data_out
    );

parameter WIDTH	=8;
parameter CLK_CNT= 5208;     //波特率baud=9600下单码元传输 码元宽度为104166  50MHz下一个时钟周期为20ns,传输一个数据位104166/20=5208个clk
parameter CLK_CNT_MID=2604;
parameter  NUM_CNT=10;

input clk;
input rst_n;
input rx_data_in;

output reg [WIDTH-1:0] rx_data_out;
output reg data_vld;
wire               start_rx;

reg [19:0]         cnt0;
wire               add_cnt0;
wire               end_cnt0;

reg [3:0]          cnt1;
wire               add_cnt1;
wire               end_cnt1;
reg               flag;
reg rx_data_in_reg0;
reg rx_data_in_reg1;
reg rx_data_in_reg2;


always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		rx_data_in_reg0<=0;
		rx_data_in_reg1<=0;
		rx_data_in_reg2<=0;
	end
	else begin
		rx_data_in_reg0<=rx_data_in;
		rx_data_in_reg1<=rx_data_in_reg0;
		rx_data_in_reg2<=rx_data_in_reg1;
	end
end

assign start_rx=(rx_data_in_reg2&&~rx_data_in_reg1)==1; //下降沿检测


always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            flag <= 1'b0;
        end
        else if(start_rx)begin
            flag <= 1'b1;
        end
        else if(end_cnt1)begin
            flag <= 1'b0;
        end
end
 
always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt0 <= 0;
        end
        else if(add_cnt0)begin
            if(end_cnt0)
                cnt0 <= 0;
            else
                cnt0 <= cnt0 + 1;
        end
end

assign add_cnt0 = flag;
assign end_cnt0 = add_cnt0 && cnt0== CLK_CNT-1;

always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            cnt1 <= 0;
        end
        else if(add_cnt1)begin
            if(end_cnt1)
                cnt1 <= 0;
            else
                cnt1 <= cnt1 + 1;
        end
end

assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1== NUM_CNT-1-1;
 
always @(posedge clk or negedge rst_n)begin 
	if(!rst_n)begin
		rx_data_out<=0;
	end
	else if(cnt0==CLK_CNT_MID-1&&cnt1!=0&&flag==1)begin
		rx_data_out[cnt1-1]<=rx_data_in_reg2;
	end
end
 
always  @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            data_vld <= 1'b0;
        end
        else if(end_cnt1)begin
            data_vld <= 1'b1;
        end
        else begin
            data_vld <= 1'b0;
        end    
end
 
endmodule
 
 

四、串口收发仿真

串口发送模块仿真波形:
在这里插入图片描述

串口接收模块仿真波形:
在这里插入图片描述


总结

看到这里模块功能其实很清晰了,两个模块完成的功能其实就是收发数据的串并转换,传输的内容具体是什么我们是不用关心的,只需要关心数据收发格式,检测到下降沿时开始传输,传输一定数据位时结束当前传输,就完成了一个数据帧的传输,即完成了uart串口通信的一次收/发。.
同时,在本模块设计中笔者是采用锁存器来锁存当vld有效时的信号,当数据流传输速度较大时,我们也可以采取fifo来缓存我们接收的数据,以免造成数据丢失


### 安装和配置 Milvus 和 Attu 的指南 #### 1. 准备工作 在 Deepin 系统中安装和配置 Milvus 及其管理工具 Attu,需要先确保系统的环境满足最低需求。Deepin 是基于 Debian 的发行版,因此可以使用 `apt` 包管理器来处理依赖项。 - **硬件要求**: 至少 8GB RAM 和 50GB 存储空间[^2]。 - **操作系统版本**: 推荐使用最新稳定版的 Deepin 或测试版 (如 deepin 23 beta)[^1]。 --- #### 2. 安装 Docker 和 Docker Compose Milvus 建议通过 Docker 来部署,因为这能简化安装过程并提供更好的兼容性。 ```bash # 更新系统包列表 sudo apt update && sudo apt upgrade -y # 安装必要的依赖 sudo apt install curl gnupg lsb-release -y # 添加官方 GPG 密钥 curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # 设置稳定的 Docker APT 源 echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 安装 Docker CE sudo apt update sudo apt install docker-ce docker-ce-cli containerd.io -y # 将当前用户加入到docker组以便无需sudo运行Docker命令 sudo usermod -aG docker $USER # 测试Docker是否正常启动 docker run hello-world # 安装 Docker Compose sudo curl -L "https://github.com/docker/compose/releases/download/v2.17.2/docker-compose-linux-x86_64" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose ``` 以上脚本会完成 Docker 和 Docker Compose 的安装,并验证它们的功能[^1]。 --- #### 3. 下载并启动 Milvus Zilliz 提供了个简单的 Docker Compose 文件用于快速部署 Milvus 社区版。 ```bash # 创建目录存储 Milvus 数据 mkdir ~/milvus_docker cd ~/milvus_docker # 获取最新的 Docker Compose 文件 wget https://raw.githubusercontent.com/milvus-io/milvus/main/docker-compose.yml # 使用 Docker Compose 启动 Milvus docker-compose up -d ``` 此时,Milvus 应该已经成功启动,默认监听地址为 `localhost:19530`[^4]。 --- #### 4. 安装 Attu CLI 工具 Attu 是 Zilliz 开发的款轻量级命令行客户端,支持与 Milvus 进行交互。 ```bash # 安装 Node.js 和 npm(如果尚未安装) sudo apt install nodejs npm -y # 全局安装 attu cli npm install -g @zilliz/attu # 初始化 Attu 并连接本地 Milvus 实例 attu init --host localhost --port 19530 ``` 初始化完成后,可以通过以下命令查看集群状态: ```bash attu status ``` --- #### 5. 验证安装 为了确认 Milvus 是否正常运行,可以尝试创建个集合并向其中插入数据。 ```bash # 列出所有集合 attu list collections # 如果为空,则创建个新的集合 attu create collection my_collection --dimension=128 --metric-type=L2 # 插入随机向量数据 attu insert random --collection=my_collection --count=1000 --dim=128 # 查询最近邻 attu search vector --collection=my_collection --vector "[1.0, 2.0, ..., 128.0]" --topk=10 ``` 上述命令展示了如何利用 Attu 对 Milvus 执行基本操作[^3]。 --- #### 6. XRDP 远程访问 (可选) 如果希望从其他设备远程管理和监控 Milvus,可以参考 XRDP 的安装方法,在 Deepin 上启用远程桌面功能[^3]。 ```bash sudo apt install xrdp -y sudo systemctl enable xrdp sudo systemctl start xrdp ``` 随后可以从 Windows 或 macOS 设备上使用 RDP 客户端连接至 Deepin 主机。 --- ### 注意事项 - 如果遇到权限问题,请确保以管理员身份 (`sudo`) 执行敏感命令。 - 在生产环境中建议使用独立的 GPU 资源加速 Milvus 性能[^4]。 ---
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

俩个圆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值