以下由特權(quán)同學(xué)的FPGA文檔摘取
Sin 曲線控制 step 脈沖信號(hào)生成的功能框圖如下所示。
基本實(shí)現(xiàn)原理
①判斷步進(jìn)電機(jī)驅(qū)動(dòng)的目標(biāo)頻率 stepper_delay_target 與當(dāng)前頻率 stepper_delay_current的值是否一致,若一致,則不做任何加速、減速操作,保持當(dāng)前速度運(yùn)行;若目標(biāo)頻率高于當(dāng)前頻率,則執(zhí)行加速;若目標(biāo)頻率低于當(dāng)前頻率,則執(zhí)行減速。
②在加速或減速控制開啟狀態(tài)下,1ms 分頻計(jì)數(shù)邏輯每個(gè) 1ms 產(chǎn)生一個(gè)高脈沖,用于切換當(dāng)前的速度。
③在每 1ms,步進(jìn)電機(jī)的速度都會(huì)加速或減速一定的頻率值,這個(gè)頻率值和勻加速總是“固定”不同,它是變化的。在低頻時(shí),速度變化量較大,而高速時(shí),速度變化量較小。這個(gè)速度到底如何變化?變化多少?我們現(xiàn)實(shí)用 matlab 產(chǎn)生了一個(gè) 0‐pi 的 sin 曲線,并且將曲線所對(duì)應(yīng)的 1024 個(gè) 16bit 數(shù)據(jù)存儲(chǔ)到了 FPGA 的片內(nèi) ROM 里(實(shí)際使用中,0~0.5pi 部分的上升曲線作為步進(jìn)電機(jī)加速的頻率曲線,而 0.5pi~pi 的下降曲線作為步進(jìn)電機(jī)減速的頻率曲線)。如圖所示,X 取值為 0~511 的曲線(左側(cè)曲線,取 0~0.5pi 的 512 個(gè)正弦值放大 32768倍,并且挪到 0 點(diǎn)以上)作為加速曲線,X 取值為 512~1023 的曲線(右側(cè)曲線,取 0.5pi~pi的 512 個(gè)正弦值放大 32768 倍)作為減速曲線。
那么這兩段曲線如何使用?
由于加速或減速所用到的 sin 查表值都是 512 個(gè),所以我們加速或減速所需經(jīng)過的中間頻率都是 512 個(gè)。對(duì)于加速操作,目標(biāo)頻率 stepper_delay_target,加速起始頻率stepper_delay_current 的差值,需要經(jīng)過 x 個(gè)中間加速頻率點(diǎn)(x 從 0 遞增到 511),我們可以算得當(dāng)前加速的 delta_speed_pulse = (stepper_delay_target ‐stepper_delay_current ) * (x 為地址對(duì)應(yīng)的 ROM 數(shù)據(jù))/32768,即最終用(stepper_delay_target ‐ delta_speed_pulse/32768)作為當(dāng)前頻率點(diǎn)。換句話說,就是用 sin 曲線作為整個(gè)加速過程的頻率差值,用目標(biāo)頻率減去這個(gè)差值,就可以得到從其實(shí)頻率逐漸靠近目標(biāo)頻率的加速過程,并且這個(gè)加速過程和圖示左側(cè)的曲線一樣越來越平滑。對(duì)于減速操作也類似,只不過它是用停止頻率或減速目標(biāo)頻率加上當(dāng)前 sin 曲線算出的頻率差值作為當(dāng)前中間頻率點(diǎn)。
④實(shí)際的 FPGA coding 中,必須把“頻率”換算為“周期”,便于計(jì)數(shù)。這個(gè)換算很簡單,用 1s 時(shí)間除以“頻率”值即可。而由于“周期”必須換算為“時(shí)鐘脈沖個(gè)數(shù)”為單位,所以我們把這個(gè)除法運(yùn)算中的“除數(shù)”也換算為“時(shí)鐘脈沖個(gè)數(shù)”為單位,因此 1s/20ns(時(shí)鐘周期為 20ns)即除數(shù) 50_000_000。
⑤算出了加速或減速過程中不斷變化的步進(jìn)電機(jī)驅(qū)動(dòng)的脈沖周期stepper_delay_current_period,就能夠產(chǎn)生步進(jìn)電機(jī)驅(qū)動(dòng)的脈沖了。文章來源:http://www.zghlxwxcb.cn/news/detail-787300.html
實(shí)際仿真的波形
以上勻加速/減速操作下,設(shè)定步進(jìn)電機(jī)的啟動(dòng)頻率為 500Hz,可以穩(wěn)定加速到 5KHz,加速時(shí)間需要 512*1ms = 512ms文章來源地址http://www.zghlxwxcb.cn/news/detail-787300.html
程序
module stepper_motor_controller(
input clk, //50MHz
input rst_n, //復(fù)位信號(hào),低電平有效
output stepper_motor_reset_n, //步進(jìn)電機(jī)復(fù)位信號(hào),低電平有效
output reg stepper_motor_en_n, //步進(jìn)電機(jī)驅(qū)動(dòng)信號(hào)輸出有效信號(hào),低電平有效
output reg stepper_motor_clk, //步進(jìn)電機(jī)的前進(jìn)脈沖,上升沿有效發(fā)起一個(gè)步進(jìn)電機(jī)轉(zhuǎn)動(dòng)
input stepper_work_en, //步進(jìn)電機(jī)使能
input[19:0] stepper_delay_target, //步進(jìn)電機(jī)兩次stpe之間的延時(shí),取值必須大于2,目標(biāo)延時(shí)值
output reg[19:0] stepper_delay_current //步進(jìn)電機(jī)兩次stpe之間的延時(shí),取值必須大于2,當(dāng)前延時(shí)值
);
parameter START_FRE = 20'd1000; //步進(jìn)電機(jī)起步頻率,單位Hz
parameter TIMER_1MS = 20'd50_000; //1ms定時(shí)計(jì)數(shù)最大值,時(shí)鐘為50MHz(20ns)
parameter CLK_NUMER_PERIORD = 32'd50_000_000; //除數(shù),單位20ns
//---------------------------------------------------------------------------
reg speed_up_en; //加速功能開啟
reg[1:0] speed_up_en_r; //加速寄存器打一拍
reg speed_down_en; //減速功能開啟
reg[1:0] speed_down_en_r;//減速寄存器打一拍
reg[19:0] stepper_cnt;
wire pos_speed_up_en; //speed_up_en上升沿,表示開始啟動(dòng)加速
wire pos_speed_down_en; //speed_down_en上升沿,表示開始啟動(dòng)減速
//---------------------------------------------------------------------------
//復(fù)位
assign stepper_motor_reset_n = rst_n;
//---------------------------------------------------------------------------
//1s加速/減速定時(shí)
reg[19:0] xcnt;
always @(posedge clk or negedge rst_n)
if(!rst_n) xcnt <= 20'd0;
else if(!speed_up_en && !speed_down_en) xcnt <= 20'd0;
else if(xcnt < (TIMER_1MS-1)) xcnt <= xcnt+1'b1;
else xcnt <= 20'd0;
wire motor_speed_change = (xcnt == (TIMER_1MS-1)); //ms定時(shí)信號(hào),高電平有效,切換速度
//---------------------------------------------------------------------------
//例化ROM,存儲(chǔ)sin輸出1024個(gè)0-pi的結(jié)果,放大1024倍
reg[9:0] rom_addr;
wire[15:0] rom_data;
blk_mem_gen_0 uut_blk_mem_gen_0 ( //IP核
.address ( rom_addr ),
.clock ( clk ),
.q ( rom_data )
);
//---------------------------------------------------------------------------
//勻加速、減速控制
//加速控制使能
always @(posedge clk or negedge rst_n)
if(!rst_n) speed_up_en <= 1'b0;
else if(motor_speed_change && (rom_addr == 10'd511)) speed_up_en <= 1'b0;
else if(((stepper_delay_current < stepper_delay_target) && stepper_work_en)) speed_up_en <= 1'b1;
else speed_up_en <= 1'b0;
always @(posedge clk)
speed_up_en_r <= {speed_up_en_r[0],speed_up_en}; //記錄電平變化
assign pos_speed_up_en = ~speed_up_en_r[1] & speed_up_en_r[0]; //speed_up_en上升沿,表示開始啟動(dòng)加速
//減速控制使能
always @(posedge clk or negedge rst_n)
if(!rst_n) speed_down_en <= 1'b0;
else if(motor_speed_change && (rom_addr == 10'd1023)) speed_down_en <= 1'b0;
else if(stepper_work_en) begin
if(stepper_delay_current > stepper_delay_target) speed_down_en <= 1'b1;
else speed_down_en <= 1'b0;
end
else begin
if(stepper_delay_current > START_FRE) speed_down_en <= 1'b1;
else speed_down_en <= 1'b0;
end
always @(posedge clk)
speed_down_en_r <= {speed_down_en_r[0],speed_down_en};
assign pos_speed_down_en = ~speed_down_en_r[1] & speed_down_en_r[0]; //speed_down_en上升沿,表示開始啟動(dòng)減速
wire neg_speed_down_en = speed_down_en_r[1] & ~speed_down_en_r[0];
//---------------------------------------------------------------------------
//ROM地址產(chǎn)生,對(duì)應(yīng)加速/減速參數(shù)選擇控制
always @(posedge clk or negedge rst_n)
if(!rst_n) rom_addr <= 10'd0;
else if(pos_speed_up_en) rom_addr <= 10'd0;
else if(pos_speed_down_en) rom_addr <= 10'd512;
else if(motor_speed_change && (speed_up_en || speed_down_en)) rom_addr <= rom_addr+1'b1;
else ;
//---------------------------------------------------------------------------
//乘法運(yùn)算
wire[35:0] mult_result;
reg[19:0] mult_datab;
reg[19:0] speed_up_start;
//鎖存加速起始頻率
always @(posedge clk or negedge rst_n)
if(!rst_n) speed_up_start <= 20'd0;
else if(pos_speed_up_en) speed_up_start <= stepper_delay_current;
//計(jì)算當(dāng)前運(yùn)行頻率和目標(biāo)頻率差
always @(posedge clk or negedge rst_n)
if(!rst_n) mult_datab <= 20'd0;
else if(pos_speed_up_en) mult_datab <= stepper_delay_target - stepper_delay_current; //加速
else if(pos_speed_down_en) begin
if(!stepper_work_en) mult_datab <= stepper_delay_current - START_FRE; //停止的減速
else mult_datab <= stepper_delay_current - stepper_delay_target; //運(yùn)行中減速
end
//頻率差*(加速頻率/32768)
mult_gen_0 uut_mult_gen_0 (
.clock ( clk ),
.dataa ( rom_data ),
.datab ( mult_datab ),
.result ( mult_result )
);
wire[19:0] delta_speed_down_pulse = mult_result[34:15]; //加速或減速頻率差值
wire[19:0] delta_speed_up_pulse = mult_result[34:15]; //加速或減速頻率差值
//---------------------------------------------------------------------------
//步進(jìn)電機(jī)使能控制
always @(posedge clk or negedge rst_n)
if(!rst_n) stepper_motor_en_n <= 1'b1;
else if(stepper_work_en) stepper_motor_en_n <= 1'b0;
else if(!stepper_work_en && (stepper_delay_current == START_FRE)) stepper_motor_en_n <= 1'b1;
//---------------------------------------------------------------------------
//步進(jìn)電機(jī)的step產(chǎn)生
//步進(jìn)電機(jī)當(dāng)前頻率產(chǎn)生
always @(posedge clk or negedge rst_n)
if(!rst_n) stepper_delay_current <= START_FRE;
else if(neg_speed_down_en) begin
if(stepper_work_en) stepper_delay_current <= stepper_delay_target;
else stepper_delay_current <= START_FRE;
end
else if(motor_speed_change) begin
if(stepper_work_en) begin
if(speed_up_en) stepper_delay_current <= speed_up_start + delta_speed_up_pulse;
else if(speed_down_en) stepper_delay_current <= stepper_delay_target + delta_speed_down_pulse;
else stepper_delay_current <= stepper_delay_target;
end
else begin
if(speed_down_en) stepper_delay_current <= START_FRE + delta_speed_down_pulse;
else stepper_delay_current <= START_FRE;
end
end
wire[19:0] stepper_delay_current_period;
wire[31:0] div_result;
div_gen_0 uut_div_gen_0 (
.clock ( clk ),
.denom ( stepper_delay_current ),
.numer ( CLK_NUMER_PERIORD ),
.quotient ( div_result ),
.remain ( )
);
assign stepper_delay_current_period = div_result[19:0];
reg[19:0] r_stepper_delay_current_period;
//步進(jìn)電機(jī)驅(qū)動(dòng)周期鎖存
always @(posedge clk or negedge rst_n)
if(!rst_n) r_stepper_delay_current_period <= 1'd0;
else if(stepper_cnt == 20'd0) r_stepper_delay_current_period <= stepper_delay_current_period;
//步進(jìn)電機(jī)時(shí)鐘頻率的計(jì)數(shù)
always @(posedge clk or negedge rst_n)
if(!rst_n) stepper_cnt <= 20'd0;
else if(stepper_cnt < r_stepper_delay_current_period[19:0]) stepper_cnt <= stepper_cnt+1'b1;
else stepper_cnt <= 20'd0;
//步進(jìn)電機(jī)時(shí)鐘頻率產(chǎn)生
always @(posedge clk or negedge rst_n)
if(!rst_n) stepper_motor_clk <= 1'b0;
else if(stepper_cnt < {1'b0,r_stepper_delay_current_period[19:1]}) stepper_motor_clk <= 1'b0;
else stepper_motor_clk <= 1'b1;
endmodule
到了這里,關(guān)于FPGA驅(qū)動(dòng)步進(jìn)電機(jī)-Sin曲線加速的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!