帧结构的串行数据接收器——Verilog实现

用Verilog 实现一个帧结构的串行数据接收器;

  1. 串行数据输入为:NRZ数据加位时钟(BCL)格式,高位在前
    帧结构为:8位构成一个字,64字构成一个帧。每帧的第一个字为同步字。
  2. 同步字图案存储在可由CPU读写的同步字寄存器(端口地址00H)中
    串行接受器在连续检测到3个同步图案后,开始接受数据,并向CPU中传送数据。串行数据接收器每接收到一个字,先送到数据寄存器中, CPU以I/O读方式,从数据寄存器中读取数据(端口地址为01H)
  3. 若数据寄存器已满,再有数据写入时,则覆盖原有的数据。在数据寄存器为空时,CPU从数据寄存器中读到的数据将是同步字寄存器的内容。
    在接收数据过程中,若任何一帧的同步字不匹配,则进入到头步状态,停止数据接收。失步后,必须重新同步(连续检测到3个同步图案),然后开始新的数据接收。
  4. 寄存器的读写采用和8031类似的控制方式,有关信号包括:双向数据(DATA[7:0])、I/O地址(ADDR[7:0])、I/O写(IOW)、和I/O读(IOR),其中IOW和IOR都是低电平有效
  5. 设计者可以根据需要增加其它的输入输出信号

设计分析

  • 端口
    在这里插入图片描述

  • 输入数据和时钟之间的关系
    在这里插入图片描述

  • 帧结构
    8位构成一个字,64字构成一个帧。每帧的第一个字为同步字。
    连续检测到三个同步,即连续三个同步头和同步图案一样的帧,才开始进行数据接收

  • 详细设计-工作阶段非常明显

    • 失步阶段:检测同步头,根据情况确定是否转入同步状态
    • 同步阶段:检测同步头,如果匹配则接收数据,仍然处于同步阶段;否则转入失步状态。
    • 注意:是台下检测i的一个同步字时需要每个时钟周期都要进行比较
  • 实现思路:采用状态机进行实现

    • 状态转换的控制
      • 计数器:接收位计数–>字,字计数–>数据帧
      • 比较器:枕头数据与同步字的比较
  • 两个状态
    在这里插入图片描述
    该状态转换关系从功能需求很容易得出
    难点:需要检测三个连续的同步帧才能从失步态到同步态
    控制不清晰

  • 四状态划分
    在这里插入图片描述
    实现难点:每个帧持续8*64个时钟周期,其中第8个时钟周期结束需要同步头比较,后面的504个时钟周期接收数据(同步态)或空等(失步态)

  • 8个状态
    在这里插入图片描述

    • 在每个状态,省略了自身状态转移的情况
    • 每个R_Headx状态持续八个周期(Read_Head1)除外
    • 每个R_Datax状态持续504个周期
    • 需要设计一个记8和一个记504的计数器辅助进行控制
  • 代码部分
    完整代码

`timescale 1ns / 1psmodule S2P (reset,clk,serial_in,ior,iow,address,data,cnt
);input           reset;input           clk;input           serial_in;input           ior;input           iow;input   [7:0]   address;inout   [7:0]   data;output          cnt;reg     [7:0]   Data;reg             counter8_en,counter504_en,counter8_clr,counter504_clr;reg     [2:0]   counter8;reg     [8:0]   counter504;reg     [7:0]   shifter,data_reg,sync_word;reg     [2:0]   pres_state,next_state;reg             cnt;parameter R_Head1 = 3'b000,R_Data1 = 3'b001,R_Head2 = 3'b010,R_Data2 = 3'b011,R_Head3 = 3'b100,R_Data3 = 3'b101,R_Head = 3'b110,R_Data = 3'b111;   //状态机always @(posedge reset or posedge clk) beginif (reset) pres_state = R_Head1;else pres_state = next_state;endalways @(pres_state,shifter,counter8,counter504) begincase(pres_state)R_Head1: if (shifter == sync_word) next_state = R_Data1;else next_state = R_Head1;R_Data1: if (counter504 == 9'b0) next_state = R_Head2;else next_state = R_Data1;R_Head2: if (counter8 == 3'b0) beginif (shifter == sync_word) next_state = R_Data2;else next_state = R_Head1;end else next_state = R_Head2;R_Data2: if (counter504 == 9'b0) next_state = R_Head3;else next_state = R_Data2;R_Head3: if (counter8 == 3'b0) beginif (shifter == sync_word) next_state = R_Data3;else next_state = R_Head1;end else next_state = R_Head3; R_Data3: if (counter504 == 9'b0) next_state = R_Head;else next_state = R_Data3;R_Head: if (counter8 == 3'b0) beginif (shifter == sync_word) next_state = R_Data;else next_state = R_Head1;end else next_state = R_Head;R_Data: if (counter504 == 9'b0) next_state = R_Head;else  next_state = R_Data;default: next_state = R_Head1;endcaseendalways @(next_state,pres_state) beginif (pres_state == R_Data) cnt = 1'b1;else cnt = 1'b0;end // 移位器和计数器always @(posedge reset or posedge clk) beginif (reset) shifter = 8'b0;else shifter = {serial_in,shifter[7:1]};endalways @(posedge clk  or posedge reset) beginif (reset) counter8 = 3'b111;else beginif (counter8_clr) counter8 = 3'b111;else if (counter8_en)counter8 = counter8 - 1; endendalways @(posedge clk  or posedge reset) beginif (reset) counter504 = 9'b1_1111_0111;else beginif (counter504_clr) counter504= 9'b1_1111_0111;else if (counter504_en)counter504 = counter504 - 1; endend// 计数器计数使能和清零信号生成always @(pres_state) beginif (pres_state == R_Data1 || pres_state == R_Data2 || pres_state == R_Data3 || pres_state == R_Data)counter8_clr = 1'b1;else counter8_clr = 1'b0;endalways @(pres_state) beginif (pres_state == R_Head2 || pres_state == R_Head3 || pres_state == R_Head) counter8_en = 1'b1;else counter8_en = 1'b0;endalways @(pres_state) beginif (pres_state == R_Head1 || pres_state == R_Head2 || pres_state == R_Head3 || pres_state == R_Head) counter504_clr = 1'b1;else counter504_clr = 1'b0;endalways @(pres_state) beginif (pres_state == R_Data1 || pres_state == R_Data2 || pres_state == R_Data3 || pres_state == R_Data) counter504_en = 1'b1;else counter504_en = 1'b0;end//数据寄存器读写和同步字寄存器的写入always @(posedge reset or posedge clk)if (reset) data_reg = 8'b0;else if (counter504_en == 1'b1 && counter504[2:0] == 3'b0) data_reg = shifter;always @(posedge reset or posedge clk) beginif (reset) sync_word = 8'b0000_0001;else if (iow == 1'b0 && address == 8'b0) sync_word = data;endalways @(ior or address or data_reg) if (ior == 1'b0 && address == 8'b1) Data = data_reg;else Data = 8'bz;assign data = Data;endmodule
  • Testbench
`timescale 1ns / 1ps
module tb_S2P;reg       reset;reg       clk;reg       serial_in;reg       ior;reg       iow;reg [7:0] address;wire[7:0] data;wire       cnt;S2P s2p (.reset(reset),.clk(clk),.serial_in(serial_in),.ior(ior),.iow(iow),.address(address),.data(data),.cnt(cnt));reg [7:0] d;assign data = (ior == 1'b1)?d:8'bz;//assign data = (ior == 1'b0 &&address == 8'b1)?d:8'bz;always begin#10 clk = ~clk; endinteger i;initial beginserial_in = 1'bZ;#10 ; while (1) beginior = 1'b1;#20; serial_in = 1'b0;#20; serial_in = 1'b1;#20; serial_in = 1'b1;#20; serial_in = 1'b1;#20; serial_in = 1'b1;#20; serial_in = 1'b1;#20; serial_in = 1'b1;#20; serial_in = 1'b0;for (i = 1;i <= 63*8;i = i + 1)#20 serial_in = {$random}%2;end  endinitial beginclk = 0;reset = 1'b1;#20#5 reset = 1'b0;endinitial beginior = 1'b1;//address = 8'b0;//s2p.pres_state = 3'b1;iow = 1'b1;address = 8'b0;d = 8'b01111110;#20#5;iow = 1'b0;//address = 8'b0;#10;address = 8'b0000_0001;//ior = 1'b0;#5 iow = 1'b1;endalways @(cnt) beginior = ~cnt;endinitial begin#20#101000;$finish;end
endmodule
  • 仿真结果
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/108953.html

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

相关文章

docker学习1

Docker jar包环境镜像&#xff0c;镜像存在docker仓库中&#xff0c;随用随取&#xff0c;无需现配环境 docker通过隔离机制&#xff0c;各个镜像之间互不干扰 docker比vm轻量化&#xff0c;每次只需运行镜像即可&#xff0c;镜像占内存小启动快&#xff0c;虚拟机启动慢&…

合宙Air724UG LuatOS-Air LVGL API控件-图片(Gif)

图片&#xff08;Gif&#xff09; GIF图片显示&#xff0c;core版本号要>3211 示例代码 方法一 -- 创建GIF图片控件 glvgl.gif_create(lvgl.scr_act()) -- 设置显示的GIF图像 lvgl.gif_set_src(g,"/lua/test.gif") -- gif图片居中 lvgl.obj_align(g, nil, lvgl…

基于SpringBoot蜗牛兼职网的设计与实现【附PPT|万字文档(LW)和搭建文档】

主要功能 前台界面&#xff1a; ①首页、兼职信息推荐、查看更多等 ②职位申请、申请日期、上传简历、点击下载简历、留言反馈等 ③个人中心、上传图片、更新信息等 后台登录&#xff1a; ①用户登录&#xff1a; 个人中心、修改密码、个人信息、职位申请管理 ②企业登录&…

Redis混合模式下的持久化原理

前言 前面文章中我们也介绍过Redis的持久化方式有两种&#xff1a;rdb持久化和aof持久化&#xff0c;具体详情可查看之前文章redis持久化。rdb持久化还是aof持久化它们都有各自的缺点。 rdb和aof缺点 rdb持久化&#xff1a;由于是定期对内存数据快照进行持久化&#xff0c;因此…

ARM架构-伪指令、伪操作、ATPCS协议

汇编中的符号&#xff1a; 1.指令&#xff1a;能够编译生成一条32位的机器码且能被CPU识别和执行 2.伪指令&#xff1a;本身不是指令&#xff0c;编译器可以将其替换成若千条指令 3.伪操作:不会生成代码&#xff0c;只是在编译阶段告诉编译器怎么编译&#xff08;例如&#x…

STM32WB55开发(4)----配置串口打印Debug调试信息

STM32WB55开发----4.配置串口打印Debug调试信息 概述硬件准备视频教学样品申请选择芯片型号配置时钟源配置时钟树RTC时钟配置查看开启STM32_WPAN条件配置HSEM配置IPCC配置RTC启动RF开启蓝牙开启串口调试配置蓝牙参数设置工程信息工程文件设置Keil工程配置代码配置结果演示 概述…

mysql5.7版本数据库主主同步

mysql5.7配置双主同步 双主模式定义前提配置一、master_1配置二、master_2配置三、双主配置四、验证主主同步 双主模式定义 双主模式是指两台服务器互为主从&#xff0c;任何一台服务器数据变更&#xff0c;都会通过复制应用到另外一方的数据库中。 随着业务发展&#xff0c;架…

C#自定义控件组件实现Chart图表(多Y轴,选择图例加粗,选择放大,缩放,点击查看信息等功能)

先看看ECharts的效果 C# 工具箱里的Chart控件就不演示了,很多效果没办法做出来,做出来效果也很不理想。所以,需要自己去手动实现工具箱里的Chart没办法实现的效果; 先看看实现后的效果 绑定数据 点击图表 点击右侧图例加粗 选择放大 右键 点击缩小,恢复

小程序中如何查看指定会员的所有订单?

在小程序中&#xff0c;查看指定会员的所有订单可以通过如下方式实现。 1. 找到指定的会员卡。在管理员后台->会员管理处&#xff0c;找到需要查看订单记录的会员卡。也支持对会员卡按卡号、手机号和等级进行搜索。 2. 查看会员卡详情。点击查看详情进入该会员卡的详情页面…

【搭建私人图床】本地PHP搭建简单Imagewheel云图床,在外远程访问

文章目录 1.前言2. Imagewheel网站搭建2.1. Imagewheel下载和安装2.2. Imagewheel网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar临时数据隧道3.2.Cpolar稳定隧道&#xff08;云端设置&#xff09;3.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 4.公网访问测…

Kotlin+MVVM 构建todo App 应用

作者&#xff1a;易科 项目介绍 使用KotlinMVVM实现的todo app&#xff0c;功能界面参考微软的Todo软件&#xff08;只实现了核心功能&#xff0c;部分功能未实现&#xff09;。 功能模块介绍 项目模块&#xff1a;添加/删除项目&#xff0c;项目负责管理todo任务任务模块&a…

4-1 张量的结构操作

张量结构操作主要包括&#xff1a;张量创建&#xff0c;索引切片&#xff0c;维度变换&#xff0c;合并分割。 一、创建张量 张量创建的许多方法和numpy中创建array的方法很像。以下记录一些比较常用的操作&#xff1a; &#xff08;1&#xff09;直接采用torch.tensor创建&…