chibijia的个人空间 https://blog.eetop.cn/178426 [收藏] [复制] [分享] [RSS]

空间首页 动态 记录 日志 相册 主题 分享 留言板 个人资料

日志

FPGA-Verilog学习(三)红外接收解码,并在数码管上显示接收到的码值(转载)

已有 5490 次阅读| 2009-10-30 21:12

下面程序主要功能是接收红外,并且解码,然后在四个数码管上显示出来(32位码)!

程序如下:

 

module IR(clk,rst_n,IR,led_cs,led_db);

  input   clk;
  input   rst_n;
  input   IR;
  output [7:0] led_cs;
  output [7:0] led_db;
 
  reg [3:0] led_cs;
  reg [7:0] led_db;
 
  reg [7:0] led1,led2,led3,led4;
  reg [15:0] irda_data;    // save irda data,than send to 7 segment led
  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;     //确╥rda的跳变沿
   
  always @ (posedge clk) //在此采用跟随寄存器
    if(rst_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上升沿

  //----------------------------------------------------------------------------
  //设计分频和计数部分:从PT2222的规范中我们发现最小的电平3质奔涫?.56ms,而
  //我们在进行采样时,一般都会对最〉牡缙讲裳?6次。也就是说要对0.56ms最少采样16
  //次。
  //              0.56ms/16=35us
  //诳??迳献源?闹髌滴?0MHz,即时钟周期为20ns,所以我们需要的分频次数为:
  //              35000/20=1750
  //在设计中我们利用了两个counter,一个counter用于计1750次时钟主频;
  //一个counter用于计算分频之后,同一种电平所scan到的点数,这个点数最后会用来判断
  //是leader的9ms 还是4.5ms,或是数据的 0 还是 1。
  //----------------------------------------------------------------------------
  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 clk)
    if (rst_n)
      counter <= 11'd0;
    else if (irda_chang)  //irda电平跳变了,就重新开始计数
      counter <= 11'd0;
    else if (counter == 11'd1750)
      counter <= 11'd0;
    else
      counter <= counter + 1'b1;
  
  //---------------------------------------------------------------------------- 
  always @ (posedge clk)
    if (rst_n)
      counter2 <= 9'd0;
    else if (irda_chang)  //irda电平跳变了,就重新开始计点
      counter2 <= 9'd0;
    else if (counter == 11'd1750)
      counter2 <= counter2 +1'b1;
  

  assign check_9ms = ((217 < counter2) & (counter2 < 297)); //257  为了增加稳定性,取一定范围
  assign check_4ms = ((88 < counter2) & (counter2 < 168));  //128
  assign low  = ((6 < counter2) & (counter2 < 26));         // 16
  assign high = ((38 < counter2) & (counter2 < 58));        // 48

  //----------------------------------------------------------------------------
  // generate statemachine  状态机
    parameter IDLE       = 3'b000, //初始状态
              LEADER_9   = 3'b001, //9ms
              LEADER_4   = 3'b010, //4ms
              DATA_STATE = 3'b100; //传输数据
 
  always @ (posedge clk)
    if (rst_n)
      cs <= IDLE;
    else
      cs <= ns; //状态位
     
  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  //完备的if---else--- ;防止生成latch
          ns =LEADER_9;
   
      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 clk)
    if (rst_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 clk)
    if (rst_n)
      irda_data <= 16'd0;
    else if ((data_cnt ==6'd32) & irda_reg1)
  begin
   led1 <= get_data[7:0];  //数据反码
   led2 <= get_data[15:8]; //数据码
   led3 <= get_data[23:16];//用户码
   led4 <= get_data[31:24];
  end
   
//---------------------------------------------------
//四个数码管共用一个8位数据线,所以采用四个数码管快速轮流显示的方法
//initial led_cs = 4'b0001;
integer i="0";

always @(posedge clk)
begin
 if(rst_n)
 begin
  led_cs <= 4'b0001;
 end
 
 else if(i==2000)
 begin
  if (led_cs==4'b1000)
  begin
   led_cs<=4'b0001;
   i<=0;
  end
  else
  begin
   led_cs<=led_cs <<1;
   i<=0;
  end
 end
 
 else i<=i+1;
 
end


//--------------------------------------------------
//四鍪?管分别显示不用的数?
//initial led_db = 0'hff;

always @(posedge clk)
if(rst_n)
begin
 led_db <= 0'hff;//共阳数码管复位
end
else
begin
 if (led_cs==4'b0001) led_db<= led1;//
 if (led_cs==4'b0010) led_db<= led2; //
 if (led_cs==4'b0100) led_db<= led3; //
 if (led_cs==4'b1000) led_db<= led4; //
end

endmodule 


点赞

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 注册

  • 关注TA
  • 加好友
  • 联系TA
  • 0

    周排名
  • 0

    月排名
  • 0

    总排名
  • 0

    关注
  • 2

    粉丝
  • 0

    好友
  • 0

    获赞
  • 32

    评论
  • 1485

    访问数
关闭

站长推荐 上一条 /1 下一条

小黑屋| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-3-29 00:03 , Processed in 0.025062 second(s), 13 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部