因为在研究 成品 激光雕刻机 时, 发现 GRBL 代码基本上都改了,主要是 通讯接通 和上位机 界面。
本节笔记开始学习下位机,希望能够理解其控制基本原理。
下载winavr(http://sourceforge.net/projects/winavr/files/),是一个编译器,
打开软件如下,
把GRBL下位机源文件中的 *.h 和 *.c 文件加入,再加入 makefile 文件, 点击 make all
即可生成 hex 文件。
*************************************************
GRBL 自带文档 的介绍,大致结构如下,
'protocol' : Accepts command lines from the serial port and passes them to 'gcode' for execution. Provides status responses for each command. Also manages run-time commands set by the serial interrupt.
'gcode' : Recieves gcode from 'protocol', parses it according to the current state
of the parser and issues commands via '..._control' modules
'spindle_control' : Commands for controlling the spindle.
'motion_control' : Accepts motion commands from 'gcode' and passes them to the 'planner'. This module
represents the public interface of the planner/stepper duo.
'planner' : Receives linear motion commands from 'motion_control' and adds them to the plan of
prepared motions. It takes care of continuously optimizing the acceleration profile
as motions are added.
'stepper' : Executes the motions by stepping the steppers according to the plan.
-------------------------------------------------------------
*****************************
对 serial.h 的理解
定义串口通讯底层函数
*****************************
#ifndef serial_h
#define serial_h
内容
#endif
标志头文件格式,防止 头文件 被重复引用。
******************************
内容1
#include "nuts_bolts.h"
包含头文件 nuts_bolts.h
nuts_bolts.h - Header file for shared definitions, variables, and functions.
共享 定义、变量和函数
************************
内容2
#ifndef RX_BUFFER_SIZE
#define RX_BUFFER_SIZE 128
#endif
从字面意思可以看出,定义接收缓存 为 128。
同理,
#ifndef TX_BUFFER_SIZE
#define TX_BUFFER_SIZE 64
#endif
***********************
内容3
#define SERIAL_NO_DATA 0xff
从字面意思,串口无数据
不知道要用在哪里?
***********************
内容4
#ifdef ENABLE_XONXOFF
#define RX_BUFFER_FULL 96 // XOFF high watermark
#define RX_BUFFER_LOW 64 // XON low watermark
#define SEND_XOFF 1
#define SEND_XON 2
#define XOFF_SENT 3
#define XON_SENT 4
#define XOFF_CHAR 0x13
#define XON_CHAR 0x11
#endif
不知道怎么用? 也不知道 watermark 水印 是什么意思?
************************
内容5
void serial_init();
字面理解,串口初始化函数。
************************
内容6
void serial_write(uint8_t data);
字面理解,将数据 data 写入串口。
************************
内容7
uint8_t serial_read();
字面理解, 从串口读出数据。
***********************
内容8
void serial_reset_read_buffer();
Reset and empty data in read buffer.
Used by e-stop and reset.
清空读缓存。
***************************************************
winavr编程提示,
uint8_t 在 stdint.h 被定义,typedef unsigned char uint8_t
从 serial.h 上看, serial.h 定义了 串口通讯的底层函数,即使不理解如何实现关系也不大,只需记住函数功能就可以了,如何实现已经被 serial.c 封装了。
-------------------------------------------------------------------------
**************************
serial.c 的理解 上
只需要理解功能,怎样实现可以暂时简单了解
low level functions for sending and recieving bytes via the serial port
***************************
内容1
#include
#include "serial.h"
#include "config.h"
#include "motion_control.h"
#include "protocol.h"
需要的头文件,
1、 定义中断 ISR,
2、serial.h 好理解
3、config.h 该文件 compile time configuration
This file contains compile-time configurations for Grbl's internal system.
For the most part, users will not need to directly modify these, but they are here for specific needs, i.e. performance tuning or adjusting to non-typical machines.
这个文件很特殊,90%的内容是解释,只有10%是代码。
需要专门一篇文章来学习。
4、motion_control.h
- high level interface for issuing motion commands
会另外开一篇文章学习
5、protocol.h
- the serial protocol master control unit
也会另外开一篇文章学习。
*****************************************
内容2
uint8_t rx_buffer[RX_BUFFER_SIZE];
uint8_t rx_buffer_head = 0;
uint8_t rx_buffer_tail = 0;
uint8_t tx_buffer[TX_BUFFER_SIZE];
uint8_t tx_buffer_head = 0;
volatile uint8_t tx_buffer_tail = 0;
目测是环形队列格式,输出 和 接收 都是 采用环形队列,感觉会有一定难度
tx_buffer_tail 前 加了一个 volatile 声明,说明 tx_buffer_tail 可能会被 几个 子程序 共享。
*******************************************
内容3
#ifdef ENABLE_XONXOFF
volatile uint8_t flow_ctrl = XON_SENT; // Flow control state variable
static uint8_t get_rx_buffer_count()
{
if (rx_buffer_head == rx_buffer_tail)
{ return(0); }
if (rx_buffer_head < rx_buffer_tail)
{ return(rx_buffer_tail-rx_buffer_head); }
return (RX_BUFFER_SIZE - (rx_buffer_head-rx_buffer_tail));
}
#endif
Returns the number of bytes in the RX buffer.
This replaces a typical byte counter to prevent the interrupt and main programs from writing to the counter at the same time.
用来判断 缓存的字节数量。
*****************************
内容4
void serial_init()
{
Set baud rate();
enable rx and tx();
enable interrupt on complete reception of a byte();
}
利用伪代码来理解整体结构,
然后,细化,
**************************
1、Set baud rate();
#if BAUD_RATE < 57600
uint16_t UBRR0_value = ((F_CPU / (8L * BAUD_RATE)) - 1)/2 ;
UCSR0A &= ~(1 << U2X0); // baud doubler off - Only needed on Uno XXX
#else
uint16_t UBRR0_value = ((F_CPU / (4L * BAUD_RATE)) - 1)/2;
UCSR0A |= (1 << U2X0); // baud doubler on for high baud rates, i.e. 115200
#endif
UBRR0H = UBRR0_value >> 8;
UBRR0L = UBRR0_value;
这里需要查看 avr 串口设置资料,涉及到寄存器配置,我不是很熟悉,感觉和找到的代码有些区别,暂时先继续。
2、enable rx and tx();
UCSR0B |= 1<<rxen0;
UCSR0B |= 1<<txen0;
通过寄存器赋值实现,RXEN0 和 TXEN0 是寄存器。
3、enable interrupt on complete reception of a byte();
UCSR0B |= 1<<rxcie0;
如果对 avr 串口编程很熟悉的话,上面的代码应该是 格式化的,就是遇到类似情况,copy paste 就可以了。
****************************************
内容5
void serial_write(uint8_t data)
{
Calculate next head();
Wait until there is space in the buffer();
Store data and advance head();
Enable Data Register Empty Interrupt to make sure tx-streaming is running();
}
同样利用伪代码 熟悉结构,然后细化
1、Calculate next head();
uint8_t next_head = tx_buffer_head + 1;
if (next_head == TX_BUFFER_SIZE)
{ next_head = 0; }
当next_head == TX_BUFFER_SIZE 时,表面走了一圈了,要再 从 0 开始。
2、 Wait until there is space in the buffer();
while (next_head == tx_buffer_tail)
{
if (sys.execute & EXEC_RESET)
{ return; } // Only check for abort to avoid an endless loop.
}
当next_head == tx_buffer_tail 时,说明环形队列中已经没有空间了,在这里循环等待。循环内部判断 sys状态,避免死循环。
3、Store data and advance head();
tx_buffer[tx_buffer_head] = data;
tx_buffer_head = next_head;
好理解
4、 Enable Data Register Empty Interrupt to make sure tx-streaming is running();
UCSR0B |= (1 << UDRIE0);
需要看avr 串口方面资料。
***************************************
内容太多了,将 serial.c 理解 分为 两部分。
--------------------------------------------------------------------------
**************************
serial.c 的理解 下
只需要理解功能,怎样实现可以暂时简单了解
low level functions for sending and recieving bytes via the serial port
***************************
内容6
ISR(SERIAL_UDRE)
{
Temporary tx_buffer_tail();
Send a byte from the buffer();
Update tail position();
Turn off Data Register Empty Interrupt to stop tx-streaming if this concludes the transfer();
}
这是AVR的中断,//USART0接收中断 // Data Register Empty Interrupt handler
其中, #define SERIAL_UDRE USART_UDRE_vect (pin_map.h 中)
http://blog.sina.com.cn/s/blog_55c3ae71010005d8.html
可以参考http://blog.sina.com.cn/s/blog_694edd930100z24y.html
// 数据从发送寄存器完整移动到移位寄存器
// 中断或轮询模式,均是写数据清零
// 每一个字符character发生一次
Temporary tx_buffer_tail()
uint8_t tail = tx_buffer_tail;
#ifdef ENABLE_XONXOFF
if (flow_ctrl == SEND_XOFF) {
UDR0 = XOFF_CHAR;
flow_ctrl = XOFF_SENT;
} else if (flow_ctrl == SEND_XON) {
UDR0 = XON_CHAR;
flow_ctrl = XON_SENT;
} else
#endif
{
#ifdef 和 #endif 之间的代码暂时不理解。
Send a byte from the buffer();
UDR0 = tx_buffer[tail];
UDR0是数据寄存器,用来放置缓存。
Update tail position();
tail++;
if (tail == TX_BUFFER_SIZE)
{ tail = 0; }
tx_buffer_tail = tail;
}
好理解
Turn off Data Register Empty Interrupt to stop tx-streaming if this concludes the transfer();
if (tail == tx_buffer_head)
{ UCSR0B &= ~(1 << UDRIE0); }
没有数据了,设置寄存器(下面为通用的,这里 n 为0,参考 http://www.amobbs.com/archiver/tid-3415797.html),
//UCSRnB USART控制和状态寄存器B
// -----------------------------------------------------------------
// | RXCIEn| TXCIEn| UDRIEn| RXENn | TXENn | UCSZn2| RXB8n | TXB8n |
// -----------------------------------------------------------------
// RXCIEn:接收结束中断使能
// TXCIEn:发送结束中断使能
// UDRIEn:USART数据寄存器空中使能
// RXENn:接收使能
// TXENn:发送使能
// UCSZn2:字符长度,具体见下面
// RXB8n:接收数据位8
// TXB8n:发送数据位8
可以看出,禁止了 USART数据寄存器空中使能。
理解程度不是很详细,因为暂时不需要,不影响 理解 整体。
***********************************************
内容7
uint8_t serial_read()
{
if (rx_buffer_head == rx_buffer_tail)
{
return SERIAL_NO_DATA;
}
else {
uint8_t data = rx_buffer[rx_buffer_tail];
rx_buffer_tail++;
if (rx_buffer_tail == RX_BUFFER_SIZE)
{ rx_buffer_tail = 0; }
#ifdef ENABLE_XONXOFF
if ((get_rx_buffer_count() < RX_BUFFER_LOW) && flow_ctrl == XOFF_SENT)
{
flow_ctrl = SEND_XON;
UCSR0B |= (1 << UDRIE0); // Force TX
}
#endif
return data;
}
}
从缓存中读出数据。
*******************************
内容8
ISR(SERIAL_RX)
{
uint8_t data = UDR0;
uint8_t next_head;
Pick off runtime command characters directly from the serial stream. These characters are not passed into the buffer, but these set system state flag bits for runtime execution();
Write character to buffer();
Write data to buffer unless it is full();
}
其中,#define SERIAL_RX USART_RX_vect
中断接受函数
1、Pick off runtime command characters directly from the serial stream. These characters are not passed into the buffer, but these set system state flag bits for runtime execution();
switch (data) {
case CMD_STATUS_REPORT: sys.execute |= EXEC_STATUS_REPORT; break; // Set as true
case CMD_CYCLE_START: sys.execute |= EXEC_CYCLE_START; break; // Set as true
case CMD_FEED_HOLD: sys.execute |= EXEC_FEED_HOLD; break; // Set as true
case CMD_RESET: mc_reset(); break; // Call motion control reset routine.
设置执行系统状态标志。
2、Write character to buffer();
default: // Write character to buffer
next_head = rx_buffer_head + 1;
if (next_head == RX_BUFFER_SIZE)
{ next_head = 0; }
3、Write data to buffer unless it is full()
if (next_head != rx_buffer_tail) {
rx_buffer[rx_buffer_head] = data;
rx_buffer_head = next_head;
#ifdef ENABLE_XONXOFF
if ((get_rx_buffer_count() >= RX_BUFFER_FULL) && flow_ctrl == XON_SENT) {
flow_ctrl = SEND_XOFF;
UCSR0B |= (1 << UDRIE0); // Force TX
}
#endif
}
}
看来 XONXOFF的很碍事,去掉就简洁很多了。
*****************************************
内容9
void serial_reset_read_buffer()
{
rx_buffer_tail = rx_buffer_head;
#ifdef ENABLE_XONXOFF
flow_ctrl = XON_SENT;
#endif
}
复位。
************************************
总体上,需要理解环形队列(这里没有分析,head 是用来写入数据的index,tail 是用来导出数据的index),就能理解50% 了,另外 对AVR 串口寄存器如果熟悉的话,就又能理解30%了。
剩下的20% 就是 XONXOFF 还没理解。
摘录AVR 串口寄存器
void init_uart(void)
{
//UDRn USART I/O数据寄存器, 不可用读修改写命令操作, 否则会改变FIFO状态
//UCSRnA USART控制和状态寄存器A
// -----------------------------------------------------------------
// |RXCn |TXCn | UDREn |FEn|DORn |UPEn |U2Xn | MPCMn |
// -----------------------------------------------------------------
// RXCn:USART接收结束标志
// TXCn:USART发送结束标志,写1可清除
// UDREn:USART数据寄存器为空标志,只有该标志为1才数据才可写入UDR0
// FEn:帧错误,未正确收到停止位
// DORn:数据过速
// UPEn:奇偶效验错误
// U2Xn:倍速发送,仅对异步操作有影响
// MPCMn:多处理器通讯模式
//UCSRnB USART控制和状态寄存器B
// -----------------------------------------------------------------
// | RXCIEn| TXCIEn| UDRIEn| RXENn | TXENn | UCSZn2| RXB8n | TXB8n |
// -----------------------------------------------------------------
// RXCIEn:接收结束中断使能
// TXCIEn:发送结束中断使能
// UDRIEn:USART数据寄存器空中使能
// RXENn:接收使能
// TXENn:发送使能
// UCSZn2:字符长度,具体见下面
// RXB8n:接收数据位8
// TXB8n:发送数据位8
//UCSRxC USART控制和状态寄存器C
// -----------------------------------------------------------------
// | - | UMSELn| UPMn1 | UPMn0 | USBSn | UCSZn1| UCXZn0| UCPOLn|
// -----------------------------------------------------------------
// UMSELn:模式选择,0为异步操作,1为同步操作
// UPMn1,UPMn0:奇偶效验模式,00禁止,01保留,10偶效验,11奇校验
// USBSn:停止位选择,0为1位停止位,1为2位停止位
// UCSZn2,UCSZn0:字符长度,000为5位, 001为 6位,010为7位, 011为8位
// 100为保留,101为保留,110为保留,111为9位
// UCPOLn:时钟极性,(异步模式应清零)
// UCPOL0 发送数据位置 接收数据位置
// 0 XCK0上升沿 XCK0下降沿
// 1 XCK0下降沿 XCK0上升沿
//UBRRnL和UBRRnH USART波特率寄存器, UBRRnH15:12为保留位:
// -----------------------------------------------------------------
// | - | - | - | - | BIT11 | BIT10 | BIT09 | BIT08 |
// -----------------------------------------------------------------
// -----------------------------------------------------------------
// | BIT07 | BIT06 | BIT05 | BIT04 | BIT03 | BIT02 | BIT01 | BIT00 |
// -----------------------------------------------------------------
}
************************************
serial 中 环形队列
简化后
************************************
去除了 如果 队列 满了 或者 空了 等判断;
也忽略了 读入的是 某种命令;
也忽略 XONXOFF
哇~~~~,这个世界清净了,现在大家知道,
TX 队列
*****************************
RX 队列
--------------------------------------------------------------
******************************
config.h 上
几乎全是注释的文件
******************************
This file contains compile-time configurations for Grbl's internal system.
For the most part,users will not need to directly modify these, but they are here for specific needs, i.e. performance tuning or adjusting to non-typical machines.
说明了这个文件的用途。
1、 Default settings. Used when resetting EEPROM. Change to desired name in defaults.h
#define DEFAULTS_GENERIC
保存在 EEPROM 中的参数,默认值。
2、Serial baud rate
#define BAUD_RATE 9600
3、Default pin mappings. Grbl officially supports the Arduino Uno only. Other processor typesmay exist from user-supplied templates or directly user-defined in pin_map.h
#define PIN_MAP_ARDUINO_UNO
默认端口配置。
4、Define runtime command special characters. These characters are 'picked-off' directly from the serial read data stream and are not passed to the grbl line execution parser.
Select characters that do not and must not exist in the streamed g-code program. ASCII control characters may be used, if they are available per user setup.
Also, extended ASCII codes (>127), which are never in g-code programs, maybe selected for interface programs.
NOTE: If changed, manually update help message in report.c.
#define CMD_STATUS_REPORT '?'
#define CMD_FEED_HOLD '!'
#define CMD_CYCLE_START '~'
#define CMD_RESET 0x18 // ctrl-x
命令符,区别 G CODE,用来控制程序。
5、The temporal resolution of the acceleration management subsystem. Higher number give smoother acceleration but may impact performance.
NOTE: Increasing this parameter will help any resolution related issues, especially with machines requiring very high accelerations and/or very fast feedrates.
In general, this will reduce the error between how the planner plans the motions and how the stepper program actually performs them.
However, at some point, the resolution can be high enough, where the errors related to numerical round-off can be great enough to cause problems and/or it's too fast for the Arduino.
The correct value for this parameter is machine dependent, so it's advised to set this only as high as needed.
Approximate successful values can range from 30L to 100L or more.
#define ACCELERATION_TICKS_PER_SECOND 50L
工作原理还不清楚,作用注释已经解释很清楚了。
6、Minimum planner junction speed. Sets the default minimum speed the planner plans for at the end of the buffer and all stops. This should not be much greater than zero and should only be changed if unwanted behavior is observed on a user's machine when running at very slow speeds.
#define MINIMUM_PLANNER_SPEED 0.0 // (mm/min)
不清楚工作机理,看起来很厉害。
7、Minimum stepper rate. Sets the absolute minimum stepper rate in the stepper program and never runs slower than this value, except when sleeping. This parameter overrides the minimum planner speed.
This is primarily used to guarantee that the end of a movement is always reached and not stop to never reach its target. This parameter should always be greater than zero.
#define MINIMUM_STEPS_PER_MINUTE 800 // (steps/min) - Integer value only
8、Time delay increments performed during a dwell. The default value is set at 50ms, which provides a maximum time delay of roughly 55 minutes, more than enough for most any application.
Increasing this delay will increase the maximum dwell time linearly, but also reduces the responsiveness of run-time command executions, like status reports, since these are performed between each dwell time step.
Also, keep in mind that the Arduino delay timer is not very accurate for long delays.
define DWELL_TIME_STEP 50 // Integer (1-255) (milliseconds)
9、If homing is enabled, homing init lock sets Grbl into an alarm state upon power up.
This forces the user to perform the homing cycle (or override the locks) before doing anything else. This is mainly a safety feature to remind the user to home, since position is unknown to Grbl.
#define HOMING_INIT_LOCK // Comment to disable
不理解,用到时再来理解。
10、The homing cycle seek and feed rates will adjust so all axes independently move at the homing seek and feed rates regardless of how many axes are in motion simultaneously.
If disabled, rates are point-to-point rates, as done in normal operation. For example in an XY diagonal motion, the diagonal motion moves at the intended rate, but the individual axes move at 70% speed.
This option just moves them all at 100% speed.
#define HOMING_RATE_ADJUST // Comment to disable
11、Define the homing cycle search patterns with bitmasks. The homing cycle first performs a search to engage the limit switches.
HOMING_SEARCH_CYCLE_x are executed in order starting with suffix 0 and searches the enabled axes in the bitmask.
This allows for users with non-standard cartesian machines, such as a lathe (x then z), to configure the homing cycle behavior to their needs.
Search cycle 0 is required, but cycles 1 and 2 are both optional and may be commented to disable.
After the search cycle, homing then performs a series of locating about the limit switches to hone in on machine zero, followed by a pull-off maneuver. HOMING_LOCATE_CYCLE governs these final moves, and this mask must contain all axes in the search.
NOTE: Later versions may have this installed in settings.
#define HOMING_SEARCH_CYCLE_0 (1<<z_axis) [="" color][="" b]="" first="" move="" z="" to="" clear="" workspace.
#define HOMING_SEARCH_CYCLE_1 ((1<<x_axis)|(1<<y_axis)) [="" color][="" b]="" then="" move="" x,y="" at="" the="" same="" time.
// #define HOMING_SEARCH_CYCLE_2 // Uncomment and add axes mask to enable
#define HOMING_LOCATE_CYCLE ((1<<x_axis)|(1<<y_axis)|(1<<z_axis))[ color][="" b]="" must="" contain="" all="" search="" axes
12、Number of homing cycles performed after when the machine initially jogs to limit switches.
This help in preventing overshoot and should improve repeatability. This value should be one or greater.
#define N_HOMING_LOCATE_CYCLE 2 // Integer (1-128)
13、Number of blocks Grbl executes upon startup.
These blocks are stored in EEPROM, where the size and addresses are defined in settings.h. With the current settings, up to 5 startup blocks may be stored and executed in order.
These startup blocks would typically be used to set the g-code parser state depending on user preferences.
#define N_STARTUP_LINE 2 // Integer (1-5)
******************************************
感觉设置很复杂,大多数都不理解,先混个脸熟。
**********************
config.h 下
advanced users only
**********************
The number of linear motions in the planner buffer to be planned at any give time.
The vast majority of RAM that Grbl uses is based on this buffer size.
Only increase if there is extra available RAM, like when re-compiling for a Teensy or Sanguino. Or decrease if the Arduino begins to crash due to the lack of available RAM or if the CPU is having trouble keeping up with planning new incoming motions as they are executed.
// #define BLOCK_BUFFER_SIZE 18 // Uncomment to override default in planner.h.
默认 是注释掉的
Line buffer size from the serial input stream to be executed.
Also, governs the size of each of the startup blocks, as they are each stored as a string of this size.
Make sure to account for the available EEPROM at the defined memory address in settings.h and for the number of desired startup blocks.
NOTE: 70 characters is not a problem except for extreme cases, but the line buffer size can be too small and g-code blocks can get truncated.
Officially, the g-code standards support up to 256 characters. In future versions, this default will be increased, when we know how much extra memory space we can re-invest into this.
// #define LINE_BUFFER_SIZE 70 // Uncomment to override default in protocol.h
Serial send and receive buffer size.
The receive buffer is often used as another streaming buffer to store incoming blocks to be processed by Grbl when its ready. Most streaming interfaces will character count and track each block send to each block response.
So, increase the receive buffer if a deeper receive buffer is needed for streaming and avaiable memory allows. The send buffer primarily handles messages in Grbl.
Only increase if large messages are sent and Grbl begins to stall, waiting to send the rest of the message.
// #define RX_BUFFER_SIZE 128 // Uncomment to override defaults in serial.h
// #define TX_BUFFER_SIZE 64
这个已经在 serial.c 中理解过了。
Toggles XON/XOFF software flow control for serial communications.
Not officially supported due to problems involving the Atmega8U2 USB-to-serial chips on current Arduinos.
The firmware on these chips do not support XON/XOFF flow control characters and the intermediate buffer in the chips cause latency and overflow problems with standard terminal programs.
However, using specifically-programmed UI's to manage this latency problem has been confirmed to work.
As well as, older FTDI FT232RL-based Arduinos(Duemilanove) are known to work with standard terminal programs since their firmware correctly manage these XON/XOFF characters.
// #define ENABLE_XONXOFF // Default disabled. Uncomment to enable.
Creates a delay between the direction pin setting and corresponding step pulse by creating another interrupt (Timer2 compare) to manage it.
The main Grbl interrupt (Timer1 compare) sets the direction pins, and does not immediately set the stepper pins, as it would in normal operation.
The Timer2 compare fires next to set the stepper pins after the step pulse delay time, and Timer2 overflow will complete the step pulse, except now delayed by the step pulse time plus the step pulse delay. (Thanks langwadt for the idea!)
This is an experimental feature that should only be used if your setup requires a longer delay between direction and step pin settings (some opto coupler based drivers), as it may adversely effect Grbl's high-end performance (>10kHz).
However, we suggest to first try our direction delay hack/solution posted in the Wiki involving inverting the stepper pin mask.
NOTE: Uncomment to enable. The recommended delay must be > 3us and the total step pulse time, which includes the Grbl settings pulse microseconds, must not exceed 127us.
Reported successful values for certain setups have ranged from 10 to 20us.
// #define STEP_PULSE_DELAY 10 // Step pulse delay in microseconds. Default disabled.
******************************
感觉 和 电机 加速度算法 之类的有关系。还没有找到适合的资料 来 帮助理解。
------------------------------------------------------------------------------
**********************
defaults.h 上
默认参数设置
**********************
通讯一建立,这些参数就会显示出来
幸好有帮助文档,https://github.com/grbl/grbl/wiki/Configuring-Grbl-v0.8
The defaults.h file serves as a central default settings file for different machine types, from DIY CNC mills to CNC conversions of off-the-shelf machines.
The settings here are supplied by users, so your results may vary.
However, this should give you a good starting point as you get to know your machine and tweak the settings for your our nefarious needs.
#ifdef DEFAULTS_GENERIC
参数设置
#endif
只理解默认的,
参数设置0、1、2
#define DEFAULT_X_STEPS_PER_MM 250.0
Grbl needs to know how far each step will take the tool in reality. To calculate steps/mm for an axis of your machine you need to know:
The mm per revolution of the lead screw
The full steps per revolution of your steppers (typically 200)
The microsteps per step of your controller (typically 1, 2, 4, 8, or 16). Tip: Using high microstep values (e.g 16) can reduce your stepper motor torque, so use the lowest that gives you the desired axes resolution and comfortable running properties.
The steps/mm can then be calculated like this: steps_per_mm = (steps_per_revolution*microsteps)/mm_per_rev
Compute this value for every axis and write these settings to Grbl.
计算方法实例,
Motor 200 steps/rev
Driver 2 microsteps/step
Screw 1.25 rev/mm
The resolution is: 2 microsteps/step * 200 step/rev * 1/1.25 rev/mm = 320 microstep/mm.
同理,
#define DEFAULT_Y_STEPS_PER_MM 250.0
#define DEFAULT_Z_STEPS_PER_MM 250.0
应该丝杆尺寸不一致,这个数字基本更改。
*************************************
参数设置3
#define DEFAULT_STEP_PULSE_MICROSECONDS 10
Step pulse, microseconds
Stepper drivers are rated for a certain minimum step pulse length. Check the data sheet or just try some numbers. You want as short pulses as the stepper drivers can reliably recognize. If the pulses are too long you might run into trouble running the system at high feed rates. Generally something between 5 and 50 microseconds works fine.
*************************************
参数设置4、5
#define DEFAULT_RAPID_FEEDRATE 500.0 // mm/min
#define DEFAULT_FEEDRATE 250.0
Default feed and seek rates, mm/min
This setting sets the default seek(G0) and feed rates(G1,G2,G3) after Grbl powers on and initializes. The seek rate (aka rapids) is used for moving from point A to point B as quickly as possible, usually for traversing into position. The seek rate should be set at the maximum speed your machine can go in any axes movement. The default feed rate usually does not enter into the picture as feed rates will generally be specified in the g-code program, but if not, this default feed rate will be used.
*************************************
参数设置6
#define DEFAULT_JUNCTION_DEVIATION 0.05 // mm
Step port invert mask, int:binary
Some cnc-stepper controllers needs its high-low inputs inverted for both direction and steps.
Signal lines are normally held high or low to signal direction or held high and goes low for a couple of microseconds to signal a step event. To achieve this, Grbl can invert the output bits to accomodate particular needs.
The invert mask value is a byte that is xored with the step and direction data before it is sent down the stepping port. That way you can use this both to invert step pulses or to invert one or more of the directions of the axes.
The bits in this byte corresponds to the pins assigned to stepping in config.h. Note that bits 0 and 1 are not used for inversion. Per default bits are assigned like this:
ARDUINO 代码复制打印
- #define X_STEP_BIT 2
- #define Y_STEP_BIT 3
- #define Z_STEP_BIT 4
- #define X_DIRECTION_BIT 5
- #define Y_DIRECTION_BIT 6
- #define Z_DIRECTION_BIT 7
If you wanted to invert the X and Y direction in this setup you would calculate a value by bitshifting like this (in your favorite calculating environment):
> (1<<x_direction_bit)|(1<<y_direction_bit)
Which is equal to 96, so issuing this command would invert them:
$6=96
Now when you view the current settings, you should now see this in your invert mask line with the binary representation of the number (bits 5 and 6 should now show a 1 to indicate inversion.)
$6=96 (step port invert mask. int:1100000)
*****************************************
参数设置7
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-255)
Step idle delay, msec
Every time your steppers complete a motion and come to a stop, Grbl will disable the steppers by default.
The stepper idle lock time is the time length Grbl will keep the steppers locked before disabling.
Depending on the system, you can set this to zero and disable it. On others, you may need 25-50 milliseconds to make sure your axes come to complete stop before disabling. (My machine tends to drift just slightly if I don't have this enabled.) OR, you can always keep your axes enabled at all times by setting this value to the maximum 255 milliseconds. Again, just to repeat, you can keep all axes always enabled by setting $7=255.
*******************************************
参数设置8
#define DEFAULT_ACCELERATION (10.0*60*60) // 10 mm/min^2
Acceleration, mm/sec^2
This is the acceleration in mm/second/second.
You don’t have to understand what that means, suffice it to say that a lower value gives smooooother acceleration while a higher value yields tighter moves and reach the desired feedrates much quicker.
In technical terms, this is the point to point acceleration of your machine, independent of axes. Set this acceleration value as high as your most limiting axes can let you without losing ANY steps.
Usually you'd like to give yourself a little buffer, because if you lose steps, Grbl has no idea this has happened (steppers are open-loop control) and will keep going.
**********************************************
参数设置9
#define DEFAULT_JUNCTION_DEVIATION 0.05 // mm
Junction deviation, mm
Cornering junction deviation is used by the acceleration manager to determine how fast it can move through a path.
The math is a bit complicated but in general, higher values gives generally faster, possibly jerkier motion. Lower values makes the acceleration manager more careful and will lead to careful and slower cornering.
So if you run into problems where your machine tries to take a corner too fast, decrease this value to make it slow down.
If you want your machine to move faster through junctions, increase this value to speed it up.
For technical people, hit this link to read about Grbl's cornering algorithm, which accounts for both velocity and junction angle with a very simple, efficient, and robust method.
*********************************************
***********************
defaults.h 下
************************
参数设置10
#define DEFAULT_MM_PER_ARC_SEGMENT 0.1
Arc, mm/segment
Grbl renders circles and arcs by subdividing them into teeny tiny lines. You will probably never need to adjust this value – but if you find that your circles are too crude (really? one tenth of a millimeter is not precise enough for you? Are you in nanotech?) you may adjust this. Lower values gives higher precision but may lead to performance issues.
***************************
参数设置11
#define DEFAULT_N_ARC_CORRECTION 25
N-arc correction, int
This is an advanced setting that shouldn't be changed unless there are circumstances that you need to. To make G02/03 arcs possible in Grbl, Grbl approximates the location of the next arc segment by a small angle approximation. N-arc correction is the number of approximate arc segments performed before Grbl computes an exact arc segment to correct for the approximation error drift. Computing these exact locations are computationally expensive, but there are some extreme cases where the small angle approximations can introduce enough error to be noticeable, like very very small arcs with a large arc segment length. Change this setting only if find strange problems with arcs, but it's not recommended to go below 3 because this may lead to buffer starvation, where the axes slow down and hiccup. But, results can vary.
****************************
参数设置12
#define DEFAULT_DECIMAL_PLACES 3
N-decimal, int
Set how many decimal places all of the floating point values Grbl reports. Not much more complicated than that.
****************************
参数设置13
#define DEFAULT_REPORT_INCHES 0 // false
Report inches, bool
Grbl v0.8 has a real-time positioning reporting feature to provide a user feedback on where the machine is exactly at that time. By default it is set to report in mm, but by sending a $13=1 command, you send this boolean flag to true and the status reporting feature will now report in inches. $13=0 to set back to mm.
名字 是 report inches,真 时,单位 inch,假时 单位 mm。
******************************
参数设置14
#define DEFAULT_AUTO_START 1 // true
Auto start, bool
In a more professional CNC environment, pros start a job by loading up their program and then pressing the 'cycle start' button on their machine. It begins the job. Grbl does the same thing, but not by default. As a learning tool, we 'auto-cycle start' any g-code command that user sends to Grbl, for just jogging the machine to see if move in the direction they think it should go, or just seeing with what their machine can do. This makes it easier to load up your machine with Grbl and pick up on how it works, rather than having to diligently hit 'cycle start' anytime you want to move any your axes. Once you learn your machine and get a good handle on g-code, you can disable the 'auto cycle-start' feature by sending Grbl $14=0 command. (May need a soft-reset or power cycle to load the change.)
Another way of saying that might be:
If $14=0 then some gcode commands like Xn, Yn etc. won't happen when you enter them at a serial terminal. If $14=1 then the gcode motion commands will happen.
Apparently big cnc's won't execute gcode until the operator presses a 'cycle start' button. The gcode commands were received but queued and awaiting the 'cycle start' button. Makes sense yes? When $14=0 then that's how grbl acts too. You need the button! (in which case attach the feed-hold button too!).
When $14=1 then the grbl software automatically presses a software version of the 'cycle start' for you each time you 'enter' a gcode command line via a serial terminal. This is done to make it more convenient for you to enter commands and see something happen without having to push the button.
*********************************
参数设置15
#define DEFAULT_INVERT_ST_ENABLE 0 // false
Invert step enable, bool
By default, the stepper enable pin is high to disable and low to enable. If your setup needs the opposite, just invert the stepper enable pin by typing $15=1. Disable with $15=0. (May need a power cycle to load the change.)
**********************************
参数设置16
#define DEFAULT_HARD_LIMIT_ENABLE 0 // false
Hard limits, bool
Hard limit switches are a safety feature to help prevent your machine from traveling way too far off the ends of travel and crashing or breaking something expensive. Basically you wire up some switches (mechanical or optical) near the end of travel of each axes, or where ever you feel like there might be trouble if your program moves too far to where it shouldn't. When the switch triggers, it will immediately stop all motion, shutdown the coolant and spindle (if connected), and go into alarm mode, which forces you to check your machine and reset everything.
To use hard limits with Grbl, the limit pins are held high with an internal pull-up resistor, so all you have to do is wire in a normally-open switch with the pin and ground and enable hard limits with $16=1. That's it. (Disable with $16=0) If you want a limit for both ends of travel of one axes, just wire in two switches in parallel with the pin and ground, so if either one of them trips, it triggers the hard limit.
Just know, that a hard limit event is considered to be critical event, where steppers immediately stop and will have likely lost steps. Grbl doesn't have any feedback on position, so it can't guarantee it has any idea where it is. So, if a hard limit is triggered, Grbl will go into an infinite loop ALARM mode, giving you a chance to check your machine and forcing you to reset Grbl. Remember it's a purely a safety feature.
If you have issues with the hard limit switch constantly triggering after you reset, a soft-reset will reset Grbl into an alarm state, where you can access the settings and Grbl commands, but all g-codes and startup blocks will be locked out. So you can disable the hard limits setting and then $X unlock the alarm. Or, you can wire in a normally-closed switch in series with ground to all the limit switches to disconnect the switches temporarily so you can have Grbl move your axes off the switches.
******************************
参数设置17
#define DEFAULT_HOMING_ENABLE 0 // false
Homing cycle, bool
Ahh, homing. Something that has been sorely needed in Grbl for a long time. It's now fully supported in v0.8. For those just initiated into CNC, the homing cycle is used to accurately and precisely locate position zero on a machine (aka machine zero) everytime you startup your Grbl between sessions. In other words, you know exactly where you are at any given time, every time. Say you start machining something or are about to start the next step in a job and the power goes out, you re-start Grbl and Grbl has no idea where it is. You're left with the task of figuring out where you are. If you have homing, you always have the machine zero reference point to locate from, so all you have to do is run the homing cycle and resume where you left off.
To set up the homing cycle for Grbl, you need to have limit switches in a fixed position that won't get bumped or moved, or else your reference point gets messed up. Usually they are setup in the farthest point in +x, +y, +z of each axes. Wire your limit switches in with the limit pins and ground, just like with the hard limits, and enable homing. If you're curious, you can use your limit switches for both hard limits AND homing. They play nice with each other.
By default, Grbl's homing cycle moves the Z-axis positive first to clear the workspace and then moves both the X and Y-axes at the same time in the positive direction. To set up how your homing cycle behaves, there are more Grbl settings down the page describing what they do (and compile-time options as well.)
Also, one more thing to note, when homing is enabled. Grbl will lock out all g-code commands until you perform a homing cycle. Meaning no axes motions, unless the lock is disabled ($X) but more on that later. Most, if not all CNC controllers, do something similar, as it mostly a safety feature to help users from making positioning mistake, which is very easy to do and be saddening when a mistake ruins a part. If you find this annoying or find any weird bugs, please let us know and we'll try to work on it so everyone is happy.
NOTE: Check out config.h for more homing options for advanced users. You can disable the homing lockout at startup, configure which axes move first during a homing cycle and in what order, and more.
***********************
参数设置18
#define DEFAULT_HOMING_DIR_MASK 0 // move positive dir
Homing dir invert mask, int:binary
By default, Grbl assumes your homing limit switches are in the positive direction, first moving the z-axis positive, then the x-y axes positive before trying to precisely locate machine zero by going back and forth slowly around the switch. If your machine has a limit switch in the negative direction, the homing direction mask can invert the axes direction. It works just like the invert stepper mask, where all you have to do set the axis direction pins to 1 that you want to invert and that axes will now search for the limit pin in the negative direction.
***************************
参数设置19
#define DEFAULT_HOMING_FEEDRATE 25.0 // mm/min
Homing feed, mm/min
The homing cycle first searches for the limit switches at a higher seek rate, and after it finds them, it moves at a slower feed rate to hone into the precise location of machine zero. Homing feed rate is that slower feed rate. Set this to whatever rate value that provides repeatable and precise machine zero locating.
**************************
参数设置20
#define DEFAULT_HOMING_RAPID_FEEDRATE 250.0 // mm/min
Homing seek, mm/min
Homing seek rate is the homing cycle search rate, or the rate at which it first tries to find the limit switches. Adjust to whatever rate gets to the limit switches in a short enough time without crashing into your limit switches if they come in too fast. This seek rate behaves a little differently than the main stepper driver. Instead of the rate from point to point, it just moves all of the axes at the same individual rate, regardless of how many axes are moving at the same time. So, the XY seek move will seem to move about 41% faster than if you would move it with a G1 command. (You can disable this in config.h if it bothers you. It's there to speed up the homing cycle.)
*******************************
参数设置21
#define DEFAULT_HOMING_DEBOUNCE_DELAY 100 // msec (0-65k)
Homing debounce, ms
Whenever a switch triggers, some of them can have electrical/mechanical noise that actually 'bounce' the signal high and low for a few milliseconds before settling in. To solve this, you need to debounce the signal, either by hardware with some kind of signal conditioner or by software with a short delay to let the signal finish bouncing. Grbl performs a short delay only homing when locating machine zero. Set this delay value to whatever your switch needs to get repeatable homing. In most cases, 5-25 milliseconds is fine.
类似单片机中 常见的 键盘 消抖
*******************************
参数设置22
#define DEFAULT_HOMING_PULLOFF 1.0 // mm
Homing pull-off, mm
To play nice with the hard limits feature, where homing can share the same limit switches, the homing cycle will move off the all of the limit switches by this pull-off travel after it completes. In other words, it helps to prevent accidental triggering of the hard limit after a homing cycle.
The homing seek rate setting controls how quickly the pull-off maneuver moves, like a G1 command.
******************************************
总共 22 个参数设置,对我这样第一次接触,内容量还是很大的。
------------------------------------------------------------------------------
*******************************
protocol.h
the serial protocol master control unit
*******************************
serial 收到 gcode 后,要通过 protocal 来处理,
****************************
内容1
#include
睡眠模式,难道要省电?
****************************
内容2
#ifndef LINE_BUFFER_SIZE
#define LINE_BUFFER_SIZE 70
#endif
Line buffer size from the serial input stream to be executed.
NOTE: Not a problem except for extreme cases, but the line buffer size can be too small and g-code blocks can get truncated. Officially, the g-code standards support up to 256 characters. In future versions, this will be increased, when we know how much extra memory space we can invest into here or we re-write the g-code parser not to have his buffer.
在 config.h 中 也有定义,不过默认 是 // 的
*****************************
内容3
void protocol_init();
Initialize the serial protocol
放在 这里 的函数 都可以 被 其它文件调用。
******************************
内容4
void protocol_process();
Read command lines from the serial port and execute them as they come in. Blocks until the serial buffer is emptied.
********************************
内容5
uint8_t protocol_execute_line(char *line);
Executes one line of input according to protocol
*******************************
内容6
void protocol_execute_runtime();
Checks and executes a runtime command at various stop points in main program
*********************************
内容7
void protocol_execute_startup();
Execute the startup script lines stored in EEPROM upon initialization
*******************************
函数数量不多,功能明确,下一步理解 .c 文件,理解如何实现。
------------------------------------------------------
************************
protocol.c 上
the serial protocol master control unit
************************
内容1 包含的头文件
#include
#include
#include "protocol.h"
#include "gcode.h"
#include "serial.h"
#include "print.h"
#include "settings.h"
#include "config.h"
#include "nuts_bolts.h"
#include "stepper.h"
#include "report.h"
#include "motion_control.h"
理解所需的头文件
和 是标准文件,输入输出 和 中断。
已经理解过的头文件:protocol.h 是 声明文件,serial.h 声明通讯函数,config.h —— compile time configuration
还没有接触的头文件
gcode.h —— rs274/ngc parser
print.h —— Functions for formatting output strings
settings.h —— eeprom configuration handling
nuts_bolts.h —— Header file for shared definitions, variables, and functions
stepper.h —— stepper motor driver: executes motion plans of planner.c using the stepper motors
report.h —— reporting and messaging methods
motion_control.h —— high level interface for issuing motion commands
这些头文件 被用到时再理解。
*****************************************
内容2 定义静态变量 数组
static char line[LINE_BUFFER_SIZE];
static uint8_t char_counter;
static uint8_t iscomment;
Line to be executed. Zero-terminated. line[LINE_BUFFER_SIZE],复习一下,
在 protocol.h 中
#ifndef LINE_BUFFER_SIZE
#define LINE_BUFFER_SIZE 70
#endif
Last character counter in line variable. char_counter
Comment/block delete flag for processor to ignore comment characters. iscomment
*****************************************
内容4 静态 函数
static void protocol_reset_line_buffer()
{
char_counter = 0; // Reset line input
iscomment = false;
}
为什么 静态? http://bbs.csdn.net/topics/350238100 7楼
定义静态函数的好处:
<1> 其他文件中可以定义相同名字的函数,不会发生冲突
<2> 静态函数不能被其他文件所用。
同样也可以理解 为什么 char_counter 静态变量
由于static变量的以上特性,可实现一些特定功能。
1. 统计次数功能
声明函数的一个局部变量,并设为static类型,作为一个计数器,这样函数每次被调用的时候就可以进行计数。这是统计函数被调用次数的最好的办法,因为这个变量是和函数息息相关的,而函数可能在多个不同的地方被调用,所以从调用者的角度来统计比较困难。
************************************************
内容 4 初始化 protocol
void protocol_init()
{
复位();
欢迎信息();
设置端口();
}
利用伪代码理解结构,然后细化,
1、复位();
protocol_reset_line_buffer();
直接调用刚才定义的静态函数就可以了。
2、欢迎信息();
report_init_message();
就是输出欢迎的信息,声明在 report.h 中。非常简单。
3、设置端口();
PINOUT_DDR &= ~(PINOUT_MASK);
PINOUT_PORT |= PINOUT_MASK;
PINOUT_PCMSK |= PINOUT_MASK;
PCICR |= (1 << PINOUT_INT);
首先 需要看一下定义,
#define PINOUT_DDR DDRC
#define PINOUT_PORT PORTC
#define PINOUT_PCMSK PCMSK1
#define PINOUT_MASK ((1<<pin_reset)|(1<<pin_feed_hold)|(1<<pin_cycle_start))
#define PINOUT_INT PCIE1
#define PIN_RESET 0
#define PIN_FEED_HOLD 1
#define PIN_CYCLE_START 2
上面的定义 位于 pin_map.h 中,而被 nuts_bolts.h 引用,再被该文件引用
这里可能需要花些精力来确认 哪个是哪个端口?
首先 看具体定义端口的
#define PIN_RESET 0 // Uno Analog Pin 0
#define PIN_FEED_HOLD 1 // Uno Analog Pin 1
#define PIN_CYCLE_START 2 // Uno Analog Pin 2
然后,看一张总图,
然后,具体 到 上面 三个端口
然后,看
#define PINOUT_MASK ((1<<pin_reset)|(1<<pin_feed_hold)|(1<<pin_cycle_start))
意思 就是 arduino上 A0 A1 A2 端口取1。(即 AVR PC0 PC1 PC2 端口 取1)
再来理解AVR中DDRC、PORTC什么意思?
http://zhidao.baidu.com/link?url ... SrQj_v1w1OLQYAnoMJq
AVR单片机的IO是3态门DDRC是C口的方向寄存器,PORTC是C口的数据寄存器,
DDRC为0时,C口为输入,IO的高低从PORTC可以读出
DDRC为1时,c为输出,输出高低有PORTC控制。
然后,再理解中断
PCMSK1 为引脚变化屏蔽寄存器 即决定某一I/O引脚变化中断是否使能。
再回到
PINOUT_DDR &= ~(PINOUT_MASK);
Set as input pins. 对 PINOUT_MASK 取反,就是 arduino上 A0 A1 A2 端口取0。
PINOUT_PORT |= PINOUT_MASK;
Enable internal pull-up resistors. Normal high operation.
PINOUT_PCMSK |= PINOUT_MASK;
Enable specific pins of the Pin Change Interrupt. A0 A1 A2 端口可以中断。
PCICR |= (1 << PINOUT_INT);
Enable Pin Change Interrupt
这里需要 理解 AVR 中断机制。暂时理解为 设置哪些引脚可以中断。
***********************************************
可能还需要 找些 AVR 中断方面的资料。
***************************
protocol.c 中
****************************
内容5
Executes user startup script, if stored.
void protocol_execute_startup()
{
uint8_t n;
for (n=0; n < N_STARTUP_LINE; n++) {
内容5A();
}
}
复习,
N_STARTUP_LINE 定义 在 config.h 中, #define N_STARTUP_LINE 2
These startup blocks would typically be used to set the g-code parser state depending on user preferences.
blocks :程序块?
内容5A();
if (!(settings_read_startup_line(n, line))) {
report_status_message(STATUS_SETTING_READ_FAIL);
} else {
if (line[0] != 0) {
printString(line); // Echo startup line to indicate execution.
report_status_message(gc_execute_line(line));
}
}
其中,settings_read_startup_line 函数, 定义在 setting.c 文件中,
Reads startup line from EEPROM. Updated pointed line string data.
没有成功,返回 false
report_status_messages 函数 根据名字 就理解意思。
在 protocol.c 文件中,static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.
只要不是零,就执行,
printString 函数 定义在print.c 中,串口写入
gc_execute_line 函数 定义在 gcode.c 中,执行命令
**************************************
内容6
Pin change interrupt for pin-out commands
ISR(PINOUT_INT_vect)
{
// Enter only if any pinout pin is actively low.
内容6A();
}
首先, #define PINOUT_INT_vect PCINT1_vect
这里要再 学习 一下 AVR 的中断,
PC0 through PC6 trigger PCINT1.
we’ll need to tell the AVR which pins we’d like for it to watch specifically.
This is done through the pin mask, which is just a normal 8-bit byte where the corresponding bit is set for each pin we’d like to be able to trigger the interrupt.
映射端口已经理解过,arduino上 A0 A1 A2 端口。(即 AVR上 PC0 PC1 PC2 端口)
内容 6A();
Enter only if any pinout pin is actively low.
if ((PINOUT_PIN & PINOUT_MASK) ^ PINOUT_MASK) {
内容6B();
}
判断条件感觉有点复杂,PINOUT_PIN 先和 PINOUT_MASK 按位与,然后再 按位 异或。
只有 PINOUT_PIN 是 低电平,才能为真
然后,
内容6B();
if (bit_isfalse(PINOUT_PIN,bit(PIN_RESET))) {
mc_reset();
} else if (bit_isfalse(PINOUT_PIN,bit(PIN_FEED_HOLD))) {
sys.execute |= EXEC_FEED_HOLD;
} else if (bit_isfalse(PINOUT_PIN,bit(PIN_CYCLE_START))) {
sys.execute |= EXEC_CYCLE_START;
}
首先,
bit_isfalse 是 个宏,定义在 nuts_bolts.h 中,
#define bit_isfalse(x,mask) ((x & mask) == 0)
mc_reset 定义在 motion_control.c 中,system reset。
sys 一个复杂的结构体,
// Define global system variables
typedef struct {
uint8_t abort; // System abort flag. Forces exit back to main loop for reset.
uint8_t state; // Tracks the current state of Grbl.
volatile uint8_t execute; // Global system runtime executor bitflag variable. See EXEC bitmasks.
int32_t position[N_AXIS]; // Real-time machine (aka home) position vector in steps.
// NOTE: This may need to be a volatile variable, if problems arise.
uint8_t auto_start; // Planner auto-start flag. Toggled off during feed hold. Defaulted by settings.
} system_t;
--------------------------------------
***********************
protocol.c 下1
***********************
#define EXEC_STATUS_REPORT bit(0) // bitmask 00000001
#define EXEC_CYCLE_START bit(1) // bitmask 00000010
#define EXEC_CYCLE_STOP bit(2) // bitmask 00000100
#define EXEC_FEED_HOLD bit(3) // bitmask 00001000
#define EXEC_RESET bit(4) // bitmask 00010000
#define EXEC_ALARM bit(5) // bitmask 00100000
#define EXEC_CRIT_EVENT bit(6) // bitmask 01000000
Define system executor bit map. Used internally by runtime protocol as runtime command flags, which notifies the main program to execute the specified runtime command asynchronously.
NOTE: The system executor uses an unsigned 8-bit volatile variable (8 flag limit.)
The default flags are always false, so the runtime protocol only needs to check for a non-zero value to know when there is a runtime command to execute.
内容7 ();
Executes run-time commands, when required.
This is called from various check points in the main program, primarily where there may be a while loop waiting for a buffer to clear space or any point where the execution time from the last check point may be more than a fraction of a second.
This is a way to execute runtime commands asynchronously (aka multitasking) with grbl's g-code parsing and planning functions. This function also serves as an interface for the interrupts to set the system runtime flags, where only the main program handles them, removing the need to define more computationally-expensive volatile variables. This also provides a controlled way to execute certain tasks without having two or more instances of the same task, such as the planner recalculating the buffer upon a feedhold or override.
NOTE: The sys.execute variable flags are set by any process, step or serial interrupts, pinouts, limit switches, or the main program.
void protocol_execute_runtime()
{
if (sys.execute) { // Enter only if any bit flag is true
uint8_t rt_exec = sys.execute; // Avoid calling volatile multiple times
内容7A();
}
}
}
System alarm. Everything has shutdown by something that has gone severely wrong.
Report the source of the error to the user. If critical, Grbl disables by entering an infinite loop until system reset/abort.
内容7A();
内容7B();
内容7C();
内容7D();
内容7E();
内容7F();
内容7G();
内容7B();
Critical event. Only hard limit qualifies. Update this as new critical events surface.
if (rt_exec & (EXEC_ALARM | EXEC_CRIT_EVENT)) {
sys.state = STATE_ALARM; // Set system alarm state
if (rt_exec & EXEC_CRIT_EVENT) {
report_alarm_message(ALARM_HARD_LIMIT);
report_feedback_message(MESSAGE_CRITICAL_EVENT);
bit_false(sys.execute,EXEC_RESET); // Disable any existing reset
} else {
report_alarm_message(ALARM_ABORT_CYCLE);
}
bit_false(sys.execute,(EXEC_ALARM | EXEC_CRIT_EVENT));
}
内容7C();
Execute system abort.
if (rt_exec & EXEC_RESET) {
sys.abort = true; // Only place this is set true.
return; // Nothing else to do but exit.
}
内容7D();
Execute and serial print status
if (rt_exec & EXEC_STATUS_REPORT) {
report_realtime_status();
bit_false(sys.execute,EXEC_STATUS_REPORT);
}
内容7E();
Initiate stepper feed hold
if (rt_exec & EXEC_FEED_HOLD) {
st_feed_hold(); // Initiate feed hold.
bit_false(sys.execute,EXEC_FEED_HOLD);
}
内容7F();
Reinitializes the stepper module running state and, if a feed hold, re-plans the buffer.
NOTE: EXEC_CYCLE_STOP is set by the stepper subsystem when a cycle or feed hold completes.
if (rt_exec & EXEC_CYCLE_STOP) {
st_cycle_reinitialize();
bit_false(sys.execute,EXEC_CYCLE_STOP);
}
内容7G();
if (rt_exec & EXEC_CYCLE_START) {
st_cycle_start(); // Issue cycle start command to stepper subsystem
if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) {
sys.auto_start = true; // Re-enable auto start after feed hold.
}
bit_false(sys.execute,EXEC_CYCLE_START);
}
信息量太大,先整理,以后慢慢看。
*********************************
内容8
Directs and executes one line of formatted input from protocol_process.
While mostly incoming streaming g-code blocks, this also executes Grbl internal commands, such as settings, initiating the homing cycle, and toggling switch states.
This differs from the runtime command module by being susceptible to when Grbl is ready to execute the next line during a cycle, so for switches like block delete, the switch only effects the lines that are processed afterward, not necessarily real-time during a cycle, since there are motions already stored in the buffer.
However, this 'lag' should not be an issue, since these commands are not typically used during a cycle.
uint8_t protocol_execute_line(char *line)
{
// Grbl internal command and parameter lines are of the form '$4=374.3' or '$' for help
if(line[0] == '$') {
uint8_t char_counter = 1;
uint8_t helper_var = 0; // Helper variable
float parameter, value;
switch( line[char_counter] ) {
内容8A();
}
return(STATUS_OK); // If '$' command makes it to here, then everything's ok.
} else {
return(gc_execute_line(line)); // Everything else is gcode
}
}
内容8A();
case 0 : 内容8B();
case '$': 内容8C();
case '#' : 内容8D();
case 'G' : 内容8E();
case 'C' : 内容8F();
case 'X' : 内容8G();
case 'H' : 内容8H();
case 'N' : 内容8I();
default : 内容8J();
内容8B();
report_grbl_help(); break;
内容8C();
Prints Grbl settings $
if ( line[++char_counter] != 0 )
{ return(STATUS_UNSUPPORTED_STATEMENT); }
else
{ report_grbl_settings(); }
break;
内容8D();
Print gcode parameters #
if ( line[++char_counter] != 0 )
{ return(STATUS_UNSUPPORTED_STATEMENT); }
else
{ report_gcode_parameters(); }
break;
内容8E();
Prints gcode parser state G
if ( line[++char_counter] != 0 )
{ return(STATUS_UNSUPPORTED_STATEMENT); }
else
{ report_gcode_modes(); }
break;
内容8F();
Set check g-code mode C
if ( line[++char_counter] != 0 )
{ return(STATUS_UNSUPPORTED_STATEMENT); }
if ( sys.state == STATE_CHECK_MODE ) {
mc_reset();
report_feedback_message(MESSAGE_DISABLED);
} else {
if (sys.state)
{ return(STATUS_IDLE_ERROR); }
sys.state = STATE_CHECK_MODE;
report_feedback_message(MESSAGE_ENABLED);
}
break;
Perform reset when toggling off. Check g-code mode should only work if Grbl is idle and ready, regardless of alarm locks.
This is mainly to keep things simple and consistent.
内容8G();
Disable alarm lock X
if ( line[++char_counter] != 0 )
{ return(STATUS_UNSUPPORTED_STATEMENT); }
if (sys.state == STATE_ALARM) {
report_feedback_message(MESSAGE_ALARM_UNLOCK);
sys.state = STATE_IDLE;
// Don't run startup script. Prevents stored moves in startup from causing accidents.
}
break;
内容8H();
Perform homing cycle H
if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
// Only perform homing if Grbl is idle or lost.
if ( sys.state==STATE_IDLE || sys.state==STATE_ALARM ) {
mc_go_home();
if (!sys.abort)
{ protocol_execute_startup(); } // Execute startup scripts after successful homing.
} else
{ return(STATUS_IDLE_ERROR); }
} else
{ return(STATUS_SETTING_DISABLED); }
break;
内容8I();
Startup lines. N
if ( line[++char_counter] == 0 ) { // Print startup lines
for (helper_var=0; helper_var < N_STARTUP_LINE; helper_var++) {
if (!(settings_read_startup_line(helper_var, line))) {
report_status_message(STATUS_SETTING_READ_FAIL);
} else {
report_startup_line(helper_var,line);
}
}
break;
} else { // Store startup line
helper_var = true; // Set helper_var to flag storing method.
// No break. Continues into default: to read remaining command characters.
}
内容8J();
Storing setting methods
if(!read_float(line, &char_counter, ¶meter))
{ return(STATUS_BAD_NUMBER_FORMAT); }
if(line[char_counter++] != '=')
{ return(STATUS_UNSUPPORTED_STATEMENT); }
if (helper_var) { // Store startup line
// Prepare sending gcode block to gcode parser by shifting all characters
helper_var = char_counter; // Set helper variable as counter to start of gcode block
do {
line[char_counter-helper_var] = line[char_counter];
} while (line[char_counter++] != 0);
// Execute gcode block to ensure block is valid.
helper_var = gc_execute_line(line); // Set helper_var to returned status code.
if (helper_var) { return(helper_var); }
else {
helper_var = trunc(parameter); // Set helper_var to int value of parameter
settings_store_startup_line(helper_var,line);
}
} else { // Store global setting.
if(!read_float(line, &char_counter, &value))
{ return(STATUS_BAD_NUMBER_FORMAT); }
if(line[char_counter] != 0)
{ return(STATUS_UNSUPPORTED_STATEMENT); }
return(settings_store_global_setting(parameter, value));
}
上面的代码解释了下面的命令
https://github.com/grbl/grbl/wiki/Configuring-Grbl-v0.8
Grbl Internal Commands:
Technically, the remaining Grbl commands are not configuration commands, but we're going to explain them here for no good reason, other than for completeness.
The three current state commands: $G, $#, ?
Grbl provides three commands to report its current state and where it is. Of the three, one of them is real-time, responding with current position. The other two are not, but respond with how incoming blocks are going to be processed depending on the states set by g-code, settings, or switches. The reason they are not realtime is that Grbl has an internal buffer that stores and plans the buffered motions. The incoming gcode blocks just tack on a new motion at the end of the buffer when it has room. The buffer basically ensures Grbl motion move at the fastest and safest rates possible, constantly re-calculating it real-time as motions finish and new ones come in.
$G - View gcode parser state
This command prints all of the active gcode modes that the parser will interpret any incoming command. These modes include G20/G21 inches/mm mode, G54-G59 active work coordinate system, G0/G1/G2/G3 active motion mode, G17/G18/G19 active plane selection, G90/G91 absolute mode, G93/G94 inverse feed rate mode, M0/M1/M2 program flow, M3/M4/M5 spindle state, M8/M9 coolant state, T tool number, and F active feed rate. It will also list any active $Sx Grbl switches, like $S1 block delete. When called, Grbl will return a line like this:
[G0 G54 G17 G21 G90 G94 M0 M5 M9 T0 F500.000]
$# - View gcode parameters
G-code parameters generally store the G54-G59 work coordinate offsets and G28/G30 home positions (must not be confused with homing and machine zero. These home positions can be set anywhere in the machine space by the G28.1/G30.1 commands). Most of these parameters are directly written to EEPROM anytime they are changed and are persistent. Meaning that they will remain the same, regardless of power-down, until they are explicitly changed.
G54-G59 work coordinates can be changed via the G10 L2 Px or G10 L20 Px command defined by the NIST gcode standard and the EMC2 (linuxcnc.org) standard. G28/G30 home positions can be changed via the G28.1 and the G30.1 commands, respectively. Please note that G92 is not persistent or held in EEPROM per g-code standards, and will reset to zero when Grbl is reset. Please read these g-code standard to understand how they are used.
When $# is called, Grbl will respond with the stored offsets from machine coordinates for each system as follows.
[G54:4.000,0.000,0.000]
[G55:4.000,6.000,7.000]
[G56:0.000,0.000,0.000]
[G57:0.000,0.000,0.000]
[G58:0.000,0.000,0.000]
[G59:0.000,0.000,0.000]
[G28:1.000,2.000,0.000]
[G30:4.000,6.000,0.000]
[G92:0.000,0.000,0.000]
For the most part, these offset are not particularly useful unless you have homing enabled. If you do have homing enabled, these are wonderfully awesome, because once you home, you can always move back to same stored position by using the work coordinate systems within the accuracy of your machine. Or if you are making multiple parts and have a tool path for just one part, all you have to do is setup your work coordinate systems to the location where the next part is going to be made and re-run that same code.
? - Current status
The ? command immediately returns Grbl's active state and the real-time current position, both in machine coordinates and work coordinates. This may be sent at any time and works asynchronously with all other processes that Grbl is doing. The $13 Grbl setting determines whether it reports millimeters or inches. When ? is pressed, Grbl will immediately reply with something like the following:
The active states Grbl can be in are: Idle, Queue, Run, Hold, Home, Alarm, Check
Idle: All systems are go and it's ready for anything.
Queue: Motion(s) are queued in the planner buffer waiting for a cycle start command to be issued. Certain processes like check g-code mode can't run while something is queued. Reset to clear the queue.
Run: Indicates a cycle is running.
Hold: A feed hold is in process of executing, or slowing down to a stop. After the hold is complete, Grbl will enter a Queue state, waiting for a cycle start to resume the program.
Home: In the middle of a homing cycle. NOTE: Positions are not updated live during the homing cycle, but they'll be set to [0,0,0] once done.
Alarm: This indicates something has gone wrong or Grbl doesn't know its position. This state locks out all g-code commands, but allows you to interact with Grbl's settings if you need to. '$X' kill alarm lock releases this state and puts Grbl in the Idle state, which will let you move things again. As said before, be cautious of what you are doing after an alarm.
Check: Grbl is in check g-code mode. It will process and respond to all g-code commands, but not motion or turn on anything. Once toggled off with another '$C' command, Grbl will reset itself.
Other Commands $C $X $H ~ ! Ctrl-X
$C - Check gcode mode
This toggles the Grbl's gcode parser to take all incoming blocks process them completely, as it would in normal operation, but it does not move any of the axes, ignores dwells, and powers off the spindle and coolant. This is intended as a way to provide the user a way to check how their new g-code program fares with Grbl's parser and monitor for any errors. (And eventually this will also check for soft limit violations.)
When toggled off, Grbl will perform an automatic soft-reset (^X). This is for two purposes. It simplifies the code management a bit. But, it also prevents users from starting a job when their g-code modes are not what they think they are. A system reset always gives the user a fresh, consistent start.
NOTE: Eventually, the check gcode mode could be re-factored to allow for a "program resume" feature in Grbl. This means that Grbl could start a g-code program anywhere. It would internally go through all of the g-code program up to the desired mid-program resume point to set all of the parser states and locations, move to that start point, and begin executing/moving from that point on. For example, say you had to E-stop in the middle of a program because you forgot something or you have the wrong tool in the spindle. Your part is fine and need to restart the program. Right now, you'll have to start the program from the beginning and let it physically move and run up to the point where you e-stopped. If you have a long program, this could take a while. Instead, a "program resume" will just go through the beginning of the program internally, without moving anything, and only begin moving from the resume point on.
$X - Kill alarm lock
Grbl's alarm mode is a state when something has gone critically wrong, like a hard limit or an abort during a cycle, or if Grbl doesn't know its position. By default, if you have homing enabled and power-up the Arduino, Grbl enters the alarm state, because it does not know its position. The alarm mode will lock all g-code blocks until the '$H' homing cycle has been performed. Or if a user needs to override the alarm lock to move their axes off their limit switches, for example, '$X' kill alarm lock will override the locks and allow g-code functions to work again.
But, tread carefully!! This should only be used in emergency situations. The position has likely been lost, and Grbl may not be where you think it is. So, it's advised to use G91 incremental mode to make short moves. Then, perform a homing cycle or reset immediately afterwards.
$H - Run homing cycle
This command is the only way to perform the homing cycle in Grbl. Previously, G28 and G30 would automatically start the homing cycle, but this is incorrect according to the g-code standards. Homing is a completely separate command handled by the controller. G28 and G30 only move to a 'home'/pre-defined position that is stored in the g-code parameters, which can be located anywhere in the machine.
TIP: After running a homing cycle, rather jogging manually all the time to a position in the middle of your workspace volume. You can set a G28 or G30 pre-defined position to be your post-homing position, closer to where you'll be machining. To set these, you'll first need to jog your machine to where you would want it to move to after homing. Type G28.1 (or G30.1) to have Grbl store that position. So then after '$H' homing, you could just enter 'G28' (or 'G30') and it'll move there auto-magically. In general, I would just move the XY axis to the center and leave the Z-axis up. This ensures that there isn't a chance the tool in the spindle doesn't catch on anything.
~ - Cycle start
This is the cycle start or resume command that can be issued at any time, as it is a real-time command. When Grbl has motions queued in its buffer and is ready to go, the ~ cycle start command will start executing the buffer and Grbl will begin moving the axes. However, by default, auto-cycle start is enabled, so new users will not need this command unless a feed hold is performed. When a feed hold is executed, cycle start will resume the program. Cycle start will only be effective when there are motions in the buffer ready to go and will not work with any other process like homing.
! - Feed hold
The feed hold command will bring the active cycle to a stop via a controlled deceleration, so not to lose position. It is also real-time and may be activated at any time. Once finished or paused, Grbl will wait until a cycle start command is issued to resume to program. Feed hold can only pause a cycle and will not affect homing or any other process.
If you need to stop a cycle mid-program and can't afford losing position, perform a feed hold to have Grbl bring everything to a controlled stop. Once finished, you can then issue a reset. Always try to execute a feed hold whenever the machine is running before hitting reset, except of course if there is some emergency situation.
Ctrl-x - Reset Grbl
This is Grbl's soft reset command. It's real-time and can be sent at any time. As the name implies, it resets Grbl, but in a controlled way, retains your machine position, and all done without powering down your Arduino. The only times a soft-reset could lose position is when problems like if the steppers were killed while they were moving. If so, it will report if Grbl's tracking of the machine position has been lost. This is because an uncontrolled deceleration can lead to lost steps, and Grbl has no feedback to how much it lost (this is the problem with steppers in general). Otherwise, Grbl will just re-initialize, run the startup lines, and continue on its merry way.
Please note that it's recommended to do a soft-reset before starting a job. This guarantees that there aren't any g-code modes active that should be from playing around or setting up your machine. So, your machine will always starts fresh and consistently, and your machine does what you expect it to.
----------------------------------------
*******************
protocol.c 下2
*******************
内容9
Process and report status one line of incoming serial data.
void protocol_process()
{
uint8_t c;
while((c = serial_read()) != SERIAL_NO_DATA) {
if ((c == '') || (c == '')) {
内容9A();
}
else{
内容9B();
}
}
}
Performs an initial filtering by removing spaces and comments and capitalizing all letters.
Runtime command check point before executing line. Prevent any furthur line executions.
NOTE: If there is no line, this function should quickly return to the main program when the buffer empties of non-executable data.
内容9A();
protocol_execute_runtime();
if (sys.abort) { return; } // Bail to main program upon system abort
if (char_counter > 0) {// Line is complete. Then execute!
line[char_counter] = 0; // Terminate string
report_status_message(protocol_execute_line(line));
}
else {
// Empty or comment line. Skip block.
report_status_message(STATUS_OK); // Send status message for syncing purposes.
}
protocol_reset_line_buffer();
内容9B();
if (iscomment) {
// Throw away all comment characters
if (c == ')') {
// End of comment. Resume line.
iscomment = false;
}
} else {
if (c <= ' ') {
// Throw away whitepace and control characters
} else if (c == '/') {
// Block delete not supported. Ignore character.
} else if (c == '(') {
// Enable comments flag and ignore all characters until ')' or EOL.
iscomment = true;
}
else if (char_counter >= LINE_BUFFER_SIZE-1) {
// Report line buffer overflow and reset
report_status_message(STATUS_OVERFLOW);
protocol_reset_line_buffer();
} else if (c >= 'a' && c <= 'z') { // Upcase lowercase
line[char_counter++] = c-'a'+'A';
} else {
line[char_counter++] = c;
}
}
********************************
protocol 的代码看完,还是糊里糊涂的。先继续。
--------------------------------------------------------------------------
**********************
nuts_bolts.h
Header file for shared definitions, variables, and functions
***********************************
nuts_bolts.h 被 protocol.c 文件 引用过,并且 定义了很多 重要 变量和结构。
****************
内容1
引用头文件
#include
#include
#include
#include "config.h"
#include "defaults.h"
#include "pin_map.h"
是 标准 头文件,
网上搜一下,
config.h 已经理解过,compile time configuration
defaults.h 也理解过,defaults settings configuration file
pin_map.h - Pin mapping configuration file,端口功能定义,需要另外一篇文章理解。
********************************
内容2
利用宏定义常量
#define false 0
#define true 1
#define N_AXIS 3 // Number of axes
#define X_AXIS 0 // Axis indexing value
#define Y_AXIS 1
#define Z_AXIS 2
#define MM_PER_INCH (25.40)
#define INCH_PER_MM (0.0393701)
什么时候用 #define 什么时候用 const 定义常量,一般如下
1,对于数值和字符常量,用#define,注意添加必要注释;
2,对于其它类型常量,用 const 限定符
区别,
define宏仅仅是展开(替换),有多少地方使用,就展开多少次,不会分配内存。(宏定义不分配内存,变量定义分配内存。) const常量会在内存中分配(可以是堆中也可以是栈中)。
宏定义很简单。
************************
内容3
Useful macros
#define clear_vector(a) memset(a, 0, sizeof(a))
#define clear_vector_float(a) memset(a, 0.0, sizeof(float)*N_AXIS)
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
memset(a, 0, sizeof(a)),用 零 清空 整型数组 a;(memset 被 string.h 声明)
memset(a, 0.0, sizeof(float)*N_AXIS),用 0.0 清空 浮点型 数组 a;
max() ,min() 很简单
***********************
内容4
Bit field and masking macros
#define bit(n) (1 << n)
#define bit_true(x,mask) (x |= mask)
#define bit_false(x,mask) (x &= ~mask)
#define bit_toggle(x,mask) (x ^= mask)
#define bit_istrue(x,mask) ((x & mask) != 0)
#define bit_isfalse(x,mask) ((x & mask) == 0)
<<:左移位 http://baike.baidu.com/link?url= ... 2S3cSwNbpmTSUmOh-jK
n = 3; //n二进制为11
例如,
[code] n = 3; //n二进制为11
b = n<<1; //n向左移动一位,b二进制为110
b = n<<2; //n向左移动二位,b二进制为1100
b = 1<<n; 1像左移动n位,相当于2的n次方,b二进制为1000[="" code]
这些位运算符号
& 按位与
~ 按位取反
¦ 按位或
< < 按位左移
∧ 按位异或
http://blog.csdn.net/superdullwolf/article/details/4649080
位运算应用口诀
清零取反要用与,某位置一可用或
若要取反和交换,轻轻松松用异或
(1) 按位与-- &
1 清零特定位 (mask中特定位置0,其它位为1,s=s&mask)
2 取某数中指定位 (mask中特定位置1,其它位为0,s=s&mask)
(2) 按位或-- |
常用来将源操作数某些位置1,其它位不变。 (mask中特定位置1,其它位为0 s=s|mask)
(3) 位异或-- ^
1 使特定位的值取反 (mask中特定位置1,其它位为0 s=s^mask)
这些宏定义 是双刃剑,除非 宏的名字特别清晰已记,或者很熟悉这些宏定义,否则也容易混淆。尤其对新手。
********************************
内容5
Define system executor bit map.
在 protocol.c 中简单理解过,
#define EXEC_STATUS_REPORT bit(0) // bitmask 00000001
#define EXEC_CYCLE_START bit(1) // bitmask 00000010
#define EXEC_CYCLE_STOP bit(2) // bitmask 00000100
#define EXEC_FEED_HOLD bit(3) // bitmask 00001000
#define EXEC_RESET bit(4) // bitmask 00010000
#define EXEC_ALARM bit(5) // bitmask 00100000
#define EXEC_CRIT_EVENT bit(6) // bitmask 01000000
// #define bit(7) // bitmask 10000000
Used internally by runtime protocol as runtime command flags, which notifies the main program to execute the specified runtime command asynchronously.
NOTE: The system executor uses an unsigned 8-bit volatile variable (8 flag limit.)
The default flags are always false, so the runtime protocol only needs to check for a non-zero value to know when there is a runtime command to execute.
上面的宏 已经在 protocol.c 被应用了,而且一般 和 system_t 结构搭配,system_t 结构如下
***********************************
内容6
Define global system variables
typedef struct {
uint8_t abort; // System abort flag. Forces exit back to main loop for reset.
uint8_t state; // Tracks the current state of Grbl.
volatile uint8_t execute; // Global system runtime executor bitflag variable. See EXEC bitmasks.
int32_t position[N_AXIS]; // Real-time machine (aka home) position vector in steps.
// NOTE: This may need to be a volatile variable, if problems arise.
uint8_t auto_start; // Planner auto-start flag. Toggled off during feed hold. Defaulted by settings.
} system_t;
extern system_t sys;
用来记录 系统 状态
*********************************
内容7
Define system state bit map.
#define STATE_IDLE 0 // Must be zero.
#define STATE_INIT 1 // Initial power up state.
#define STATE_QUEUED 2 // Indicates buffered blocks, awaiting cycle start.
#define STATE_CYCLE 3 // Cycle is running
#define STATE_HOLD 4 // Executing feed hold
#define STATE_HOMING 5 // Performing homing cycle
#define STATE_ALARM 6 // In alarm state. Locks out all g-code processes. Allows settings access.
#define STATE_CHECK_MODE 7 // G-code check mode. Locks out planner and motion only.
// #define STATE_JOG 8 // Jogging mode is unique like homing.
The state variable primarily tracks the individual functions of Grbl to manage each without overlapping.
It is also used as a messaging flag for critical events.
******************************
内容8
声明 函数
int read_float(char *line, uint8_t *char_counter, float *float_ptr);
void delay_ms(uint16_t ms);
void delay_us(uint32_t us);
void sys_sync_current_position();
******************************
GRBL 的内容量 很多,只是浏览 一下 就很费力气,更别说理解要费多少精力。
-----------------------------------------------------------------
**********************
nuts_bolts.c
暂时只了解功能即可
***********************
不得不说,如果第一遍就把所有代码理解,对我来说是不可能完成的任务。必须要有取舍,这个文件就可以暂时不求理解其如何实现,只了解功能即可。
nuts_bolts.c - Shared functions
*********************
内容1
引用头文件
#include
#include "nuts_bolts.h"
#include "gcode.h"
#include "planner.h"
gcode.h - rs274/ngc parser. 一个重量级头文件
planner.h - buffers movement commands and manages the acceleration profile plan
*************************
内容2
#define MAX_INT_DIGITS 8 // Maximum number of digits in int32 (and float)
extern float __floatunsisf (unsigned long);
************************
内容3
Extracts a floating point value from a string.
The following code is based loosely on the avr-libc strtod() function by Michael Stumpf and Dmitry Xmelkov and many freely available conversion method examples, but has been highly optimized for Grbl.
For known CNC applications, the typical decimal value is expected to be in the range of E0 to E-4.
Scientific notation is officially not supported by g-code, and the 'E' character may be a g-code word on some CNC systems.
So, 'E' notation will not be recognized.
NOTE: Thanks to Radu-Eosif Mihailescu for identifying the issues with using strtod().
int read_float(char *line, uint8_t *char_counter, float *float_ptr)
{
char *ptr = line + *char_counter;
unsigned char c;
// Grab first character and increment pointer. No spaces assumed in line.
c = *ptr++;
// Capture initial positive/minus character
bool isnegative = false;
if (c == '-') {
isnegative = true;
c = *ptr++;
} else if (c == '+') {
c = *ptr++;
}
// Extract number into fast integer. Track decimal in terms of exponent value.
uint32_t intval = 0;
int8_t exp = 0;
uint8_t ndigit = 0;
bool isdecimal = false;
while(1) {
c -= '0';
if (c <= 9) {
ndigit++;
if (ndigit <= MAX_INT_DIGITS) {
if (isdecimal) { exp--; }
intval = (((intval << 2) + intval) << 1) + c; // intval*10 + c
} else {
if (!(isdecimal)) { exp++; } // Drop overflow digits
}
} else if (c == (('.'-'0') & 0xff) && !(isdecimal)) {
isdecimal = true;
} else {
break;
}
c = *ptr++;
}
// Return if no digits have been read.
if (!ndigit) { return(false); };
// Convert integer into floating point.
float fval;
fval = __floatunsisf(intval);
// Apply decimal. Should perform no more than two floating point multiplications for the
// expected range of E0 to E-4.
if (fval != 0) {
while (exp <= -2) {
fval *= 0.01;
exp += 2;
}
if (exp < 0) {
fval *= 0.1;
} else if (exp > 0) {
do {
fval *= 10.0;
} while (--exp > 0);
}
}
// Assign floating point value with correct sign.
if (isnegative) {
*float_ptr = -fval;
} else {
*float_ptr = fval;
}
*char_counter = ptr - line - 1; // Set char_counter to next statement
return(true);
}
有点复杂。
***************************************
内容4
Delays variable defined milliseconds.
Compiler compatibility fix for _delay_ms(), which only accepts constants in future compiler releases.
void delay_ms(uint16_t ms)
{
while ( ms-- ) { _delay_ms(1); }
}
**********************************
内容5
Delays variable defined microseconds.
Compiler compatibility fix for _delay_us(), which only accepts constants in future compiler releases.
Written to perform more efficiently with larger delays, as the counter adds parasitic time in each iteration.
void delay_us(uint32_t us)
{
while (us) {
if (us < 10) {
_delay_us(1);
us--;
} else if (us < 100) {
_delay_us(10);
us -= 10;
} else if (us < 1000) {
_delay_us(100);
us -= 100;
} else {
_delay_ms(1);
us -= 1000;
}
}
}
*************************************
内容6
Syncs all internal position vectors to the current system position.
void sys_sync_current_position()
{
plan_set_current_position(sys.position[X_AXIS],sys.position[Y_AXIS],sys.position[Z_AXIS]);
gc_set_current_position(sys.position[X_AXIS],sys.position[Y_AXIS],sys.position[Z_AXIS]);
}
*************************************
大概可以看出,这个文件是起辅助作用的,不直接操作CNC 相关设置。
</pin_reset)|(1<<pin_feed_hold)|(1<<pin_cycle_start))
</pin_reset)|(1<<pin_feed_hold)|(1<<pin_cycle_start))
</x_direction_bit)|(1<<y_direction_bit)
</x_axis)|(1<<y_axis)|(1<</x_axis)|(1<</rxcie0;
</txen0;
</rxen0;
|