version 0.1

This commit is contained in:
Simen Svale Skogsrud 2009-01-25 00:48:56 +01:00
commit 9df29ad3b3
18 changed files with 1669 additions and 0 deletions

165
COPYING.txt Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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