博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PPM解码器
阅读量:4953 次
发布时间:2019-06-12

本文共 6174 字,大约阅读时间需要 20 分钟。

PPM即Pulse Position Modulation(脉冲位置调制),利用脉冲的相对位置来传递信息的一种调制方式。在这种调制方式中,数据能够高速的传递。本文就来详细介绍一下PPM解码器。

1、PPM的功能描述

输入信号

  • clk,时钟周期为0.59us
  • rst,异步复位信号,低电平有效
  • din,输入的PPM编码后的数据

输出信号

  • [7:0] dout,PPM解码后的8位数据
  • d_en,输出数据有效标志,高电平有效,持续一个时钟周期
  • f_en,帧头检测有效标志,高电平有效,持续一个时钟周期

PPM数据编码格式.png

PPM数据帧格式.png

2、PPM的功能分析

计数器用来控制时序,移位寄存器用来暂存数据,状态机用来进行状态转换。

2.1计数器

时钟的周期是0.59us,而输入的每一位数据宽度为9.44us=0.59us※16,解码2bit的数据需要的时间为75.52us=0.59us※128,解码一个完整的8位数据,需要302.08us=75.52us※4。基于以上分析,我们可以设置3个计数器来控制数据的采样。

  • count0,0~15,每16个时钟周期采一位din信号。
  • count1,0~7,解码2bit需要采到8位din信号。
  • count2,0~3,完成一个完整的8位信号,需要解码2bit数据4次。

计数器count0.png

计数器count1.png
计数器count2.png

2.2移位寄存器

我们要对输入数据的8位数据进行判读,就要求我们对数据进行暂存。这里我们采用移位寄存器对输入数据进行暂存。与此同时,输出的8bit数据是2bit数据输出累加到8bit,所以我们也需要移位寄存器对输出数据进行暂存。

  • [7:0] reg1,对输入的数据进行移位操作,{reg1[6:0],din}
  • [7:0] reg2,对输出的数据进行暂存,等待8bit移满,就进行数据的输出,{2'b11,reg2[7:2]}{2'b00,reg2[7:2]}{2'b10,reg2[7:2]}{2'b01,reg2[7:2]}

移位寄存器reg1.png

移位寄存器reg2.png

2.3状态机

在传送数据的时候,主要有两个状态。要么是收到帧头解码数据,要么是没有收到帧头不进行解码。

  • S0,表示没有收到帧头,处于未工作状态。
  • S1,表示收到帧头,开始进行解码。

状态转移图.png

:以上电路图和状态转移图的判断条件有所简化。

具体代码如下:

module PPM(       clk,       rst,       din,       dout,       d_en,       f_en);          input clk,rst;   input din;   output [7:0] dout;   output d_en,f_en;   reg [7:0] dout;   reg d_en,f_en;   reg [3:0] count0;   reg [2:0] count1;   reg [2:0] count2;   reg [7:0] reg1;   reg [7:0] reg2;   reg cs,ns;  parameter  SOF=8'b01111011,             EOF=4'b1101,            d_00=8'b10111111,            d_01=8'b11101111,            d_10=8'b11111011,            d_11=8'b11111110,               S0=1'b0,               S1=1'b1;          always@(posedge clk or negedge rst)       begin         if(!rst)            cs<=S0;         else           cs<=ns;       end       always@(cs or count0 or count1 or reg1)         begin          case(cs)            S0:begin             if((count0==15)&&(reg1==SOF))               begin               ns=S1;              f_en=1'b1;              end             else                begin                ns=S0;               f_en=1'b0;                end             end     S1:begin    if((count0==15)&&(count1==3)&&(reg1[3:0]==EOF))    begin      ns=S0;      f_en=1'b0;    end  else    begin      ns=S1;      f_en=1'b0;    end  end  default:begin             ns=ns;            f_en=1'b0;           end  endcase          end      always@(posedge clk or negedge rst)       begin        if(!rst)          begin        count0<=0;        reg1<=8'b00000000;        end     else        begin           if(count0==15)            begin           reg1<={reg1[6:0],din};          count0<=0;         end     else     count0<=count0+1;    endendalways@(posedge clk or negedge rst)   begin    if(!rst)       count1<=0;   else   begin if(cs==S1)  if(count0==15)     if(count1==7)       count1<=0;     else       count1<=count1+1;  else    count1<=count1;else  count1<=0; endend    always@(posedge clk or negedge rst)begin  if(!rst)  count2<=0;elsebegin  if((count0==15)&&(cs==S1)&&(count1==7))    if(count2==3)      count2<=0;    else      count2<=count2+1;endend always@(posedge clk or negedge rst) begin if(!rst)     d_en<=0;   else     begin       if((count0==15)&&(count1==7)&&(cs==S1)&&(count2==3))           d_en<=1;       else         d_en<=0;      end  end always@(posedge clk or negedge rst) beginif(!rst)  reg2<=8'b00000000;elsebegin   if(cs==S1)   if((count0==15)&&(count1==7)&&(count2<=3))               begin          case(reg1)          d_00:reg2<={2'b00,reg2[7:2]};          d_01:reg2<={2'b01,reg2[7:2]};          d_10:reg2<={2'b10,reg2[7:2]};            d_11:reg2<={2'b11,reg2[7:2]};          default:reg2<=reg2;          endcase            end     else reg2<=reg2;     else reg2<=0;       endend        always@(posedge clk or negedge rst)  begin  if(!rst)dout<=0;  else   begin   if((d_en)&&(cs==S1))dout<=reg2;  else if (cs==S0)dout<=0; endend     endmodule

对以上代码做如下说明

用拼接符号{}实现了移位寄存器,在使用拼接符号时一定要指定每一个元素的位宽。在位拼接表达式中不允许存在没有指明位数的信号。
仿真波形图.png

3、testbench的编写

我们下面举一个例子来说明用文件读入的方法对存储器赋值。

先定义一个有256个地址的字节存贮器
reg [7:0] mem[40:0]; 地址为0~40,一个地址上存放着8bit的数据
利用文件读入的方法对men赋值

  • initial $readmemb("mem.txt",mem);
    以二进制的方式读取mem.txt中的数据到mem中。
  • initial $readmemh("mem.txt",mem,16);
    以十六进制的方式读取mem.txt中的数据到mem[16]-mem[40]。
  • initial $readmemh("mem.data",mem,23,1);
    以十六进制的方式读取mem.txt中的数据到mem[23]-mem[1]。

对读入文件做几点说明

  • 不同地址的数据以空格键或者回车键结束,从mem[0]开始读入数据。
  • 对一个地址的数据读入是从高位开始的,即从mem[0][7]开始读入mem.txt中的第一个数据,第一位地址的第7个元素为mem[1][7]=0 。
  • 对读入文件的命名规则,比如.txt文件名为mem,那么读入文件名应该为“mem.txt”。
  • 在Verilog中支持的文件路径格式为C:/Users/XQ/Desktop/mem.txt,而不是传统Windows底下的C:\Users\XQ\Desktop\mem.txt
  • 必须在run xx ns以后才能对存储器进行复制,初始的存储器的值都为xx。

    下面是一个名为mem的txt文件:

    00000000 //无效输入   01111011 //帧头   10111111 //"00"   11101111 //"01"   11111011 //"10"   11111110 //"11"输出数据e4   11111011 //"10"   11111110 //"11"   10111111 //"00"   11101111 //"01"输出数据4e   11010000 //帧尾   00001100   01111011 //帧头   11111011 //"10"   11111110 //"11"   10111111 //"00"   11101111 //"01"输出数据4e   11111110 //"11"   11101111 //"01"   11111011 //"10"   11111110 //"11"输出数据e7   10111111 //"00"   11101111 //"01"   11111110 //"11"   11101111 //"01"输出数据74   11010010 //帧尾   11010010   01111011 //帧头   10111111 //"00"   11101111 //"01"   11111011 //"10"   11111110 //"11"输出数据e4   10111111 //"00"   11101111 //"01"   11111011 //"10"   11111110 //"11"输出数据e4   11111011 //"10"   11111110 //"11"   10111111 //"00"   11101111 //"01"输出数据4e   11010000 //帧尾

tb文件代码如下:

`timescale 1ns/1ns    module PPM_top;     reg clk,rst;     reg din;     wire [7:0]dout;     wire d_en,f_en;     reg [7:0] mem[40:0];      integer i,j;     initial       begin           $readmemb("C:/Users/XQ/Desktop/mem.txt",mem);          for(i=0;i<41;i=i+1)             for(j=7;j>=0;j=j-1)               begin                #9440                  din=mem[i][j];                  $display("mem[%0d][%0d]=%b",i,j,mem[i][j]);             end           end  always     #295 clk=~clk;   initial     begin      clk=0;      rst=1;      #200     rst=0;     #259     rst=1;       end  PPM ut1(           .clk(clk),           .rst(rst),           .din(din),           .d_en(d_en),           .f_en(f_en),           .dout(dout)           );                 endmodule

:reg类型的数据默认为是无符号的数,若reg [7:0] j那么在j=j-1中就不会出现负数,而是0-1=8'b11111111=255;若integer [7:0] j那么就会出现0-1=-1,正好符合我们的本意。采用integer配合FOR语句,行数比较少,但是integer不能综合,只能用来仿真。

转载于:https://www.cnblogs.com/xuqing125/p/8888081.html

你可能感兴趣的文章
BZOJ 3097 Hash Killer I
查看>>
UINavigationController的视图层理关系
查看>>
AX2009获取库存查询当前显示的维度
查看>>
web页面调用Linux脚本,apache – 如何从Web服务器调用本地shell脚本...
查看>>
html阴影效果怎么做,css 内阴影怎么做
查看>>
宏观经济
查看>>
生活清单
查看>>
李春雷 | 夜宿棚花村
查看>>
辅导员面试
查看>>
事业单位笔试题
查看>>
公文种类
查看>>
公共基础知识
查看>>
给普通话点穴
查看>>
公文格式
查看>>
优秀辅导员工作案例
查看>>
高校突发事件应急处置方法
查看>>
Sublime搭建Java程序运行环境
查看>>
班级管理
查看>>
声律启蒙
查看>>
Web测试与App测试的区别
查看>>