OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 9157|回复: 4

verilog写的红外解码模块,可与nios II接口作为按键输入,也可直接与其他verilog编写的FPGA模块连接

[复制链接]

40

主题

179

帖子

0

精华

高级会员

Rank: 4

积分
921
金钱
921
注册时间
2013-10-23
在线时间
94 小时
发表于 2014-4-29 13:11:26 | 显示全部楼层 |阅读模式

[mw_shl_code=c,true]本设计根据网上最多的那个红外解码模块改写而成。其中IR为红外接收头的输入,key_db为按键值输出总线 key_int为接收到红外信号后的中断信息,默认时低电平,当开始解码时,则跳至高电平,当解码完成,则跳至 低电平。可以用来作为nios II处理器的一个外部中断请求,使用时在只需要在qsys或sopc builder中加入一个带 中断输入功能的IO口,IO中断设为下降沿触发即可。当中断到来时,读取key_db总线的值。key_db采用 通用的输入PIO,无需再开中断功能。 module my_IR(clk,rst_n,IR,key_db,key_int,clk_test); input clk; input rst_n; input IR; output [7:0] key_db; output key_int; output clk_test; reg [3:0] led_cs; reg [7:0] key_db; 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的跳变沿 reg[15:0] cnt_scan;//扫描频率计数器 always @ (posedge clk) //在此采用跟随寄存器 if(!rst_n) begin irda_reg0 <= 1'b0; irda_reg1 <= 1'b0; irda_reg2 <= 1'b0; end else begin led_cs <= 4'b0000; //是数码管的位选择处于导通状态 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 //target="_self">开发板上自带的主频?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; reg [10:0]cnt3; reg clk_test; always@(posedge clk) begin if(cnt3==11'd1750)begin clk_test<=~clk_test;cnt3<=11'b0;end else cnt3<=cnt3+1'b1; end 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 reg key_int; always @ (posedge clk) if (!rst_n) irda_data <= 16'd0; else if ((data_cnt ==6'd32) & irda_reg1) begin key_db <= get_data[15:8]; //数据码 key_int<=1'b0; end else if(data_cnt ==6'd1)key_int<=1'b1; endmodule ---------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------- c程序设计部分 //本设计中因为采用了彩屏,所以程序中有部分和彩屏相关的代码,不用,根据你自己的理解,删掉即可。若再有不懂,欢迎加QQ:528369266 #include <unistd.h> #include "my_types.h" #include "system.h" #include "stdio.h" #include "priv/alt_legacy_irq.h" //alt_irq_register()这个函数是在这个文件中申明的,所以必须包含此文件 #include "altera_avalon_pio_regs.h" #include "sys/alt_irq.h" #include "lcd.h" alt_u32 key_word; alt_u8 w1; void IR_ISR(void *context,unsigned long id); int IRQ_Init(void); // 调试信息显示开关 #define ENABLE_APP_DEBUG // turn on debug message #ifdef ENABLE_APP_DEBUG #define APP_DEBUG(x) DEBUG(x) #else #define APP_DEBUG(x) #endif // nIRQ中断初始化 int IRQ_Init(void) { IOWR_ALTERA_AVALON_PIO_IRQ_MASK(IR_EXINT_BASE, 1); // 使能中断 IOWR_ALTERA_AVALON_PIO_EDGE_CAP(IR_EXINT_BASE, 0); // 清中断边沿捕获寄存器 // 注册ISR return alt_irq_register(IR_EXINT_IRQ,NULL,IR_ISR); } // 中断服务子函数 void IR_ISR(void *context,unsigned long id) { IOWR_ALTERA_AVALON_PIO_EDGE_CAP(IR_EXINT_BASE, 1); // 清中断边沿捕获寄存器 key_word=IORD_ALTERA_AVALON_PIO_DATA(IR_DATA_BASE); } int main(void) { lcd_init(); if(!IRQ_Init())printf("register succeed!\n"); else printf("register failed!\n"); while(1); return 0; } [/mw_shl_code]

 


http://xiaomeige.taobao.com。做最用心的FPGA学习板和教程资料
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

557

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165046
金钱
165046
注册时间
2010-12-1
在线时间
2102 小时
发表于 2014-4-29 15:12:56 | 显示全部楼层
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

8

主题

81

帖子

0

精华

初级会员

Rank: 2

积分
183
金钱
183
注册时间
2013-7-13
在线时间
17 小时
发表于 2014-4-29 17:25:48 | 显示全部楼层
顶!
回复 支持 反对

使用道具 举报

31

主题

271

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
450
金钱
450
注册时间
2012-5-18
在线时间
6 小时
发表于 2014-4-29 19:00:42 | 显示全部楼层
顶。
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
21
金钱
21
注册时间
2015-12-13
在线时间
0 小时
发表于 2015-12-13 16:20:39 | 显示全部楼层
果断的赞一个
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-6-29 00:18

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表