FPGA自定义UART传输(包含:matlab数据拆分)
引言:本程序是在工程实践中写的模块,经验证,可靠。由于大多书本上讲的都是仅仅传输1个数据,然后根据这个数据亮灯。这种在工程中几乎用不上工程实际中,往往我们需要根据地址不同,传给不同的寄存器,从而控制比如脉冲宽度,长度,延时,个数等功能。
由于我们需要在testbench中算出每一帧的检验和,所以我们用了matlab来进行数据拆分,从而计算校验和。如果手工算也可以,但帧数过多后,相当麻烦,而且易错。
此处,先把matlab代码上传
#matlab数据拆分代码(获得检验值)
clc;
clear;
add='18' ;%地址,16进制
data0=16;%输入十进制的16bit数据add_dec=uint8(hex2dec(add));data1=uint16(data0);%输入16bit
data1_bit=dec2bin(data1); %输入数据二进制格式
data2unit8=uint8(zeros([1 2]));%存储2个8位数据的数组
data2unit8(1)=bitand(data1,255);%低8位
data2unit8(2)=bitand(bitshift(data1,-8),255);%高8位
data_low8bit=dec2hex(data2unit8(1));%低8位的数据16进制
data_high8bit=dec2hex(data2unit8(2));%高8位的数据16进制数据
output1=bitxor(add_dec,data2unit8(1));
check_sum=bitxor(output1,data2unit8(2));%得到校验和
check_sum_hex=dec2hex(check_sum);%得到校验和的16进制形式
#UART代码
接收顶层模块
`timescale 1ns / 1psmodule uart_rx_core #(parameter BAUD_RATE = 115_200, // Baud rateparameter CLOCK_RATE = 50_000_000 // Clock rate)(input clk,input rx_en, // 接收使能input rx_pin, // 数据输入管脚output [ 7:0] addr, // 接收的32bit数据output [15:0] data, // 接收的32bit数据output valid // 一次数据协议解码成功);wire [ 7:0] rx_data; // 接收的8 bit数据wire rx_done; // 数据接收完毕,产生一个高脉冲uart_rx_module #(.BAUD_RATE ( BAUD_RATE ), // Baud rate.CLOCK_RATE ( CLOCK_RATE ) // Clock rate) Uuart_rx (.clk( clk ),.rx_en( rx_en ), // 接收使能.rx_pin( rx_pin ), // 数据输入管脚.rx_data( rx_data ), // 每次接收的8 bit数据.rx_done( rx_done ) // 数据接收完毕,产生一个高脉冲);uart_decode_module Uuart_decode (.clk( clk ),.rx_data( rx_data ), // 接收的8 bit数据.rx_done( rx_done ), // 数据接收完毕,产生一个高脉冲.addr( addr ), // 地址码.data( data ), // 数据组.valid( valid ) // 一次数据协议解码成功);endmodule
`timescale 1ns / 1psmodule uart_rx_module #(parameter BAUD_RATE = 115_200, // Baud rateparameter CLOCK_RATE = 50_000_000 // Clock rate)(input clk,input rx_en, // 接收使能input rx_pin, // 数据输入管脚output [ 7:0] rx_data, // 接收的8 bit数据output rx_done // 数据接收完毕,产生一个高脉冲);/* 产生波特率采样时钟 --------------------------------------------------- */wire baud_clk; // 波特率采样时钟wire en_baud_gene; // 使能波特率采样时钟baud_gene_module #(.BAUD_RATE ( BAUD_RATE ), // Baud rate.CLOCK_RATE ( CLOCK_RATE ) // Clock rate) Urx_baud_gene (.clk( clk ),.en( en_baud_gene ), // 计数使能,高电平时波特率发生器才工作.baud_clk( baud_clk ) // 波特率采样时钟输出);/* ---------------------------------------------------------------------- *//* rx_pin下降沿检测 ----------------------------------------------------- */reg [1:0] rx_pin_r = 1'b0;always @ (posedge clk)rx_pin_r <= {rx_pin_r[0:0], rx_pin};wire rx_pin_fall = (!rx_pin_r[0]) & rx_pin_r[1];// 下降沿检测wire rx_start = rx_pin_fall;/* ---------------------------------------------------------------------- *//* 串口接收控制 --------------------------------------------------------- */reg en_baud_r = 1'b0;//Li:接收数据使能区域reg [ 7:0] rx_data_r = 8'b0;reg rx_done_r = 1'b0;reg [ 3:0] rx_ii = 4'b0;/* 接收数据格式:1位起始位,8位数据位,1位停止位,其中起始位为0;无校验位;停止位为1 */always @ (posedge clk)if (rx_en) // 当rx_en被拉高时开始工作case (rx_ii) // 每个baud_clk接收一位数据4'd0 : // 开始信号,有数据发送过来,准备接收------//Li:启动if (rx_start) begin en_baud_r <= 1'b1; rx_done_r <= 1'b0; rx_ii <= rx_ii + 1'b1; //Li:刚开始的下降沿启动end4'd1 : // 接收起始位if (baud_clk) begin en_baud_r <= 1'b1; rx_done_r <= 1'b0; rx_ii <= rx_ii + 1'b1; end4'd2, 4'd3, 4'd4, 4'd5, 4'd6, 4'd7, 4'd8, 4'd9 :// 将rx_pin的值保存到rx_data_r中,从最低位到最高位; LSB first defaultif (baud_clk) begin en_baud_r <= 1'b1; rx_data_r[rx_ii-2] <= rx_pin; rx_done_r <= 1'b0; rx_ii <= rx_ii + 1'b1; end4'd10 : // 接收停止位,无校验位,如果没有什么特别需求,可直接忽略if (baud_clk) begin en_baud_r <= 1'b0; rx_done_r <= 1'b1; rx_ii <= rx_ii + 1'b1; end4'd11 : // 产生一个时钟周期的高脉冲rx_done_r,表示数据接收完毕begin en_baud_r <= 1'b0; rx_done_r <= 1'b0; rx_ii <= 4'd0; enddefault: ;endcaseelse beginen_baud_r <= 1'b0; rx_data_r <= 8'd0; rx_done_r <= 1'b0; rx_ii <= 4'd0; endassign en_baud_gene = en_baud_r;/* ---------------------------------------------------------------------- */assign rx_data = rx_data_r;assign rx_done = rx_done_r;endmodule
`timescale 1ns / 1ps
/*-------------------------------------------------------------------------------------* 串口波特率产生*----------------------------------------------------------------------------------*/
module baud_gene_module #(parameter BAUD_RATE = 115_200, // Baud rateparameter CLOCK_RATE = 50_000_000 // Clock rate)(input clk,input en, // 计数使能,高电平时波特率发生器才工作output baud_clk // 波特率采样时钟输出);/* 以下函数供Verilog使用,Verilog_2005和SystemVerilog有"$clog2"函数 */function integer clog2(input integer value);beginvalue = value-1;for (clog2=0; value>0; clog2=clog2+1)value = value>>1;endendfunction// 分频计数DIVIDER = 时钟CLOCK_RATE / 波特率BAUD_RATE,并取整// (所以整除之前先加波特率BAUD_RATE的一半)localparam DIVIDER = (CLOCK_RATE+BAUD_RATE/2) / BAUD_RATE;// 计数器的值localparam BAUD_VALUE = DIVIDER - 1;localparam BAUD_HALF = BAUD_VALUE/2 - 1;// 计数器位宽计算localparam CNT_WID = clog2(DIVIDER);reg [CNT_WID-1:0] baud_cnt = BAUD_VALUE;always @ (posedge clk)if (baud_cnt==BAUD_VALUE)baud_cnt <= {CNT_WID{1'b0}};else if (en)baud_cnt <= baud_cnt + 1'b1;elsebaud_cnt <= {CNT_WID{1'b0}};assign baud_clk = (baud_cnt==BAUD_HALF) ? 1'b1 : 1'b0;endmodule
`timescale 1ns / 1psmodule uart_decode_module(input clk,input [ 7:0] rx_data, // 接收的8 bit数据input rx_done, // 数据接收完毕,产生一个高脉冲output [ 7:0] addr, // 地址码output [15:0] data, // 数据组output valid // 一次数据协议解码成功);/* 有限状态机,三过程块建模风格 ********************************************/// 状态编码localparam FRAME_HEAD = 4'd0, // 帧头(1byte)CMD_ADDR = 4'd1, // 地址(1byte)CMD_DATA0 = 4'd2, // 数据(2byte)CMD_DATA1 = 4'd3,CHECK_SUM = 4'd4, // 校验(1byte,异或和)FRAME_TAIL = 4'd5, // 帧尾(1byte)DONE = 4'd6; // 本帧接收结束reg [ 3:0] now_state = FRAME_HEAD, next_state = FRAME_HEAD;reg [ 7:0] rx_data_r = 8'd0;reg rx_done_r = 1'b0;//reg data_number='d0;// 1.实现状态转换always @ (posedge clk) begin//: trans_staterx_data_r <= rx_data;rx_done_r <= rx_done;if (rx_done_r || now_state==DONE)now_state <= next_state;end//: trans_statereg [ 7:0] check_sum;// 2.产生下一个状态always @ (*) begin//: set_next_statecheck_sum = addr ^ data[ 7: 0]^data[15: 8];// next_state = now_state; // 下面分支的缺省状态case (now_state)FRAME_HEAD : if(rx_data_r == 8'hF1) next_state = CMD_ADDR;else next_state = FRAME_HEAD;CMD_ADDR : next_state = CMD_DATA0;CMD_DATA0 : next_state = CMD_DATA1;CMD_DATA1 : next_state = CHECK_SUM;CHECK_SUM : if(rx_data_r == check_sum) next_state = FRAME_TAIL;else next_state = FRAME_HEAD;FRAME_TAIL : if(rx_data_r == 8'hF2) next_state = DONE;else next_state = FRAME_HEAD;DONE : next_state = FRAME_HEAD;default : next_state = FRAME_HEAD;endcaseend//: set_next_state// 3.产生状态机的输出值reg [ 7:0] addr_r = 8'd0;reg [32:0] data_r = 32'd0;reg valid_r = 1'b0;reg valid_r_r = 1'b0;always @ (posedge clk) begincase (now_state)FRAME_HEAD : valid_r <= 1'b0;CMD_ADDR : begin valid_r <= 1'b0; addr_r <= rx_data_r; endCMD_DATA0 : begin valid_r <= 1'b0; data_r[7:0] <= rx_data_r; endCMD_DATA1 : begin valid_r <= 1'b0; data_r[15:8] <= rx_data_r; endCHECK_SUM : valid_r <= 1'b0;FRAME_TAIL : valid_r <= 1'b0;DONE : valid_r <= 1'b1;// data_number<=data_number+1; default : ;endcaseend//: set_out_stateassign addr = addr_r;assign data = data_r;always @ (posedge clk)beginvalid_r_r<=valid_r;endassign valid = valid_r_r;endmodule
#心得体会:
matlab中16进制是没法直接表示的,我尝试a=0x7 这样赋值是不行的。16进制必须是字符形式a=‘0x7’,如果要参与运算,请转换为10进制来参与运算。
注意即使check_sum没错,也许测试文件里帧头这些错误也可能。
最终效果:
自定义uart,一共24帧。控制24个变量参数。
FPGA自定义UART传输(包含:matlab数据拆分)相关推荐
- simulink自定义信号源方法matlab数据导入sim
simulink自定义信号源 方法: https://jingyan.baidu.com/article/e6c8503c7abdb2e54f1a18a0.html https://jingyan.b ...
- 基于FPGA的UART全双工数据控制器
引言: UART串行通讯协议是一种经典通讯协议,尽管在当前,它的通讯传输速度已经不能满足高数据量传输场景,但在传统的工业应用中还十分普遍广泛.在网上,一般所见到的可应用于FPGA设计的UART接口都遗 ...
- 【Java 网络编程】TCP 传输机制 ( 数据拆分 | 排序 | 顺序发送 | 顺序组装 | 超时重发 )
文章目录 I TCP 传输过程 II TCP 传输示例 III TCP 传输特殊情况处理 I TCP 传输过程 1. TCP 传输过程 : 排序 , 顺序发送 , 顺序组装 ; ① 排序 : TCP ...
- HDMI原理详解以及时序流程(视频是三对差分信号,音频Audio是PCM级(无压缩)传输,包含在数据包内,依靠协议规定采样)HDMI可以传输RGB与YUV两种格式
资料来源:HDMI介绍与流程 - TaigaComplex - 博客园 最近要用ZYNQ开发版的HDMI做显示,看着硬件管脚和例程只能发呆,于是决心去弄清楚HDMI的工作原理,查找了很多资料,都是碎片 ...
- 数据拆分缺点和解决方案
MySQL垂直拆分和水平拆分的优缺点和共同点总结 数据的拆分(Sharding)根据其拆分分规则的类型,可以分为两种拆分模式.一种是按照不同的表(或者Schema)来切分到不同的数据库(主机)之上,这 ...
- 基于 FPGA 的 UART 控制器设计(VHDL)(下)
今天给大侠带来基于FPGA的 UART 控制器设计(VHDL)(下),由于篇幅较长,分三篇.今天带来第三篇,下篇,使用 FPGA 实现 UART.话不多说,上货. 之前有关于 Veriliog HDL ...
- 【FPGA】UART串口通信
目录 前言 一丶通信方式 1.串行通信 2.并行通信 二丶UART 串口通信 三丶模块设计 四丶发送模块 1.代码 2.仿真 五丶接收模块 1.代码 2.仿真 六丶顶层模块 1.代码 2.模块原理图 ...
- CPLD/FPGA的UART接口设计之系统时钟(晶振)和波特率关系
UART(UniversalAsynchronous ReceiverTransmitter,通用异步收发器)是一种广泛使用的异步串行数据通信协议.目前大多数MCU.串口通信IC等芯片或模块均支持UA ...
- 基于FPGA的UART接口协议设计
一.PC终端概述 PC终端,Personal Computer 智能终端,通俗的讲,就是利用电脑GUI界面控制我们的外部硬件电路. 因此设计到了PC与外部硬件电路的通信接口.对于台式电脑.个人笔记本, ...
最新文章
- 一款纯css3实现的响应式导航
- 上千个电脑文件怎么搬?用Python一键复制移动
- Unbuntu 下安装node 环境
- boost::array用法的测试程序
- dede如何做SEO,一起探讨下
- 前后端分离后的前端时代 1
- final、static、finally总结
- 了解JQuery TextArea的取值与赋值问题
- SQLMETAL :Linq对象生成
- vue状态管理存取数据_Vue中的数据通信和状态管理
- (转)“领导者”沈南鹏:逼着自己不断思考,作为VC没有选择
- 51单片机c语言呼吸灯程序,给你的51单片机作品加个呼吸灯(程序)
- 使用AStar算法解决八数码问题
- 如何通过QQ机器人技术实现禅道bug的自动提交功能
- 今日头条张一鸣:做CEO要避免理性的自负
- 基于PLC的锅炉控制,基于s7-200的锅炉压力控制的设计,基于西门子S7-200plc与MCGS锅炉压力PID控制系统设计
- 求三角形面积-gyy
- Python操控鼠标和键盘
- portal使用常见错误
- 制作大白菜装系统U盘以及重装系统