一、开发环境
- Verilog
- Quartus 13.1
- Modelsim
- 基于NEC协议
二、准备工作
2.1、需要具备的知识
- case
- always
- 时钟分频
- 状态机
2.2、红外线基础
- 8位地址和8位指令长度
地址用来区分不同的红外遥控器,指令是我们主要关注的部分。 - 地址和指令都将传输两次
传输顺序由先到后(地址码-地址反码-控制码-控制反码)这样做主要目的是确保数据的可靠。 - 脉冲位置调制
- 载波频率是38Khz
- 位持续的时间1.125ms以及2.25ms
三、代码部分
/*Copyright belong to afterdm@qq.com
*Create data 2020/11/18
*Last modified data 2020/11/24
*Version v1.0.0.3
*Descriptions infrared drive
*Please delete within 24 hours without special circumstances
*/
module infrared(
input clk,
input rst,
input signal,
output reg [7:0] command,
output reg repetition
);
//define parameter
/******define state machine*****/
parameter IFDState_setout = 5'b00001;
parameter IFDState_standard = 5'b00010;
parameter IFDState_select = 5'b00100;
parameter IFDState_getdata = 5'b01000;
parameter IFDState_command = 5'b10000;
/******define time duration*****/
parameter IFDstandard = 10'd900;
parameter IFDgetdata = 10'd450;
parameter IFDcommand = 10'd225;
parameter IFDhivalue = 10'd168;
parameter IFDlovalue = 10'd56;
/******define permissible error*/
parameter IFDpermissible = 4'd10;
//define reg
/******define div signal********/
reg divClk;
reg [8:0] divClkCount;
/******define timekeep**********/
reg IFDtimeFlag;
reg [5:0] IFDtimeCount;
/******define state machine*****/
reg [5:0] IFDstate, IFDnextState;
/******define data container****/
reg [5:0] IFDdataCount;
reg [31:0] IFDdata;
//div clk (the input clk is 50M, generate 0.1M = 10vs)
always @(posedge clk or negedge rst) begin
if(rst == 1'b0) begin
divClkCount <= 9'b0;
divClk <= 1'b0;
end
else if(divClkCount == 9'd249) begin
divClkCount <= 9'b0;
divClk <= ~divClk;
end
else begin
divClkCount <= divClkCount + 1'b1;
end
end
//state machine
always @(posedge divClk or negedge rst) begin
if(rst == 1'b0) begin
IFDstate <= IFDState_setout;
end
else begin
IFDstate <= IFDnextState;
end
end
//signal duration count
always @(posedge divClk or negedge rst) begin
if(rst == 1'b0) begin
IFDtimeCount <= 10'b0;
end
else if(IFDtimeFlag == 1'b1) begin
IFDtimeCount <= IFDtimeCount + 1'b1;
end
else begin
IFDtimeCount <= 10'b0;
end
end
//handle function
always @(posedge divClk or negedge rst) begin
if(rst == 1'b0) begin
IFDtimeFlag <= 1'b0;
IFDnextState <= IFDState_setout;
IFDdata <= 32'b0;
IFDdataCount <= 6'b0;
command <= 16'd0;
repetition <= 1'b0;
end
else begin
if(signal == 1'b0) begin
case(IFDstate)
IFDState_setout : begin
IFDtimeFlag <= 1'b1;
IFDnextState <= IFDState_standard;
end
IFDState_select : begin
IFDtimeFlag <= 1'b0;
if ((IFDtimeCount > IFDgetdata - IFDpermissible) &&
(IFDtimeCount < IFDgetdata + IFDpermissible)) begin
IFDnextState <= IFDState_getdata;
IFDdata <= 32'b0;
IFDdataCount <= 6'd0;
end
else if((IFDtimeCount > IFDcommand - IFDpermissible) &&
(IFDtimeCount < IFDcommand + IFDpermissible)) begin
IFDnextState <= IFDState_command;
repetition <= 1'b1;
end
else begin
IFDnextState <= IFDState_setout;
end
end
IFDState_getdata : begin
if(IFDtimeFlag == 1'b1) begin
IFDtimeFlag <= 1'b0;
IFDdataCount <= IFDdataCount + 1'b1;
if ((IFDtimeCount > IFDhivalue - IFDpermissible) &&
(IFDtimeCount < IFDhivalue + IFDpermissible)) begin
IFDdata <= {1'b1, IFDdata[31:1]};
end
else if((IFDtimeCount > IFDlovalue - IFDpermissible) &&
(IFDtimeCount < IFDlovalue + IFDpermissible)) begin
IFDdata <= {1'b0, IFDdata[31:1]};
end
else begin
IFDnextState <= IFDState_setout;
end
end
end
default : begin
end
endcase
end
else begin
case(IFDstate)
IFDState_setout : begin
IFDtimeFlag <= 1'b0;
end
IFDState_standard : begin
if ((IFDtimeCount > IFDstandard - IFDpermissible) &&
(IFDtimeCount < IFDstandard + IFDpermissible)) begin
IFDnextState <= IFDState_select;
IFDtimeFlag <= 1'b0;
end
else begin
IFDnextState <= IFDState_setout;
end
end
IFDState_select : begin
IFDtimeFlag <= 1'b1;
end
IFDState_getdata : begin
if(IFDdataCount == 6'd32) begin
if (((IFDdata[7:0] ^ IFDdata[15:8]) == 8'hff) &&
((IFDdata[23:16] ^ IFDdata[31:24]) == 8'hff)) begin
command <= IFDdata[23:16];
IFDnextState <= IFDState_setout;
end
else begin
IFDnextState <= IFDState_setout;
end
end
else begin
IFDtimeFlag = 1'b1;
end
end
IFDState_command : begin
repetition <= 1'b0;
IFDnextState <= IFDState_setout;
end
default : begin
end
endcase
end
end
end
endmodule