🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] > # 说明 因为平时经常要驱动步进电机,在这里写一个简单的驱动四相八拍电机,这个模块主要是为了配合MCU,MCU给出方向,步进步数,然后给一个上升沿的触发信号就可以了。 > # 组成模块 ## 定时器模块 用于产生驱动步进电机的脉冲,可对时钟进行分频 timer: ```verilog `timescale 1ns / 1ps // ******************************************************************** // FileName : timer.v // Author :hpy // Email :yuan_hp@qq.com // Date :2020年11月23日 // Description :一个用verilog实现的定时器 // -------------------------------------------------------------------- module timer #(parameter WIDTH = 32)( input clk, input rst_n, input [ WIDTH - 1 : 0 ] T, //周期 input [ WIDTH - 1 : 0 ] duty, //占空比 output reg[ 0 : 0 ] intr , //中断信号 output pwm //输出pwm ); reg[ WIDTH - 1 : 0 ] Cnt; reg[ 0 : 0 ] pwm_reg; assign pwm = (T==0)? 0 : (T == 1)? clk : pwm_reg; always@(posedge clk or negedge rst_n) begin if(!rst_n)begin Cnt <= 0; intr <= 0; end else begin if(Cnt >= T - 1'b1) begin Cnt <= 0; intr <= 1'b1; end else begin Cnt <= Cnt + 1'b1; intr <= 1'b0; end pwm_reg <= (Cnt<= duty)?1'b1:1'b0; end end endmodule ``` ## 可控脉冲生成模块 用于生成给定步数的脉冲 MultiPluseGen.v ```verilog `timescale 1ns / 1ps // ******************************************************************** // FileName : MultiPluseGen.v // Author :hpy // Email :yuan_hp@qq.com // Date :2020年11月24日 // Description :触发一次产生多个脉冲,脉冲个数可控 // -------------------------------------------------------------------- module MultiPluseGen #( parameter integer WIDTH = 32 )( input clk, // input rst_n, input en, input start, //触发信号标志, 上升沿触发 input [ WIDTH - 1 : 0] step,//产生的脉冲个数 input [ WIDTH - 1 : 0] period, //产生的脉冲周期,对clk的分频 output pluse, output done //一次触发完成标志,1 触发完成 0 等待触发或者触发中 ); wire start_p ,work_clk ; reg start_f1; reg [ WIDTH - 1 : 0 ] cnt , step_reg ; assign start_p = start & ~start_f1; //check posedge assign pluse = ((cst == S1) && en )? work_clk : 1'b0; assign done = cst == S0; localparam S0 = 1'b0, S1 = 1'b1; reg [0:0] cst,nst; always@(posedge work_clk or negedge rst_n) begin if(!rst_n)start_f1 <= 0; else if(en)start_f1 <= start; end //go to next status always@(posedge work_clk or negedge rst_n) begin if(!rst_n)begin cst <= S0; end else begin cst <= en ? nst : cst; end end // // always@(*) begin //nst = S0; case(cst) S0: nst = (en & start_p) ? S1 : S0; // if en and check the posedge of start,go to S1 status S1: nst = ((1==en) && (cnt>= step_reg)) ? S0:S1; default: nst = S0; endcase end always @ (posedge work_clk or negedge rst_n ) begin if(!rst_n)begin cnt <= 0; step_reg <= 0; end else begin if(en)begin if((cst == S0) && (start_p==1'b1)) begin cnt <= 1; step_reg <= step; end else if(nst == S1) cnt <= cnt + 1; else cnt <= 0; end end end wire [WIDTH - 1 : 0]duty; assign duty = (period >> 1) - 1'b1; wire sclk; assign sclk = en ; timer timer_inst ( .clk(clk), .rst_n(rst_n), .T(period), //周期 .duty(duty), //占空比 .pwm(work_clk) ); endmodule ``` ## 将脉冲转化为输出的模块 StepMotor.v ```verilog `timescale 1ns / 1ps // ******************************************************************** // FileName : StepMotor48.v // Author :hpy // Email :yuan_hp@qq.com // Date :2020年11月24日 // Description :这是五线四相电机驱动模块(四象八拍电机) pwm --> 驱动 // -------------------------------------------------------------------- module StepMotor48( input pwm, input rst_n, input en, input dir, output reg [3:0] driver ); reg [7:0] cst, nst; // status localparam S0 = 4'b1000, S1 = 4'b1100, S2 = 4'b0100, S3 = 4'b0110, S4 = 4'b0010, S5 = 4'b0011, S6 = 4'b0001, S7 = 4'b1001; // go to next state transition always @(posedge pwm or negedge rst_n) begin if(!rst_n)begin cst = S0; end else begin if(en) cst = nst; end end //state transition always @ (cst) begin nst = S0; case(cst) S0: nst = en? S1 :S0 ; S1: nst = en? S2 :S1 ; S2: nst = en? S3 :S2 ; S3: nst = en? S4 :S3 ; S4: nst = en? S5 :S4 ; S5: nst = en? S6 :S5 ; S6: nst = en? S7 :S6 ; S7: nst = en? S0 :S7 ; default:nst = S0; endcase end //out integer i; always@(posedge pwm or negedge rst_n) begin if(! rst_n )begin driver = S0; end else begin if(en)begin if(dir) driver = nst; else for(i=0;i<4;i=i+1) driver[i] = nst[3-i] ; end end end endmodule ``` ## 仿真时序生成 tb.v ```verilog `timescale 1ns / 1ps module tb ; reg clk,rst_n; //生成始时钟 parameter NCLK = 20; //此时时钟为50MHz initial begin clk=0; forever clk=#(NCLK/2) ~clk; end /****************** ADD module inst ******************/ reg [31:0] step; reg start,dir , en; wire done, pluse; MultiPluseGen #(.WIDTH(32)) MultiPluseGen_inst ( .clk(clk), // .rst_n(rst_n), .en(en), .start(start), //触发信号标志, 上升沿触发 .step(step),//产生的脉冲个数 .period(5), //产生的脉冲周期,对clk的分频 .done(done), //一次触发完成标志,1 触发完成 0 等待触发或者触发中 .pluse(pluse) ); StepMotor48 motor( .pwm(pluse), .rst_n(rst_n), .en(en), .dir(dir) ); /****************** --- module inst ******************/ initial begin $dumpfile("wave.lxt2"); $dumpvars(0, tb); //dumpvars(深度, 实例化模块1,实例化模块2,.....) end initial begin rst_n = 1; start = 0; dir = 0; step=0; #(NCLK) rst_n=0; #(NCLK) rst_n=1; //复位信号 repeat(10000) @(posedge MultiPluseGen_inst.work_clk)begin # 1 ; //作为延时时间 if(done)begin start = $random; en = $random; dir = $random; if(start)step[3:0] = $random; end else start = 0; end $display("运行结束!"); $dumpflush; $finish; $stop; end endmodule ``` > # 仿真结果 ![](https://img.kancloud.cn/66/e8/66e838be940c8f9cf9f5c3a9c2fc844c_1110x324.png)