玩转FPGA山寨版

看了《玩转FPGA》,写的不错,写写山寨版和大家交流!

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

一、Verilog HDL代码

////////////////////////////////////////////////////////

module Infra(
 clock,
 reset_n,
 IR,
 Infra
);
  input         clock;
  input     reset_n;
  input     IR;
  output reg [7:0] Infra;
 
  reg [31:0] get_data;     // use for saving 32 bytes irda data
  reg [5:0]  data_cnt;     // 32 bytes irda data counter
  reg [2:0]  cs,ns;
  reg error_flag;          // 32 bytes data期间,数据错误标志

  //----------------------------------------------------------------------------
  reg irda_reg0;       //为了避免亚稳态,避免驱动多个寄存器,这一个不使用。
  reg irda_reg1;       //这个才可以使用,以下程序中代表irda的状态
  reg irda_reg2;       //为了确定irda的边沿,再打一次寄存器,以下程序中代表irda的前一状态
  wire irda_neg_pulse; //确定irda的下降沿
  wire irda_pos_pulse; //确定irda的上升沿
  wire irda_chang;     //确定irda的跳变沿
   
  always@(posedge clock or negedge reset_n) //在此采用跟随寄存器
    if(!reset_n)
      begin
        irda_reg0 <= 1'b0;
        irda_reg1 <= 1'b0;
        irda_reg2 <= 1'b0;
      end
    else
      begin
        irda_reg0 <= IR;
        irda_reg1 <= irda_reg0;
        irda_reg2 <= irda_reg1;
      end
     
  assign irda_chang = irda_neg_pulse | irda_pos_pulse;  //IR接收信号的改变,上升或者下降
  assign irda_neg_pulse = irda_reg2 & (~irda_reg1);   //IR接收信号irda下降沿
  assign irda_pos_pulse = (~irda_reg2) & irda_reg1;      //IR接收信号irda上升沿

 
  reg [10:0] counter;  //分频1750次
  reg [8:0]  counter2; //计数分频后的点数
  wire check_9ms;  // check leader 9ms time
  wire check_4ms;  // check leader 4.5ms time
  wire low;        // check  data="0" time
  wire high;       // check  data="1" time
 
  //----------------------------------------------------------------------------
  //分频1750计数
always@(posedge clock or negedge reset_n)
begin
    if (!reset_n)  counter <= 11'd0;
    else if (irda_chang)   counter <= 11'd0; //irda电平跳变了,就重新开始计数
    else if (counter == 11'd1750)  counter <= 11'd0;
    else   counter <= counter + 1'b1;
end
  //---------------------------------------------------------------------------- 
always@(posedge clock or negedge reset_n)
begin
    if(!reset_n)  counter2 <= 9'd0;
    else if (irda_chang) counter2 <= 9'd0; //irda电平跳变了,就重新开始计点
    else if (counter == 11'd1750)  counter2 <= counter2 +1'b1;
 end

  assign check_9ms = ((9'd217 < counter2) && (counter2 < 9'd297)); //257  为了增加稳定性,取一定范围
  assign check_4ms = ((9'd88 < counter2) && (counter2 < 9'd168));  //128
  assign low  = ((9'd6  < counter2) && (counter2 < 9'd26));         // 16
  assign high = ((9'd38 < counter2) && (counter2 < 9'd58));        // 48

  //----------------------------------------------------------------------------
  // generate statemachine  状态机
    parameter IDLE       = 3'b000, //初始状态
              LEADER_9   = 3'b001, //9ms
              LEADER_4   = 3'b010, //4ms
              DATA_STATE = 3'b100; //传输数据
 
always@(posedge clock or negedge reset_n)
begin
    if(!reset_n)  cs <= IDLE;
    else         cs <= ns; //状态位
end
    
 always@( * )
    case (cs)
      IDLE:
        if (~irda_reg1)  ns = LEADER_9;
        else             ns = IDLE;
   
      LEADER_9:
        if (irda_pos_pulse)   //leader 9ms check
          begin
            if (check_9ms)   ns = LEADER_4;
            else             ns = IDLE;
          end
        else  ns =LEADER_9; //完备的if---else--- ;防止生成latch
         
      LEADER_4:
        if (irda_neg_pulse)  // leader 4.5ms check
          begin
            if (check_4ms)  ns = DATA_STATE;
            else            ns = IDLE;
          end
        else  ns = LEADER_4;
   
      DATA_STATE:
   if ((data_cnt == 6'd32) & irda_reg2 & irda_reg1)     ns = IDLE;
   else if (error_flag)       ns = IDLE;
   else     ns = DATA_STATE;
      default:       ns = IDLE;
    endcase

  //状态机中的输出,用时序电路来描述
  always@(posedge clock or negedge reset_n)
    if (!reset_n)
      begin
        data_cnt <= 6'd0;
        get_data <= 32'd0;
        error_flag <= 1'b0;
      end
 
    else if (cs == IDLE)
      begin
        data_cnt <= 6'd0;
        get_data <= 32'd0;
        error_flag <= 1'b0;
      end
 
    else if (cs == DATA_STATE)
      begin
        if (irda_pos_pulse)  // low 0.56ms check
          begin
            if (!low)  //error
              error_flag <= 1'b1;
          end
        else if (irda_neg_pulse)  //check 0.56ms/1.68ms data 0/1
          begin
            if (low)  get_data[0] <= 1'b0;
            else if (high)  get_data[0] <= 1'b1;
            else  error_flag <= 1'b1;             
            get_data[31:1] <= get_data[30:0];
            data_cnt <= data_cnt + 1'b1;
          end
      end

 always@(posedge clock or negedge reset_n)
  begin
    if (!reset_n) Infra <= 8'bzzzz_zzzz;
    else if ((data_cnt ==6'd32) & irda_reg1)
       Infra <= {get_data[8],get_data[9],get_data[10],get_data[11],get_data[12],get_data[13],get_data[14],get_data[15]};
 end

endmodule

//////////////////////////////////////////////////////////////////////////////////////////////////////////

二、顶层工程文件

三、C语言代码

#include"io.h"
#include"system.h"
#include"alt_types.h"
#include"sys/alt_irq.h"
#include"avalon_slave_SEG7.h"

void HX1838_Init();
void HX1838_ISR(void* context, alt_u32 id);

int main(void)
{
    alt_u8 i;
    for(i=0;i<8;i++)  seg7(SEG7_BASE,0,i);
    HX1838_Init();
    while(1)
    {

    };
    return 0;
}

void HX1838_Init()
{
    IOWR(IR_BASE,2,0xFF);
    alt_irq_register(IR_IRQ,0,HX1838_ISR);
}
void HX1838_ISR(void* context, alt_u32 id)
{
     alt_u8 data;
     data = IORD_8DIRECT(IR_BASE,0);
     seg7_show(SEG7_BASE,data);
}

posted on 2011-02-16 15:55  Neddy11  阅读(4717)  评论(0)    收藏  举报