掛載完U盤(pán)并且進(jìn)行內(nèi)存訪問(wèn),剩余空間讀取以后,進(jìn)入WorkingFromSDfile函數(shù),這是主函數(shù)中while循環(huán)之前的最后一個(gè)函數(shù),也是程序的重頭戲。
res = f_open(&file,"0:/test/data.nc", FA_OPEN_EXISTING | FA_READ);
用上面的指令打開(kāi)U盤(pán)目錄下的DATA.NC的G代碼文件以后,繼續(xù)判斷返回的參數(shù)RES,這個(gè)參數(shù)一直需要判斷,如果FR_OK,才可以繼續(xù)往下執(zhí)行。我們先分配一個(gè)100個(gè)字節(jié)單元的空間:
char riadok[100];
然后將U盤(pán)中前100char的內(nèi)容讀取出來(lái),讀完一次len++后,執(zhí)行
gc_execute_line函數(shù),此函數(shù)用于執(zhí)行100char單元的命令,其中命令不能有非法格式,我們打開(kāi)一個(gè)客戶(hù)發(fā)送給我們的NC文件看一下。
G0X29.385Y118.536Z1.000F10000
G1Z-2.000F10000
G1X28.533Y119.424F10000
X28.144Y119.886
X27.936Y120.202
首先,將G代碼進(jìn)行分組,和進(jìn)行模式判斷并且設(shè)置相應(yīng)的結(jié)構(gòu)體,結(jié)構(gòu)體的定義如下:
typedef struct {
? uint8_t status_code;? ? ? ? ? ? // 解析器狀態(tài)
? uint8_t motion_mode;? ? ? ? ? ? //運(yùn)動(dòng)模式 {G0, G1, G2, G3, G80}
? uint8_t inverse_feed_rate_mode;? // {G93, G94}
? uint8_t inches_mode;? ? ? ? ? ? // 單位
? uint8_t absolute_mode;? ? ? ? ? // 絕對(duì)位移/相對(duì)位移
? uint8_t program_flow;? ? ? ? ? ? // 程序流
? int8_t spindle_direction;? ? ? ? // 主軸方向
? uint8_t coolant_mode;? ? ? ? ? ? //冷卻液使能
? float feed_rate;? ? ? ? ? ? ? ? // 給進(jìn)速率
? float position[3];? ? ? ? ? ? ? //主軸位置
? uint8_t tool;? ? ? ? ? ? ? ? ? ? ? //主軸/工具
? uint8_t plane_axis_0,
? ? ? ? ? plane_axis_1,
? ? ? ? ? plane_axis_2;? ? ? ? ? ? // 選擇水平面軸
? uint8_t coord_select;? ? ? ? ? ? // G54,具體看指令
? float coord_system[N_AXIS];? ? ? // G54+,具體看指令? ? ? ? ?
? float coord_offset[N_AXIS];? ? ? //? ?
uint16_t rpm; //主軸轉(zhuǎn)速
} parser_state_t;
1、第一步為G代碼的解析,將具體的G代碼進(jìn)行分組和模式設(shè)置,也就是判斷為G0,則解析器知道了下面的工作是快速定位到某一個(gè)坐標(biāo)。
比如G0X29.385Y118.536Z1.000F10000表達(dá)的意思是:以10000的速度,快速移動(dòng)到XYZ坐標(biāo)。
我們?cè)O(shè)置結(jié)構(gòu)體GC的模式為運(yùn)動(dòng)模式,并且具體為#define MOTION_MODE_SEEK 0 //
G0:快速搜尋到具體位置。
2、參數(shù)處理:?jiǎn)挝槐仨毥y(tǒng)一,否則解析器不認(rèn)。
用next_statement將字母取出來(lái),這里,G0已經(jīng)讀完了,繼續(xù):
case 'X': target[X_AXIS] = to_millimeters(value); bit_true(axis_words,bit(X_AXIS)); break;
? ? ? case 'Y': target[Y_AXIS] = to_millimeters(value); bit_true(axis_words,bit(Y_AXIS)); break;
? ? ? case 'Z': target[Z_AXIS] = to_millimeters(value); bit_true(axis_words,bit(Z_AXIS)); break;
3、根據(jù)不同的指令類(lèi)型,設(shè)置完GC的結(jié)構(gòu)體以后,我們已經(jīng)把該條指令解讀完成了,下一步當(dāng)然就是實(shí)際執(zhí)行該條指令了,用到了下一個(gè)重要的函數(shù)protocol_execute_runtime。
protocol_execute_runtime
此函數(shù)定義在? protocol.c中,指令并不會(huì)馬上執(zhí)行,而是要等待調(diào)度器的調(diào)度。進(jìn)入此函數(shù)后,首先判斷一下是否有系統(tǒng)故障產(chǎn)生,如果嚴(yán)重,GRBL會(huì)直接退出,具體操作是:
回報(bào)故障信息,調(diào)用bit_false設(shè)置系統(tǒng)參數(shù)execute,通知不要再解析了,已經(jīng)出故障了,等這一位設(shè)置完成以后,等待重新上電或者復(fù)位才能繼續(xù)運(yùn)行。
如果出現(xiàn)了系統(tǒng)中斷情況,繼續(xù)處理完,接著處理下面的重要函數(shù):
st_feed_hold,在減速階段,進(jìn)行FEED的保持。接著將系統(tǒng)的結(jié)構(gòu)體配置完成:
typedef struct {
? uint8_t abort;? ? ? ? ? ? ? ? //系統(tǒng)中止
? uint8_t state;? ? ? ? ? ? ? ? // GRBL的當(dāng)前狀態(tài)
? volatile uint8_t execute;? ? ? //系統(tǒng)運(yùn)行狀態(tài)
? int32_t position[N_AXIS];? ? ? // 實(shí)時(shí)位置
? uint8_t auto_start;? ? ? ? ? ? // 自動(dòng)重啟
} system_t;
之后就可以等待單步執(zhí)行完成了,具體調(diào)度器是如何控制定時(shí)器,輸出一定頻率的脈沖,我們這里主要用到了定時(shí)器2,在定時(shí)器2的中斷程序中有很復(fù)雜的運(yùn)算。
定時(shí)器的中斷服務(wù)程序定義在? stepper.c 中,而定時(shí)器的初始化則定義在函數(shù)st_init中.
STEPPER.C是直接驅(qū)動(dòng)步進(jìn)電機(jī)的程序,在文件中,首先申明了一個(gè)步進(jìn)電機(jī)的結(jié)構(gòu)體,如下:
typedef struct {
? // 使用BRESENHAM算法
? int32_t counter_x,? ? ? ? // 繪制直線的XYZ參數(shù)
? ? ? ? ? counter_y,
? ? ? ? ? counter_z;
? uint32_t event_count;
? uint32_t step_events_completed;? // 完成此運(yùn)動(dòng)需要的步數(shù)量
//下面用于梯形的產(chǎn)生
? uint32_t cycles_per_step_event;? ? ?
? uint32_t trapezoid_tick_cycle_counter;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? uint32_t trapezoid_adjusted_rate;? ? ?
? uint32_t min_safe_rate;
} stepper_t;
此結(jié)構(gòu)體用于TIM2的中斷函數(shù)中,具體TIM2如何用,需要怎么樣的配置,在移植的時(shí)候很關(guān)鍵,下一篇再解讀。