对于电机这一块,我们专业也开了很多理论课,所以,对于直流电机的控制还是蛮熟悉的,只是都停留在理论知识上,今天终于实践了一把。大家如果对直流电机的特性和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视图