version 0.1
This commit is contained in:
commit
9df29ad3b3
165
COPYING.txt
Normal file
165
COPYING.txt
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates
|
||||||
|
the terms and conditions of version 3 of the GNU General Public
|
||||||
|
License, supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License,
|
||||||
|
other than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
a) under this License, provided that you make a good faith effort to
|
||||||
|
ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
|
||||||
|
b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from
|
||||||
|
a header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the object code that the
|
||||||
|
Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that,
|
||||||
|
taken together, effectively do not restrict modification of the
|
||||||
|
portions of the Library contained in the Combined Work and reverse
|
||||||
|
engineering for debugging such modifications, if you also do each of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
|
||||||
|
d) Do one of the following:
|
||||||
|
|
||||||
|
0) Convey the Minimal Corresponding Source under the terms of this
|
||||||
|
License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
|
||||||
|
1) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (a) uses at run time
|
||||||
|
a copy of the Library already present on the user's computer
|
||||||
|
system, and (b) will operate properly with a modified version
|
||||||
|
of the Library that is interface-compatible with the Linked
|
||||||
|
Version.
|
||||||
|
|
||||||
|
e) Provide Installation Information, but only if you would otherwise
|
||||||
|
be required to provide such information under section 6 of the
|
||||||
|
GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the
|
||||||
|
Application with a modified version of the Linked Version. (If
|
||||||
|
you use option 4d0, the Installation Information must accompany
|
||||||
|
the Minimal Corresponding Source and Corresponding Application
|
||||||
|
Code. If you use option 4d1, you must provide the Installation
|
||||||
|
Information in the manner specified by section 6 of the GNU GPL
|
||||||
|
for conveying Corresponding Source.)
|
||||||
|
|
||||||
|
5. Combined Libraries.
|
||||||
|
|
||||||
|
You may place library facilities that are a work based on the
|
||||||
|
Library side by side in a single library together with other library
|
||||||
|
facilities that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based
|
||||||
|
on the Library, uncombined with any other library facilities,
|
||||||
|
conveyed under the terms of this License.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU Lesser General Public License from time to time. Such new
|
||||||
|
versions will be similar in spirit to the present version, but may
|
||||||
|
differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Library as you received it specifies that a certain numbered version
|
||||||
|
of the GNU Lesser General Public License "or any later version"
|
||||||
|
applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that published version or of any later version
|
||||||
|
published by the Free Software Foundation. If the Library as you
|
||||||
|
received it does not specify a version number of the GNU Lesser
|
||||||
|
General Public License, you may choose any version of the GNU Lesser
|
||||||
|
General Public License ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
89
Makefile
Normal file
89
Makefile
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
# Part of Grbl
|
||||||
|
#
|
||||||
|
# Copyright (c) 2009 Simen Svale Skogsrud
|
||||||
|
#
|
||||||
|
# Grbl is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Grbl is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
# This is a prototype Makefile. Modify it according to your needs.
|
||||||
|
# You should at least check the settings for
|
||||||
|
# DEVICE ....... The AVR device you compile for
|
||||||
|
# CLOCK ........ Target AVR clock rate in Hertz
|
||||||
|
# OBJECTS ...... The object files created from your source files. This list is
|
||||||
|
# usually the same as the list of source files with suffix ".o".
|
||||||
|
# PROGRAMMER ... Options to avrdude which define the hardware you use for
|
||||||
|
# uploading to the AVR and the interface where this hardware
|
||||||
|
# is connected.
|
||||||
|
# FUSES ........ Parameters for avrdude to flash the fuses appropriately.
|
||||||
|
|
||||||
|
DEVICE = atmega168
|
||||||
|
CLOCK = 20000000
|
||||||
|
PROGRAMMER = -c avrisp2 -P usb
|
||||||
|
OBJECTS = main.o motion_control.o gcode.o spindle_control.o wiring_serial.o serial_protocol.o
|
||||||
|
FUSES = -U hfuse:w:0xd9:m -U lfuse:w:0x24:m
|
||||||
|
|
||||||
|
# Tune the lines below only if you know what you are doing:
|
||||||
|
|
||||||
|
AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE) -B 10
|
||||||
|
COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) -I.
|
||||||
|
|
||||||
|
# symbolic targets:
|
||||||
|
all: main.hex
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(COMPILE) -c $< -o $@
|
||||||
|
|
||||||
|
.S.o:
|
||||||
|
$(COMPILE) -x assembler-with-cpp -c $< -o $@
|
||||||
|
# "-x assembler-with-cpp" should not be necessary since this is the default
|
||||||
|
# file type for the .S (with capital S) extension. However, upper case
|
||||||
|
# characters are not always preserved on Windows. To ensure WinAVR
|
||||||
|
# compatibility define the file type manually.
|
||||||
|
|
||||||
|
.c.s:
|
||||||
|
$(COMPILE) -S $< -o $@
|
||||||
|
|
||||||
|
flash: all
|
||||||
|
$(AVRDUDE) -U flash:w:main.hex:i
|
||||||
|
|
||||||
|
fuse:
|
||||||
|
$(AVRDUDE) $(FUSES)
|
||||||
|
|
||||||
|
# Xcode uses the Makefile targets "", "clean" and "install"
|
||||||
|
install: flash fuse
|
||||||
|
|
||||||
|
# if you use a bootloader, change the command below appropriately:
|
||||||
|
load: all
|
||||||
|
bootloadHID main.hex
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f main.hex main.elf $(OBJECTS)
|
||||||
|
|
||||||
|
# file targets:
|
||||||
|
main.elf: $(OBJECTS)
|
||||||
|
$(COMPILE) -o main.elf $(OBJECTS) -lm
|
||||||
|
|
||||||
|
main.hex: main.elf
|
||||||
|
rm -f main.hex
|
||||||
|
avr-objcopy -j .text -j .data -O ihex main.elf main.hex
|
||||||
|
avr-size main.hex *.o
|
||||||
|
# If you have an EEPROM section, you must also create a hex file for the
|
||||||
|
# EEPROM and add it to the "flash" target.
|
||||||
|
|
||||||
|
# Targets for code debugging and analysis:
|
||||||
|
disasm: main.elf
|
||||||
|
avr-objdump -d main.elf
|
||||||
|
|
||||||
|
cpp:
|
||||||
|
$(COMPILE) -E main.c
|
73
config.h
Normal file
73
config.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
config.h - configuration data for Grbl
|
||||||
|
Part of Grbl
|
||||||
|
|
||||||
|
Copyright (c) 2009 Simen Svale Skogsrud
|
||||||
|
|
||||||
|
Grbl is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Grbl is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef config_h
|
||||||
|
#define config_h
|
||||||
|
|
||||||
|
#define VERSION "0.1"
|
||||||
|
|
||||||
|
#define X_STEPS_PER_MM 100.0
|
||||||
|
#define Y_STEPS_PER_MM 100.0
|
||||||
|
#define Z_STEPS_PER_MM 100.0
|
||||||
|
|
||||||
|
#define INCHES_PER_MM 25.4
|
||||||
|
#define X_STEPS_PER_INCH X_STEPS_PER_MM*INCHES_PER_MM
|
||||||
|
#define Y_STEPS_PER_INCH Y_STEPS_PER_MM*INCHES_PER_MM
|
||||||
|
#define Z_STEPS_PER_INCH Z_STEPS_PER_MM*INCHES_PER_MM
|
||||||
|
|
||||||
|
#define RAPID_FEEDRATE 1270.0 // in millimeters per minute
|
||||||
|
#define DEFAULT_FEEDRATE 635.0
|
||||||
|
|
||||||
|
#define STEPPERS_ENABLE_DDR DDRB
|
||||||
|
#define STEPPERS_ENABLE_PORT PORTB
|
||||||
|
#define STEPPERS_ENABLE_BIT 6
|
||||||
|
|
||||||
|
#define STEP_DDR DDRB
|
||||||
|
#define STEP_PORT PORTB
|
||||||
|
#define X_STEP_BIT 0
|
||||||
|
#define Y_STEP_BIT 2
|
||||||
|
#define Z_STEP_BIT 4
|
||||||
|
#define STEP_MASK (1<<X_STEP_BIT)|(1<<Y_STEP_BIT)|(1<<Z_STEP_BIT)
|
||||||
|
|
||||||
|
#define DIRECTION_DDR DDRB
|
||||||
|
#define DIRECTION_PORT PORTB
|
||||||
|
#define X_DIRECTION_BIT 1
|
||||||
|
#define Y_DIRECTION_BIT 3
|
||||||
|
#define Z_DIRECTION_BIT 5
|
||||||
|
#define DIRECTION_MASK (1<<X_DIRECTION_BIT)|(1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)
|
||||||
|
|
||||||
|
#define LIMIT_DDR DDRC
|
||||||
|
#define LIMIT_PORT PORTC
|
||||||
|
#define X_LIMIT_BIT 0
|
||||||
|
#define Y_LIMIT_BIT 1
|
||||||
|
#define Z_LIMIT_BIT 2
|
||||||
|
#define LIMIT_MASK (1<<X_LIMIT_BIT)|(1<<Y_LIMIT_BIT)|(1<<Z_LIMIT_BIT)
|
||||||
|
|
||||||
|
#define SPINDLE_ENABLE_DDR DDRC
|
||||||
|
#define SPINDLE_ENABLE_PORT PORTC
|
||||||
|
#define SPINDLE_ENABLE_BIT 3
|
||||||
|
|
||||||
|
#define SPINDLE_DIRECTION_DDR DDRC
|
||||||
|
#define SPINDLE_DIRECTION_PORT PORTC
|
||||||
|
#define SPINDLE_DIRECTION_BIT 4
|
||||||
|
|
||||||
|
#define BAUD_RATE 14400
|
||||||
|
|
||||||
|
#endif
|
308
gcode.c
Normal file
308
gcode.c
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
/*
|
||||||
|
gcode.c - rs274/ngc parser.
|
||||||
|
Part of Grbl
|
||||||
|
|
||||||
|
Copyright (c) 2009 Simen Svale Skogsrud
|
||||||
|
|
||||||
|
Grbl is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Grbl is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This code is inspired by the Arduino GCode Interpreter by Mike Ellery and the NIST RS274/NGC Interpreter
|
||||||
|
by Kramer, Proctor and Messina. */
|
||||||
|
|
||||||
|
/* Intentionally not supported:
|
||||||
|
- Canned cycles
|
||||||
|
- Tool radius compensatino
|
||||||
|
- A,B,C-axes
|
||||||
|
- Multiple coordinate systems
|
||||||
|
- Evaluation of expressions
|
||||||
|
- Variables
|
||||||
|
- Multiple home locations
|
||||||
|
- Probing
|
||||||
|
- Spindle direction
|
||||||
|
- Override control
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Omitted for the time being:
|
||||||
|
|
||||||
|
group 0 = {G10, G28, G30, G53, G92, G92.1, G92.2, G92.3} (Non modal G-codes)
|
||||||
|
group 5 = {G93, G94} feed rate mode
|
||||||
|
group 12 = {G54, G55, G56, G57, G58, G59, G59.1, G59.2, G59.3} coordinate system selection
|
||||||
|
group 13 = {G61, G61.1, G64} path control mode
|
||||||
|
group 4 = {M0, M1, M2, M30, M60} stopping
|
||||||
|
group 8 = {M7, M8, M9} coolant (special case: M7 and M8 may be active at the same time)
|
||||||
|
group 9 = {M48, M49} enable/disable feed and speed override switches
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gcode.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "nuts_bolts.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "motion_control.h"
|
||||||
|
#include "spindle_control.h"
|
||||||
|
|
||||||
|
#define NEXT_ACTION_DEFAULT 0
|
||||||
|
#define NEXT_ACTION_DWELL 1
|
||||||
|
#define NEXT_ACTION_GO_HOME 2
|
||||||
|
|
||||||
|
#define MOTION_MODE_RAPID_LINEAR 0 // G0
|
||||||
|
#define MOTION_MODE_LINEAR 1 // G1
|
||||||
|
#define MOTION_MODE_CW_ARC 2 // G2
|
||||||
|
#define MOTION_MODE_CCW_ARC 3 // G3
|
||||||
|
#define MOTION_MODE_CANCEL 4 // G80
|
||||||
|
|
||||||
|
#define PLANE_XY 0; // G17
|
||||||
|
#define PLANE_XZ 1; // G18
|
||||||
|
#define PLANE_YZ 2; // G19
|
||||||
|
|
||||||
|
#define PATH_CONTROL_MODE_EXACT_PATH 0
|
||||||
|
#define PATH_CONTROL_MODE_EXACT_STOP 1
|
||||||
|
#define PATH_CONTROL_MODE_CONTINOUS 2
|
||||||
|
|
||||||
|
#define PROGRAM_FLOW_RUNNING 0
|
||||||
|
#define PROGRAM_FLOW_PAUSED 1
|
||||||
|
#define PROGRAM_FLOW_COMPLETED 2
|
||||||
|
|
||||||
|
#define SPINDLE_DIRECTION_CW 0
|
||||||
|
#define SPINDLE_DIRECTION_CCW 1
|
||||||
|
|
||||||
|
// Using packed bit fields saves a "lot" of invaluable SRAM, but bumps the compiled size of this unit
|
||||||
|
// by 100 bytes. If we get tight on code space, consider using byte aligned values again.
|
||||||
|
struct ParserState {
|
||||||
|
uint32_t line_number;
|
||||||
|
uint8_t status_code:5;
|
||||||
|
|
||||||
|
uint8_t motion_mode:3; /* {G0, G1, G2, G3, G38.2, G80, G81, G82, G83, G84, G85, G86, G87, G88, G89} */
|
||||||
|
uint8_t inverse_feed_rate_mode:1; /* G93, G94 */
|
||||||
|
uint8_t plane:2; /* {G17, G18, G19} */
|
||||||
|
uint8_t inches_mode:1; /* 0 = millimeter mode, 1 = inches mode {G20, G21} */
|
||||||
|
uint8_t program_flow:2;
|
||||||
|
int spindle_direction:2;
|
||||||
|
double feed_rate; /* Millimeters/second */
|
||||||
|
double logical_position[3]; /* Where the interpreter considers the tool to be at this point in the code */
|
||||||
|
uint8_t tool;
|
||||||
|
int16_t spindle_speed; /* RPM/100 */
|
||||||
|
};
|
||||||
|
struct ParserState state;
|
||||||
|
|
||||||
|
#define FAIL(status) state.status_code = status;
|
||||||
|
|
||||||
|
int read_double(char *line, //!< string: line of RS274/NGC code being processed
|
||||||
|
int *counter, //!< pointer to a counter for logical_position on the line
|
||||||
|
double *double_ptr); //!< pointer to double to be read
|
||||||
|
|
||||||
|
int next_statement(char *letter, double *double_ptr, char *line, int *counter);
|
||||||
|
|
||||||
|
|
||||||
|
void gc_init() {
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
state.feed_rate = DEFAULT_FEEDRATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float to_millimeters(double value) {
|
||||||
|
return(state.inches_mode ? value * INCHES_PER_MM : value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Executes one line of 0-terminated G-Code. The line is assumed to contain only uppercase
|
||||||
|
// characters and signed floats (no whitespace).
|
||||||
|
uint8_t gc_execute_line(char *line) {
|
||||||
|
int counter;
|
||||||
|
char letter;
|
||||||
|
double value;
|
||||||
|
double unit_converted_value;
|
||||||
|
double inverse_feed_rate;
|
||||||
|
|
||||||
|
uint8_t absolute_mode = 0; /* 0 = relative motion, 1 = absolute motion {G90, G91} */
|
||||||
|
uint8_t next_action = NEXT_ACTION_DEFAULT; /* One of the NEXT_ACTION_-constants */
|
||||||
|
|
||||||
|
double target[3], offset[3];
|
||||||
|
|
||||||
|
double p, r;
|
||||||
|
int int_value, axis;
|
||||||
|
|
||||||
|
state.line_number++;
|
||||||
|
state.status_code = GCSTATUS_OK;
|
||||||
|
|
||||||
|
/* First: parse all statements */
|
||||||
|
|
||||||
|
if (line[0] == '(') { return(state.status_code); }
|
||||||
|
if (line[0] == '/') { counter++; } // ignore block delete
|
||||||
|
|
||||||
|
// Pass 1: Commands
|
||||||
|
while(next_statement(&letter, &value, line, &counter)) {
|
||||||
|
int_value = trunc(value);
|
||||||
|
switch(letter) {
|
||||||
|
case 'G':
|
||||||
|
switch(int_value) {
|
||||||
|
case 0: state.motion_mode = MOTION_MODE_RAPID_LINEAR; break;
|
||||||
|
case 1: state.motion_mode = MOTION_MODE_LINEAR; break;
|
||||||
|
case 2: state.motion_mode = MOTION_MODE_CW_ARC; break;
|
||||||
|
case 3: state.motion_mode = MOTION_MODE_CCW_ARC; break;
|
||||||
|
case 4: next_action = NEXT_ACTION_DWELL; break;
|
||||||
|
case 17: state.plane = PLANE_XY; break;
|
||||||
|
case 18: state.plane = PLANE_XZ; break;
|
||||||
|
case 19: state.plane = PLANE_YZ; break;
|
||||||
|
case 20: state.inches_mode = true; break;
|
||||||
|
case 21: state.inches_mode = false; break;
|
||||||
|
case 28: case 30: next_action = NEXT_ACTION_GO_HOME; break;
|
||||||
|
case 53: absolute_mode = 1; break;
|
||||||
|
case 80: state.motion_mode = MOTION_MODE_CANCEL; break;
|
||||||
|
case 93: state.inverse_feed_rate_mode = true; break;
|
||||||
|
case 94: state.inverse_feed_rate_mode = false; break;
|
||||||
|
default: FAIL(GCSTATUS_UNSUPPORTED_STATEMENT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'M':
|
||||||
|
switch(int_value) {
|
||||||
|
case 0: case 1: state.program_flow = PROGRAM_FLOW_PAUSED; break;
|
||||||
|
case 2: state.program_flow = PROGRAM_FLOW_COMPLETED; break;
|
||||||
|
case 3: state.spindle_direction = 1; break;
|
||||||
|
case 4: state.spindle_direction = -1; break;
|
||||||
|
case 5: state.spindle_direction = 0; break;
|
||||||
|
default: FAIL(GCSTATUS_UNSUPPORTED_STATEMENT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'T': state.tool = trunc(value); break;
|
||||||
|
}
|
||||||
|
if(state.status_code) { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there were any errors parsing this line, we will return right away with the bad news
|
||||||
|
if (state.status_code) { return(state.status_code); }
|
||||||
|
|
||||||
|
// Pass 2: Parameters
|
||||||
|
counter = 0;
|
||||||
|
clear_vector(offset);
|
||||||
|
while(next_statement(&letter, &value, line, &counter)) {
|
||||||
|
int_value = trunc(value);
|
||||||
|
unit_converted_value = to_millimeters(value);
|
||||||
|
switch(letter) {
|
||||||
|
case 'F':
|
||||||
|
if (state.inverse_feed_rate_mode) {
|
||||||
|
inverse_feed_rate = unit_converted_value; // seconds per motion for this motion only
|
||||||
|
} else {
|
||||||
|
state.feed_rate = unit_converted_value; // millimeters pr second
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'I': case 'J': case 'K': offset[letter-'I'] = unit_converted_value; break;
|
||||||
|
case 'P': p = value; break;
|
||||||
|
case 'R': r = unit_converted_value; break;
|
||||||
|
case 'S': state.spindle_speed = value; break;
|
||||||
|
case 'X': case 'Y': case 'Z':
|
||||||
|
axis = letter - 'X';
|
||||||
|
if (absolute_mode) {
|
||||||
|
target[axis] = unit_converted_value;
|
||||||
|
} else {
|
||||||
|
target[axis] = state.logical_position[axis]+unit_converted_value;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update spindle state
|
||||||
|
if (state.spindle_direction) {
|
||||||
|
spindle_run(state.spindle_direction, state.spindle_speed);
|
||||||
|
} else {
|
||||||
|
spindle_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform any physical actions
|
||||||
|
switch (next_action) {
|
||||||
|
case NEXT_ACTION_GO_HOME: mc_go_home(); break;
|
||||||
|
case NEXT_ACTION_DWELL: mc_dwell(trunc(p*1000)); break;
|
||||||
|
case NEXT_ACTION_DEFAULT:
|
||||||
|
switch (state.motion_mode) {
|
||||||
|
case MOTION_MODE_CANCEL: break;
|
||||||
|
case MOTION_MODE_RAPID_LINEAR: case MOTION_MODE_LINEAR:
|
||||||
|
if (inverse_feed_rate) {
|
||||||
|
mc_linear_motion(target[X_AXIS], target[Y_AXIS], target[Z_AXIS],
|
||||||
|
inverse_feed_rate, true);
|
||||||
|
} else {
|
||||||
|
mc_linear_motion(target[X_AXIS], target[Y_AXIS], target[Z_AXIS],
|
||||||
|
(state.motion_mode == MOTION_MODE_LINEAR) ? state.feed_rate : RAPID_FEEDRATE,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MOTION_MODE_CW_ARC: case MOTION_MODE_CCW_ARC:
|
||||||
|
// to be implemented
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mc_execute();
|
||||||
|
|
||||||
|
// As far as the parser is concerned, the logical_position is now == target. In reality the
|
||||||
|
// motion control system might still be processing the action and the real tool position
|
||||||
|
// in any intermediate location.
|
||||||
|
memcpy(state.logical_position, target, sizeof(state.logical_position));
|
||||||
|
|
||||||
|
return(state.status_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gc_get_status(double *position, uint8_t *status_code, int *inches_mode, uint32_t *line_number)
|
||||||
|
{
|
||||||
|
int axis;
|
||||||
|
if (state.inches_mode) {
|
||||||
|
for(axis = X_AXIS; axis <= Z_AXIS; axis++) {
|
||||||
|
position[axis] = state.logical_position[axis]*INCHES_PER_MM;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(position, state.logical_position, sizeof(position));
|
||||||
|
}
|
||||||
|
*status_code = state.status_code;
|
||||||
|
*inches_mode = state.inches_mode;
|
||||||
|
*line_number = state.line_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parses the next statement and leaves the counter on the first character following
|
||||||
|
// the statement. Returns 1 if there was a statements, 0 if end of string was reached
|
||||||
|
// or there was an error (check state.status_code).
|
||||||
|
int next_statement(char *letter, double *double_ptr, char *line, int *counter) {
|
||||||
|
if (*line == 0) {
|
||||||
|
return(0); // No more statements
|
||||||
|
}
|
||||||
|
|
||||||
|
*letter = *line;
|
||||||
|
if((*letter < 'A') || (*letter > 'Z')) {
|
||||||
|
FAIL(GCSTATUS_EXPECTED_COMMAND_LETTER);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
*counter++;
|
||||||
|
if (!read_double(line, counter, double_ptr)) {
|
||||||
|
return(0);
|
||||||
|
};
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_double(char *line, //!< string: line of RS274/NGC code being processed
|
||||||
|
int *counter, //!< pointer to a counter for position on the line
|
||||||
|
double *double_ptr) //!< pointer to double to be read
|
||||||
|
{
|
||||||
|
char *start = line + *counter;
|
||||||
|
char *end;
|
||||||
|
|
||||||
|
*double_ptr = strtod(start, &end);
|
||||||
|
if(end == start) {
|
||||||
|
FAIL(GCSTATUS_BAD_NUMBER_FORMAT);
|
||||||
|
return(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
*counter = end - line;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
41
gcode.h
Normal file
41
gcode.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
gcode.c - rs274/ngc parser.
|
||||||
|
Part of Grbl
|
||||||
|
|
||||||
|
Copyright (c) 2009 Simen Svale Skogsrud
|
||||||
|
|
||||||
|
Grbl is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Grbl is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef gcode_h
|
||||||
|
#define gcode_h
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
#define GCSTATUS_OK 0
|
||||||
|
#define GCSTATUS_BAD_NUMBER_FORMAT 1
|
||||||
|
#define GCSTATUS_EXPECTED_COMMAND_LETTER 2
|
||||||
|
#define GCSTATUS_UNSUPPORTED_STATEMENT 3
|
||||||
|
#define GCSTATUS_MOTION_CONTROL_ERROR 4
|
||||||
|
|
||||||
|
// Initialize the parser
|
||||||
|
void gc_init();
|
||||||
|
|
||||||
|
// Execute one block of rs275/ngc/g-code
|
||||||
|
uint8_t gc_execute_line(char *line);
|
||||||
|
|
||||||
|
// get the current logical position (in current units), the current status code and the unit mode
|
||||||
|
void gc_get_status(double *position, uint8_t *status_code, int *inches_mode, uint32_t *line_number);
|
||||||
|
|
||||||
|
#endif
|
41
main.c
Normal file
41
main.c
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
main.c - An embedded CNC Controller with rs274/ngc (g-code) support
|
||||||
|
Part of Grbl
|
||||||
|
|
||||||
|
Copyright (c) 2009 Simen Svale Skogsrud
|
||||||
|
|
||||||
|
Grbl is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Grbl is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/sleep.h>
|
||||||
|
#include "motion_control.h"
|
||||||
|
#include "gcode.h"
|
||||||
|
#include "spindle_control.h"
|
||||||
|
#include "serial_protocol.h"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
mc_init(); // initialize motion control subsystem
|
||||||
|
gc_init(); // initialize gcode-parser
|
||||||
|
spindle_init(); // initialize spindle controller
|
||||||
|
sp_init(); // initialize the serial protocol
|
||||||
|
|
||||||
|
gc_execute_line("123.1");
|
||||||
|
for(;;){
|
||||||
|
sleep_mode();
|
||||||
|
sp_process(); // process the serial protocol
|
||||||
|
}
|
||||||
|
return 0; /* never reached */
|
||||||
|
}
|
338
motion_control.c
Normal file
338
motion_control.c
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
/*
|
||||||
|
motion_control.c - cartesian robot controller.
|
||||||
|
Part of Grbl
|
||||||
|
|
||||||
|
Copyright (c) 2009 Simen Svale Skogsrud
|
||||||
|
|
||||||
|
Grbl is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Grbl is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This code was inspired by the Arduino GCode_Interpreter by Mike Ellery. */
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "motion_control.h"
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "nuts_bolts.h"
|
||||||
|
|
||||||
|
// position represents the current position of the head measured in steps
|
||||||
|
// target is the target for the current linear motion
|
||||||
|
// step_count contains the absolute values of the steps to travel along each axis
|
||||||
|
// direction is the sign of the motion for each axis (-1: reverse, 0: standby, 1: forward)
|
||||||
|
|
||||||
|
#define MODE_AT_REST 0
|
||||||
|
#define MODE_LINEAR 1
|
||||||
|
#define MODE_ARC 2
|
||||||
|
#define MODE_DWELL 3
|
||||||
|
#define MODE_HOME 4
|
||||||
|
#define MODE_LIMIT_OVERRUN -1
|
||||||
|
|
||||||
|
#define PHASE_HOME_RETURN 0
|
||||||
|
#define PHASE_HOME_NUDGE 1
|
||||||
|
|
||||||
|
#define ONE_MINUTE_OF_MICROSECONDS 60000000
|
||||||
|
|
||||||
|
// Parameters when mode is MODE_ARC
|
||||||
|
struct LinearMotionParameters {
|
||||||
|
int8_t direction[3]; // The direction of travel along each axis (-1, 0 or 1)
|
||||||
|
uint16_t feed_rate;
|
||||||
|
int32_t target[3], // The target position in absolute steps
|
||||||
|
step_count[3], // Absolute steps of travel along each axis
|
||||||
|
counter[3], // A counter used in the bresenham algorithm for line plotting
|
||||||
|
maximum_steps; // The larges absolute step-count of any axis
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parameters when mode is MODE_LINEAR
|
||||||
|
struct ArcMotionParameters {
|
||||||
|
uint32_t radius;
|
||||||
|
int16_t degrees;
|
||||||
|
int ccw;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HomeCycleParameters {
|
||||||
|
int8_t direction[3]; // The direction of travel along each axis (-1, 0 or 1)
|
||||||
|
int8_t phase; // current phase of the home cycle.
|
||||||
|
int8_t away[3]; // a vector of booleans. True for each axis that is still away.
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The whole state of the motion-control-system in one struct. Makes the code a little bit hard to
|
||||||
|
read, but lets us initialize the state of the system by just clearing a single, contigous block of memory.
|
||||||
|
By overlaying the variables of the different modes in a union we save a few bytes of precious SRAM.
|
||||||
|
*/
|
||||||
|
struct MotionControlState {
|
||||||
|
int8_t mode; // The current operation mode
|
||||||
|
int32_t position[3]; // The current position of the tool in absolute steps
|
||||||
|
int32_t update_delay_us; // Microseconds between each update in the current mode
|
||||||
|
union {
|
||||||
|
struct LinearMotionParameters linear; // variables used in MODE_LINEAR
|
||||||
|
struct ArcMotionParameters arc; // variables used in MODE_ARC
|
||||||
|
struct HomeCycleParameters home; // variables used in MODE_HOME
|
||||||
|
uint32_t dwell_milliseconds; // variable used in MODE_DWELL
|
||||||
|
int8_t limit_overrun_direction[3]; // variable used in MODE_LIMIT_OVERRUN
|
||||||
|
};
|
||||||
|
};
|
||||||
|
struct MotionControlState state;
|
||||||
|
|
||||||
|
int check_limit_switches();
|
||||||
|
void enable_steppers();
|
||||||
|
void disable_steppers();
|
||||||
|
void set_direction_pins(int8_t *direction);
|
||||||
|
inline void step_steppers(uint8_t *enabled);
|
||||||
|
void limit_overrun(uint8_t *direction);
|
||||||
|
int check_limit_switch(int axis);
|
||||||
|
inline void step_axis(uint8_t axis);
|
||||||
|
|
||||||
|
void mc_init()
|
||||||
|
{
|
||||||
|
// Initialize state variables
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
|
||||||
|
// Configure directions of interface pins
|
||||||
|
STEP_DDR |= STEP_MASK;
|
||||||
|
DIRECTION_DDR |= DIRECTION_MASK;
|
||||||
|
LIMIT_DDR &= ~(LIMIT_MASK);
|
||||||
|
STEPPERS_ENABLE_DDR |= 1<<STEPPERS_ENABLE_BIT;
|
||||||
|
|
||||||
|
disable_steppers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void limit_overrun(uint8_t *direction)
|
||||||
|
{
|
||||||
|
state.mode = MODE_LIMIT_OVERRUN;
|
||||||
|
memcpy(state.limit_overrun_direction, direction, sizeof(state.limit_overrun_direction));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mc_dwell(uint32_t milliseconds)
|
||||||
|
{
|
||||||
|
mc_wait();
|
||||||
|
state.mode = MODE_DWELL;
|
||||||
|
state.dwell_milliseconds = milliseconds;
|
||||||
|
state.update_delay_us = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mc_linear_motion(double x, double y, double z, float feed_rate, int invert_feed_rate)
|
||||||
|
{
|
||||||
|
mc_wait();
|
||||||
|
state.mode = MODE_LINEAR;
|
||||||
|
|
||||||
|
state.linear.target[X_AXIS] = trunc(x*X_STEPS_PER_MM);
|
||||||
|
state.linear.target[Y_AXIS] = trunc(y*Y_STEPS_PER_MM);
|
||||||
|
state.linear.target[Z_AXIS] = trunc(z*Z_STEPS_PER_MM);
|
||||||
|
|
||||||
|
uint8_t axis; // loop variable
|
||||||
|
|
||||||
|
// Determine direction and travel magnitude for each axis
|
||||||
|
for(axis = X_AXIS; axis <= Z_AXIS; axis++) {
|
||||||
|
state.linear.step_count[axis] = abs(state.linear.target[axis] - state.position[axis]);
|
||||||
|
state.linear.direction[axis] = sign(state.linear.step_count[axis]);
|
||||||
|
}
|
||||||
|
// Find the magnitude of the axis with the longest travel
|
||||||
|
state.linear.maximum_steps = max(state.linear.step_count[Z_AXIS],
|
||||||
|
max(state.linear.step_count[X_AXIS], state.linear.step_count[Y_AXIS]));
|
||||||
|
|
||||||
|
// Set up a neat counter for each axis
|
||||||
|
for(axis = X_AXIS; axis <= Z_AXIS; axis++) {
|
||||||
|
state.linear.counter[axis] = -state.linear.maximum_steps/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set our direction pins
|
||||||
|
set_direction_pins(state.linear.direction);
|
||||||
|
|
||||||
|
// Calculate the microseconds we need to wait between each step to achieve the desired feed rate
|
||||||
|
if (invert_feed_rate) {
|
||||||
|
state.update_delay_us =
|
||||||
|
(feed_rate*1000000.0)/state.linear.maximum_steps;
|
||||||
|
} else {
|
||||||
|
// Ask old Phytagoras how many millimeters our next move is going to take us:
|
||||||
|
float millimeters_of_travel =
|
||||||
|
sqrt(pow((X_STEPS_PER_MM*state.linear.step_count[X_AXIS]),2) +
|
||||||
|
pow((Y_STEPS_PER_MM*state.linear.step_count[Y_AXIS]),2) +
|
||||||
|
pow((Z_STEPS_PER_MM*state.linear.step_count[Z_AXIS]),2));
|
||||||
|
state.update_delay_us =
|
||||||
|
((millimeters_of_travel * ONE_MINUTE_OF_MICROSECONDS) / feed_rate) / state.linear.maximum_steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void perform_linear_motion()
|
||||||
|
{
|
||||||
|
// Flags to keep track of which axes to step
|
||||||
|
uint8_t step[3];
|
||||||
|
uint8_t axis; // loop variable
|
||||||
|
|
||||||
|
// Trace the line
|
||||||
|
clear_vector(step);
|
||||||
|
for(axis = X_AXIS; axis <= Z_AXIS; axis++) {
|
||||||
|
if (state.linear.target[axis] != state.position[axis])
|
||||||
|
{
|
||||||
|
state.linear.counter[axis] += state.linear.step_count[axis];
|
||||||
|
if (state.linear.counter[axis] > 0)
|
||||||
|
{
|
||||||
|
step[axis] = true;
|
||||||
|
state.linear.counter[axis] -= state.linear.maximum_steps;
|
||||||
|
state.position[axis] += state.linear.direction[axis];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step[X_AXIS] | step[Y_AXIS] | step[Z_AXIS]) {
|
||||||
|
step_steppers(step);
|
||||||
|
|
||||||
|
// If we trip any limit switch while moving: Abort, abort!
|
||||||
|
if (check_limit_switches()) {
|
||||||
|
limit_overrun(state.linear.direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
_delay_us(state.update_delay_us);
|
||||||
|
} else {
|
||||||
|
state.mode = MODE_AT_REST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mc_go_home()
|
||||||
|
{
|
||||||
|
state.mode = MODE_HOME;
|
||||||
|
memset(state.home.direction, -1, sizeof(state.home.direction)); // direction = [-1,-1,-1]
|
||||||
|
set_direction_pins(state.home.direction);
|
||||||
|
clear_vector(state.home.away);
|
||||||
|
}
|
||||||
|
|
||||||
|
void perform_go_home()
|
||||||
|
{
|
||||||
|
int axis;
|
||||||
|
if(state.home.phase == PHASE_HOME_RETURN) {
|
||||||
|
// We are running all axes in reverse until all limit switches are tripped
|
||||||
|
// Check all limit switches:
|
||||||
|
for(axis=X_AXIS; axis <= Z_AXIS; axis++) {
|
||||||
|
state.home.away[axis] |= check_limit_switch(axis);
|
||||||
|
}
|
||||||
|
// Step steppers. First retract along Z-axis. Then X and Y.
|
||||||
|
if(state.home.away[Z_AXIS]) {
|
||||||
|
step_axis(Z_AXIS);
|
||||||
|
} else {
|
||||||
|
// Check if all axes are home
|
||||||
|
if(!(state.home.away[X_AXIS] || state.home.away[Y_AXIS])) {
|
||||||
|
// All axes are home, prepare next phase: to nudge the tool carefully out of the limit switches
|
||||||
|
memset(state.home.direction, 1, sizeof(state.home.direction)); // direction = [1,1,1]
|
||||||
|
set_direction_pins(state.home.direction);
|
||||||
|
state.home.phase == PHASE_HOME_NUDGE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
step_steppers(state.home.away);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(axis=X_AXIS; axis <= Z_AXIS; axis++) {
|
||||||
|
if(check_limit_switch(axis)) {
|
||||||
|
step_axis(axis);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// When this code is reached it means all axes are free of their limit-switches. Complete the cycle and rest:
|
||||||
|
clear_vector(state.position); // By definition this is location [0, 0, 0]
|
||||||
|
state.mode = MODE_AT_REST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mc_execute() {
|
||||||
|
enable_steppers();
|
||||||
|
while(state.mode) {
|
||||||
|
switch(state.mode) {
|
||||||
|
case MODE_AT_REST: break;
|
||||||
|
case MODE_DWELL: _delay_ms(state.dwell_milliseconds); state.mode = MODE_AT_REST; break;
|
||||||
|
case MODE_LINEAR: perform_linear_motion();
|
||||||
|
case MODE_HOME: perform_go_home();
|
||||||
|
}
|
||||||
|
_delay_us(state.update_delay_us);
|
||||||
|
}
|
||||||
|
disable_steppers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mc_wait() {
|
||||||
|
return; // No concurrency support yet. So waiting for all to pass is moot.
|
||||||
|
}
|
||||||
|
|
||||||
|
int mc_status()
|
||||||
|
{
|
||||||
|
return(state.mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_limit_switches()
|
||||||
|
{
|
||||||
|
// Dual read as crude debounce
|
||||||
|
return((LIMIT_PORT & LIMIT_MASK) | (LIMIT_PORT & LIMIT_MASK));
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_limit_switch(int axis)
|
||||||
|
{
|
||||||
|
uint8_t mask = 0;
|
||||||
|
switch (axis) {
|
||||||
|
case X_AXIS: mask = 1<<X_LIMIT_BIT; break;
|
||||||
|
case Y_AXIS: mask = 1<<Y_LIMIT_BIT; break;
|
||||||
|
case Z_AXIS: mask = 1<<Z_LIMIT_BIT; break;
|
||||||
|
}
|
||||||
|
return((LIMIT_PORT&mask) || (LIMIT_PORT&mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_steppers()
|
||||||
|
{
|
||||||
|
STEPPERS_ENABLE_PORT |= 1<<STEPPERS_ENABLE_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void disable_steppers()
|
||||||
|
{
|
||||||
|
STEPPERS_ENABLE_PORT &= ~(1<<STEPPERS_ENABLE_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the direction pins for the stepper motors according to the provided vector.
|
||||||
|
// direction is an array of three 8 bit integers representing the direction of
|
||||||
|
// each motor. The values should be -1 (reverse), 0 or 1 (forward).
|
||||||
|
void set_direction_pins(int8_t *direction)
|
||||||
|
{
|
||||||
|
/* Sorry about this convoluted code! It uses the fact that bit 7 of each direction
|
||||||
|
int is set when the direction == -1, but is 0 when direction is forward. This
|
||||||
|
way we can generate the whole direction bit-mask without doing any comparisions
|
||||||
|
or branching. Fast and compact, yet practically unreadable. Sorry sorry sorry.
|
||||||
|
*/
|
||||||
|
uint8_t forward_bits = ~(
|
||||||
|
((direction[X_AXIS]&128)>>(7-X_DIRECTION_BIT)) |
|
||||||
|
((direction[Y_AXIS]&128)>>(7-Y_DIRECTION_BIT)) |
|
||||||
|
((direction[Z_AXIS]&128)>>(7-Z_DIRECTION_BIT))
|
||||||
|
);
|
||||||
|
DIRECTION_PORT = DIRECTION_PORT & ~(DIRECTION_MASK) | forward_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step enabled steppers. Enabled should be an array of three bytes. Each byte represent one
|
||||||
|
// stepper motor in the order X, Y, Z. Set the bytes of the steppers you want to step to
|
||||||
|
// 1, and the rest to 0.
|
||||||
|
inline void step_steppers(uint8_t *enabled)
|
||||||
|
{
|
||||||
|
STEP_PORT |= enabled[X_AXIS]<<X_STEP_BIT | enabled[Y_AXIS]<<Y_STEP_BIT | enabled[Z_AXIS]<<Z_STEP_BIT;
|
||||||
|
_delay_us(5);
|
||||||
|
STEP_PORT &= ~STEP_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step only one motor
|
||||||
|
inline void step_axis(uint8_t axis)
|
||||||
|
{
|
||||||
|
uint8_t mask = 0;
|
||||||
|
switch (axis) {
|
||||||
|
case X_AXIS: mask = 1<<X_STEP_BIT; break;
|
||||||
|
case Y_AXIS: mask = 1<<Y_STEP_BIT; break;
|
||||||
|
case Z_AXIS: mask = 1<<Z_STEP_BIT; break;
|
||||||
|
}
|
||||||
|
STEP_PORT &= mask;
|
||||||
|
_delay_us(5);
|
||||||
|
STEP_PORT &= ~STEP_MASK;
|
||||||
|
}
|
49
motion_control.h
Normal file
49
motion_control.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
motion_control.h - cartesian robot controller.
|
||||||
|
Part of Grbl
|
||||||
|
|
||||||
|
Copyright (c) 2009 Simen Svale Skogsrud
|
||||||
|
|
||||||
|
Grbl is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Grbl is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef motion_control_h
|
||||||
|
#define motion_control_h
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
/* All coordinates are in step-counts. */
|
||||||
|
|
||||||
|
// Initializes the motion_control subsystem resources
|
||||||
|
void mc_init();
|
||||||
|
|
||||||
|
// Prepare for linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second
|
||||||
|
// unless invert_feed_rate is true. Then the feed_rate states the number of seconds for the whole movement.
|
||||||
|
void mc_linear_motion(double x, double y, double z, float feed_rate, int invert_feed_rate);
|
||||||
|
// Prepare linear motion relative to the current position.
|
||||||
|
void mc_dwell(uint32_t milliseconds);
|
||||||
|
// Prepare to send the tool position home
|
||||||
|
void mc_go_home();
|
||||||
|
// Start the prepared operation.
|
||||||
|
void mc_execute();
|
||||||
|
|
||||||
|
// Block until the motion control system is idle
|
||||||
|
void mc_wait();
|
||||||
|
|
||||||
|
|
||||||
|
// Check motion control status. result == 0: the system is idle. result > 0: the system is busy,
|
||||||
|
// result < 0: the system is in an error state.
|
||||||
|
int mc_status();
|
||||||
|
|
||||||
|
#endif
|
41
nuts_bolts.h
Normal file
41
nuts_bolts.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
motion_control.h - cartesian robot controller.
|
||||||
|
Part of Grbl
|
||||||
|
|
||||||
|
Copyright (c) 2009 Simen Svale Skogsrud
|
||||||
|
|
||||||
|
Grbl is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Grbl is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef nuts_bolts_h
|
||||||
|
#define nuts_bolts_h
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||||
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||||
|
|
||||||
|
#define false 0
|
||||||
|
#define true 1
|
||||||
|
|
||||||
|
// Decide the sign of a value
|
||||||
|
#define sign(a) (a>0 ? 1 : ((a<0) ? -1 : 0))
|
||||||
|
|
||||||
|
#define clear_vector(a) memset(a, 0, sizeof(a))
|
||||||
|
|
||||||
|
#define X_AXIS 0
|
||||||
|
#define Y_AXIS 1
|
||||||
|
#define Z_AXIS 2
|
||||||
|
|
||||||
|
#endif
|
15
readme.txt
Normal file
15
readme.txt
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
Grbl - An embedded rs274/ngc (g-code) interpreter, cartesian bot controller, readout and exerciser
|
||||||
|
Inspired by the Arduino GCode Interpreter by Mike Ellery
|
||||||
|
|
||||||
|
Goals:
|
||||||
|
* Suitable for both milling and deposition fabrication
|
||||||
|
* Support GCode from common free and cheap CAM-packages right out of the box
|
||||||
|
* Optional support for a alphanumeric LCD readout, a joystick and a few buttons for program control
|
||||||
|
* Optional support for automated cutter length calibration when milling
|
||||||
|
* Support "headless" fabrication by buffering all code to SD-card or similar
|
||||||
|
|
||||||
|
Limitations:
|
||||||
|
* No support for Arduino software (but will run fine on an Arduino board if you program it with an ISP)
|
||||||
|
* Limited GCode-support. Focus on the kind of GCode produced by automated CAM tools. Leave human GCoders frustrated.
|
||||||
|
|
||||||
|
|
89
serial_protocol.c
Normal file
89
serial_protocol.c
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
serial_protocol.c - the serial protocol master control unit
|
||||||
|
Part of Grbl
|
||||||
|
|
||||||
|
Copyright (c) 2009 Simen Svale Skogsrud
|
||||||
|
|
||||||
|
Grbl is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Grbl is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include "serial_protocol.h"
|
||||||
|
#include "gcode.h"
|
||||||
|
#include "wiring_serial.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include "nuts_bolts.h"
|
||||||
|
|
||||||
|
#define BLOCK_BUFFER_SIZE 128
|
||||||
|
|
||||||
|
char line[BLOCK_BUFFER_SIZE];
|
||||||
|
uint8_t line_counter;
|
||||||
|
|
||||||
|
void prompt() {
|
||||||
|
printString(PROMPT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_result() {
|
||||||
|
double position[3];
|
||||||
|
int inches_mode;
|
||||||
|
uint8_t status_code;
|
||||||
|
uint32_t line_number;
|
||||||
|
gc_get_status(position, &status_code, &inches_mode, &line_number);
|
||||||
|
printByte('[');
|
||||||
|
printInteger(trunc(position[X_AXIS]*100));
|
||||||
|
printByte(',');
|
||||||
|
printInteger(trunc(position[Y_AXIS]*100));
|
||||||
|
printByte(',');
|
||||||
|
printInteger(trunc(position[Z_AXIS]*100));
|
||||||
|
printByte(']');
|
||||||
|
printByte(' ');
|
||||||
|
printByte('@');
|
||||||
|
printInteger(line_number);
|
||||||
|
printByte(':');
|
||||||
|
switch(status_code) {
|
||||||
|
case GCSTATUS_OK: printString("0 OK\n"); break;
|
||||||
|
case GCSTATUS_BAD_NUMBER_FORMAT: printString("1 Bad number format\n");
|
||||||
|
case GCSTATUS_EXPECTED_COMMAND_LETTER: printString("2 Expected command letter\n"); break;
|
||||||
|
case GCSTATUS_UNSUPPORTED_STATEMENT: printString("3 Unsupported statement\n"); break;
|
||||||
|
case GCSTATUS_MOTION_CONTROL_ERROR: printString("4 Motion control error\n"); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sp_init()
|
||||||
|
{
|
||||||
|
beginSerial(BAUD_RATE);
|
||||||
|
|
||||||
|
printString("Grbl ");
|
||||||
|
printString(VERSION);
|
||||||
|
printByte('\n');
|
||||||
|
prompt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sp_process()
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
while((c = serialRead()) != -1)
|
||||||
|
{
|
||||||
|
if(c == '\n') {
|
||||||
|
line[line_counter] = 0;
|
||||||
|
gc_execute_line(line);
|
||||||
|
line_counter = 0;
|
||||||
|
print_result();
|
||||||
|
prompt();
|
||||||
|
} else {
|
||||||
|
line[line_counter] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
serial_protocol.h
Normal file
28
serial_protocol.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
serial_protocol.h - the serial protocol master control unit
|
||||||
|
Part of Grbl
|
||||||
|
|
||||||
|
Copyright (c) 2009 Simen Svale Skogsrud
|
||||||
|
|
||||||
|
Grbl is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Grbl is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef serial_h
|
||||||
|
#define serial_h
|
||||||
|
|
||||||
|
#define PROMPT ">>>"
|
||||||
|
|
||||||
|
void sp_init();
|
||||||
|
void sp_process();
|
||||||
|
|
||||||
|
#endif
|
44
spindle_control.c
Normal file
44
spindle_control.c
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
spindle_control.c - spindle control methods
|
||||||
|
Part of Grbl
|
||||||
|
|
||||||
|
Copyright (c) 2009 Simen Svale Skogsrud
|
||||||
|
|
||||||
|
Grbl is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Grbl is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "spindle_control.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
void spindle_init()
|
||||||
|
{
|
||||||
|
SPINDLE_ENABLE_DDR |= 1<<SPINDLE_ENABLE_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spindle_run(int direction, uint32_t rpm)
|
||||||
|
{
|
||||||
|
if(direction >= 0) {
|
||||||
|
SPINDLE_DIRECTION_PORT &= ~(1<<SPINDLE_DIRECTION_BIT);
|
||||||
|
} else {
|
||||||
|
SPINDLE_DIRECTION_PORT |= 1<<SPINDLE_DIRECTION_BIT;
|
||||||
|
}
|
||||||
|
SPINDLE_ENABLE_PORT |= 1<<SPINDLE_ENABLE_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spindle_stop()
|
||||||
|
{
|
||||||
|
SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT);
|
||||||
|
}
|
30
spindle_control.h
Normal file
30
spindle_control.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
spindle_control.h - spindle control methods
|
||||||
|
Part of Grbl
|
||||||
|
|
||||||
|
Copyright (c) 2009 Simen Svale Skogsrud
|
||||||
|
|
||||||
|
Grbl is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Grbl is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef spindle_control_h
|
||||||
|
#define spindle_control_h
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
void spindle_init();
|
||||||
|
void spindle_run(int direction, uint32_t rpm);
|
||||||
|
void spindle_stop();
|
||||||
|
|
||||||
|
#endif
|
7
todo.txt
Normal file
7
todo.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
* Use timer interrupts to drive steppers
|
||||||
|
* Tool table
|
||||||
|
* Tool length offsets
|
||||||
|
* Tool change M6
|
||||||
|
* Coolant control
|
||||||
|
* Path Control Modes
|
||||||
|
* Spindle speed support
|
56
wiring_private.h
Normal file
56
wiring_private.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
wiring_private.h - Internal header file.
|
||||||
|
Part of Arduino - http://www.arduino.cc/
|
||||||
|
|
||||||
|
Copyright (c) 2005-2006 David A. Mellis
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General
|
||||||
|
Public License along with this library; if not, write to the
|
||||||
|
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
|
Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
$Id: wiring.h 239 2007-01-12 17:58:39Z mellis $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WiringPrivate_h
|
||||||
|
#define WiringPrivate_h
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef cbi
|
||||||
|
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
|
||||||
|
#endif
|
||||||
|
#ifndef sbi
|
||||||
|
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define EXTERNAL_INT_0 0
|
||||||
|
#define EXTERNAL_INT_1 1
|
||||||
|
|
||||||
|
#define EXTERNAL_NUM_INTERRUPTS 2
|
||||||
|
|
||||||
|
typedef void (*voidFuncPtr)(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
212
wiring_serial.c
Normal file
212
wiring_serial.c
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
wiring_serial.c - serial functions.
|
||||||
|
Part of Arduino - http://www.arduino.cc/
|
||||||
|
|
||||||
|
Copyright (c) 2005-2006 David A. Mellis
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General
|
||||||
|
Public License along with this library; if not, write to the
|
||||||
|
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
|
Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "wiring_private.h"
|
||||||
|
|
||||||
|
// Define constants and variables for buffering incoming serial data. We're
|
||||||
|
// using a ring buffer (I think), in which rx_buffer_head is the index of the
|
||||||
|
// location to which to write the next incoming character and rx_buffer_tail
|
||||||
|
// is the index of the location from which to read.
|
||||||
|
#define RX_BUFFER_SIZE 128
|
||||||
|
|
||||||
|
unsigned char rx_buffer[RX_BUFFER_SIZE];
|
||||||
|
|
||||||
|
int rx_buffer_head = 0;
|
||||||
|
int rx_buffer_tail = 0;
|
||||||
|
|
||||||
|
void beginSerial(long baud)
|
||||||
|
{
|
||||||
|
#if defined(__AVR_ATmega168__)
|
||||||
|
UBRR0H = ((F_CPU / 16 + baud / 2) / baud - 1) >> 8;
|
||||||
|
UBRR0L = ((F_CPU / 16 + baud / 2) / baud - 1);
|
||||||
|
|
||||||
|
// enable rx and tx
|
||||||
|
sbi(UCSR0B, RXEN0);
|
||||||
|
sbi(UCSR0B, TXEN0);
|
||||||
|
|
||||||
|
// enable interrupt on complete reception of a byte
|
||||||
|
sbi(UCSR0B, RXCIE0);
|
||||||
|
#else
|
||||||
|
UBRRH = ((F_CPU / 16 + baud / 2) / baud - 1) >> 8;
|
||||||
|
UBRRL = ((F_CPU / 16 + baud / 2) / baud - 1);
|
||||||
|
|
||||||
|
// enable rx and tx
|
||||||
|
sbi(UCSRB, RXEN);
|
||||||
|
sbi(UCSRB, TXEN);
|
||||||
|
|
||||||
|
// enable interrupt on complete reception of a byte
|
||||||
|
sbi(UCSRB, RXCIE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// defaults to 8-bit, no parity, 1 stop bit
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialWrite(unsigned char c)
|
||||||
|
{
|
||||||
|
#if defined(__AVR_ATmega168__)
|
||||||
|
while (!(UCSR0A & (1 << UDRE0)))
|
||||||
|
;
|
||||||
|
|
||||||
|
UDR0 = c;
|
||||||
|
#else
|
||||||
|
while (!(UCSRA & (1 << UDRE)))
|
||||||
|
;
|
||||||
|
|
||||||
|
UDR = c;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int serialAvailable()
|
||||||
|
{
|
||||||
|
return (RX_BUFFER_SIZE + rx_buffer_head - rx_buffer_tail) % RX_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int serialRead()
|
||||||
|
{
|
||||||
|
// if the head isn't ahead of the tail, we don't have any characters
|
||||||
|
if (rx_buffer_head == rx_buffer_tail) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
unsigned char c = rx_buffer[rx_buffer_tail];
|
||||||
|
rx_buffer_tail = (rx_buffer_tail + 1) % RX_BUFFER_SIZE;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialFlush()
|
||||||
|
{
|
||||||
|
// don't reverse this or there may be problems if the RX interrupt
|
||||||
|
// occurs after reading the value of rx_buffer_head but before writing
|
||||||
|
// the value to rx_buffer_tail; the previous value of rx_buffer_head
|
||||||
|
// may be written to rx_buffer_tail, making it appear as if the buffer
|
||||||
|
// were full, not empty.
|
||||||
|
rx_buffer_head = rx_buffer_tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__AVR_ATmega168__)
|
||||||
|
SIGNAL(SIG_USART_RECV)
|
||||||
|
#else
|
||||||
|
SIGNAL(SIG_UART_RECV)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#if defined(__AVR_ATmega168__)
|
||||||
|
unsigned char c = UDR0;
|
||||||
|
#else
|
||||||
|
unsigned char c = UDR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int i = (rx_buffer_head + 1) % RX_BUFFER_SIZE;
|
||||||
|
|
||||||
|
// if we should be storing the received character into the location
|
||||||
|
// just before the tail (meaning that the head would advance to the
|
||||||
|
// current location of the tail), we're about to overflow the buffer
|
||||||
|
// and so we don't write the character or advance the head.
|
||||||
|
if (i != rx_buffer_tail) {
|
||||||
|
rx_buffer[rx_buffer_head] = c;
|
||||||
|
rx_buffer_head = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printMode(int mode)
|
||||||
|
{
|
||||||
|
// do nothing, we only support serial printing, not lcd.
|
||||||
|
}
|
||||||
|
|
||||||
|
void printByte(unsigned char c)
|
||||||
|
{
|
||||||
|
serialWrite(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printNewline()
|
||||||
|
{
|
||||||
|
printByte('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
void printString(const char *s)
|
||||||
|
{
|
||||||
|
while (*s)
|
||||||
|
printByte(*s++);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printIntegerInBase(unsigned long n, unsigned long base)
|
||||||
|
{
|
||||||
|
unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
|
||||||
|
unsigned long i = 0;
|
||||||
|
|
||||||
|
if (n == 0) {
|
||||||
|
printByte('0');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (n > 0) {
|
||||||
|
buf[i++] = n % base;
|
||||||
|
n /= base;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i > 0; i--)
|
||||||
|
printByte(buf[i - 1] < 10 ?
|
||||||
|
'0' + buf[i - 1] :
|
||||||
|
'A' + buf[i - 1] - 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printInteger(long n)
|
||||||
|
{
|
||||||
|
if (n < 0) {
|
||||||
|
printByte('-');
|
||||||
|
n = -n;
|
||||||
|
}
|
||||||
|
|
||||||
|
printIntegerInBase(n, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printHex(unsigned long n)
|
||||||
|
{
|
||||||
|
printIntegerInBase(n, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printOctal(unsigned long n)
|
||||||
|
{
|
||||||
|
printIntegerInBase(n, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printBinary(unsigned long n)
|
||||||
|
{
|
||||||
|
printIntegerInBase(n, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Including print() adds approximately 1500 bytes to the binary size,
|
||||||
|
* so we replace it with the smaller and less-confusing printString(),
|
||||||
|
* printInteger(), etc.
|
||||||
|
void print(const char *format, ...)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
vsnprintf(buf, 256, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
printString(buf);
|
||||||
|
}
|
||||||
|
*/
|
43
wiring_serial.h
Normal file
43
wiring_serial.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
Based on wiring.h - Partial implementation of the Wiring API for the ATmega8.
|
||||||
|
Part of Arduino - http://www.arduino.cc/
|
||||||
|
|
||||||
|
Copyright (c) 2005-2006 David A. Mellis
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General
|
||||||
|
Public License along with this library; if not, write to the
|
||||||
|
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||||
|
Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
$Id: wiring.h 387 2008-03-08 21:30:00Z mellis $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef wiring_h
|
||||||
|
#define wiring_h
|
||||||
|
|
||||||
|
void beginSerial(long);
|
||||||
|
void serialWrite(unsigned char);
|
||||||
|
int serialAvailable(void);
|
||||||
|
int serialRead(void);
|
||||||
|
void serialFlush(void);
|
||||||
|
void printMode(int);
|
||||||
|
void printByte(unsigned char c);
|
||||||
|
void printNewline(void);
|
||||||
|
void printString(const char *s);
|
||||||
|
void printInteger(long n);
|
||||||
|
void printHex(unsigned long n);
|
||||||
|
void printOctal(unsigned long n);
|
||||||
|
void printBinary(unsigned long n);
|
||||||
|
void printIntegerInBase(unsigned long n, unsigned long base);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user