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

UART双向通信实现(序列机)

前言        

        UART(通用异步收发传输器)是一种串行通信协议,用于在电子设备之间进行数据传输。RS232是UART协议的一种常见实现标准,广泛应用于计算机和外围设备之间的通信。它定义了串行数据的传输格式和电气特性,以确保不同设备之间的兼容性和可靠性。RS232协议采用异步串行通信方式,通过数据线将并行数据转换为串行数据进行传输,接收端再将串行数据恢复为并行数据。RS232的标准包括信号电平、连接器类型和数据格式等规范,确保了设备之间的正确通信。它的常见应用包括计算机串口、调制解调器、打印机等设备的连接。

        UART通信实现与验证(RS232)

正文

一、UART双向通信实现(序列机)的设计验证

        1.项目需求

        完成9600波特率串口的数据收发实验

        2.技术介绍

        采用序列机架构,使用锁相环产生一个16倍9600波特率的时钟,当该时钟计数到16时,表示串口数据发送的1bit数据传输完成(即1bit数据在计数0时放置与txd数据线上,在16时完成该数据传输,下次计数0时传输下1bit数据)。为保证数据接收正常,数据接收需要在9600波特率的时钟的周期中心接收,对应16倍时钟,在计数器到7或8的时刻进行数据接收。

        为完成数据收发实验,将接收的数据在发送出去,完成数据回环,可以通过上位机去观察接收的数据是否完整以此验证实验成功。

        涉及到数据传递,虽然时钟相同但是正常情况需要进行数据缓存(建议,如果是异步时钟,必须进行数据缓存),常用的数据缓存有异步fifo,双口ram(本实验实验异步fifo)

        3.顶层架构

        

        4.端口描述

clk时钟接口(50Mhz)
rst_n复位按键(低电平有效)
rxd数据接收接口
txd数据发送接口

二、代码验证

顶层连线

module uart_tx_rx(
	input			clk	,
	input			rst_n	,
	input 		rxd	,
	
	output 		txd	
);

	wire clk_01536;
	wire rst_en;
	
	clk_uart	clk_uart_inst (
		.areset 	( ~rst_n ),
		.inclk0 	( clk ),
		.c0 		( clk_01536 ),
		.locked 	( rst_en )
	);
	
	wire[7:0]data,q_sig;
	wire rdempty,rdreq,down;

	uart_rx rx(
		.clk	(clk_01536	),
		.rst_n	(rst_en		),
		.rxd	(rxd			),//数据接收
		    
		.data	(data			),//接收数据打包
		.down	(down			) //输出有效
	);
	
	fifo	fifo_inst (
		.data 	(data	),
		.rdclk 	(clk_01536  ),
		.rdreq 	(rdreq  ),
		.wrclk 	(clk_01536  ),
		.wrreq 	(down  ),
		.q 		(q_sig  ),
		.rdempty (rdempty 	),
		.wrfull 	(  )
	);

	uart_txd_v1 tx(
		.clk		(clk_01536	),
		.rst_n	(rst_en		),
		.data		(q_sig		),
	   .done		(rdempty		),
		
		.txd		(txd			),
		.rd_en	(rdreq		)
	);
endmodule

收数据模块

module uart_rx(
	input				clk	,
	input				rst_n	,
	input				rxd	,//数据接收
		
	output reg[7:0]data	,//接收数据打包
	output reg 		down	 //输出有效
);
	reg state;
	reg [7:0]temp;
	reg [7:0]cnt;
	
	always@(posedge clk,negedge rst_n)//cnt在工作状态计数
	begin
		if(!rst_n)
			cnt <= 0;
		else if(state == 1)
			cnt <= cnt + 1;
		else
			cnt <= 0;
	end
	
	always@(posedge clk,negedge rst_n)
	begin
		if(!rst_n)
			state <= 0;
		else
			case(state)
				0:	if(rxd == 0)//等待起始信号
						state <= 1;
					else
						state <= 0;
				1: if(cnt == 153)//完成一包数据接收
						state <= 0;
					else
						state <= 1;
			default:state <= 0;
			endcase
	end
	
	always@(posedge clk,negedge rst_n)
	begin
		if(!rst_n)
			begin
				temp <= 0;
				down <= 0;
				data <= 0;
			end
		else
			case(cnt)
				0:
				begin
					temp <= 0;
					down <= 0;
					data <= data;
				end
				1*16+7:temp[0] <= rxd;//在每个时序的中间收数据,数据在N*16时放在rxd上,保证数据稳定,在N*16 + 7时读
				2*16+7:temp[1] <= rxd;
				3*16+7:temp[2] <= rxd;
				4*16+7:temp[3] <= rxd;
				5*16+7:temp[4] <= rxd;
				6*16+7:temp[5] <= rxd;
				7*16+7:temp[6] <= rxd;
				8*16+7:temp[7] <= rxd;
				9*16+7:
				begin
					down <= 1;
					data <= temp;
				end
				9*16+7+1:down <= 0;
			endcase
	end
	
endmodule

发数据模块

module uart_txd(//fifo不为空时发
	input			clk	,//0.1536 = 9600 * 16 = 153600hz = 0.1536Mhz 
	input			rst_n	,
	input	[7:0]	data	,
	input			done	,
	
	output reg	txd	,
	output reg 	rd_en	
);
	
	reg [7:0]temp;
	reg [7:0]cnt;
	reg state;
	
	always@(posedge clk,negedge rst_n)//计数器在工作时进行计数
	begin
		if(!rst_n)
			cnt <= 0;
			else if(state == 1)//fifo不空,开始发送
			if(cnt < 10*16)
				cnt <= cnt + 1;
			else
				cnt <= 0;
			else
		cnt <= 0;
	end
	
	always@(posedge clk,negedge rst_n)
	begin
		if(!rst_n)
			state <= 0;
		else case(state)
				0:	if(done == 0)
						state <= 1;
					else
						state <= 0;
				1: if(cnt == 10*16)
						state <= 0;
					else
						state <= 1;
				default:state <= 0;
			endcase
	end
	
	always@(posedge clk,negedge rst_n)
	begin
		if(!rst_n)
			rd_en <= 0;
		else
			case(cnt)
				0:rd_en <= 0;
				1:rd_en <= 1;
				2:rd_en <= 0;
			endcase
	end
	
	always@(posedge clk,negedge rst_n)
	begin
		if(!rst_n)
			txd <= 1;
		else
			case(cnt)
				0:txd <= 1;
				1:txd <= 0;//起始位
				3:temp <= data;
				1*16:txd <= temp[0];//数据在时序开始时放在txd,
				2*16:txd <= temp[1];
				3*16:txd <= temp[2];
				4*16:txd <= temp[3];
				5*16:txd <= temp[4];
				6*16:txd <= temp[5];
				7*16:txd <= temp[6];
				8*16:txd <= temp[7];
				9*16:txd <= 1;
			endcase
	end

endmodule

http://www.dtcms.com/a/109373.html

相关文章:

  • (三十)导入系统内置库 math库
  • 基于大模型预测升主动脉瘤的多维度诊疗研究报告
  • 抖音短视频安卓版流畅度测评 - 真实
  • 关于pycharm远程连接服务器如何debug
  • ngx_log_init
  • RTOS基础 -- NXP M4小核的RPMsg-lite与端点机制回顾
  • Qt基础:主界面窗口类QMainWindow
  • 前端切片上传、上传进度、断点续传、秒传
  • maven项目添加第三方JAR包
  • 《Java编程思想》读书笔记:第九章 接口
  • TI-BQ34Z100 STM32CubeIDE STM32L151 调试过程,含详细步骤文档、代码工程、测试记录、BQ34Z100手册等相关资料
  • 数据框的添加
  • P2758 编辑距离
  • 08_paho.mqtt.cpp库使用示例
  • Python学习笔记(8)关于列表内置函数和多维列表
  • Java 常用数据结构详解
  • Java8 到 Java21 系列之 Stream API:数据处理的新方式(Java 8)
  • Node.js 安装与配置全攻略:从入门到高效开发
  • 做题记录:和为K的子数组
  • 二极管正负极区分
  • Mermaid 语法教程
  • kali中vmtools失效用不了解决方法
  • Leetcode 857 -- 贪心 | 数学
  • 【C语言】整数和浮点数在内存中的存储
  • 使用pkexec 和其策略文件安全提权执行外部程序
  • linux文件上传下载lrzsz
  • LangChain核心解析:掌握AI开发的“链“式思维
  • 【KMP】P4391 [BalticOI 2009] Radio Transmission 无线传输|普及+
  • 蜜蜡是什么?蜜蜡与琥珀的区别以及蜜蜡的收藏价值一览
  • 《AI大模型应知应会100篇》第57篇:LlamaIndex使用指南:构建高效知识库