module timer #( parameter DW = 16, parameter AW = 12 )( input clk, //时钟 input rst, //同步复位,高电平有效 input [DW-1:0] din, //数据输入 input [AW-1:0] addr, //地址输入 input we, //高电平写使能 output reg[DW-1:0] dout, //数据输出 output reg T0_PWM_P,//输入端口 output reg T0_PWM_N,//输入端口 output reg T1_PWM_P,//输出端口 output reg T1_PWM_N,//输出端口 output reg intp_T0,//定时器T0[0]溢出中断,[1]比较中断 output reg intp_T1//定时器T1[0]溢出中断,[1]比较中断 ); /* 定时器T0/T1 --------------------------------------- 向上计数模式 计数器TCNTx达到上溢值TATSx,装入影子寄存器 计数值TCNTx小于比较值TCMPx,Tx_PWM_P为初始极性 计数值TCNTx越过比较值TCMPx后,Tx_PWM发生翻转 Tx_PWM_P与Tx_PWM_N为差分信号 --------------------------------------- 控制寄存器TCTR 低8位[7:0]控制T0,高8位[15:8]控制T1 [0]启动控制:置1开始计数,置0停止并复位 [1]极性控制:计数值大于比较值时,Tx_PWM_P=[1] --------------------------------------- 分频器: |->T0 clk->|div|--| |->T1 系统时钟送入分配器,分频器输出作为T0/T1的时钟源。 分频器计算公式 Fdiv=(N+1)F Fdiv:分配器输出频率 N :分频系数TDIV F :系统时钟频率 --------------------------------------- 影子寄存器 TDIV,TATSx,TCMPx有影子寄存器。 其作用是在分频器、定时器溢出时将设定值写入,防止计数器跑飞。 --------------------------------------- 定时器中断 定时器T0/T1发生溢出,会触发一次中断。 --------------------------------------- */ //地址定义 localparam TCTR_A = 12'h00;//定时器控制寄存器 localparam TDIV_A = 12'h01;//定时器分频系数寄存器 localparam TATS0_A = 12'h02;//定时器0上溢寄存器 localparam TCMP0_A = 12'h03;//定时器0比较值寄存器 localparam TCNT0_A = 12'h04;//定时器0当前值 localparam TATS1_A = 12'h05;//定时器1上溢寄存器 localparam TCMP1_A = 12'h06;//定时器1比较值寄存器 localparam TCNT1_A = 12'h07;//定时器1当前值 //寄存器定义 reg[15:0]TCTR; reg[15:0]TDIV; reg[15:0]TDIV_r;//影子寄存器 reg[15:0]TATS0; reg[15:0]TATS0_r;//影子寄存器 reg[15:0]TCMP0; reg[15:0]TCMP0_r;//影子寄存器 reg[15:0]TCNT0; reg[15:0]TATS1; reg[15:0]TATS1_r;//影子寄存器 reg[15:0]TCMP1; reg[15:0]TCMP1_r;//影子寄存器 reg[15:0]TCNT1; reg DIV_EN;//分频器输出使能 reg [15:0]DIV_CNT;//分频器计数器 //分频器 always @(posedge clk) begin if(rst) begin DIV_CNT<=16'h0; TDIV_r<=16'h0; end else begin if(DIV_CNT==TDIV_r) begin//分频器溢出 DIV_EN<=1'b1;//输出使能信号 DIV_CNT<=16'h0; if(TDIV_r!=TDIV)//写入影子寄存器 TDIV_r<=TDIV; end else begin//分频器计数+1 DIV_CNT<=DIV_CNT+1;//计数器+1 DIV_EN<=1'b0; end end end always @(posedge clk) begin if(rst) begin TCTR <= 16'h0; TDIV <= 16'h0; TATS0 <= 16'h0; TATS1 <= 16'h0; TCMP0 <= 16'h0; TCMP1 <= 16'h0; dout <= 16'h0; end else if(we) case (addr)//数据总线写入 TCTR_A: #0.1 TCTR <= din; TDIV_A: #0.1 TDIV <= din; TATS0_A: #0.1 TATS0 <= din; TCMP0_A: #0.1 TCMP0 <= din; TATS1_A: #0.1 TATS1 <= din; TCMP1_A: #0.1 TCMP1 <= din; default: ; endcase else begin case (addr)//数据总线读取 TCTR_A: #0.1 dout <= TCTR; TCNT0_A: #0.1 dout <= TCNT0; TCNT1_A: #0.1 dout <= TCNT1; default: dout <= 16'h0; endcase end end //计数器控制 always @(posedge clk) begin if(rst) begin TCNT0 <= 16'h0; TCNT1 <= 16'h0; intp_T0 <= 1'b0; intp_T1 <= 1'b0; end else begin if(TCTR[0]) begin//T0 if(TCNT0==TATS0_r) begin//定时器溢出 TCNT0 <= 16'h0;//置0 intp_T0 <= 1'b1;//T0溢出中断 TATS0_r <= TATS0;//写影子寄存器 TCMP0_r <= TCMP0;//写影子寄存器 end else begin TCNT0 <= TCNT0+1;//定时器+1 intp_T0 <= 1'b0; end end else begin//停止状态 TCNT0 <= 16'h0; intp_T0 <= 1'b0; TATS0_r <= TATS0; TCMP0_r <= TCMP0; end if(TCTR[8]) begin//T1 if(TCNT1==TATS1_r) begin//定时器溢出 TCNT1 <= 16'h0;//置0 intp_T1 <= 1'b1;//T1溢出中断 TATS1_r <= TATS1;//写影子寄存器 TCMP1_r <= TCMP1;//写影子寄存器 end else begin TCNT1 <= TCNT1+1;//定时器+1 intp_T0 <= 1'b0; end end else begin//停止状态 TCNT1 <= 16'h0; intp_T0 <= 1'b0; TATS1_r <= TATS1; TCMP1_r <= TCMP1; end end end //PWM产生 always @(*) begin if(TCNT0<=TCMP0_r) begin T0_PWM_P = TCTR[1]; T0_PWM_N = ~TCTR[1]; end else begin T0_PWM_P = ~TCTR[1]; T0_PWM_N = TCTR[1]; end if(TCNT1<=TCMP1_r) begin T1_PWM_P = TCTR[9]; T1_PWM_N = ~TCTR[9]; end else begin T1_PWM_P = ~TCTR[9]; T1_PWM_N = TCTR[9]; end end endmodule