红外解码编码学习----verilog
在设计中运用红外遥控器可以很好的解决按键缺少的问题,还可以方便的控制产品。
红外发射部分:
红外发射管:


判断红外发射管的好坏
:
电路原理图:



接收部分:




传输的NEC协议:


本实验电路:

verilog 程序:
发送程序:
/********************************Copyright**************************************
**----------------------------File information--------------------------
** File name :IR_send.v
** CreateDate :2015.06
** Funtions :红外信号的发送程序,发送格式:引导码+8bit用户码+8bit用户反码(或者用户反码)+8bit数据码+8bit用户反码+结束码
** Operate on :M5C06N3L114C7
** Copyright :All rights reserved.
** Version :V1.0
**---------------------------Modify the file information----------------
** Modified by :
** Modified data :
** Modify Content:
*******************************************************************************/
module IR_send (
clk,
rst_n,
key_1,
key_2,
IR_out,
led_1,
led_2,
led_3,
led_4
// testdata
);
input clk; //24M/20m
input rst_n;
input key_1;
input key_2;
output IR_out;
output reg led_1;
output reg led_2;
output led_3;
output led_4;
// output [7;0] testdata;
//-------------------//
`define CLK_20M
// `define CLK_24M
// `define CLK_50M
`ifdef CLK_20M
parameter t_38k = 10'd526;
parameter t_38k_half = 10'd263;
parameter t_9ms = 18'd179999;
parameter t_4_5ms = 17'd89999;
parameter t_13_5ms = 19'd269999;
parameter t_560us = 14'd11199;
parameter t_1_12ms = 15'd22399;
parameter t_1_68ms = 16'd33599;
parameter t_2_24ms = 16'd44799;
`endif
`ifdef CLK_24M
parameter t_38k = 10'd630;
parameter t_38k_half = 10'd315;
parameter t_9ms = 18'd215999;
parameter t_4_5ms = 17'd107999;
parameter t_13_5ms = 19'd323999;
parameter t_560us = 14'd13439;
parameter t_1_12ms = 15'd26879;
parameter t_1_68ms = 16'd40319;
parameter t_2_24ms = 16'd53759;
`endif
`ifdef CLK_50M
parameter t_38k = 11'd1315;
parameter t_38k_half = 10'd657;
parameter t_9ms = 19'd449999;
parameter t_4_5ms = 18'd224999;
parameter t_13_5ms = 20'd674999;
parameter t_560us = 15'd27999;
parameter t_1_12ms = 16'd55999;
parameter t_1_68ms = 17'd83999;
parameter t_2_24ms = 17'd111999;
`endif
parameter DATA_USER = 8'h00;
//---------------------------------//
//分频38Khz时钟
reg [10:0] cnt1;
wire clk_38k;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt1 <= 0;
end
else if(cnt1 == t_38k)
begin
cnt1 <= 0;
end
else cnt1 <= cnt1 + 1;
end
assign clk_38k = (cnt1<t_38k_half)?1:0;
//-------------------------------------------//
// wire key_1_flg;
// wire key_2_flg;
// key_shake U1(
// .clk_100M(clk),
// .rst_n(rst_n),
//
// .key_in(key_1),
// .key_out(key_1_flg)
// );
//
// key_shake U2(
// .clk_100M(clk),
// .rst_n(rst_n),
//
// .key_in(key_2),
// .key_out(key_2_flg)
// );
reg [2:0] key_1_flag;
wire key_1_neg;
wire key_1_pos;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
key_1_flag <= 3'b000;
end
else
begin
key_1_flag <= {key_1_flag[1:0],key_1};
end
end
assign key_1_pos = (key_1_flag[2:1]== 2'b01);
reg [2:0] key_2_flag;
wire key_2_neg;
wire key_2_pos;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
key_2_flag <= 3'b000;
end
else
begin
key_2_flag <= {key_2_flag[1:0],key_2};
end
end
assign key_2_pos = (key_2_flag[2:1] == 2'b01);
//------------------------------------------//
parameter IDEL = 3'D0; //初始化状态,等待发送命令
parameter START = 3'D1; //开始发送引导码
parameter SEND_USER = 3'D2; //发送用户码
parameter SEND_UNUSER= 3'D3; //发送用户反码
parameter SEND_DATA = 3'D4; //发送数据
parameter SEND_UNDATA= 3'D5; //发送数据反码
parameter FINISH = 3'D6; //发送结束码
parameter FINISH_1 = 3'D7; //发送结束
reg [2:0] state;
reg start_en;
wire start_over;
reg zero_en;
wire zero_over;
reg one_en;
wire one_over;
reg finish_en;
wire finish_over;
reg sendover;
reg [7:0] shiftdata;
reg [3:0] i;
reg [7:0] DATA;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
state <= IDEL;
start_en <= 0;
zero_en <= 0;
one_en <= 0;
finish_en <= 0;
sendover <= 0;
shiftdata <= 0;
i <= 0;
DATA <= 8'D0;
led_1 <= 1;
led_2 <= 1;
end
else
begin
case(state)
IDEL:
begin
start_en <= 0;
zero_en <= 0;
one_en <= 0;
finish_en <= 0;
sendover <= 0;
shiftdata <= 0;
i <= 0;
DATA <= 8'd0;
if(key_1_pos)
begin
state <= START;
DATA <= 8'd1;
end
else if(key_2_pos)
begin
state <= START;
DATA <= 8'd2;
end
else state <= IDEL;
end
START: //发送引导码
begin
if(start_over)
begin
start_en <= 0;
state <= SEND_USER;
shiftdata <= DATA_USER;
end
else
begin
start_en <= 1;
state <= START;
end
end
SEND_USER:
begin
// led_3 <= 1;
if((i==7)&&(one_over||zero_over)) //结束位
begin
i <=0;
shiftdata <= ~DATA_USER;
state <= SEND_UNUSER;
one_en <= 0;
zero_en <= 0;
end
else
begin
if(zero_over||one_over) //1bit发送结束
begin
i <= i + 1;
one_en <= 0;
zero_en <= 0;
end
else if(shiftdata[i])
begin
one_en <= 1;
end
else if(!shiftdata[i]) zero_en <= 1;
else
begin
i <= i ;
one_en <= one_en;
zero_en <= zero_en;
end
end
end
SEND_UNUSER:
begin
led_1 <= ~led_1;
if((i==7)&&(one_over||zero_over)) //结束位
begin
i <=0;
state <= SEND_DATA;
shiftdata <= DATA;
one_en <= 0;
zero_en <= 0;
end
else
begin
if(zero_over||one_over) //1bit发送结束
begin
i <= i + 1;
one_en <= 0;
zero_en <= 0;
end
else if(shiftdata[i])
begin
one_en <= 1;
end
else if(!shiftdata[i]) zero_en <= 1;
else
begin
i <= i ;
one_en <= one_en;
zero_en <= zero_en;
end
end
end
SEND_DATA:
begin
led_2 <= ~led_2 ;
if((i==7)&&(one_over||zero_over)) //结束位
begin
i <=0;
state <= SEND_UNDATA;
shiftdata <= ~DATA;
one_en <= 0;
zero_en <= 0;
end
else
begin
if(zero_over||one_over) //1bit发送结束
begin
i <= i + 1;
one_en <= 0;
zero_en <= 0;
end
else if(shiftdata[i])
begin
one_en <= 1;
end
else if(!shiftdata[i]) zero_en <= 1;
else
begin
i <= i ;
one_en <= one_en;
zero_en <= zero_en;
end
end
end
SEND_UNDATA:
begin
if((i==7)&&(one_over||zero_over)) //结束位
begin
i <=0;
shiftdata <= 0;
state <= FINISH;
one_en <= 0;
zero_en <= 0;
end
else
begin
if(zero_over||one_over) //1bit发送结束
begin
i <= i + 1;
one_en <= 0;
zero_en <= 0;
end
else if(shiftdata[i])
begin
one_en <= 1;
end
else if(!shiftdata[i]) zero_en <= 1;
else
begin
i <= i ;
one_en <= one_en;
zero_en <= zero_en;
end
end
end
FINISH:
begin
if(finish_over)
begin
finish_en <= 0;
state <= FINISH_1;
end
else
begin
finish_en <= 1;
state <= FINISH;
end
end
FINISH_1:
begin
sendover <= 1;
state <= IDEL;
end
default: state <= IDEL;
endcase
end
end
//----------------------------------------------//
//引导码,9ms载波加4.5ms空闲
reg [19:0] cnt2;
wire start_flag;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt2 <= 0;
end
else if(start_en)
begin
if(cnt2 >= t_13_5ms) cnt2 <= t_13_5ms+1;
else cnt2 <= cnt2 + 1;
end
else cnt2 <= 0;
end
assign start_over = (cnt2 == t_13_5ms)?1:0;
assign start_flag = (start_en&&(cnt2 <= t_9ms))?1:0;
//----------------------------------------------//
//比特0, 560us载波 + 560us空闲
reg [15:0] cnt3;
wire zero_flag;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt3 <= 0;
end
else if(zero_en)
begin
if(cnt3 >= t_1_12ms) cnt3 <= t_1_12ms+1;
else cnt3 <= cnt3 + 1;
end
else cnt3 <= 0;
end
assign zero_over = (cnt3 == t_1_12ms)?1:0;
assign zero_flag = (zero_en&&(cnt3 <= t_560us))?1:0;
//----------------------------------------------//
//比特1, 560us载波 + 1.68ms空闲
reg [16:0] cnt4;
wire one_flag;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt4 <= 0;
end
else if(one_en)
begin
if(cnt4 >= t_2_24ms) cnt4 <= t_2_24ms+1;
else cnt4 <= cnt4 + 1;
end
else cnt4 <= 0;
end
assign one_over = (cnt4 == t_2_24ms)?1:0;
assign one_flag = (one_en&&(cnt4 <= t_560us))?1:0;
//----------------------------------------------//
//结束码, 560us载波
reg [14:0] cnt5;
wire finish_flag;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt5 <= 0;
end
else if(finish_en)
begin
if(cnt5 >= t_560us) cnt5 <= t_560us+1;
else cnt5 <= cnt5 + 1;
end
else cnt5 <= 0;
end
assign finish_over = (cnt5 == t_560us)?1:0;
assign finish_flag = (finish_en&&(cnt5 <= t_560us))?1:0;
//-----------------------------------//
wire ir_out;
assign ir_out = start_flag||zero_flag||one_flag||finish_flag;
assign IR_out = ir_out&&clk_38k;
assign led_3 = i[1];
assign led_4 = i[0];
endmodule
接收程序:
/********************************Copyright**************************************
**----------------------------File information--------------------------
** File name :ir_resive.v
** CreateDate :2015.06
** Funtions : 中断接收程序。结束数据为:引导码+用户码+用户反码+数据码+数据反码。
** Operate on :M5C06N3L114C7
** Copyright :All rights reserved.
** Version :V1.0
**---------------------------Modify the file information----------------
** Modified by :
** Modified data :
** Modify Content:
*******************************************************************************/
module IR_resive (
clk,
rst_n,
ir_in,
led_error,
led_5,
led_6,
led_7,
test_data
);
input clk;
input rst_n;
input ir_in;
output led_error;
output led_5;
output led_6;
output led_7;
output [7:0] test_data;
//---------------------------------------------//
reg [2:0] ir_in_reg;
wire ir_in_pos;
wire ir_in_neg;
wire ir_in_change;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
ir_in_reg <= 3'b111;
end
else
begin
ir_in_reg <= {ir_in_reg[1:0],ir_in};
end
end
assign ir_in_pos = (ir_in_reg[2:1] == 2'b01)?1:0;
assign ir_in_neg = (ir_in_reg[2:1] == 2'b10)?1:0;
assign ir_in_change = ir_in_pos|ir_in_neg;
//------------------------------------//
//设计分频和计数部分:从1838T的 技术手册中,可以得出最小的脉冲持续时间为500us,在采样时可以对最小的电平采样16次,即对500us采样16次,
//则每次的采样间隔时间是 500us/16=31.25us 时钟频率为FCLK = X MHZ, 则最小采样计数为:N =31.25*X,
//然后再用一个计数器计数同一电平的采样计数时间。
//最后判断是leader的9ms 还是4.5ms,或是数据的 0 还是 1。
//--------------------------------------------------------//
`define FCLK_20M
// `define FCLK_24M `
`ifdef FCLK_20M
parameter t_31_25us = 10'd625;
parameter t_100k = 200;
`endif
`ifdef FCLK_24M
parameter t_31_25us = 10'd750; //
parameter t_100k = 240;
`endif
`ifdef FCLK_50M
parameter t_31_25us = 11'd1562; //
parameter t_100k = 500;
`endif
parameter t_low_H = 26;
parameter t_low_L = 13; //16
parameter t_high_H=67; //54 1.7MS左右
parameter t_high_L=35 ;
parameter t_9ms_H =9'd398; //288
parameter t_9ms_L =9'd278;
parameter t_4_5ms_H =9'd154; //144
parameter t_4_5ms_L =9'd134;
parameter t_watch = 9'd500; //定时,计数达到500,则已经跑飞,
parameter t_1s = 16'd31999;
//---------------------------------------------//
reg idel_flag;
reg [10:0] cnt;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt <= 0;
end
else if(idel_flag) cnt <= 0; //空闲状态,不再变化
else if(ir_in_change) cnt <= 0;
else if(cnt == t_31_25us) cnt <= 0;
else cnt<= cnt + 1;
end
reg [8:0] cnt1;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt1 <= 0;
end
else if(idel_flag) cnt1 <= 0;
else if(ir_in_change) cnt1 <= 0;
else if(cnt == t_31_25us) cnt1 <= cnt1 + 1;
else cnt1 <= cnt1;
end
wire t_9ms_flag;
wire t_4_5_ms_flag;
wire short_flag; //短电平,可是高电平也可以是低电平
wire long_flag; //长电平,肯定是高电平
assign t_9ms_flag = ((cnt1 > t_9ms_L)&&(cnt1 < t_9ms_H));
assign t_4_5_ms_flag = ((cnt1 > t_4_5ms_L)&&(cnt1 < t_4_5ms_H));
assign long_flag = ((cnt1 > t_high_L)&&(cnt1 < t_high_H));
assign short_flag = ((cnt1 > t_low_L)&&(cnt1 < t_low_H));
wire watchdog;
assign watchdog = (cnt1 > t_watch)?1:0;
//---------------------------------------------//
parameter IDEL = 4'd0;
parameter L_9MS = 4'd1;
parameter L_4_5MS = 4'd2;
parameter DATA_R = 4'd4;
parameter FINISH_R= 4'd8;
reg [3:0] state;
reg [31:0] shiftdata;
reg [5:0] n;
reg error_flag;
reg r_over;
reg [31:0] rdata;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
state <= IDEL;
shiftdata <= 0;
n <= 0;
error_flag <= 0;
rdata <= 0;
r_over<= 0;
idel_flag <= 0;
// led_5 <= 1;
// led_6 <= 1;
end
// else if(watchdog) state <= IDEL;
else
begin
case(state)
IDEL:
begin
idel_flag <= 1; //空闲状态
shiftdata <= 0;
n <= 0;
error_flag <= 0;
r_over<= 0;
if(ir_in_reg[1] ==0)
begin
state <= L_9MS; //检测到拉低数据线
idel_flag <= 0;
end
else state <= IDEL;
end
L_9MS: //9ms为低电平,数据线拉高时结束
begin
// led_5 <= 0;
if(watchdog) state <= IDEL;
else if(ir_in_pos)
begin
if(t_9ms_flag) state <= L_4_5MS;
else
begin
state <= IDEL;
error_flag <= 1;
end
end
else state <= L_9MS;
end
L_4_5MS:
begin
if(watchdog) state <= IDEL;
else if(ir_in_neg)
begin
if(t_4_5_ms_flag) state <= DATA_R;
else
begin
state <= IDEL;
error_flag <= 1;
end
end
else state <= L_4_5MS;
end
DATA_R:
begin
// led_6 <= 0;
if(watchdog) state <= IDEL;
else if((n == 32)&&(ir_in_reg[2:1] == 2'b11)) state <= FINISH_R;
else if(ir_in_pos)
begin
if(short_flag) state <= DATA_R;
else
begin
state <= IDEL;
error_flag <= 1;
end
end
else if(ir_in_neg)
begin
n<= n + 1;
if(short_flag) shiftdata[n] <= 0; //从低位到高位依次接收,这样数据的位置是 相反的
else if(long_flag) shiftdata[n] <= 1; //从原来的{用户码,用户反码,数据,数据反码}变为{数据反码,数据,用户反码,用户码}
else //所以要调整数据位置
begin
state <= IDEL;
error_flag <= 1;
end
end
else state <= DATA_R;
end
FINISH_R:
begin
r_over <= 1;
rdata <= {shiftdata[7:0],shiftdata[15:8],shiftdata[23:16],shiftdata[31:24]}; //调整位置
state <= IDEL;
end
default:state <= IDEL;
endcase
end
end
//---------------------------------------------//
assign led_5 = (rdata[15:8] == 8'h01)?0:1;
assign led_6 = (rdata[15:8] == 8'h02)?0:1;
assign led_7 = (rdata[31:24] == 8'h00)?0:1;
assign test_data = rdata[15:8];
// assign test_data = {error_flag,t_4_5_ms_flag,ir_in_change,ir_in_reg[1],state[3:0]};
endmodule
按键消抖(与以前有修改):
/********************************Copyright************************************** **----------------------------File information-------------------------- ** File name :key_shake.v ** CreateDate :2015.03 ** Funtions : 按键的消抖操作:在复位之后的100us内,不响应按键的操作,在之后有按键按下后,有20ms的延迟,之后输出按键输出. ** Operate on :M5C06N3L114C7 ** Copyright :All rights reserved[F]. ** Version :V1.0 **---------------------------Modify the file information---------------- ** Modified by : ** Modified data : 2015.04 2015.06 ** Modify Content:V1.1:clk-->clk_100M, 常数声明放到一起,便于修改。 增加实用20Mclk,并将输出修改为连续高电平 *******************************************************************************/ module key_shake ( clk_100M, rst_n, key_in, key_out ); input clk_100M; //100Mhz input rst_n; input key_in; output key_out; //-------------------------------------- //在复位之后的100us内,不响应按键的操作 // `define CLK_100M `define CLK_20M `ifdef CLK_100M parameter t_100us = 14'd9999; parameter t1ms = 17'd99999; //定时1ms parameter t_20ms = 5'd20; `endif `ifdef CLK_20M parameter t_100us = 14'd1999; parameter t1ms = 17'd19999; //定时1ms parameter t_20ms = 5'd20; `endif reg [13:0] cnt; reg key_en; //复位之后允许按键输入标志 always @(posedge clk_100M or negedge rst_n) begin if(!rst_n) begin cnt <= 0; key_en <=0; end else begin if(cnt == t_100us) begin key_en <= 1; end else begin key_en <= 0; cnt <= cnt + 1; end end end //-------------------------------------------------- wire HtoL_flag; //下降沿标志 wire LtoH_flag; //上升沿标志 reg [2:0] key_reg; always @(posedge clk_100M or negedge rst_n) begin if(!rst_n) begin key_reg <= 3'b111; //默认没按下状态为高,按下之后为低.反之则为3'b000; end else begin key_reg <= {key_reg[1:0],key_in}; end end assign HtoL_flag = key_en?(key_reg[2:1] == 2'b10):0; //下降沿检测,一个时钟的高电平 assign LtoH_flag = key_en?(key_reg[2:1] == 2'b01):0; //上升沿检测,一个时钟的高电平 //--------------------------------------------- reg cnt_en; //计数使能标志 reg [16:0] cnt2; always @(posedge clk_100M or negedge rst_n) begin if(!rst_n) begin cnt2 <= 17'd0; end else if((cnt_en)&&(cnt2 == t1ms)) begin cnt2 <= 17'd0; end else if(cnt_en) begin cnt2 <= cnt2 + 17'd1; end else cnt2 <= 17'd0; end reg [4:0] cnt3; always @(posedge clk_100M or negedge rst_n) begin if(!rst_n) begin cnt3 <= 5'd0; end else if((cnt_en)&&(cnt2 == t1ms)) begin if(cnt3 == t_20ms ) cnt3 <= t_20ms; else cnt3 <= cnt3 + 1; end else if(!cnt_en) cnt3 <= 5'd0; end //---------------------------------- //按键状态机 reg [2:0] i; reg key_down; //按键按下标志 reg key_up; //按键释放标志 always @(posedge clk_100M or negedge rst_n) begin if(!rst_n) begin key_down <= 0; key_up <= 0; i <= 0; cnt_en <= 0; end else begin case(i) 'd0: begin key_down <= 0; key_up <= 0; if(HtoL_flag) i <= 'd1; //检测到按下 else if(LtoH_flag) i <= 'd2; //检测到释放按键 else i <= 'd0; end 'd1: begin if(cnt3 == t_20ms ) begin if(!key_in) //检测到按键依然被按下 begin key_down <= 1; //按键按下成功 i <= 'd3; cnt_en <= 0; end else begin key_down <= 0; i <= 'd0; cnt_en <= 0; end end else cnt_en <= 1; end 'd2: begin if(cnt3 == t_20ms ) begin if(key_in) //检测到按键被释放 begin key_up <= 1; //按键释放成功 i <= 'd4; cnt_en <= 0; end else begin key_up <= 0; i <= 'd0; cnt_en <= 0; end end else cnt_en <= 1; end 'd3: begin if(key_in) begin key_down <= 0; i <= 'd0; end else i <= 'd3; end 'd4: begin if(!key_in) begin key_up <= 0; i <= 'd0; end else i <= 'd4; end default:i <= 'd0; endcase end end assign key_out = key_down; //当按键被按下有效时 // assign key_out = key_up; //当按键被释放后才有效时 endmodule
将两个程序合在一起的顶层文件:
/********************************Copyright**************************************
**----------------------------File information--------------------------
** File name :IR_TOP.v
** CreateDate :2015.06
** Funtions : 中断的顶层文件
** Operate on :M5C06N3F256C7
** Copyright :All rights reserved.
** Version :V1.0
**---------------------------Modify the file information----------------
** Modified by :
** Modified data :
** Modify Content:
*******************************************************************************/
module IR_TOP (
clk,
rst_n,
ir_in,
ir_out,
key_1,
key_2,
led_d1,
led_d2,
led_d3,
led_d4,
led_d5,
led_d6,
led_d7,
led_d8,
test_data
);
input clk;
input rst_n;
input key_1;
input key_2;
input ir_in;
output ir_out;
output led_d1;
output led_d2;
output led_d3;
output led_d4;
output led_d5;
output led_d6;
output led_d7;
output led_d8;
output [7:0] test_data;
//---------------------------------------------//
wire key_1_flag;
wire key_2_flag;
key_shake U1(
.clk_100M(clk),
.rst_n(rst_n),
.key_in(key_1),
.key_out(key_1_flag)
);
key_shake U2(
.clk_100M(clk),
.rst_n(rst_n),
.key_in(key_2),
.key_out(key_2_flag)
);
wire [7:0] data_t;
IR_send u1(
.clk(clk),
.rst_n(rst_n),
.key_1(key_1_flag),
.key_2(key_2_flag),
.IR_out(ir_out),
.led_1(led_d1),
.led_2(led_d2),
.led_3(led_d3),
.led_4(led_d4)
);
IR_resive u2(
.clk(clk),
.rst_n(rst_n),
.ir_in(ir_in),
.led_error(led_d8),
.led_5(led_d5),
.led_6(led_d6),
.led_7(led_d7),
.test_data(data_t)
);
//---------------------------------------------//
assign test_data = data_t;
endmodule
仿真图:
接收仿真图:


发送仿真图:


浙公网安备 33010602011771号