步进电机是一种能够将电脉冲信号转换成角位移或线位移的机电元件,它实际上是一种单相或多相同步电动机。单相步进电动机有单路电脉冲驱动,输出功率一般很小,其用途为微小功率驱动。多相步进电动机有多相方波脉冲驱动,用途很广。使用多相步进电动机时,单路电脉冲信号可先通过脉冲分配器转换为多相脉冲信号,在经功率放大后分别送入步进电动机各相绕组。每输入一个脉冲到脉冲分配器,电动机各相的通电状态就发生变化,转子会转过一定的角度(称为步距角)。正常情况下,步进电机转过的总角度和输入的脉冲数成正比;连续输入一定频率的脉冲时,电动机的转速与输入脉冲的频率保持严格的对应关系,不受电压波动和负载变化的影响。由于步进电动机能直接接收数字量的输入,所以特别适合于微机控制。
本实验是采用双四拍来控制四相步进电机的运行:AB-BC-CD-DA-AB;利用PWM信号控制电机,电机的各相电流大小取决于PWM信号的占空比,所以通过改变PWM信号的占空比来控制电机各相的电流。
//程序实现的功能:使用PWM方法来控制步进电机细分旋转,实现1/4细分(4.5°/步)控制和不细分控制(18°/步)。Key控制电机的正、反转,key2控制电机的正常运行和细分运行 module step_motor ( clk, rst_n, key1, key2, motor ); input clk; //系统时钟50MHZ; input rst_n; //复位信号,低电平有效; input key1; //控制电机正、反转; input key2; //控制电机的运行模式; output[3:0] motor; //步进电机的A、B、C、D四相; //键盘消抖 reg[1:0] key_r1; always @ (posedge clk or negedge rst_n) begin if(!rst_n) key_r1<=2'b11; else key_r1<={key1,key2}; end reg[1:0] key_r2; always @ (posedge clk or negedge rst_n) begin if(!rst_n) key_r2<=2'b11; else key_r2<=key_r1; end wire[1:0] neg_key1; assign neg_key1=(~key_r1)&(key_r2); reg[19:0] cnt; always @ (posedge clk or negedge rst_n) begin if(!rst_n) cnt<=20'd0; else if(neg_key1) cnt<=20'd0; else cnt<=cnt+1'b1; end reg[1:0] key_r3; always @ (posedge clk or negedge rst_n) begin if(!rst_n) key_r3<=2'b11; else if(cnt==20'hfffff) //当有按键按下时,延时20ms,再次读入按键值; key_r3<={key1,key2}; end reg[1:0] key_r4; always @ (posedge clk or negedge rst_n) begin if(!rst_n) key_r4<=2'b11; else key_r4<=key_r3; end wire[1:0] neg_key2; assign neg_key2=(~key_r3)&key_r4 ; reg [23:0] delay; always @ (posedge clk or negedge rst_n) begin if(!rst_n) delay<=24'd0; else delay<=delay+1'b1; end reg dir; //电机正、反转 always @ (posedge clk or negedge rst_n) begin if(!rst_n) dir<=1'b0; else if(neg_key2[1]) dir<=~dir; end reg mode ; //电机模式选择; always @ (posedge clk or negedge rst_n) begin if(!rst_n) mode<=1'b0; else if(neg_key2[0]) mode<=~mode; end wire speed_clk; // 电机转动速度控制时钟; assign speed_clk=(delay[23:0]==24'hffffff); //大约3HZ; reg[3:0] num; always @ (posedge clk or negedge rst_n) begin if(!rst_n) num<=4'b0000; else if(speed_clk) begin if(dir) num<=num+1'b1; else num<=num-1'b1; end end reg[3:0] motor_r ; always @ (posedge clk or negedge rst_n) begin if(!rst_n) motor_r<=4'd0; else if(speed_clk) begin case(num[1:0]) 2'b00 : motor_r<=4'b1100; 2'b01 : motor_r<=4'b0110; 2'b10 : motor_r<=4'b0011; 2'b11 : motor_r<=4'b1001; default :motor_r<=4'b0000; endcase end end wire pwm_clk; //pwm计数时钟; assign pwm_clk=(delay[6:0]==7'h7f); reg [3:0] pwm_cnt; //pwm计数器; always @(posedge clk or negedge rst_n) begin if(!rst_n) pwm_cnt<=4'd0; else if(pwm_clk) pwm_cnt<=pwm_cnt+1'b1; end reg[15:0] duty_ratio; //占空比; reg[3:0] pwm_out; always @ (posedge clk or negedge rst_n) //PWM A相通道; begin if(!rst_n) pwm_out[3]<=1'b0; else if(pwm_cnt[3:0]<duty_ratio[15:12]) pwm_out[3]<=1'b1; else pwm_out[3]<=1'b0; end always @ (posedge clk or negedge rst_n) //PWM B相通道; begin if(!rst_n) pwm_out[2]<=1'b0; else if(pwm_cnt[3:0]<duty_ratio[11:8]) pwm_out[2]<=1'b1; else pwm_out[2]<=1'b0; end always @ (posedge clk or negedge rst_n) //PWM C相通道; begin if(!rst_n) pwm_out[1]<=1'b0; else if(pwm_cnt[3:0]<duty_ratio[7:4]) pwm_out[1]<=1'b1; else pwm_out[1]<=1'b0; end always @ (posedge clk or negedge rst_n) //PWM D相通道; begin if(!rst_n) pwm_out[0]<=1'b0; else if(pwm_cnt[3:0]<duty_ratio[3:0]) pwm_out[0]<=1'b1; else pwm_out[0]<=1'b0; end always @ (*) //四项步进电机pwm 细分参数表; begin case(num) 4'h0 : duty_ratio=16'hf000; 4'h1 : duty_ratio=16'he600; 4'h2 : duty_ratio=16'hbb00; 4'h3 : duty_ratio=16'h6e00; 4'h4 : duty_ratio=16'h0f00; 4'h5 : duty_ratio=16'h0e60; 4'h6 : duty_ratio=16'h0bb0; 4'h7 : duty_ratio=16'h06e0; 4'h8 : duty_ratio=16'h00f0; 4'h9 : duty_ratio=16'h00e6; 4'ha : duty_ratio=16'h00bb; 4'hb : duty_ratio=16'h006e; 4'hc : duty_ratio=16'h000f; 4'hd : duty_ratio=16'h600e; 4'he : duty_ratio=16'hb00b; 4'hf : duty_ratio=16'he006; default : duty_ratio=16'h0000; endcase end assign motor=mode? pwm_out :motor_r; //输出模块选择(细分/正常) endmodule