引言:本程序是在工程实践中写的模块,经验证,可靠。由于大多书本上讲的都是仅仅传输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数据拆分)相关推荐

  1. simulink自定义信号源方法matlab数据导入sim

    simulink自定义信号源 方法: https://jingyan.baidu.com/article/e6c8503c7abdb2e54f1a18a0.html https://jingyan.b ...

  2. 基于FPGA的UART全双工数据控制器

    引言: UART串行通讯协议是一种经典通讯协议,尽管在当前,它的通讯传输速度已经不能满足高数据量传输场景,但在传统的工业应用中还十分普遍广泛.在网上,一般所见到的可应用于FPGA设计的UART接口都遗 ...

  3. 【Java 网络编程】TCP 传输机制 ( 数据拆分 | 排序 | 顺序发送 | 顺序组装 | 超时重发 )

    文章目录 I TCP 传输过程 II TCP 传输示例 III TCP 传输特殊情况处理 I TCP 传输过程 1. TCP 传输过程 : 排序 , 顺序发送 , 顺序组装 ; ① 排序 : TCP ...

  4. HDMI原理详解以及时序流程(视频是三对差分信号,音频Audio是PCM级(无压缩)传输,包含在数据包内,依靠协议规定采样)HDMI可以传输RGB与YUV两种格式

    资料来源:HDMI介绍与流程 - TaigaComplex - 博客园 最近要用ZYNQ开发版的HDMI做显示,看着硬件管脚和例程只能发呆,于是决心去弄清楚HDMI的工作原理,查找了很多资料,都是碎片 ...

  5. 数据拆分缺点和解决方案

    MySQL垂直拆分和水平拆分的优缺点和共同点总结 数据的拆分(Sharding)根据其拆分分规则的类型,可以分为两种拆分模式.一种是按照不同的表(或者Schema)来切分到不同的数据库(主机)之上,这 ...

  6. 基于 FPGA 的 UART 控制器设计(VHDL)(下)

    今天给大侠带来基于FPGA的 UART 控制器设计(VHDL)(下),由于篇幅较长,分三篇.今天带来第三篇,下篇,使用 FPGA 实现 UART.话不多说,上货. 之前有关于 Veriliog HDL ...

  7. 【FPGA】UART串口通信

    目录 前言 一丶通信方式 1.串行通信 2.并行通信 二丶UART 串口通信 三丶模块设计 四丶发送模块 1.代码 2.仿真 五丶接收模块 1.代码 2.仿真 六丶顶层模块 1.代码 2.模块原理图 ...

  8. CPLD/FPGA的UART接口设计之系统时钟(晶振)和波特率关系

    UART(UniversalAsynchronous ReceiverTransmitter,通用异步收发器)是一种广泛使用的异步串行数据通信协议.目前大多数MCU.串口通信IC等芯片或模块均支持UA ...

  9. 基于FPGA的UART接口协议设计

    一.PC终端概述 PC终端,Personal Computer 智能终端,通俗的讲,就是利用电脑GUI界面控制我们的外部硬件电路. 因此设计到了PC与外部硬件电路的通信接口.对于台式电脑.个人笔记本, ...

最新文章

  1. 一款纯css3实现的响应式导航
  2. 上千个电脑文件怎么搬?用Python一键复制移动
  3. Unbuntu 下安装node 环境
  4. boost::array用法的测试程序
  5. dede如何做SEO,一起探讨下
  6. 前后端分离后的前端时代 1
  7. final、static、finally总结
  8. 了解JQuery TextArea的取值与赋值问题
  9. SQLMETAL :Linq对象生成
  10. vue状态管理存取数据_Vue中的数据通信和状态管理
  11. (转)“领导者”沈南鹏:逼着自己不断思考,作为VC没有选择
  12. 51单片机c语言呼吸灯程序,给你的51单片机作品加个呼吸灯(程序)
  13. 使用AStar算法解决八数码问题
  14. 如何通过QQ机器人技术实现禅道bug的自动提交功能
  15. 今日头条张一鸣:做CEO要避免理性的自负
  16. 基于PLC的锅炉控制,基于s7-200的锅炉压力控制的设计,基于西门子S7-200plc与MCGS锅炉压力PID控制系统设计
  17. 求三角形面积-gyy
  18. Python操控鼠标和键盘
  19. portal使用常见错误
  20. 制作大白菜装系统U盘以及重装系统

热门文章

  1. jquery源码 DOM加载
  2. redis数据库入门
  3. SmartImageView框架的使用
  4. irrlicht1.3中文支持
  5. Yahoo!的网站项目工作流程
  6. UA MATH566 统计理论5 假设检验:p值
  7. PE文件结构 - NT头学习
  8. php 循环从数据库分页取数据批量修改数据
  9. Day10-Python3基础-协程、异步IO、redis缓存、rabbitMQ队列
  10. 关于创业公司产品开发原则