tag 标签: 红外解码

相关博文
  • 热度 29
    2014-4-29 19:54
    3032 次阅读|
    3 个评论
    本设计根据网上最多的那个红外解码模块改写而成。其中IR为红外接收头的输入,key_db为按键值输出总线 key_int为接收到红外信号后的中断信息,默认时低电平,当开始解码时,则跳至高电平,当解码完成,则跳至 低电平。可以用来作为nios II处理器的一个外部中断请求,使用时在只需要在qsys或sopc builder中加入一个带 中断输入功能的IO口,IO中断设为下降沿触发即可。当中断到来时,读取key_db总线的值。key_db采用 通用的输入PIO,无需再开中断功能。 clk_test为调试时作为嵌入式逻辑分析仪的采样信号,实际使用时可将相关代码删去。这里只发代码,若有想要工程的,欢迎索取。 注:clk为50M,若非50M,则无法正确进行红外解码。解决方法:1、用锁相环产生一个50M的时钟;2、修改counter的值,只要保证counter每计数时间到35us清零一次即可。 module my_IR(clk,rst_n,IR,key_db,key_int,clk_test);   input   clk;   input   rst_n;   input   IR;   output key_db;  output key_int;  output clk_test;     reg led_cs;   reg key_db;     reg irda_data;    // save irda data,than send to 7 segment led   reg get_data;     // use for saving 32 bytes irda data   reg   data_cnt;     // 32 bytes irda data counter   reg   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 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 counter;  //分频1750次   reg   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 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 = 1'b0;             else if (high)               get_data = 1'b1;             else               error_flag = 1'b1;                          get_data = get_data ;             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 ; //数据码   key_int=1'b0;    end    else if(data_cnt ==6'd1)key_int=1'b1;     endmodule ---------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------- c程序设计部分 //本设计中因为采用了彩屏,所以程序中有部分和彩屏相关的代码,不用,根据你自己的理解,删掉即可。若再有不懂,欢迎交流 #include #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; }        
相关资源