完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
电子发烧友论坛|
|
|
相关推荐
3 个讨论
|
|
|
可以参考下
【转载】 从同学手上借来一个小型红外发射遥控器和一个HS0038红外接收头,把接收头直接插在FPGA学习板上的扩展槽里就能使用了!于是开始了为期一个星期的红外学习,呵呵,之前没有搞过,还有就是Verilog的编程基础还很差,所以花了不少时间! 从网上下载几篇关于红外发射与接收的文章看了一下,大概知道了红外的一些基础知识!(这是编程之前必备的功课)~现在我简单介绍一下基本原理:当我们按下遥控器的按键时,遥控器将发出一串二进制代码,我们称它为一帧数据。可将它们分为5 部分,分别为引导码、用户码、用户反码、数据码、数据反码。遥控器发射代码时,均是低位在前。高位在后。其中引导码高电平为9ms,低电平为4.5ms,当接收到此码时,表示一帧数据的开始。 解码的关键是如何识别"0"和"1",从位的定义我们可以发现"0"和"1"均以0.565mS的低电平开始,不同的是高电平的宽度不同,"0"为0.56mS,"1"为1.68mS,所以必须根据高电平的宽度区别"0"和"1",如果从0.565mS低电平过后,开始延时,0.56mS以后,若读到的电平为低,说明该位为"0",反之则为"1"。 附件里有两篇关于红外的文章,大家可以参考一下,写的比我的好~呵呵 本程序主要功能是接收红外,并且解码,然后在四个数码管上显示出来(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 |
|
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
/9
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-12-13 19:40 , Processed in 0.736075 second(s), Total 45, Slave 36 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191

淘帖
119