A modest serial transmitter for AVR MCUs in restricted circumstances.
#define PRINTBANG_PORT PORTB
#define PRINTBANG_PIN PB0
#define PRINTBANG_IMPLEMENTATION
#include "printbang.h"
// ...
for (int i = 0;; i++)
{
bangln(PSTR("Hello from program space!"));
bang(PSTR("Running for ")); bang(i, 10); bangln(PSTR(" seconds."));
_delay_ms(1000);
}
For AVR projects where you just don't have any more leeway than a digital pin, a few clock cycles, and a couple of flash bytes.
printbang implements a cycle-counted transmission routine that is speed-limited by an user-defined assembly snippet. Instead of relying on a buffer like other software serial implementations, the function is called once for every word. This also minimizes the cycles spent in time-critical code.
- No dependency on timers or hardware UARTs/USI
- Supports 1-8 data bits, LSB- or MSB-first transmission and even/odd parity
- 250000 baud default configuration for common clock frequencies
- Basic Arduino Serial-style formatting for numeric data types
- Doesn't depend on the Arduino core or the C++ runtime
- Doesn't depend on avr-libc formatting
- State- and heapless
- Recursive formatting routines can result in heavy stack load for long integers
- Interrupts are masked during transmission of a word
HAVE_PRINTBANG_CONFIG_H
(source)
If this macro is defined, <printbang_config.h>
will be included before
printbang.h
.
PRINTBANG_PORT
and PRINTBANG_PORT_IO
(source)
Either of these macros define the port of the pin used for serial output.
If PRINTBANG_PORT_IO
is not defined, it will be derived from PRINTBANG_PORT
by subtracting the SFR memory offset from it:
#define PRINTBANG_PORT PORTA
// is equivalent to
#define PRINTBANG_PORT_IO _SFR_IO_ADDR(PORTA)
PRINTBANG_PIN
and PRINTBANG_PIN_MASK
(source)
Either of these macros define the pin(s) on the chosen port to be used for serial output.
If PRINTBANG_PIN_MASK
is not defined, it will be derived from PRINTBANG_PIN
by converting it into a bit mask:
#define PRINTBANG_PIN PA0
// is equivalent to
#define PRINTBANG_PIN_MASK _BV(PA0)
PRINTBANG_DELAY
(source)
This macro is an inline assembly snippet that limits the speed of the transmission routine to a particular baudrate. If it is not defined, the following defaults are used for common clock frequencies:
- 16.5MHz: 250000 baud, 58 delay cycles, 0% deviation
- 16MHz: 250000 baud, 56 delay cycles, 0% deviation
- 8MHz: 250000 baud, 24 delay cycles, 0% deviation
- 4MHz: 250000 baud, 8 delay cycles, 0% deviation
PRINTBANG_DELAY_CLOBBER
(source)
This macro will be used as the clobber section of the inline assembly and allows delay snippets to clobber registers, e.g. for looping.
TODO: Use a temporary variable instead
PRINTBANG_PARITY_EVEN
and PRINTBANG_PARITY_ODD
(source)
If one of these macros is defined, a bit with the given parity will be appended
to every transmitted word. This functionality depends on avr-libc's
util/parity.h
.
PRINTBANG_DATA_BITS
(source)
This macro defines the number of data bits transmitted per word. Counting always starts at the least significant bit; if MSB-first transmission is used, the byte will be aligned to the left side.
// Saves one bit per word but limits transmission to ASCII characters
#define PRINTBANG_DATA_BITS 7
PRINTBANG_ORDER_MSB
(source)
If this macro is defined, transmission will occur in MSB-first order. Otherwise, LSB-first order will be used.
PRINTBANG_LINE_ENDING
(source)
This macro expands to a string literal that will be used by bangln
to
terminate a line. It defaults to "\r\n"
.
PRINTBANG_IMPLEMENTATION
(source)
printbang is a header-only library. When including it, its functions are declared, but only defined if this macro is set.
The recommended way of using printbang in your project involves setting
PRINTBANG_IMPLEMENTATION
in a single source file, most commonly wherever your
main function is located. All other source files can then include printbang.h
without defining this macro.
void bang_char(char value)
(source)
Transmits a single word over the serial pin. Interrupts are masked during the runtime of this function.
void bang_str(const char *str)
(source)
Transmits a null-terminated string from RAM. Calling this function on a program-space string will result in garbage being transmitted.
void bang_pstr(PGM_P str)
(source)
Transmits a null-terminated string from program space. Calling this function on a RAM string will result in garbage being transmitted.
void bang_uint(unsigned int value, unsigned char base)
(source)
Transmits unsigned int
respectively int
values. The passed value is
formatted in a given base
.
void bang_ulong(unsigned long value, unsigned char base)
(source)
Transmits unsigned long
respectively long
values. The passed value is
formatted in a given base
.
void bang_ulonglong(unsigned long long value, unsigned char base
(source)
Transmits unsigned long long
respectively long long
values. The passed value
is formatted in a given base
.
void bang_float(float value, unsigned char base)
(source)
Transmits float
values. The floating point formatting is very rudimentary and
will simply concatenate the number to a given number of decimal places
. One
trailing zero is always appended.
Since double
is an alias for float
in avr-libc, this function should be used
for double
values as well.
void bang(...)
(source)
bang
provides a simple generic wrapper to all bang_x
functions. If C++ is
used, it is implemented as an overloaded wrapper function. If C is used, it is
implemented as a _Generic
macro.
Because gcc doesn't disinguish between const char *
and const PROGMEM char *
at compile-time, all constant strings are handled as program-space pointers by
bang
. If you want to bang
a constant string literal from RAM you need to
call bang_str
directly, but consider wrapping it in PSTR(...)
to put it
in program space instead and save memory.
void bangln(...)
(source)
This is a macro that first calls bang
on the passed arguments and then
bang_pstr
on printbang_line_ending
.