对于电机这一块,我们专业也开了很多理论课,所以,对于直流电机的控制还是蛮熟悉的,只是都停留在理论知识上,今天终于实践了一把。大家如果对直流电机的特性和PWM技术不熟悉,可以查看相关的资料就可以了。

下面是控制电路

    当motor_a是高电平时,Q3,Q1,Q5导通,A端位高电平,B端为低电平,直流电机正转;由于Q5的集电极通过一个二极管连接到H桥的另外一个控制端motor_b,将motor_b的电压钳在1.0V以下,所以,不管motor_b输出高电平还是地电平,Q6、Q4、Q2都会截止,不会造成H桥短路;

   当motor_a是低电平时,Q3,Q1,Q5截止,motor_b输出的电平可以控制电机的反转或停机。当motor_b输出高电平时,Q6,Q4,Q2导通,A端为低电平,B端为高电平,电机反转;当motor_b输出为低电平时,Q6,Q4,Q2截止;电机停机;

//程序实现的功能:利用FPGA产生PWM技术来控制直流电机的停、起;正、反转;加减速
module dc_motor
      (
       clk,
       rst_n,
       key1,
       key2,
       key3,
       motor_a,
       motor_b
      );

input       clk;       //系统时钟 50MHZ;
input       rst_n;     //复位信号,低电平有效;
input       key1;      //控制电机加速、减速;
input       key2;      //控制电机启、停;
input       key3;      //控制电机正、反转;
output      motor_a;   //直流电机的两个控制端;
output      motor_b;   

wire[3:0] duty_ratio ;      //占空比,
wire pwm_out    ;           //pwm输出;
wire pwm_en;                //pwm使能信号;
 
pwm      pwm
         (
          .clk(clk),
          .rst_n(rst_n),
          .duty_ratio(duty_ratio),
          .pwm_en(pwm_en),
          .pwm_out(pwm_out)

         );

motor_control   motor_control
           (
             .clk(clk),
             .rst_n(rst_n),
             .key1(key1),
             .key2(key2),
             .key3(key3),
             .pwm_in(pwm_out),
             .duty_ratio(duty_ratio),
             .pwm_en(pwm_en),
             .motor_a(motor_a),
             .motor_b(motor_b)
                      
           ); 

            
endmodule         


module pwm
    (
      clk,
      rst_n,
      pwm_en,
      duty_ratio,
      pwm_out 
       
    );

input     clk;       
input     rst_n;
input     pwm_en;       //pwm使能信号;
input[3:0]duty_ratio;   //占空比;
output    pwm_out;      //pwm输出;

reg[15:0] cnt;        //PWM内部计数器;
always @(posedge clk or negedge rst_n)
  begin
      if(!rst_n)
        cnt<=16'd0;
      else if(pwm_en)
        cnt<=cnt+1'b1;  
  end  
  
reg pwm_out_r;
always @ (posedge clk or negedge rst_n)
  begin
        if(!rst_n)
           pwm_out_r<=1'b0;
        else if((pwm_en)&&(cnt[15:12]<=duty_ratio)) 
           pwm_out_r<=1'b1;
        else
           pwm_out_r<=1'b0;     
  end

assign pwm_out=pwm_out_r;
endmodule    

module motor_control
        (
         clk,
         rst_n,
         key1,
         key2,
         key3,
         pwm_in,
         pwm_en,
         duty_ratio,
         motor_a,
         motor_b
         
        );
 
input      clk;           //系统时钟 50MHZ;
input      rst_n;         //复位信号,低电平有效;
input      key1;          //控制电机加速、减速;
input      key2;          //控制电机启、停;
input      key3;          //控制电机正、反转;
input      pwm_in;        //pwm输入;
output     pwm_en;        //pwm使能;
output[3:0]duty_ratio;    //占空比;
output     motor_a;       //直流电机的两个控制端;
output     motor_b;        

//键盘消抖;
reg[2:0] key_r1;
always @ (posedge clk  or negedge rst_n)
  begin
       if(!rst_n)
         key_r1<=3'b111;
       else
        key_r1<={key1,key2,key3} ; 
  end  
      
reg[2:0] key_r2;
always @ (posedge clk or negedge rst_n)
  begin
       if(!rst_n)
         key_r2<=3'b111;
       else
        key_r2<=key_r1; 
  end  

wire[2:0] neg_key1;
assign neg_key1=(~key_r1)&key_r2;    // 脉冲下降沿检测;

reg [19:0]   time_cnt;     
always @(posedge clk or negedge rst_n)
 begin
       if(!rst_n)
          time_cnt<=20'd0;
       else if(neg_key1)      //检测到有按键按下,延时20ms;
         time_cnt<=20'd0;
       else
         time_cnt<=time_cnt+1'b1;    
 end 

reg[2:0] key_r3;
always @(posedge clk or negedge rst_n)
  begin
      if(!rst_n)
         key_r3<=3'b111;
      else if(time_cnt==20'hfffff)    //延时20ms后再次检测;
         key_r3<={key1,key2,key3};  
  end
  
reg[2:0] key_r4;
always @ (posedge clk  or negedge rst_n)
  begin
       if(!rst_n)
         key_r4<=3'b111;
       else
        key_r4<=key_r3; 
  end 

wire[2:0] neg_key2;
assign neg_key2=(~key_r3)&(key_r4);

//控制电机;

reg[3:0]  duty_ratio_r;
always @ (posedge clk or negedge rst_n)
  begin
       if(!rst_n)
         duty_ratio_r<=4'd0;
       else if(neg_key2[2])  
         duty_ratio_r<=duty_ratio+1'b1;       //电机加减速;
  end  
  
assign duty_ratio=duty_ratio_r;

reg pwm_en_r;
always @ (posedge clk or negedge rst_n)
  begin
       if(!rst_n)
         pwm_en_r<=1'b0;
        else if(neg_key2[1])                  //电机停起;
         pwm_en_r=~pwm_en_r; 
  end 
  
assign  pwm_en=pwm_en_r;

reg motor_dir;
always @ (posedge clk or negedge rst_n)
  begin
     if(!rst_n)
       motor_dir<=1'b0;
     else if(neg_key2[0])
       motor_dir<=~motor_dir;              //电机正反转;
  end
   
assign  motor_a=motor_dir? pwm_in:1'b0;
assign  motor_b=motor_dir? 1'b0:pwm_in;
    
endmodule        

 

RTL视图