Wgranie zmian do repozytorium

This commit is contained in:
2026-05-10 16:46:04 +02:00
commit f171113450
1607 changed files with 254616 additions and 0 deletions

View File

@@ -0,0 +1,243 @@
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseColons: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowBreakBeforeNoexceptSpecifier: Never
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterExternBlock: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
KeepEmptyLinesAtEOF: false
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PackConstructorInitializers: BinPack
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakScopeResolution: 500
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
PPIndentWidth: -1
QualifierAlignment: Leave
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseTab: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE

View File

@@ -0,0 +1,46 @@
Thank you for opening an issue on an Adafruit Arduino library repository. To
improve the speed of resolution please review the following guidelines and
common troubleshooting steps below before creating the issue:
- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use
the forums at http://forums.adafruit.com to ask questions and troubleshoot why
something isn't working as expected. In many cases the problem is a common issue
that you will more quickly receive help from the forum community. GitHub issues
are meant for known defects in the code. If you don't know if there is a defect
in the code then start with troubleshooting on the forum first.
- **If following a tutorial or guide be sure you didn't miss a step.** Carefully
check all of the steps and commands to run have been followed. Consult the
forum if you're unsure or have questions about steps in a guide/tutorial.
- **For Arduino projects check these very common issues to ensure they don't apply**:
- For uploading sketches or communicating with the board make sure you're using
a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes
very hard to tell the difference between a data and charge cable! Try using the
cable with other devices or swapping to another cable to confirm it is not
the problem.
- **Be sure you are supplying adequate power to the board.** Check the specs of
your board and plug in an external power supply. In many cases just
plugging a board into your computer is not enough to power it and other
peripherals.
- **Double check all soldering joints and connections.** Flakey connections
cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints.
- **Ensure you are using an official Arduino or Adafruit board.** We can't
guarantee a clone board will have the same functionality and work as expected
with this code and don't support them.
If you're sure this issue is a defect in the code and checked the steps above
please fill in the following fields to provide enough troubleshooting information.
You may delete the guideline and text above to just leave the following details:
- Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE**
- Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO
VERSION HERE**
- List the steps to reproduce the problem below (if possible attach a sketch or
copy the sketch code in too): **LIST REPRO STEPS BELOW**

View File

@@ -0,0 +1,26 @@
Thank you for creating a pull request to contribute to Adafruit's GitHub code!
Before you open the request please review the following guidelines and tips to
help it be more easily integrated:
- **Describe the scope of your change--i.e. what the change does and what parts
of the code were modified.** This will help us understand any risks of integrating
the code.
- **Describe any known limitations with your change.** For example if the change
doesn't apply to a supported platform of the library please mention it.
- **Please run any tests or examples that can exercise your modified code.** We
strive to not break users of the code and running tests/examples helps with this
process.
Thank you again for contributing! We will try to test and integrate the change
as soon as we can, but be aware we have many GitHub repositories to manage and
can't immediately respond to every request. There is no need to bump or check in
on a pull request (it will clutter the discussion of the request).
Also don't be worried if the request is closed or not integrated--sometimes the
priorities of Adafruit's GitHub code (education, ease of use) might not match the
priorities of the pull request. Don't fret, the open source community thrives on
forks and GitHub makes it easy to keep your changes in a forked repo.
After reviewing the guidelines above you can delete this text from the pull request.

View File

@@ -0,0 +1,33 @@
name: Arduino Library CI
on: [pull_request, push, repository_dispatch]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-python@v4
with:
python-version: '3.x'
- uses: actions/checkout@v3
- uses: actions/checkout@v3
with:
repository: adafruit/ci-arduino
path: ci
- name: Install the prerequisites
run: bash ci/actions_install.sh
- name: Check for correct code formatting with clang-format
run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r .
- name: Check for correct documentation with doxygen
env:
GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }}
PRETTYNAME : "Adafruit Bus IO Library"
run: bash ci/doxy_gen_and_deploy.sh
- name: Test the code on supported platforms
run: python3 ci/build_platform.py main_platforms zero feather32u4

View File

@@ -0,0 +1 @@
{"type": "library", "name": "Adafruit BusIO", "version": "1.17.4", "spec": {"owner": "adafruit", "id": 6214, "name": "Adafruit BusIO", "requirements": null, "uri": null}}

View File

@@ -0,0 +1,384 @@
#include <Adafruit_BusIO_Register.h>
#if !defined(SPI_INTERFACES_COUNT) || \
(defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0))
/*!
* @brief Create a register we access over an I2C Device (which defines the
* bus and address)
* @param i2cdevice The I2CDevice to use for underlying I2C access
* @param reg_addr The address pointer value for the I2C/SMBus register, can
* be 8 or 16 bits
* @param width The width of the register data itself, defaults to 1 byte
* @param byteorder The byte order of the register (used when width is > 1),
* defaults to LSBFIRST
* @param address_width The width of the register address itself, defaults
* to 1 byte
*/
Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice,
uint16_t reg_addr,
uint8_t width,
uint8_t byteorder,
uint8_t address_width) {
_i2cdevice = i2cdevice;
_spidevice = nullptr;
_addrwidth = address_width;
_address = reg_addr;
_byteorder = byteorder;
_width = width;
}
/*!
* @brief Create a register we access over an SPI Device (which defines the
* bus and CS pin)
* @param spidevice The SPIDevice to use for underlying SPI access
* @param reg_addr The address pointer value for the SPI register, can
* be 8 or 16 bits
* @param type The method we use to read/write data to SPI (which is not
* as well defined as I2C)
* @param width The width of the register data itself, defaults to 1 byte
* @param byteorder The byte order of the register (used when width is > 1),
* defaults to LSBFIRST
* @param address_width The width of the register address itself, defaults
* to 1 byte
*/
Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_SPIDevice *spidevice,
uint16_t reg_addr,
Adafruit_BusIO_SPIRegType type,
uint8_t width,
uint8_t byteorder,
uint8_t address_width) {
_spidevice = spidevice;
_spiregtype = type;
_i2cdevice = nullptr;
_addrwidth = address_width;
_address = reg_addr;
_byteorder = byteorder;
_width = width;
}
/*!
* @brief Create a register we access over an I2C or SPI Device. This is a
* handy function because we can pass in nullptr for the unused interface,
* allowing libraries to mass-define all the registers
* @param i2cdevice The I2CDevice to use for underlying I2C access, if
* nullptr we use SPI
* @param spidevice The SPIDevice to use for underlying SPI access, if
* nullptr we use I2C
* @param reg_addr The address pointer value for the I2C/SMBus/SPI register,
* can be 8 or 16 bits
* @param type The method we use to read/write data to SPI (which is not
* as well defined as I2C)
* @param width The width of the register data itself, defaults to 1 byte
* @param byteorder The byte order of the register (used when width is > 1),
* defaults to LSBFIRST
* @param address_width The width of the register address itself, defaults
* to 1 byte
*/
Adafruit_BusIO_Register::Adafruit_BusIO_Register(
Adafruit_I2CDevice *i2cdevice, Adafruit_SPIDevice *spidevice,
Adafruit_BusIO_SPIRegType type, uint16_t reg_addr, uint8_t width,
uint8_t byteorder, uint8_t address_width) {
_spidevice = spidevice;
_i2cdevice = i2cdevice;
_spiregtype = type;
_addrwidth = address_width;
_address = reg_addr;
_byteorder = byteorder;
_width = width;
}
/*!
* @brief Create a register we access over a GenericDevice
* @param genericdevice Generic device to use
* @param reg_addr Register address we will read/write
* @param width Width of the register in bytes (1-4)
* @param byteorder Byte order of register data (LSBFIRST or MSBFIRST)
* @param address_width Width of the register address in bytes (1 or 2)
*/
Adafruit_BusIO_Register::Adafruit_BusIO_Register(
Adafruit_GenericDevice *genericdevice, uint16_t reg_addr, uint8_t width,
uint8_t byteorder, uint8_t address_width) {
_i2cdevice = nullptr;
_spidevice = nullptr;
_genericdevice = genericdevice;
_addrwidth = address_width;
_address = reg_addr;
_byteorder = byteorder;
_width = width;
}
/*!
* @brief Write a buffer of data to the register location
* @param buffer Pointer to data to write
* @param len Number of bytes to write
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_Register::write(uint8_t *buffer, uint8_t len) {
uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF),
(uint8_t)(_address >> 8)};
if (_i2cdevice) {
return _i2cdevice->write(buffer, len, true, addrbuffer, _addrwidth);
}
if (_spidevice) {
if (_spiregtype == ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE) {
// very special case!
// pass the special opcode address which we set as the high byte of the
// regaddr
addrbuffer[0] =
(uint8_t)(_address >> 8) & ~0x01; // set bottom bit low to write
// the 'actual' reg addr is the second byte then
addrbuffer[1] = (uint8_t)(_address & 0xFF);
// the address appears to be a byte longer
return _spidevice->write(buffer, len, addrbuffer, _addrwidth + 1);
}
if (_spiregtype == ADDRBIT8_HIGH_TOREAD) {
addrbuffer[0] &= ~0x80;
}
if (_spiregtype == ADDRBIT8_HIGH_TOWRITE) {
addrbuffer[0] |= 0x80;
}
if (_spiregtype == AD8_HIGH_TOREAD_AD7_HIGH_TOINC) {
addrbuffer[0] &= ~0x80;
addrbuffer[0] |= 0x40;
}
return _spidevice->write(buffer, len, addrbuffer, _addrwidth);
}
if (_genericdevice) {
return _genericdevice->writeRegister(addrbuffer, _addrwidth, buffer, len);
}
return false;
}
/*!
* @brief Write up to 4 bytes of data to the register location
* @param value Data to write
* @param numbytes How many bytes from 'value' to write
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_Register::write(uint32_t value, uint8_t numbytes) {
if (numbytes == 0) {
numbytes = _width;
}
if (numbytes > 4) {
return false;
}
// store a copy
_cached = value;
for (int i = 0; i < numbytes; i++) {
if (_byteorder == LSBFIRST) {
_buffer[i] = value & 0xFF;
} else {
_buffer[numbytes - i - 1] = value & 0xFF;
}
value >>= 8;
}
return write(_buffer, numbytes);
}
/*!
* @brief Read data from the register location. This does not do any error
* checking!
* @return Returns 0xFFFFFFFF on failure, value otherwise
*/
uint32_t Adafruit_BusIO_Register::read(void) {
if (!read(_buffer, _width)) {
return -1;
}
uint32_t value = 0;
for (int i = 0; i < _width; i++) {
value <<= 8;
if (_byteorder == LSBFIRST) {
value |= _buffer[_width - i - 1];
} else {
value |= _buffer[i];
}
}
return value;
}
/*!
* @brief Read cached data from last time we wrote to this register
* @return Returns 0xFFFFFFFF on failure, value otherwise
*/
uint32_t Adafruit_BusIO_Register::readCached(void) { return _cached; }
/*!
@brief Read a number of bytes from a register into a buffer
@param buffer Buffer to read data into
@param len Number of bytes to read into the buffer
@return true on successful read, otherwise false
*/
bool Adafruit_BusIO_Register::read(uint8_t *buffer, uint8_t len) {
uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF),
(uint8_t)(_address >> 8)};
if (_i2cdevice) {
return _i2cdevice->write_then_read(addrbuffer, _addrwidth, buffer, len);
}
if (_spidevice) {
if (_spiregtype == ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE) {
// very special case!
// pass the special opcode address which we set as the high byte of the
// regaddr
addrbuffer[0] =
(uint8_t)(_address >> 8) | 0x01; // set bottom bit high to read
// the 'actual' reg addr is the second byte then
addrbuffer[1] = (uint8_t)(_address & 0xFF);
// the address appears to be a byte longer
return _spidevice->write_then_read(addrbuffer, _addrwidth + 1, buffer,
len);
}
if (_spiregtype == ADDRBIT8_HIGH_TOREAD) {
addrbuffer[0] |= 0x80;
}
if (_spiregtype == ADDRBIT8_HIGH_TOWRITE) {
addrbuffer[0] &= ~0x80;
}
if (_spiregtype == AD8_HIGH_TOREAD_AD7_HIGH_TOINC) {
addrbuffer[0] |= 0x80 | 0x40;
}
return _spidevice->write_then_read(addrbuffer, _addrwidth, buffer, len);
}
if (_genericdevice) {
return _genericdevice->readRegister(addrbuffer, _addrwidth, buffer, len);
}
return false;
}
/*!
* @brief Read 2 bytes of data from the register location
* @param value Pointer to uint16_t variable to read into
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_Register::read(uint16_t *value) {
if (!read(_buffer, 2)) {
return false;
}
if (_byteorder == LSBFIRST) {
*value = _buffer[1];
*value <<= 8;
*value |= _buffer[0];
} else {
*value = _buffer[0];
*value <<= 8;
*value |= _buffer[1];
}
return true;
}
/*!
* @brief Read 1 byte of data from the register location
* @param value Pointer to uint8_t variable to read into
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_Register::read(uint8_t *value) {
if (!read(_buffer, 1)) {
return false;
}
*value = _buffer[0];
return true;
}
/*!
* @brief Pretty printer for this register
* @param s The Stream to print to, defaults to &Serial
*/
void Adafruit_BusIO_Register::print(Stream *s) {
uint32_t val = read();
s->print("0x");
s->print(val, HEX);
}
/*!
* @brief Pretty printer for this register
* @param s The Stream to print to, defaults to &Serial
*/
void Adafruit_BusIO_Register::println(Stream *s) {
print(s);
s->println();
}
/*!
* @brief Create a slice of the register that we can address without
* touching other bits
* @param reg The Adafruit_BusIO_Register which defines the bus/register
* @param bits The number of bits wide we are slicing
* @param shift The number of bits that our bit-slice is shifted from LSB
*/
Adafruit_BusIO_RegisterBits::Adafruit_BusIO_RegisterBits(
Adafruit_BusIO_Register *reg, uint8_t bits, uint8_t shift) {
_register = reg;
_bits = bits;
_shift = shift;
}
/*!
* @brief Read 4 bytes of data from the register
* @return data The 4 bytes to read
*/
uint32_t Adafruit_BusIO_RegisterBits::read(void) {
uint32_t val = _register->read();
val >>= _shift;
return val & ((1 << (_bits)) - 1);
}
/*!
* @brief Write 4 bytes of data to the register
* @param data The 4 bytes to write
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_RegisterBits::write(uint32_t data) {
uint32_t val = _register->read();
// mask off the data before writing
uint32_t mask = (1 << (_bits)) - 1;
data &= mask;
mask <<= _shift;
val &= ~mask; // remove the current data at that spot
val |= data << _shift; // and add in the new data
return _register->write(val, _register->width());
}
/*!
* @brief The width of the register data, helpful for doing calculations
* @returns The data width used when initializing the register
*/
uint8_t Adafruit_BusIO_Register::width(void) { return _width; }
/*!
* @brief Set the default width of data
* @param width the default width of data read from register
*/
void Adafruit_BusIO_Register::setWidth(uint8_t width) { _width = width; }
/*!
* @brief Set register address
* @param address the address from register
*/
void Adafruit_BusIO_Register::setAddress(uint16_t address) {
_address = address;
}
/*!
* @brief Set the width of register address
* @param address_width the width for register address
*/
void Adafruit_BusIO_Register::setAddressWidth(uint16_t address_width) {
_addrwidth = address_width;
}
#endif // SPI exists

View File

@@ -0,0 +1,117 @@
#ifndef Adafruit_BusIO_Register_h
#define Adafruit_BusIO_Register_h
#include <Arduino.h>
#if !defined(SPI_INTERFACES_COUNT) || \
(defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0))
#include <Adafruit_GenericDevice.h>
#include <Adafruit_I2CDevice.h>
#include <Adafruit_SPIDevice.h>
typedef enum _Adafruit_BusIO_SPIRegType {
ADDRBIT8_HIGH_TOREAD = 0,
/*!<
* ADDRBIT8_HIGH_TOREAD
* When reading a register you must actually send the value 0x80 + register
* address to the device. e.g. To read the register 0x0B the register value
* 0x8B is sent and to write 0x0B is sent.
*/
AD8_HIGH_TOREAD_AD7_HIGH_TOINC = 1,
/*!<
* ADDRBIT8_HIGH_TOWRITE
* When writing to a register you must actually send the value 0x80 +
* the register address to the device. e.g. To write to the register 0x19 the
* register value 0x99 is sent and to read 0x19 is sent.
*/
ADDRBIT8_HIGH_TOWRITE = 2,
/*!<
* ADDRESSED_OPCODE_LOWBIT_TO_WRITE
* Used by the MCP23S series, we send 0x40 |'rd with the opcode
* Then set the lowest bit to write
*/
ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE = 3,
} Adafruit_BusIO_SPIRegType;
/*!
* @brief The class which defines a device register (a location to read/write
* data from)
*/
class Adafruit_BusIO_Register {
public:
Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice, uint16_t reg_addr,
uint8_t width = 1, uint8_t byteorder = LSBFIRST,
uint8_t address_width = 1);
Adafruit_BusIO_Register(Adafruit_SPIDevice *spidevice, uint16_t reg_addr,
Adafruit_BusIO_SPIRegType type, uint8_t width = 1,
uint8_t byteorder = LSBFIRST,
uint8_t address_width = 1);
Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice,
Adafruit_SPIDevice *spidevice,
Adafruit_BusIO_SPIRegType type, uint16_t reg_addr,
uint8_t width = 1, uint8_t byteorder = LSBFIRST,
uint8_t address_width = 1);
Adafruit_BusIO_Register(Adafruit_GenericDevice *genericdevice,
uint16_t reg_addr, uint8_t width = 1,
uint8_t byteorder = LSBFIRST,
uint8_t address_width = 1);
bool read(uint8_t *buffer, uint8_t len);
bool read(uint8_t *value);
bool read(uint16_t *value);
uint32_t read(void);
uint32_t readCached(void);
bool write(uint8_t *buffer, uint8_t len);
bool write(uint32_t value, uint8_t numbytes = 0);
uint8_t width(void);
void setWidth(uint8_t width);
void setAddress(uint16_t address);
void setAddressWidth(uint16_t address_width);
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
void print(Stream *s = &Serial);
void println(Stream *s = &Serial);
#else
void print(Stream *s);
void println(Stream *s);
#endif
private:
Adafruit_I2CDevice *_i2cdevice;
Adafruit_SPIDevice *_spidevice;
Adafruit_GenericDevice *_genericdevice;
Adafruit_BusIO_SPIRegType _spiregtype;
uint16_t _address;
uint8_t _width, _addrwidth, _byteorder;
uint8_t _buffer[4]; // we won't support anything larger than uint32 for
// non-buffered read
uint32_t _cached = 0;
};
/*!
* @brief The class which defines a slice of bits from within a device register
* (a location to read/write data from)
*/
class Adafruit_BusIO_RegisterBits {
public:
Adafruit_BusIO_RegisterBits(Adafruit_BusIO_Register *reg, uint8_t bits,
uint8_t shift);
bool write(uint32_t value);
uint32_t read(void);
private:
Adafruit_BusIO_Register *_register;
uint8_t _bits, _shift;
};
#endif // SPI exists
#endif // BusIO_Register_h

View File

@@ -0,0 +1,90 @@
/*
Written with help by Claude!
https://claude.ai/chat/335f50b1-3dd8-435e-9139-57ec7ca26a3c (at this time
chats are not shareable :(
*/
#include "Adafruit_GenericDevice.h"
/*!
* @brief Create a Generic device with the provided read/write functions
* @param obj Pointer to object instance
* @param read_func Function pointer for reading raw data
* @param write_func Function pointer for writing raw data
* @param readreg_func Function pointer for reading registers (optional)
* @param writereg_func Function pointer for writing registers (optional) */
Adafruit_GenericDevice::Adafruit_GenericDevice(
void *obj, busio_genericdevice_read_t read_func,
busio_genericdevice_write_t write_func,
busio_genericdevice_readreg_t readreg_func,
busio_genericdevice_writereg_t writereg_func) {
_obj = obj;
_read_func = read_func;
_write_func = write_func;
_readreg_func = readreg_func;
_writereg_func = writereg_func;
_begun = false;
}
/*! @brief Simple begin function (doesn't do much at this time)
@return true always
*/
bool Adafruit_GenericDevice::begin(void) {
_begun = true;
return true;
}
/*!
@brief Marks the GenericDevice as no longer in use.
@note: Since this is a GenericDevice, if you are using this with a Serial
object, this does NOT disable serial communication or release the RX/TX pins.
That must be done manually by calling Serial.end().
*/
void Adafruit_GenericDevice::end(void) { _begun = false; }
/*! @brief Write a buffer of data
@param buffer Pointer to buffer of data to write
@param len Number of bytes to write
@return true if write was successful, otherwise false */
bool Adafruit_GenericDevice::write(const uint8_t *buffer, size_t len) {
if (!_begun)
return false;
return _write_func(_obj, buffer, len);
}
/*! @brief Read data into a buffer
@param buffer Pointer to buffer to read data into
@param len Number of bytes to read
@return true if read was successful, otherwise false */
bool Adafruit_GenericDevice::read(uint8_t *buffer, size_t len) {
if (!_begun)
return false;
return _read_func(_obj, buffer, len);
}
/*! @brief Read from a register location
@param addr_buf Buffer containing register address
@param addrsiz Size of register address in bytes
@param buf Buffer to store read data
@param bufsiz Size of data to read in bytes
@return true if read was successful, otherwise false */
bool Adafruit_GenericDevice::readRegister(uint8_t *addr_buf, uint8_t addrsiz,
uint8_t *buf, uint16_t bufsiz) {
if (!_begun || !_readreg_func)
return false;
return _readreg_func(_obj, addr_buf, addrsiz, buf, bufsiz);
}
/*! @brief Write to a register location
@param addr_buf Buffer containing register address
@param addrsiz Size of register address in bytes
@param buf Buffer containing data to write
@param bufsiz Size of data to write in bytes
@return true if write was successful, otherwise false */
bool Adafruit_GenericDevice::writeRegister(uint8_t *addr_buf, uint8_t addrsiz,
const uint8_t *buf,
uint16_t bufsiz) {
if (!_begun || !_writereg_func)
return false;
return _writereg_func(_obj, addr_buf, addrsiz, buf, bufsiz);
}

View File

@@ -0,0 +1,56 @@
#ifndef ADAFRUIT_GENERICDEVICE_H
#define ADAFRUIT_GENERICDEVICE_H
#include <Arduino.h>
typedef bool (*busio_genericdevice_read_t)(void *obj, uint8_t *buffer,
size_t len);
typedef bool (*busio_genericdevice_write_t)(void *obj, const uint8_t *buffer,
size_t len);
typedef bool (*busio_genericdevice_readreg_t)(void *obj, uint8_t *addr_buf,
uint8_t addrsiz, uint8_t *data,
uint16_t datalen);
typedef bool (*busio_genericdevice_writereg_t)(void *obj, uint8_t *addr_buf,
uint8_t addrsiz,
const uint8_t *data,
uint16_t datalen);
/*!
* @brief Class for communicating with a device via generic read/write functions
*/
class Adafruit_GenericDevice {
public:
Adafruit_GenericDevice(
void *obj, busio_genericdevice_read_t read_func,
busio_genericdevice_write_t write_func,
busio_genericdevice_readreg_t readreg_func = nullptr,
busio_genericdevice_writereg_t writereg_func = nullptr);
bool begin(void);
void end(void);
bool read(uint8_t *buffer, size_t len);
bool write(const uint8_t *buffer, size_t len);
bool readRegister(uint8_t *addr_buf, uint8_t addrsiz, uint8_t *buf,
uint16_t bufsiz);
bool writeRegister(uint8_t *addr_buf, uint8_t addrsiz, const uint8_t *buf,
uint16_t bufsiz);
protected:
/*! @brief Function pointer for reading raw data from the device */
busio_genericdevice_read_t _read_func;
/*! @brief Function pointer for writing raw data to the device */
busio_genericdevice_write_t _write_func;
/*! @brief Function pointer for reading a 'register' from the device */
busio_genericdevice_readreg_t _readreg_func;
/*! @brief Function pointer for writing a 'register' to the device */
busio_genericdevice_writereg_t _writereg_func;
bool _begun; ///< whether we have initialized yet (in case the function needs
///< to do something)
private:
void *_obj; ///< Pointer to object instance
};
#endif // ADAFRUIT_GENERICDEVICE_H

View File

@@ -0,0 +1,320 @@
#include "Adafruit_I2CDevice.h"
// #define DEBUG_SERIAL Serial
/*!
* @brief Create an I2C device at a given address
* @param addr The 7-bit I2C address for the device
* @param theWire The I2C bus to use, defaults to &Wire
*/
Adafruit_I2CDevice::Adafruit_I2CDevice(uint8_t addr, TwoWire *theWire) {
_addr = addr;
_wire = theWire;
_begun = false;
#ifdef ARDUINO_ARCH_SAMD
_maxBufferSize = 250; // as defined in Wire.h's RingBuffer
#elif defined(ESP32)
_maxBufferSize = I2C_BUFFER_LENGTH;
#else
_maxBufferSize = 32;
#endif
}
/*!
* @brief Initializes and does basic address detection
* @param addr_detect Whether we should attempt to detect the I2C address
* with a scan. 99% of sensors/devices don't mind, but once in a while they
* don't respond well to a scan!
* @return True if I2C initialized and a device with the addr found
*/
bool Adafruit_I2CDevice::begin(bool addr_detect) {
_wire->begin();
_begun = true;
if (addr_detect) {
return detected();
}
return true;
}
/*!
* @brief De-initialize device, turn off the Wire interface
*/
void Adafruit_I2CDevice::end(void) {
// Not all port implement Wire::end(), such as
// - ESP8266
// - AVR core without WIRE_HAS_END
// - ESP32: end() is implemented since 2.0.1 which is latest at the moment.
// Temporarily disable for now to give time for user to update.
#if !(defined(ESP8266) || \
(defined(ARDUINO_ARCH_AVR) && !defined(WIRE_HAS_END)) || \
defined(ARDUINO_ARCH_ESP32))
_wire->end();
_begun = false;
#endif
}
/*!
* @brief Scans I2C for the address - note will give a false-positive
* if there's no pullups on I2C
* @return True if I2C initialized and a device with the addr found
*/
bool Adafruit_I2CDevice::detected(void) {
// Init I2C if not done yet
if (!_begun && !begin()) {
return false;
}
// A basic scanner, see if it ACK's
_wire->beginTransmission(_addr);
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("Address 0x"));
DEBUG_SERIAL.print(_addr, HEX);
#endif
#ifdef ARDUINO_ARCH_MBED
_wire->write(0); // forces a write request instead of a read
#endif
if (_wire->endTransmission() == 0) {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println(F(" Detected"));
#endif
return true;
}
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println(F(" Not detected"));
#endif
return false;
}
/*!
* @brief Write a buffer or two to the I2C device. Cannot be more than
* maxBufferSize() bytes.
* @param buffer Pointer to buffer of data to write. This is const to
* ensure the content of this buffer doesn't change.
* @param len Number of bytes from buffer to write
* @param prefix_buffer Pointer to optional array of data to write before
* buffer. Cannot be more than maxBufferSize() bytes. This is const to
* ensure the content of this buffer doesn't change.
* @param prefix_len Number of bytes from prefix buffer to write
* @param stop Whether to send an I2C STOP signal on write
* @return True if write was successful, otherwise false.
*/
bool Adafruit_I2CDevice::write(const uint8_t *buffer, size_t len, bool stop,
const uint8_t *prefix_buffer,
size_t prefix_len) {
if ((len + prefix_len) > maxBufferSize()) {
// currently not guaranteed to work if more than 32 bytes!
// we will need to find out if some platforms have larger
// I2C buffer sizes :/
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println(F("\tI2CDevice could not write such a large buffer"));
#endif
return false;
}
_wire->beginTransmission(_addr);
// Write the prefix data (usually an address)
if ((prefix_len != 0) && (prefix_buffer != nullptr)) {
if (_wire->write(prefix_buffer, prefix_len) != prefix_len) {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println(F("\tI2CDevice failed to write"));
#endif
return false;
}
}
// Write the data itself
if (_wire->write(buffer, len) != len) {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println(F("\tI2CDevice failed to write"));
#endif
return false;
}
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tI2CWRITE @ 0x"));
DEBUG_SERIAL.print(_addr, HEX);
DEBUG_SERIAL.print(F(" :: "));
if ((prefix_len != 0) && (prefix_buffer != nullptr)) {
for (uint16_t i = 0; i < prefix_len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(prefix_buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
}
}
for (uint16_t i = 0; i < len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (i % 32 == 31) {
DEBUG_SERIAL.println();
}
}
if (stop) {
DEBUG_SERIAL.print("\tSTOP");
}
#endif
if (_wire->endTransmission(stop) == 0) {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println();
// DEBUG_SERIAL.println("Sent!");
#endif
return true;
} else {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("\tFailed to send!");
#endif
return false;
}
}
/*!
* @brief Read from I2C into a buffer from the I2C device.
* Cannot be more than maxBufferSize() bytes.
* @param buffer Pointer to buffer of data to read into
* @param len Number of bytes from buffer to read.
* @param stop Whether to send an I2C STOP signal on read
* @return True if read was successful, otherwise false.
*/
bool Adafruit_I2CDevice::read(uint8_t *buffer, size_t len, bool stop) {
size_t pos = 0;
while (pos < len) {
size_t read_len =
((len - pos) > maxBufferSize()) ? maxBufferSize() : (len - pos);
bool read_stop = (pos < (len - read_len)) ? false : stop;
if (!_read(buffer + pos, read_len, read_stop))
return false;
pos += read_len;
}
return true;
}
bool Adafruit_I2CDevice::_read(uint8_t *buffer, size_t len, bool stop) {
#if defined(TinyWireM_h)
size_t recv = _wire->requestFrom((uint8_t)_addr, (uint8_t)len);
#elif defined(ARDUINO_ARCH_MEGAAVR)
size_t recv = _wire->requestFrom(_addr, len, stop);
#else
size_t recv = _wire->requestFrom((uint8_t)_addr, (uint8_t)len, (uint8_t)stop);
#endif
if (recv != len) {
// Not enough data available to fulfill our obligation!
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tI2CDevice did not receive enough data: "));
DEBUG_SERIAL.println(recv);
#endif
return false;
}
for (uint16_t i = 0; i < len; i++) {
buffer[i] = _wire->read();
}
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tI2CREAD @ 0x"));
DEBUG_SERIAL.print(_addr, HEX);
DEBUG_SERIAL.print(F(" :: "));
for (uint16_t i = 0; i < len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (len % 32 == 31) {
DEBUG_SERIAL.println();
}
}
DEBUG_SERIAL.println();
#endif
return true;
}
/*!
* @brief Write some data, then read some data from I2C into another buffer.
* Cannot be more than maxBufferSize() bytes. The buffers can point to
* same/overlapping locations.
* @param write_buffer Pointer to buffer of data to write from
* @param write_len Number of bytes from buffer to write.
* @param read_buffer Pointer to buffer of data to read into.
* @param read_len Number of bytes from buffer to read.
* @param stop Whether to send an I2C STOP signal between the write and read
* @return True if write & read was successful, otherwise false.
*/
bool Adafruit_I2CDevice::write_then_read(const uint8_t *write_buffer,
size_t write_len, uint8_t *read_buffer,
size_t read_len, bool stop) {
if (!write(write_buffer, write_len, stop)) {
return false;
}
return read(read_buffer, read_len);
}
/*!
* @brief Returns the 7-bit address of this device
* @return The 7-bit address of this device
*/
uint8_t Adafruit_I2CDevice::address(void) { return _addr; }
/*!
* @brief Change the I2C clock speed to desired (relies on
* underlying Wire support!
* @param desiredclk The desired I2C SCL frequency
* @return True if this platform supports changing I2C speed.
* Not necessarily that the speed was achieved!
*/
bool Adafruit_I2CDevice::setSpeed(uint32_t desiredclk) {
#if defined(__AVR_ATmega328__) || \
defined(__AVR_ATmega328P__) // fix arduino core set clock
// calculate TWBR correctly
if ((F_CPU / 18) < desiredclk) {
#ifdef DEBUG_SERIAL
Serial.println(F("I2C.setSpeed too high."));
#endif
return false;
}
uint32_t atwbr = ((F_CPU / desiredclk) - 16) / 2;
if (atwbr > 16320) {
#ifdef DEBUG_SERIAL
Serial.println(F("I2C.setSpeed too low."));
#endif
return false;
}
if (atwbr <= 255) {
atwbr /= 1;
TWSR = 0x0;
} else if (atwbr <= 1020) {
atwbr /= 4;
TWSR = 0x1;
} else if (atwbr <= 4080) {
atwbr /= 16;
TWSR = 0x2;
} else { // if (atwbr <= 16320)
atwbr /= 64;
TWSR = 0x3;
}
TWBR = atwbr;
#ifdef DEBUG_SERIAL
Serial.print(F("TWSR prescaler = "));
Serial.println(pow(4, TWSR));
Serial.print(F("TWBR = "));
Serial.println(atwbr);
#endif
return true;
#elif (ARDUINO >= 157) && !defined(ARDUINO_STM32_FEATHER) && \
!defined(TinyWireM_h)
_wire->setClock(desiredclk);
return true;
#else
(void)desiredclk;
return false;
#endif
}

View File

@@ -0,0 +1,36 @@
#ifndef Adafruit_I2CDevice_h
#define Adafruit_I2CDevice_h
#include <Arduino.h>
#include <Wire.h>
///< The class which defines how we will talk to this device over I2C
class Adafruit_I2CDevice {
public:
Adafruit_I2CDevice(uint8_t addr, TwoWire *theWire = &Wire);
uint8_t address(void);
bool begin(bool addr_detect = true);
void end(void);
bool detected(void);
bool read(uint8_t *buffer, size_t len, bool stop = true);
bool write(const uint8_t *buffer, size_t len, bool stop = true,
const uint8_t *prefix_buffer = nullptr, size_t prefix_len = 0);
bool write_then_read(const uint8_t *write_buffer, size_t write_len,
uint8_t *read_buffer, size_t read_len,
bool stop = false);
bool setSpeed(uint32_t desiredclk);
/*! @brief How many bytes we can read in a transaction
* @return The size of the Wire receive/transmit buffer */
size_t maxBufferSize() { return _maxBufferSize; }
private:
uint8_t _addr;
TwoWire *_wire;
bool _begun;
size_t _maxBufferSize;
bool _read(uint8_t *buffer, size_t len, bool stop);
};
#endif // Adafruit_I2CDevice_h

View File

@@ -0,0 +1,10 @@
#ifndef _ADAFRUIT_I2C_REGISTER_H_
#define _ADAFRUIT_I2C_REGISTER_H_
#include <Adafruit_BusIO_Register.h>
#include <Arduino.h>
typedef Adafruit_BusIO_Register Adafruit_I2CRegister;
typedef Adafruit_BusIO_RegisterBits Adafruit_I2CRegisterBits;
#endif

View File

@@ -0,0 +1,512 @@
#include "Adafruit_SPIDevice.h"
// #define DEBUG_SERIAL Serial
#ifdef BUSIO_USE_FAST_PINIO
#define BUSIO_SET_CLOCK_LOW() (*clkPort = *clkPort & ~clkPinMask)
#define BUSIO_SET_CLOCK_HIGH() (*clkPort = *clkPort | clkPinMask)
#define BUSIO_READ_MISO() (*misoPort & misoPinMask)
#define BUSIO_WRITE_MOSI(value) \
do { \
if (value) \
*mosiPort = *mosiPort | mosiPinMask; \
else \
*mosiPort = *mosiPort & ~mosiPinMask; \
} while (0)
#else
#define BUSIO_SET_CLOCK_LOW() digitalWrite(_sck, LOW)
#define BUSIO_SET_CLOCK_HIGH() digitalWrite(_sck, HIGH)
#define BUSIO_READ_MISO() digitalRead(_miso)
#define BUSIO_WRITE_MOSI(value) digitalWrite(_mosi, value)
#endif
/*!
* @brief Create an SPI device with the given CS pin and settings
* @param cspin The arduino pin number to use for chip select
* @param freq The SPI clock frequency to use, defaults to 1MHz
* @param dataOrder The SPI data order to use for bits within each byte,
* defaults to SPI_BITORDER_MSBFIRST
* @param dataMode The SPI mode to use, defaults to SPI_MODE0
* @param theSPI The SPI bus to use, defaults to &theSPI
*/
Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, uint32_t freq,
BusIOBitOrder dataOrder,
uint8_t dataMode, SPIClass *theSPI) {
#ifdef BUSIO_HAS_HW_SPI
_cs = cspin;
_sck = _mosi = _miso = -1;
_spi = theSPI;
_begun = false;
_spiSetting = new SPISettings(freq, dataOrder, dataMode);
_freq = freq;
_dataOrder = dataOrder;
_dataMode = dataMode;
#else
// unused, but needed to suppress compiler warns
(void)cspin;
(void)freq;
(void)dataOrder;
(void)dataMode;
(void)theSPI;
#endif
}
/*!
* @brief Create an SPI device with the given CS pin and settings
* @param cspin The arduino pin number to use for chip select
* @param sckpin The arduino pin number to use for SCK
* @param misopin The arduino pin number to use for MISO, set to -1 if not
* used
* @param mosipin The arduino pin number to use for MOSI, set to -1 if not
* used
* @param freq The SPI clock frequency to use, defaults to 1MHz
* @param dataOrder The SPI data order to use for bits within each byte,
* defaults to SPI_BITORDER_MSBFIRST
* @param dataMode The SPI mode to use, defaults to SPI_MODE0
*/
Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, int8_t sckpin,
int8_t misopin, int8_t mosipin,
uint32_t freq, BusIOBitOrder dataOrder,
uint8_t dataMode) {
_cs = cspin;
_sck = sckpin;
_miso = misopin;
_mosi = mosipin;
#ifdef BUSIO_USE_FAST_PINIO
csPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(cspin));
csPinMask = digitalPinToBitMask(cspin);
if (mosipin != -1) {
mosiPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(mosipin));
mosiPinMask = digitalPinToBitMask(mosipin);
}
if (misopin != -1) {
misoPort = (BusIO_PortReg *)portInputRegister(digitalPinToPort(misopin));
misoPinMask = digitalPinToBitMask(misopin);
}
clkPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(sckpin));
clkPinMask = digitalPinToBitMask(sckpin);
#endif
_freq = freq;
_dataOrder = dataOrder;
_dataMode = dataMode;
_begun = false;
}
/*!
* @brief Release memory allocated in constructors
*/
Adafruit_SPIDevice::~Adafruit_SPIDevice() {
if (_spiSetting)
delete _spiSetting;
}
/*!
* @brief Initializes SPI bus and sets CS pin high
* @return Always returns true because there's no way to test success of SPI
* init
*/
bool Adafruit_SPIDevice::begin(void) {
if (_cs != -1) {
pinMode(_cs, OUTPUT);
digitalWrite(_cs, HIGH);
}
if (_spi) { // hardware SPI
#ifdef BUSIO_HAS_HW_SPI
_spi->begin();
#endif
} else {
pinMode(_sck, OUTPUT);
if ((_dataMode == SPI_MODE0) || (_dataMode == SPI_MODE1)) {
// idle low on mode 0 and 1
digitalWrite(_sck, LOW);
} else {
// idle high on mode 2 or 3
digitalWrite(_sck, HIGH);
}
if (_mosi != -1) {
pinMode(_mosi, OUTPUT);
digitalWrite(_mosi, HIGH);
}
if (_miso != -1) {
pinMode(_miso, INPUT);
}
}
_begun = true;
return true;
}
/*!
* @brief Transfer (send/receive) a buffer over hard/soft SPI, without
* transaction management
* @param buffer The buffer to send and receive at the same time
* @param len The number of bytes to transfer
*/
void Adafruit_SPIDevice::transfer(uint8_t *buffer, size_t len) {
//
// HARDWARE SPI
//
if (_spi) {
#ifdef BUSIO_HAS_HW_SPI
#if defined(SPARK)
_spi->transfer(buffer, buffer, len, nullptr);
#elif defined(STM32)
for (size_t i = 0; i < len; i++) {
_spi->transfer(buffer[i]);
}
#else
_spi->transfer(buffer, len);
#endif
return;
#endif
}
//
// SOFTWARE SPI
//
uint8_t startbit;
if (_dataOrder == SPI_BITORDER_LSBFIRST) {
startbit = 0x1;
} else {
startbit = 0x80;
}
bool towrite, lastmosi = !(buffer[0] & startbit);
uint8_t bitdelay_us = (1000000 / _freq) / 2;
for (size_t i = 0; i < len; i++) {
uint8_t reply = 0;
uint8_t send = buffer[i];
/*
Serial.print("\tSending software SPI byte 0x");
Serial.print(send, HEX);
Serial.print(" -> 0x");
*/
// Serial.print(send, HEX);
for (uint8_t b = startbit; b != 0;
b = (_dataOrder == SPI_BITORDER_LSBFIRST) ? b << 1 : b >> 1) {
if (bitdelay_us) {
delayMicroseconds(bitdelay_us);
}
if (_dataMode == SPI_MODE0 || _dataMode == SPI_MODE2) {
towrite = send & b;
if ((_mosi != -1) && (lastmosi != towrite)) {
BUSIO_WRITE_MOSI(towrite);
lastmosi = towrite;
}
BUSIO_SET_CLOCK_HIGH();
if (bitdelay_us) {
delayMicroseconds(bitdelay_us);
}
if (_miso != -1) {
if (BUSIO_READ_MISO())
reply |= b;
}
BUSIO_SET_CLOCK_LOW();
} else if (_dataMode == SPI_MODE3) {
if (_mosi != -1) { // transmit on falling edge
BUSIO_WRITE_MOSI(send & b);
}
BUSIO_SET_CLOCK_LOW();
if (bitdelay_us) {
delayMicroseconds(bitdelay_us);
}
BUSIO_SET_CLOCK_HIGH();
if (bitdelay_us) {
delayMicroseconds(bitdelay_us);
}
if (_miso != -1) { // read on rising edge
if (BUSIO_READ_MISO()) {
reply |= b;
}
}
} else { // || _dataMode == SPI_MODE1)
BUSIO_SET_CLOCK_HIGH();
if (bitdelay_us) {
delayMicroseconds(bitdelay_us);
}
if (_mosi != -1) {
BUSIO_WRITE_MOSI(send & b);
}
BUSIO_SET_CLOCK_LOW();
if (_miso != -1) {
if (BUSIO_READ_MISO()) {
reply |= b;
}
}
}
}
if (_miso != -1) {
buffer[i] = reply;
}
}
return;
}
/*!
* @brief Transfer (send/receive) one byte over hard/soft SPI, without
* transaction management
* @param send The byte to send
* @return The byte received while transmitting
*/
uint8_t Adafruit_SPIDevice::transfer(uint8_t send) {
uint8_t data = send;
transfer(&data, 1);
return data;
}
/*!
* @brief Manually begin a transaction (calls beginTransaction if hardware
* SPI)
*/
void Adafruit_SPIDevice::beginTransaction(void) {
if (_spi) {
#ifdef BUSIO_HAS_HW_SPI
_spi->beginTransaction(*_spiSetting);
#endif
}
}
/*!
* @brief Manually end a transaction (calls endTransaction if hardware SPI)
*/
void Adafruit_SPIDevice::endTransaction(void) {
if (_spi) {
#ifdef BUSIO_HAS_HW_SPI
_spi->endTransaction();
#endif
}
}
/*!
* @brief Assert/Deassert the CS pin if it is defined
* @param value The state the CS is set to
*/
void Adafruit_SPIDevice::setChipSelect(int value) {
if (_cs != -1) {
digitalWrite(_cs, value);
}
}
/*!
* @brief Write a buffer or two to the SPI device, with transaction
* management.
* @brief Manually begin a transaction (calls beginTransaction if hardware
* SPI) with asserting the CS pin
*/
void Adafruit_SPIDevice::beginTransactionWithAssertingCS() {
beginTransaction();
setChipSelect(LOW);
}
/*!
* @brief Manually end a transaction (calls endTransaction if hardware SPI)
* with deasserting the CS pin
*/
void Adafruit_SPIDevice::endTransactionWithDeassertingCS() {
setChipSelect(HIGH);
endTransaction();
}
/*!
* @brief Write a buffer or two to the SPI device, with transaction
* management.
* @param buffer Pointer to buffer of data to write
* @param len Number of bytes from buffer to write
* @param prefix_buffer Pointer to optional array of data to write before
* buffer.
* @param prefix_len Number of bytes from prefix buffer to write
* @return Always returns true because there's no way to test success of SPI
* writes
*/
bool Adafruit_SPIDevice::write(const uint8_t *buffer, size_t len,
const uint8_t *prefix_buffer,
size_t prefix_len) {
beginTransactionWithAssertingCS();
// do the writing
#if defined(ARDUINO_ARCH_ESP32)
if (_spi) {
if (prefix_len > 0) {
_spi->transferBytes((uint8_t *)prefix_buffer, nullptr, prefix_len);
}
if (len > 0) {
_spi->transferBytes((uint8_t *)buffer, nullptr, len);
}
} else
#endif
{
for (size_t i = 0; i < prefix_len; i++) {
transfer(prefix_buffer[i]);
}
for (size_t i = 0; i < len; i++) {
transfer(buffer[i]);
}
}
endTransactionWithDeassertingCS();
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tSPIDevice Wrote: "));
if ((prefix_len != 0) && (prefix_buffer != nullptr)) {
for (uint16_t i = 0; i < prefix_len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(prefix_buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
}
}
for (uint16_t i = 0; i < len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (i % 32 == 31) {
DEBUG_SERIAL.println();
}
}
DEBUG_SERIAL.println();
#endif
return true;
}
/*!
* @brief Read from SPI into a buffer from the SPI device, with transaction
* management.
* @param buffer Pointer to buffer of data to read into
* @param len Number of bytes from buffer to read.
* @param sendvalue The 8-bits of data to write when doing the data read,
* defaults to 0xFF
* @return Always returns true because there's no way to test success of SPI
* writes
*/
bool Adafruit_SPIDevice::read(uint8_t *buffer, size_t len, uint8_t sendvalue) {
memset(buffer, sendvalue, len); // clear out existing buffer
beginTransactionWithAssertingCS();
transfer(buffer, len);
endTransactionWithDeassertingCS();
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tSPIDevice Read: "));
for (uint16_t i = 0; i < len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (len % 32 == 31) {
DEBUG_SERIAL.println();
}
}
DEBUG_SERIAL.println();
#endif
return true;
}
/*!
* @brief Write some data, then read some data from SPI into another buffer,
* with transaction management. The buffers can point to same/overlapping
* locations. This does not transmit-receive at the same time!
* @param write_buffer Pointer to buffer of data to write from
* @param write_len Number of bytes from buffer to write.
* @param read_buffer Pointer to buffer of data to read into.
* @param read_len Number of bytes from buffer to read.
* @param sendvalue The 8-bits of data to write when doing the data read,
* defaults to 0xFF
* @return Always returns true because there's no way to test success of SPI
* writes
*/
bool Adafruit_SPIDevice::write_then_read(const uint8_t *write_buffer,
size_t write_len, uint8_t *read_buffer,
size_t read_len, uint8_t sendvalue) {
beginTransactionWithAssertingCS();
// do the writing
#if defined(ARDUINO_ARCH_ESP32)
if (_spi) {
if (write_len > 0) {
_spi->transferBytes((uint8_t *)write_buffer, nullptr, write_len);
}
} else
#endif
{
for (size_t i = 0; i < write_len; i++) {
transfer(write_buffer[i]);
}
}
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tSPIDevice Wrote: "));
for (uint16_t i = 0; i < write_len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(write_buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (write_len % 32 == 31) {
DEBUG_SERIAL.println();
}
}
DEBUG_SERIAL.println();
#endif
// do the reading
for (size_t i = 0; i < read_len; i++) {
read_buffer[i] = transfer(sendvalue);
}
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tSPIDevice Read: "));
for (uint16_t i = 0; i < read_len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(read_buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (read_len % 32 == 31) {
DEBUG_SERIAL.println();
}
}
DEBUG_SERIAL.println();
#endif
endTransactionWithDeassertingCS();
return true;
}
/*!
* @brief Write some data and read some data at the same time from SPI
* into the same buffer, with transaction management. This is basicaly a wrapper
* for transfer() with CS-pin and transaction management. This /does/
* transmit-receive at the same time!
* @param buffer Pointer to buffer of data to write/read to/from
* @param len Number of bytes from buffer to write/read.
* @return Always returns true because there's no way to test success of SPI
* writes
*/
bool Adafruit_SPIDevice::write_and_read(uint8_t *buffer, size_t len) {
beginTransactionWithAssertingCS();
transfer(buffer, len);
endTransactionWithDeassertingCS();
return true;
}

View File

@@ -0,0 +1,149 @@
#ifndef Adafruit_SPIDevice_h
#define Adafruit_SPIDevice_h
#include <Arduino.h>
#if !defined(SPI_INTERFACES_COUNT) || \
(defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0))
// HW SPI available
#include <SPI.h>
#define BUSIO_HAS_HW_SPI
#else
// SW SPI ONLY
enum { SPI_MODE0, SPI_MODE1, SPI_MODE2, SPI_MODE3 };
typedef uint8_t SPIClass;
#endif
// some modern SPI definitions don't have BitOrder enum
#if (defined(__AVR__) && !defined(ARDUINO_ARCH_MEGAAVR)) || \
defined(ESP8266) || defined(TEENSYDUINO) || defined(SPARK) || \
defined(ARDUINO_ARCH_SPRESENSE) || defined(MEGATINYCORE) || \
defined(DXCORE) || defined(ARDUINO_AVR_ATmega4809) || \
defined(ARDUINO_AVR_ATmega4808) || defined(ARDUINO_AVR_ATmega3209) || \
defined(ARDUINO_AVR_ATmega3208) || defined(ARDUINO_AVR_ATmega1609) || \
defined(ARDUINO_AVR_ATmega1608) || defined(ARDUINO_AVR_ATmega809) || \
defined(ARDUINO_AVR_ATmega808) || defined(ARDUINO_ARCH_ARC32) || \
defined(ARDUINO_ARCH_XMC)
typedef enum _BitOrder {
SPI_BITORDER_MSBFIRST = MSBFIRST,
SPI_BITORDER_LSBFIRST = LSBFIRST,
} BusIOBitOrder;
#elif defined(ESP32) || defined(__ASR6501__) || defined(__ASR6502__)
// some modern SPI definitions don't have BitOrder enum and have different SPI
// mode defines
typedef enum _BitOrder {
SPI_BITORDER_MSBFIRST = SPI_MSBFIRST,
SPI_BITORDER_LSBFIRST = SPI_LSBFIRST,
} BusIOBitOrder;
#else
// Some platforms have a BitOrder enum but its named MSBFIRST/LSBFIRST
#define SPI_BITORDER_MSBFIRST MSBFIRST
#define SPI_BITORDER_LSBFIRST LSBFIRST
typedef BitOrder BusIOBitOrder;
#endif
#if defined(__IMXRT1062__) // Teensy 4.x
// *Warning* I disabled the usage of FAST_PINIO as the set/clear operations
// used in the cpp file are not atomic and can effect multiple IO pins
// and if an interrupt happens in between the time the code reads the register
// and writes out the updated value, that changes one or more other IO pins
// on that same IO port, those change will be clobbered when the updated
// values are written back. A fast version can be implemented that uses the
// ports set and clear registers which are atomic.
// typedef volatile uint32_t BusIO_PortReg;
// typedef uint32_t BusIO_PortMask;
// #define BUSIO_USE_FAST_PINIO
#elif defined(__MBED__) || defined(__ZEPHYR__)
// Boards based on RTOS cores like mbed or Zephyr are not going to expose the
// low level registers needed for fast pin manipulation
#undef BUSIO_USE_FAST_PINIO
#elif defined(ARDUINO_ARCH_XMC)
#undef BUSIO_USE_FAST_PINIO
#elif defined(__AVR__) || defined(TEENSYDUINO)
typedef volatile uint8_t BusIO_PortReg;
typedef uint8_t BusIO_PortMask;
#define BUSIO_USE_FAST_PINIO
#elif defined(ESP8266) || defined(ESP32) || defined(__SAM3X8E__) || \
defined(ARDUINO_ARCH_SAMD)
typedef volatile uint32_t BusIO_PortReg;
typedef uint32_t BusIO_PortMask;
#define BUSIO_USE_FAST_PINIO
#elif (defined(__arm__) || defined(ARDUINO_FEATHER52)) && \
!defined(ARDUINO_ARCH_RP2040) && !defined(ARDUINO_SILABS) && \
!defined(ARDUINO_UNOR4_MINIMA) && !defined(ARDUINO_UNOR4_WIFI) && \
!defined(PORTDUINO)
typedef volatile uint32_t BusIO_PortReg;
typedef uint32_t BusIO_PortMask;
#if !defined(__ASR6501__) && !defined(__ASR6502__)
#define BUSIO_USE_FAST_PINIO
#endif
#else
#undef BUSIO_USE_FAST_PINIO
#endif
/**! The class which defines how we will talk to this device over SPI **/
class Adafruit_SPIDevice {
public:
#ifdef BUSIO_HAS_HW_SPI
Adafruit_SPIDevice(int8_t cspin, uint32_t freq = 1000000,
BusIOBitOrder dataOrder = SPI_BITORDER_MSBFIRST,
uint8_t dataMode = SPI_MODE0, SPIClass *theSPI = &SPI);
#else
Adafruit_SPIDevice(int8_t cspin, uint32_t freq = 1000000,
BusIOBitOrder dataOrder = SPI_BITORDER_MSBFIRST,
uint8_t dataMode = SPI_MODE0, SPIClass *theSPI = nullptr);
#endif
Adafruit_SPIDevice(int8_t cspin, int8_t sck, int8_t miso, int8_t mosi,
uint32_t freq = 1000000,
BusIOBitOrder dataOrder = SPI_BITORDER_MSBFIRST,
uint8_t dataMode = SPI_MODE0);
~Adafruit_SPIDevice();
bool begin(void);
bool read(uint8_t *buffer, size_t len, uint8_t sendvalue = 0xFF);
bool write(const uint8_t *buffer, size_t len,
const uint8_t *prefix_buffer = nullptr, size_t prefix_len = 0);
bool write_then_read(const uint8_t *write_buffer, size_t write_len,
uint8_t *read_buffer, size_t read_len,
uint8_t sendvalue = 0xFF);
bool write_and_read(uint8_t *buffer, size_t len);
uint8_t transfer(uint8_t send);
void transfer(uint8_t *buffer, size_t len);
void beginTransaction(void);
void endTransaction(void);
void beginTransactionWithAssertingCS();
void endTransactionWithDeassertingCS();
private:
#ifdef BUSIO_HAS_HW_SPI
SPIClass *_spi = nullptr;
SPISettings *_spiSetting = nullptr;
#else
uint8_t *_spi = nullptr;
uint8_t *_spiSetting = nullptr;
#endif
uint32_t _freq;
BusIOBitOrder _dataOrder;
uint8_t _dataMode;
void setChipSelect(int value);
int8_t _cs, _sck, _mosi, _miso;
#ifdef BUSIO_USE_FAST_PINIO
BusIO_PortReg *mosiPort, *clkPort, *misoPort, *csPort;
BusIO_PortMask mosiPinMask, misoPinMask, clkPinMask, csPinMask;
#endif
bool _begun;
};
#endif // Adafruit_SPIDevice_h

View File

@@ -0,0 +1,11 @@
# Adafruit Bus IO Library
# https://github.com/adafruit/Adafruit_BusIO
# MIT License
cmake_minimum_required(VERSION 3.5)
idf_component_register(SRCS "Adafruit_I2CDevice.cpp" "Adafruit_BusIO_Register.cpp" "Adafruit_SPIDevice.cpp" "Adafruit_GenericDevice.cpp"
INCLUDE_DIRS "."
REQUIRES arduino-esp32)
project(Adafruit_BusIO)

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017 Adafruit Industries
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,8 @@
# Adafruit Bus IO Library [![Build Status](https://github.com/adafruit/Adafruit_BusIO/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_BusIO/actions)
This is a helper library to abstract away I2C, SPI, and 'generic transport' (e.g. UART) transactions and registers
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
MIT license, all text above must be included in any redistribution

View File

@@ -0,0 +1 @@
COMPONENT_ADD_INCLUDEDIRS = .

View File

@@ -0,0 +1,219 @@
/*
Advanced example of using bstracted transport for reading and writing
register data from a UART-based device such as a TMC2209
Written with help by Claude!
https://claude.ai/chat/335f50b1-3dd8-435e-9139-57ec7ca26a3c (at this time
chats are not shareable :(
*/
#include "Adafruit_BusIO_Register.h"
#include "Adafruit_GenericDevice.h"
// Debugging macros
#define DEBUG_SERIAL Serial
#ifdef DEBUG_SERIAL
#define DEBUG_PRINT(x) DEBUG_SERIAL.print(x)
#define DEBUG_PRINTLN(x) DEBUG_SERIAL.println(x)
#define DEBUG_PRINT_HEX(x) \
do { \
if (x < 0x10) \
DEBUG_SERIAL.print('0'); \
DEBUG_SERIAL.print(x, HEX); \
DEBUG_SERIAL.print(' '); \
} while (0)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#define DEBUG_PRINT_HEX(x)
#endif
#define TMC2209_IOIN 0x06
class TMC2209_UART {
private:
Stream *_uart_stream;
uint8_t _addr;
static bool uart_read(void *thiz, uint8_t *buffer, size_t len) {
TMC2209_UART *dev = (TMC2209_UART *)thiz;
uint16_t timeout = 100;
while (dev->_uart_stream->available() < len && timeout--) {
delay(1);
}
if (timeout == 0) {
DEBUG_PRINTLN("Read timeout!");
return false;
}
DEBUG_PRINT("Reading: ");
for (size_t i = 0; i < len; i++) {
buffer[i] = dev->_uart_stream->read();
DEBUG_PRINT_HEX(buffer[i]);
}
DEBUG_PRINTLN("");
return true;
}
static bool uart_write(void *thiz, const uint8_t *buffer, size_t len) {
TMC2209_UART *dev = (TMC2209_UART *)thiz;
DEBUG_PRINT("Writing: ");
for (size_t i = 0; i < len; i++) {
DEBUG_PRINT_HEX(buffer[i]);
}
DEBUG_PRINTLN("");
dev->_uart_stream->write(buffer, len);
return true;
}
static bool uart_readreg(void *thiz, uint8_t *addr_buf, uint8_t addrsiz,
uint8_t *data, uint16_t datalen) {
TMC2209_UART *dev = (TMC2209_UART *)thiz;
while (dev->_uart_stream->available())
dev->_uart_stream->read();
uint8_t packet[4] = {0x05, uint8_t(dev->_addr << 1), addr_buf[0], 0x00};
packet[3] = calcCRC(packet, 3);
if (!uart_write(thiz, packet, 4))
return false;
// Read back echo
uint8_t echo[4];
if (!uart_read(thiz, echo, 4))
return false;
// Verify echo
for (uint8_t i = 0; i < 4; i++) {
if (echo[i] != packet[i]) {
DEBUG_PRINTLN("Echo mismatch");
return false;
}
}
uint8_t response[8]; // sync + 0xFF + reg + 4 data bytes + CRC
if (!uart_read(thiz, response, 8))
return false;
// Verify response
if (response[0] != 0x05) {
DEBUG_PRINTLN("Invalid sync byte");
return false;
}
if (response[1] != 0xFF) {
DEBUG_PRINTLN("Invalid reply address");
return false;
}
if (response[2] != addr_buf[0]) {
DEBUG_PRINTLN("Register mismatch");
return false;
}
uint8_t crc = calcCRC(response, 7);
if (crc != response[7]) {
DEBUG_PRINTLN("CRC mismatch");
return false;
}
memcpy(data, &response[3], 4);
return true;
}
static bool uart_writereg(void *thiz, uint8_t *addr_buf, uint8_t addrsiz,
const uint8_t *data, uint16_t datalen) {
TMC2209_UART *dev = (TMC2209_UART *)thiz;
while (dev->_uart_stream->available())
dev->_uart_stream->read();
uint8_t packet[8] = {0x05,
uint8_t(dev->_addr << 1),
uint8_t(addr_buf[0] | 0x80),
data[0],
data[1],
data[2],
data[3],
0x00};
packet[7] = calcCRC(packet, 7);
if (!uart_write(thiz, packet, 8))
return false;
uint8_t echo[8];
if (!uart_read(thiz, echo, 8))
return false;
for (uint8_t i = 0; i < 8; i++) {
if (echo[i] != packet[i]) {
DEBUG_PRINTLN("Write echo mismatch");
return false;
}
}
return true;
}
static uint8_t calcCRC(uint8_t *data, uint8_t length) {
uint8_t crc = 0;
for (uint8_t i = 0; i < length; i++) {
uint8_t currentByte = data[i];
for (uint8_t j = 0; j < 8; j++) {
if ((crc >> 7) ^ (currentByte & 0x01)) {
crc = (crc << 1) ^ 0x07;
} else {
crc = crc << 1;
}
currentByte = currentByte >> 1;
}
}
return crc;
}
public:
TMC2209_UART(Stream *serial, uint8_t addr)
: _uart_stream(serial), _addr(addr) {}
Adafruit_GenericDevice *createDevice() {
return new Adafruit_GenericDevice(this, uart_read, uart_write, uart_readreg,
uart_writereg);
}
};
void setup() {
Serial.begin(115200);
while (!Serial)
;
delay(100);
Serial.println("TMC2209 Generic Device register read/write test!");
Serial1.begin(115200);
TMC2209_UART uart(&Serial1, 0);
Adafruit_GenericDevice *device = uart.createDevice();
device->begin();
// Create register object for IOIN
Adafruit_BusIO_Register ioin_reg(device,
TMC2209_IOIN, // device and register address
4, // width = 4 bytes
MSBFIRST, // byte order
1); // address width = 1 byte
Serial.print("IOIN = 0x");
Serial.println(ioin_reg.read(), HEX);
// Create RegisterBits for VERSION field (bits 31:24)
Adafruit_BusIO_RegisterBits version_bits(
&ioin_reg, 8, 24); // 8 bits wide, starting at bit 24
Serial.println("Reading VERSION...");
uint8_t version = version_bits.read();
Serial.print("VERSION = 0x");
Serial.println(version, HEX);
}
void loop() { delay(1000); }

View File

@@ -0,0 +1,98 @@
/*
Abstracted transport for reading and writing data from a UART-based
device such as a TMC2209
Written with help by Claude!
https://claude.ai/chat/335f50b1-3dd8-435e-9139-57ec7ca26a3c (at this time
chats are not shareable :(
*/
#include "Adafruit_GenericDevice.h"
/**
* Basic UART device class that demonstrates using GenericDevice with a Stream
* interface. This example shows how to wrap a Stream (like HardwareSerial or
* SoftwareSerial) with read/write callbacks that can be used by BusIO's
* register functions.
*/
class UARTDevice {
public:
UARTDevice(Stream *serial) : _serial(serial) {}
// Static callback for writing data to UART
// Called by GenericDevice when data needs to be sent
static bool uart_write(void *thiz, const uint8_t *buffer, size_t len) {
UARTDevice *dev = (UARTDevice *)thiz;
dev->_serial->write(buffer, len);
return true;
}
// Static callback for reading data from UART
// Includes timeout and will return false if not enough data available
static bool uart_read(void *thiz, uint8_t *buffer, size_t len) {
UARTDevice *dev = (UARTDevice *)thiz;
uint16_t timeout = 100;
while (dev->_serial->available() < len && timeout--) {
delay(1);
}
if (timeout == 0) {
return false;
}
for (size_t i = 0; i < len; i++) {
buffer[i] = dev->_serial->read();
}
return true;
}
// Create a GenericDevice instance using our callbacks
Adafruit_GenericDevice *createDevice() {
return new Adafruit_GenericDevice(this, uart_read, uart_write);
}
private:
Stream *_serial; // Underlying Stream instance (HardwareSerial, etc)
};
void setup() {
Serial.begin(115200);
while (!Serial)
;
delay(100);
Serial.println("Generic Device test!");
// Initialize UART for device communication
Serial1.begin(115200);
// Create UART wrapper and BusIO device
UARTDevice uart(&Serial1);
Adafruit_GenericDevice *device = uart.createDevice();
device->begin();
// Test write/read cycle
uint8_t write_buf[4] = {0x5, 0x0, 0x0, 0x48};
uint8_t read_buf[8];
Serial.println("Writing data...");
if (!device->write(write_buf, 4)) {
Serial.println("Write failed!");
return;
}
Serial.println("Reading response...");
if (!device->read(read_buf, 8)) {
Serial.println("Read failed!");
return;
}
// Print response bytes
Serial.print("Got response: ");
for (int i = 0; i < 8; i++) {
Serial.print("0x");
Serial.print(read_buf[i], HEX);
Serial.print(" ");
}
Serial.println();
}
void loop() { delay(1000); }

View File

@@ -0,0 +1,22 @@
#include <Adafruit_I2CDevice.h>
Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(0x10);
void setup() {
while (!Serial) {
delay(10);
}
Serial.begin(115200);
Serial.println("I2C address detection test");
if (!i2c_dev.begin()) {
Serial.print("Did not find device at 0x");
Serial.println(i2c_dev.address(), HEX);
while (1)
;
}
Serial.print("Device found on address 0x");
Serial.println(i2c_dev.address(), HEX);
}
void loop() {}

View File

@@ -0,0 +1,45 @@
#include <Adafruit_I2CDevice.h>
#define I2C_ADDRESS 0x60
Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(I2C_ADDRESS);
void setup() {
while (!Serial) {
delay(10);
}
Serial.begin(115200);
Serial.println("I2C device read and write test");
if (!i2c_dev.begin()) {
Serial.print("Did not find device at 0x");
Serial.println(i2c_dev.address(), HEX);
while (1)
;
}
Serial.print("Device found on address 0x");
Serial.println(i2c_dev.address(), HEX);
uint8_t buffer[32];
// Try to read 32 bytes
i2c_dev.read(buffer, 32);
Serial.print("Read: ");
for (uint8_t i = 0; i < 32; i++) {
Serial.print("0x");
Serial.print(buffer[i], HEX);
Serial.print(", ");
}
Serial.println();
// read a register by writing first, then reading
buffer[0] = 0x0C; // we'll reuse the same buffer
i2c_dev.write_then_read(buffer, 1, buffer, 2, false);
Serial.print("Write then Read: ");
for (uint8_t i = 0; i < 2; i++) {
Serial.print("0x");
Serial.print(buffer[i], HEX);
Serial.print(", ");
}
Serial.println();
}
void loop() {}

View File

@@ -0,0 +1,43 @@
#include <Adafruit_BusIO_Register.h>
#include <Adafruit_I2CDevice.h>
#define I2C_ADDRESS 0x60
Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(I2C_ADDRESS);
void setup() {
while (!Serial) {
delay(10);
}
Serial.begin(115200);
Serial.println("I2C device register test");
if (!i2c_dev.begin()) {
Serial.print("Did not find device at 0x");
Serial.println(i2c_dev.address(), HEX);
while (1)
;
}
Serial.print("Device found on address 0x");
Serial.println(i2c_dev.address(), HEX);
Adafruit_BusIO_Register id_reg =
Adafruit_BusIO_Register(&i2c_dev, 0x0C, 2, LSBFIRST);
uint16_t id;
id_reg.read(&id);
Serial.print("ID register = 0x");
Serial.println(id, HEX);
Adafruit_BusIO_Register thresh_reg =
Adafruit_BusIO_Register(&i2c_dev, 0x01, 2, LSBFIRST);
uint16_t thresh;
thresh_reg.read(&thresh);
Serial.print("Initial threshold register = 0x");
Serial.println(thresh, HEX);
thresh_reg.write(~thresh);
Serial.print("Post threshold register = 0x");
Serial.println(thresh_reg.read(), HEX);
}
void loop() {}

View File

@@ -0,0 +1,40 @@
#include <Adafruit_BusIO_Register.h>
// Define which interface to use by setting the unused interface to NULL!
#define SPIDEVICE_CS 10
Adafruit_SPIDevice *spi_dev = NULL; // new Adafruit_SPIDevice(SPIDEVICE_CS);
#define I2C_ADDRESS 0x5D
Adafruit_I2CDevice *i2c_dev = new Adafruit_I2CDevice(I2C_ADDRESS);
void setup() {
while (!Serial) {
delay(10);
}
Serial.begin(115200);
Serial.println("I2C or SPI device register test");
if (spi_dev && !spi_dev->begin()) {
Serial.println("Could not initialize SPI device");
}
if (i2c_dev) {
if (i2c_dev->begin()) {
Serial.print("Device found on I2C address 0x");
Serial.println(i2c_dev->address(), HEX);
} else {
Serial.print("Did not find I2C device at 0x");
Serial.println(i2c_dev->address(), HEX);
}
}
Adafruit_BusIO_Register id_reg =
Adafruit_BusIO_Register(i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, 0x0F);
uint8_t id = 0;
id_reg.read(&id);
Serial.print("ID register = 0x");
Serial.println(id, HEX);
}
void loop() {}

View File

@@ -0,0 +1,35 @@
#include <Adafruit_SPIDevice.h>
#define SPIDEVICE_CS 10
Adafruit_SPIDevice spi_dev =
Adafruit_SPIDevice(SPIDEVICE_CS, 100000, SPI_BITORDER_MSBFIRST, SPI_MODE1);
// Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS, 13, 12, 11,
// 100000, SPI_BITORDER_MSBFIRST, SPI_MODE1);
void setup() {
while (!Serial) {
delay(10);
}
Serial.begin(115200);
Serial.println("SPI device mode test");
if (!spi_dev.begin()) {
Serial.println("Could not initialize SPI device");
while (1)
;
}
}
void loop() {
Serial.println("\n\nTransfer test");
for (uint16_t x = 0; x <= 0xFF; x++) {
uint8_t i = x;
Serial.print("0x");
Serial.print(i, HEX);
spi_dev.read(&i, 1, i);
Serial.print("/");
Serial.print(i, HEX);
Serial.print(", ");
delay(25);
}
}

View File

@@ -0,0 +1,43 @@
#include <Adafruit_SPIDevice.h>
#define SPIDEVICE_CS 10
Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS);
void setup() {
while (!Serial) {
delay(10);
}
Serial.begin(115200);
Serial.println("SPI device read and write test");
if (!spi_dev.begin()) {
Serial.println("Could not initialize SPI device");
while (1)
;
}
uint8_t buffer[32];
// Try to read 32 bytes
spi_dev.read(buffer, 32);
Serial.print("Read: ");
for (uint8_t i = 0; i < 32; i++) {
Serial.print("0x");
Serial.print(buffer[i], HEX);
Serial.print(", ");
}
Serial.println();
// read a register by writing first, then reading
buffer[0] = 0x8F; // we'll reuse the same buffer
spi_dev.write_then_read(buffer, 1, buffer, 2, false);
Serial.print("Write then Read: ");
for (uint8_t i = 0; i < 2; i++) {
Serial.print("0x");
Serial.print(buffer[i], HEX);
Serial.print(", ");
}
Serial.println();
}
void loop() {}

View File

@@ -0,0 +1,268 @@
/***************************************************
This is an example for how to use Adafruit_BusIO_RegisterBits from
Adafruit_BusIO library.
Designed specifically to work with the Adafruit RTD Sensor
----> https://www.adafruit.com/products/3328
uisng a MAX31865 RTD-to-Digital Converter
----> https://datasheets.maximintegrated.com/en/ds/MAX31865.pdf
This sensor uses SPI to communicate, 4 pins are required to
interface.
A fifth pin helps to detect when a new conversion is ready.
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Example written (2020/3) by Andreas Hardtung/AnHard.
BSD license, all text above must be included in any redistribution
****************************************************/
#include <Adafruit_BusIO_Register.h>
#include <Adafruit_SPIDevice.h>
#define MAX31865_SPI_SPEED (5000000)
#define MAX31865_SPI_BITORDER (SPI_BITORDER_MSBFIRST)
#define MAX31865_SPI_MODE (SPI_MODE1)
#define MAX31865_SPI_CS (10)
#define MAX31865_READY_PIN (2)
Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(
MAX31865_SPI_CS, MAX31865_SPI_SPEED, MAX31865_SPI_BITORDER,
MAX31865_SPI_MODE, &SPI); // Hardware SPI
// Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice( MAX31865_SPI_CS, 13, 12, 11,
// MAX31865_SPI_SPEED, MAX31865_SPI_BITORDER, MAX31865_SPI_MODE); // Software
// SPI
// MAX31865 chip related
// *********************************************************************************************
Adafruit_BusIO_Register config_reg =
Adafruit_BusIO_Register(&spi_dev, 0x00, ADDRBIT8_HIGH_TOWRITE, 1, MSBFIRST);
Adafruit_BusIO_RegisterBits bias_bit =
Adafruit_BusIO_RegisterBits(&config_reg, 1, 7);
Adafruit_BusIO_RegisterBits auto_bit =
Adafruit_BusIO_RegisterBits(&config_reg, 1, 6);
Adafruit_BusIO_RegisterBits oneS_bit =
Adafruit_BusIO_RegisterBits(&config_reg, 1, 5);
Adafruit_BusIO_RegisterBits wire_bit =
Adafruit_BusIO_RegisterBits(&config_reg, 1, 4);
Adafruit_BusIO_RegisterBits faultT_bits =
Adafruit_BusIO_RegisterBits(&config_reg, 2, 2);
Adafruit_BusIO_RegisterBits faultR_bit =
Adafruit_BusIO_RegisterBits(&config_reg, 1, 1);
Adafruit_BusIO_RegisterBits fi50hz_bit =
Adafruit_BusIO_RegisterBits(&config_reg, 1, 0);
Adafruit_BusIO_Register rRatio_reg =
Adafruit_BusIO_Register(&spi_dev, 0x01, ADDRBIT8_HIGH_TOWRITE, 2, MSBFIRST);
Adafruit_BusIO_RegisterBits rRatio_bits =
Adafruit_BusIO_RegisterBits(&rRatio_reg, 15, 1);
Adafruit_BusIO_RegisterBits fault_bit =
Adafruit_BusIO_RegisterBits(&rRatio_reg, 1, 0);
Adafruit_BusIO_Register maxRratio_reg =
Adafruit_BusIO_Register(&spi_dev, 0x03, ADDRBIT8_HIGH_TOWRITE, 2, MSBFIRST);
Adafruit_BusIO_RegisterBits maxRratio_bits =
Adafruit_BusIO_RegisterBits(&maxRratio_reg, 15, 1);
Adafruit_BusIO_Register minRratio_reg =
Adafruit_BusIO_Register(&spi_dev, 0x05, ADDRBIT8_HIGH_TOWRITE, 2, MSBFIRST);
Adafruit_BusIO_RegisterBits minRratio_bits =
Adafruit_BusIO_RegisterBits(&minRratio_reg, 15, 1);
Adafruit_BusIO_Register fault_reg =
Adafruit_BusIO_Register(&spi_dev, 0x07, ADDRBIT8_HIGH_TOWRITE, 1, MSBFIRST);
Adafruit_BusIO_RegisterBits range_high_fault_bit =
Adafruit_BusIO_RegisterBits(&fault_reg, 1, 7);
Adafruit_BusIO_RegisterBits range_low_fault_bit =
Adafruit_BusIO_RegisterBits(&fault_reg, 1, 6);
Adafruit_BusIO_RegisterBits refin_high_fault_bit =
Adafruit_BusIO_RegisterBits(&fault_reg, 1, 5);
Adafruit_BusIO_RegisterBits refin_low_fault_bit =
Adafruit_BusIO_RegisterBits(&fault_reg, 1, 4);
Adafruit_BusIO_RegisterBits rtdin_low_fault_bit =
Adafruit_BusIO_RegisterBits(&fault_reg, 1, 3);
Adafruit_BusIO_RegisterBits voltage_fault_bit =
Adafruit_BusIO_RegisterBits(&fault_reg, 1, 2);
// Print the details of the configuration register.
void printConfig(void) {
Serial.print("BIAS: ");
if (bias_bit.read())
Serial.print("ON");
else
Serial.print("OFF");
Serial.print(", AUTO: ");
if (auto_bit.read())
Serial.print("ON");
else
Serial.print("OFF");
Serial.print(", ONES: ");
if (oneS_bit.read())
Serial.print("ON");
else
Serial.print("OFF");
Serial.print(", WIRE: ");
if (wire_bit.read())
Serial.print("3");
else
Serial.print("2/4");
Serial.print(", FAULTCLEAR: ");
if (faultR_bit.read())
Serial.print("ON");
else
Serial.print("OFF");
Serial.print(", ");
if (fi50hz_bit.read())
Serial.print("50HZ");
else
Serial.print("60HZ");
Serial.println();
}
// Check and print faults. Then clear them.
void checkFaults(void) {
if (fault_bit.read()) {
Serial.print("MAX: ");
Serial.println(maxRratio_bits.read());
Serial.print("VAL: ");
Serial.println(rRatio_bits.read());
Serial.print("MIN: ");
Serial.println(minRratio_bits.read());
if (range_high_fault_bit.read())
Serial.println("Range high fault");
if (range_low_fault_bit.read())
Serial.println("Range low fault");
if (refin_high_fault_bit.read())
Serial.println("REFIN high fault");
if (refin_low_fault_bit.read())
Serial.println("REFIN low fault");
if (rtdin_low_fault_bit.read())
Serial.println("RTDIN low fault");
if (voltage_fault_bit.read())
Serial.println("Voltage fault");
faultR_bit.write(1); // clear fault
}
}
void setup() {
#if (MAX31865_1_READY_PIN != -1)
pinMode(MAX31865_READY_PIN, INPUT_PULLUP);
#endif
while (!Serial) {
delay(10);
}
Serial.begin(115200);
Serial.println("SPI Adafruit_BusIO_RegisterBits test on MAX31865");
if (!spi_dev.begin()) {
Serial.println("Could not initialize SPI device");
while (1)
;
}
// Set up for automode 50Hz. We don't care about selfheating. We want the
// highest possible sampling rate.
auto_bit.write(0); // Don't switch filtermode while auto_mode is on.
fi50hz_bit.write(1); // Set filter to 50Hz mode.
faultR_bit.write(1); // Clear faults.
bias_bit.write(1); // In automode we want to have the bias current always on.
delay(5); // Wait until bias current settles down.
// 10.5 time constants of the input RC network is required.
// 10ms worst case for 10kω reference resistor and a 0.1µF capacitor
// across the RTD inputs. Adafruit Module has 0.1µF and only
// 430/4300ω So here 0.43/4.3ms
auto_bit.write(
1); // Now we can set automode. Automatically starting first conversion.
// Test the READY_PIN
#if (defined(MAX31865_READY_PIN) && (MAX31865_READY_PIN != -1))
int i = 0;
while (digitalRead(MAX31865_READY_PIN) && i++ <= 100) {
delay(1);
}
if (i >= 100) {
Serial.print("ERROR: Max31865 Pin detection does not work. PIN:");
Serial.println(MAX31865_READY_PIN);
}
#else
delay(100);
#endif
// Set ratio range.
// Setting the temperatures would need some more calculation - not related to
// Adafruit_BusIO_RegisterBits.
uint16_t ratio = rRatio_bits.read();
maxRratio_bits.write((ratio < 0x8fffu - 1000u) ? ratio + 1000u : 0x8fffu);
minRratio_bits.write((ratio > 1000u) ? ratio - 1000u : 0u);
printConfig();
checkFaults();
}
void loop() {
#if (defined(MAX31865_READY_PIN) && (MAX31865_1_READY_PIN != -1))
// Is conversion ready?
if (!digitalRead(MAX31865_READY_PIN))
#else
// Warant conversion is ready.
delay(21); // 21ms for 50Hz-mode. 19ms in 60Hz-mode.
#endif
{
// Read ratio, calculate temperature, scale, filter and print.
Serial.println(rRatio2C(rRatio_bits.read()) * 100.0f,
0); // Temperature scaled by 100
// Check, print, clear faults.
checkFaults();
}
// Do something else.
// delay(15000);
}
// Module/Sensor related. Here Adafruit PT100 module with a 2_Wire PT100 Class C
// *****************************
float rRatio2C(uint16_t ratio) {
// A simple linear conversion.
const float R0 = 100.0f;
const float Rref = 430.0f;
const float alphaPT = 0.003850f;
const float ADCmax = (1u << 15) - 1.0f;
const float rscale = Rref / ADCmax;
// Measured temperature in boiling water 101.08°C with factor a = 1 and b = 0.
// Rref and MAX at about 22±2°C. Measured temperature in ice/water bath 0.76°C
// with factor a = 1 and b = 0. Rref and MAX at about 22±2°C.
// const float a = 1.0f / (alphaPT * R0);
const float a = (100.0f / 101.08f) / (alphaPT * R0);
// const float b = 0.0f; // 101.08
const float b = -0.76f; // 100.32 > 101.08
return filterRing(((ratio * rscale) - R0) * a + b);
}
// General purpose
// *********************************************************************************************
#define RINGLENGTH 250
float filterRing(float newVal) {
static float ring[RINGLENGTH] = {0.0};
static uint8_t ringIndex = 0;
static bool ringFull = false;
if (ringIndex == RINGLENGTH) {
ringFull = true;
ringIndex = 0;
}
ring[ringIndex] = newVal;
uint8_t loopEnd = (ringFull) ? RINGLENGTH : ringIndex + 1;
float ringSum = 0.0f;
for (uint8_t i = 0; i < loopEnd; i++)
ringSum += ring[i];
ringIndex++;
return ringSum / loopEnd;
}

View File

@@ -0,0 +1,40 @@
#include <Adafruit_BusIO_Register.h>
#include <Adafruit_SPIDevice.h>
#define SPIDEVICE_CS 10
Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS);
void setup() {
while (!Serial) {
delay(10);
}
Serial.begin(115200);
Serial.println("SPI device register test");
if (!spi_dev.begin()) {
Serial.println("Could not initialize SPI device");
while (1)
;
}
Adafruit_BusIO_Register id_reg =
Adafruit_BusIO_Register(&spi_dev, 0x0F, ADDRBIT8_HIGH_TOREAD);
uint8_t id = 0;
id_reg.read(&id);
Serial.print("ID register = 0x");
Serial.println(id, HEX);
Adafruit_BusIO_Register thresh_reg = Adafruit_BusIO_Register(
&spi_dev, 0x0C, ADDRBIT8_HIGH_TOREAD, 2, LSBFIRST);
uint16_t thresh = 0;
thresh_reg.read(&thresh);
Serial.print("Initial threshold register = 0x");
Serial.println(thresh, HEX);
thresh_reg.write(~thresh);
Serial.print("Post threshold register = 0x");
Serial.println(thresh_reg.read(), HEX);
}
void loop() {}

View File

@@ -0,0 +1,9 @@
name=Adafruit BusIO
version=1.17.4
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
sentence=This is a library for abstracting away UART, I2C and SPI interfacing
paragraph=This is a library for abstracting away UART, I2C and SPI interfacing
category=Signal Input/Output
url=https://github.com/adafruit/Adafruit_BusIO
architectures=*

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
lib/Archiwum/LCD-I2C.zip Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

13
lib/ArduinoThread/.gitignore vendored Normal file
View File

@@ -0,0 +1,13 @@
# Compiled Object files
*.slo
*.lo
*.o
# Compiled Dynamic libraries
*.so
*.dylib
# Compiled Static libraries
*.lai
*.la
*.a

1
lib/ArduinoThread/.piopm Normal file
View File

@@ -0,0 +1 @@
{"type": "library", "name": "ArduinoThread", "version": "2.1.1", "spec": {"owner": "ivanseidel", "id": 7097, "name": "ArduinoThread", "requirements": null, "uri": null}}

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Ivan Seidel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

205
lib/ArduinoThread/README.md Normal file
View File

@@ -0,0 +1,205 @@
![ArduinoThread Logo](https://raw.githubusercontent.com/ivanseidel/ArduinoThread/master/extras/ArduinoThread.png)
Arduino does not support "REAL" parallel tasks (aka Threads), but we can make use of this Library to
improve our code, and easily schedule tasks with fixed (or variable) time between runs.
This Library helps to maintain organized and to facilitate the use of multiple tasks. We can
use Timers Interrupts, and make it really powerfull, running "pseudo-background" tasks under the rug.
For example, I personaly use it for all my projects, and put all sensor aquisition and
filtering inside it, leaving the main loop, just for logic and "cool" part.
#### ArduinoThreads is a library for managing the periodic execution of multiple tasks.
Blinking an LED is often the very first thing an Arduino user learns. And this demonstrates that periodically performing one single task, like toggling the LED state, is really easy. However, one may quickly discover that managing multiple periodic tasks is not so simple if the tasks have different execution periods.
ArduinoThreads is designed to simplify programs that need to perform multiple periodic tasks. The user defines a Thread object for each of those tasks, then lets the library manage their scheduled execution.
It should be noted that these are not “threads” in the real computer-science meaning of the term: tasks are implemented as functions that are periodically run to completion. On the one hand, this means that the only way a task can “yield” the CPU is by returning to the caller, and it is thus inadvisable to delay() or do long waits inside a task. On the other hand, this makes ArduinoThreads memory friendly, as no stack needs to be allocated per task.
## Installation
1. "Download":https://github.com/ivanseidel/ArduinoThread/archive/master.zip the Master branch from gitHub.
2. Unzip and modify the Folder name to "ArduinoThread" (Remove the '-master')
3. Paste the modified folder on your Library folder (On your `Libraries` folder inside Sketchbooks or Arduino software).
4. Restart Arduino IDE
**If you are here, because another Library requires this class, just don't waste time reading bellow. Install and ready.**
## Getting Started
There are many examples showing many ways to use it. Here, we will explain Class itself,
what it does and "how" it does.
There are basicaly, three Classes included in this Library:
`Thread`, `ThreadController` and `StaticThreadController` (both controllers inherit from Thread).
- `Thread class`: This is the basic class, witch contains methods to set and run callbacks,
check if the Thread should be runned, and also creates a unique ThreadID on the instantiation.
- `ThreadController class`: Responsable for "holding" multiple Threads. Can also be called
as "a group of Threads", and is used to perform run in every Thread ONLY when needed.
- `StaticThreadController class`: Slighly faster and smaller version of `ThreadController`.
It works similar to `ThreadController`, but once constructed it can't add or remove threads to run.
* The instantiation of a Thread class is very simple:
```c++
Thread myThread = Thread();
// or, if initializing a pointer
Thread* myThread = new Thread();
```
* Setting up a thread is essential. You can configure many things:
```c++
myThread.enabled = true; // Default enabled value is true
myThread.setInterval(10); // Setts the wanted interval to be 10ms
/*
This is useful for debugging
(Thread Name is disabled by default, to use less memory)
(Enable it by definint USE_THREAD_NAMES on 'Thread.h')
*/
myThread.ThreadName = "myThread tag";
// This will set the callback of the Thread: "What should I run"?
myThread.onRun(callback_function); // callback_function is the name of the function
```
Ok, creating Threads are not so hard. But what do we do with them now?
* First, let's see how Threads should work, to understand what a `ThreadController` is and does
```c++
// First check if our Thread "should" be runned
if(myThread.shouldRun()){
// Yes, the Thread should be runned, let's run it
myThread.run();
}
```
Now that you got the idea, let's think a little bit: What if i have 3, 5, 100 Threads. Do I need to check EACH one?!?
* The answer is: NO. Create a `ThreadController` or `StaticThreadController`,
and put all your boring-complex Threads inside it!
```c++
// Instantiate a new ThreadController
ThreadController controller = ThreadController();
// Now, put a bunch of Threads inside it, FEED it!
controller.add(&myThread); // Notice the & before the thread, IF it's not instantied as a pointer.
controller.add(&hisThread);
controller.add(&sensorReadings);
...
```
or
```c++
// Instantiate a new StaticThreadController with the number of threads to be supplied as template parameter
StaticThreadController<3> controller (&myThread, &hisThread, &sensorReadings);
// You don't need to do anything else, controller now contains all the threads.
...
```
* You have created, configured, grouped it. What is missing? Yes, whe should RUN it!
```c++
// call run on a Thread, a ThreadController or a StaticThreadController to run it
controller.run();
```
This will run all the Threads that NEED to be runned.
Congratulations, you have learned the basics of `ArduinoThread`. If you want some TIPS, see bellow.
### TIPs and Warnings
* ThreadController is not a `LinkedList`. It's "MAXIMUM" size (the maximum Threads that it can
store) is defined on ThreadController.h (default is 15)
* !!!! VERY IMPORTANT !!!! When extending `Thread` class and implementing the function
`run()`, always remember to put `runned();` after all, otherwhise the `Thread` will ALWAYS run.
* It's a good idea, to create a Timer interrupt and call a ThreadController.run() there.
That way, you don't need to worry about reading sensors and doing time-sensitive stuff
on your main code (loop). Check `ControllerWithTimer` example.
* Inheriting from `Thread` or even `ThreadController` is always a good idea.
For example, I always create base classes of sensors that extends `Thread`,
so that I can "register" the sensors inside a ThreadController, and forget
about really reading sensors, just getting theirs values within my main code.
Checkout `SensorThread` example.
* Remember that `ThreadController` is in fact, a Thread. If you want to enable
or disable a GROUP of Threads, think about putting all of them inside a ThreadController,
and adding this ThreadController to another ThreadController (YES! One ThreadController
inside another). Check `ControllerInController` example.
* There is a `StaticThreadController` which is better to use when you know exact number of
threads to run. You cannot add or remove threads in runtime, but `StaticThreadController`
doesn't have additional memory overhead to keep all the treads together, doesn't have any
limitations how many threads to store (except of available memory) and also the code may be slighly
more optimized because all the threads always exist and no need to do any runtime checks.
* Check the full example `CustomTimedThread` for a cool application of Threads that runs
for a period, after a button is pressed.
* Running tasks on the Timer interrupts must be tought REALLY carefully
You cannot use "sleep()" inside a interrupt, because it will get into a infinite loop.
Things must do stuff quickly. Waiting too loooong on a interrupt, means waiting too
loooong on the main code (loop)
Things might get "scrambled". Since Timers interrupts actualy "BREAK" your code in half
and start running the interrupt, you might want to call `noInterrupts` and `interrupts`
on places where cannot be interrupted:
```c++
noInterrupts();
// Put the code that CANNOT be interrupted...
interrupts(); // This will enable the interrupts egain. DO NOT FORGET!
```
## Library Reference
### You should know:
- `bool Thread::enabled` - Enables or disables the Thread. (do not stop it from running, but will
return false when shouldRun() is called)
- `void Thread::setInterval()` - Setts the desired interval for the Thread (in Ms).
- `bool Thread::shouldRun()` - Returns true, if the Thread should be runned.
(Basicaly,the logic is: (reached time AND is enabled?).
- `void Thread::onRun(<function>)` - The target callback function to be called.
- `void Thread::run()` - This will run the Thread (call the callback function).
- `int Thread::ThreadID` - Theoretically, it's the address of memory. It's unique, and can
be used to compare if two threads are identical.
- `int Thread::ThreadName` - A human-redable thread name. Default is "Thread ThreadID"
eg.: "Thread 141515"; Note that to enable this attribute, you must uncomment the line that disables it on 'Thread.h';
- protected: `void Thread::runned()` - Used to reset internal timer of the Thread.
This is automaticaly called AFTER a call to `run()`.
- `void ThreadController::run()` - This will run the all `Threads` within the `ThreadController`,
only if needed (if shouldRun returns true);
- `bool ThreadController::add(Thread* _thread)` - This will add a the thread to the ThreadController,
and return `true` if suceeded (it the array is full, returns false).
- `void ThreadController::remove(Thread* _thread)` - This will remove the Thread from the ThreadController.
- `void ThreadController::remove(int index)` - This will remove the thread on the position `index`.
- `void ThreadController::clear()` - This will remove ALL threads from the ThreadController array.
- `int ThreadController::size(bool cached = true)` - Returns how many Threads are allocated
inside the ThreadController. If cached is `false`, will force the calculation of threads.
- `Thread* ThreadController::get(int index)` - Returns the Thread on the position `index`.
- `void StaticThreadController::run()` - This will run the all `Threads` within the `StaicThreadController`,
only if needed (if shouldRun returns true);
- `int StaticThreadController::size()` - Returns how many Threads are allocated inside the StaticThreadController.
- `Thread* ThreadController::get(int index)` - Returns the Thread on the position `index` and `nullptr` if `index`
is out of bounds.
### You don't need to know:
- Nothing, yet ;)

View File

@@ -0,0 +1,75 @@
/*
StaticThreadController.h - Controlls a list of Threads with different timings
Basicaly, what it does is to keep track of current Threads and run when
necessary.
StaticThreadController is an extended class of Thread, because of that,
it allows you to add a StaticThreadController inside another kind of ThreadController...
It works exact as ThreadController except you can't add or remove treads dynamically.
Created by Alex Eremin, September, 2016.
Released into the public domain.
*/
#ifndef StaticThreadController_h
#define StaticThreadController_h
#include "Thread.h"
template <int N>
class StaticThreadController: public Thread{
protected:
//since this is a static controller, the pointers themselves can be const
//it should be distinguished from 'const Thread* thread[N]'
Thread * const thread[N];
public:
template <typename... T>
StaticThreadController(T... params) :
Thread(),
thread{params...}
{
#ifdef USE_THREAD_NAMES
// Overrides name
ThreadName = "StaticThreadController ";
ThreadName = ThreadName + ThreadID;
#endif
};
// run() Method is overrided
void run() override
{
// Run this thread before
if(_onRun != nullptr && shouldRun())
_onRun();
for(int i = 0; i < N; i++){
// Is enabled? Timeout exceeded?
if(thread[i]->shouldRun()){
thread[i]->run();
}
}
// StaticThreadController extends Thread, so we should flag as runned thread
runned();
}
// Return the quantity of Threads
static constexpr int size() { return N; };
// Return the I Thread on the array
// Returns nullptr if index is out of bounds
Thread* get(int index) {
return (index >= 0 && index < N) ? thread[index] : nullptr;
};
// Return the I Thread on the array
// Doesn't perform any bounds checks and behaviour is
// unpredictable in case of index > N
Thread& operator[](int index) {
return *thread[index];
};
};
#endif

View File

@@ -0,0 +1,52 @@
#include "Thread.h"
Thread::Thread(void (*callback)(void), unsigned long _interval){
enabled = true;
onRun(callback);
_cached_next_run = 0;
last_run = millis();
ThreadID = (int)this;
#ifdef USE_THREAD_NAMES
ThreadName = "Thread ";
ThreadName = ThreadName + ThreadID;
#endif
setInterval(_interval);
};
void Thread::runned(unsigned long time){
// Saves last_run
last_run = time;
// Cache next run
_cached_next_run = last_run + interval;
}
void Thread::setInterval(unsigned long _interval){
// Save interval
interval = _interval;
// Cache the next run based on the last_run
_cached_next_run = last_run + interval;
}
bool Thread::shouldRun(unsigned long time){
// If the "sign" bit is set the signed difference would be negative
bool time_remaining = (time - _cached_next_run) & 0x80000000;
// Exceeded the time limit, AND is enabled? Then should run...
return !time_remaining && enabled;
}
void Thread::onRun(void (*callback)(void)){
_onRun = callback;
}
void Thread::run(){
if(_onRun != NULL)
_onRun();
// Update last_run and _cached_next_run
runned();
}

View File

@@ -0,0 +1,89 @@
/*
Thread.h - An runnable object
Thread is responsable for holding the "action" for something,
also, it responds if it "should" or "should not" run, based on
the current time;
For instructions, go to https://github.com/ivanseidel/ArduinoThread
Created by Ivan Seidel Gomes, March, 2013.
Released into the public domain.
*/
#ifndef Thread_h
#define Thread_h
#if defined(ARDUINO) && ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#include <inttypes.h>
/*
Uncomment this line to enable ThreadName Strings.
It might be usefull if you are loging thread with Serial,
or displaying a list of threads...
*/
// #define USE_THREAD_NAMES 1
class Thread{
protected:
// Desired interval between runs
unsigned long interval;
// Last runned time in Ms
unsigned long last_run;
// Scheduled run in Ms (MUST BE CACHED)
unsigned long _cached_next_run;
/*
IMPORTANT! Run after all calls to run()
Updates last_run and cache next run.
NOTE: This MUST be called if extending
this class and implementing run() method
*/
void runned(unsigned long time);
// Default is to mark it runned "now"
void runned() { runned(millis()); }
// Callback for run() if not implemented
void (*_onRun)(void);
public:
// If the current Thread is enabled or not
bool enabled;
// ID of the Thread (initialized from memory adr.)
int ThreadID;
#ifdef USE_THREAD_NAMES
// Thread Name (used for better UI).
String ThreadName;
#endif
Thread(void (*callback)(void) = NULL, unsigned long _interval = 0);
// Set the desired interval for calls, and update _cached_next_run
virtual void setInterval(unsigned long _interval);
// Return if the Thread should be runned or not
virtual bool shouldRun(unsigned long time);
// Default is to check whether it should run "now"
bool shouldRun() { return shouldRun(millis()); }
// Callback set
void onRun(void (*callback)(void));
// Runs Thread
virtual void run();
};
#endif

View File

@@ -0,0 +1,115 @@
#include "Thread.h"
#include "ThreadController.h"
ThreadController::ThreadController(unsigned long _interval): Thread(){
cached_size = 0;
clear();
setInterval(_interval);
#ifdef USE_THREAD_NAMES
// Overrides name
ThreadName = "ThreadController ";
ThreadName = ThreadName + ThreadID;
#endif
}
/*
ThreadController run() (cool stuf)
*/
void ThreadController::run(){
// Run this thread before
if(_onRun != NULL)
_onRun();
unsigned long time = millis();
int checks = 0;
for(int i = 0; i < MAX_THREADS && checks <= cached_size; i++){
// Object exists? Is enabled? Timeout exceeded?
if(thread[i]){
checks++;
if(thread[i]->shouldRun(time)){
thread[i]->run();
}
}
}
// ThreadController extends Thread, so we should flag as runned thread
runned();
}
/*
List controller (boring part)
*/
bool ThreadController::add(Thread* _thread){
// Check if the Thread already exists on the array
for(int i = 0; i < MAX_THREADS; i++){
if(thread[i] != NULL && thread[i]->ThreadID == _thread->ThreadID)
return true;
}
// Find an empty slot
for(int i = 0; i < MAX_THREADS; i++){
if(!thread[i]){
// Found a empty slot, now add Thread
thread[i] = _thread;
cached_size++;
return true;
}
}
// Array is full
return false;
}
void ThreadController::remove(int id){
// Find Threads with the id, and removes
bool found = false;
for(int i = 0; i < MAX_THREADS; i++){
if(thread[i]->ThreadID == id){
thread[i] = NULL;
cached_size--;
return;
}
}
}
void ThreadController::remove(Thread* _thread){
remove(_thread->ThreadID);
}
void ThreadController::clear(){
for(int i = 0; i < MAX_THREADS; i++){
thread[i] = NULL;
}
cached_size = 0;
}
int ThreadController::size(bool cached){
if(cached)
return cached_size;
int size = 0;
for(int i = 0; i < MAX_THREADS; i++){
if(thread[i])
size++;
}
cached_size = size;
return cached_size;
}
Thread* ThreadController::get(int index){
int pos = -1;
for(int i = 0; i < MAX_THREADS; i++){
if(thread[i] != NULL){
pos++;
if(pos == index)
return thread[i];
}
}
return NULL;
}

View File

@@ -0,0 +1,53 @@
/*
ThreadController.h - Controlls a list of Threads with different timings
Basicaly, what it does is to keep track of current Threads and run when
necessary.
ThreadController is an extended class of Thread, because of that,
it allows you to add a ThreadController inside another ThreadController...
For instructions, go to https://github.com/ivanseidel/ArduinoThread
Created by Ivan Seidel Gomes, March, 2013.
Released into the public domain.
*/
#ifndef ThreadController_h
#define ThreadController_h
#include "Thread.h"
#include "inttypes.h"
#define MAX_THREADS 15
class ThreadController: public Thread{
protected:
Thread* thread[MAX_THREADS];
int cached_size;
public:
ThreadController(unsigned long _interval = 0);
// run() Method is overrided
void run();
// Adds a thread in the first available slot (remove first)
// Returns if the Thread could be added or not
bool add(Thread* _thread);
// remove the thread (given the Thread* or ThreadID)
void remove(int _id);
void remove(Thread* _thread);
// Removes all threads
void clear();
// Return the quantity of Threads
int size(bool cached = true);
// Return the I Thread on the array
// Returns NULL if none found
Thread* get(int index);
};
#endif

View File

@@ -0,0 +1,78 @@
#include <Thread.h>
#include <ThreadController.h>
int ledPin = 13;
// ThreadController that will controll all threads
ThreadController controll = ThreadController();
//My Thread
Thread myThread = Thread();
//His Thread
Thread hisThread = Thread();
//Blink Led Thread
Thread blinkLedThread = Thread();
//ThreadController, that will be added to controll
ThreadController groupOfThreads = ThreadController();
// callback for myThread
void niceCallback(){
Serial.print("COOL! I'm running on: ");
Serial.println(millis());
}
// callback for hisThread
void boringCallback(){
Serial.println("BORING...");
}
// callback for blinkLedThread
void blinkLed(){
static bool ledStatus = false;
ledStatus = !ledStatus;
digitalWrite(ledPin, ledStatus);
Serial.print("blinking: ");
Serial.println(ledStatus);
}
void setup(){
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
// Configure myThread
myThread.onRun(niceCallback);
myThread.setInterval(500);
// Configure hisThread
hisThread.onRun(boringCallback);
hisThread.setInterval(250);
// Configure blinkLedThread
blinkLedThread.onRun(blinkLed);
blinkLedThread.setInterval(100);
// Adds myThread to the controll
controll.add(&myThread);
// Adds hisThread and blinkLedThread to groupOfThreads
groupOfThreads.add(&hisThread);
groupOfThreads.add(&blinkLedThread);
// Add groupOfThreads to controll
controll.add(&groupOfThreads);
}
void loop(){
// run ThreadController
// this will check every thread inside ThreadController,
// if it should run. If yes, he will run it;
controll.run();
// Rest of code
float h = 3.1415;
h/=2;
}

View File

@@ -0,0 +1,100 @@
#include <Thread.h>
#include <ThreadController.h>
/*
This example, requires a Timer Interrupt Library.
If you are using Arduino NANO, UNO... (with ATmega168/328)
Please go to: http://playground.arduino.cc/code/timer1
If you are using Arduino DUE,
Please go to: https://github.com/ivanseidel/DueTimer
Include the library corresponding to your Arduino.
*/
// #include <DueTimer.h>
// #include <TimerOne.h>
// ThreadController that will controll all threads
ThreadController controll = ThreadController();
//My Thread
Thread myThread = Thread();
//His Thread
Thread hisThread = Thread();
// callback for myThread
void myThreadCallback(){
Serial.println("myThread\t\tcallback");
}
// callback for hisThread
void hisThreadCallback(){
Serial.println("\thisThread\tcallback");
}
// This is the callback for the Timer
void timerCallback(){
controll.run();
}
void setup(){
Serial.begin(9600);
// Configure myThread
myThread.onRun(myThreadCallback);
myThread.setInterval(500);
// Configure myThread
hisThread.onRun(hisThreadCallback);
hisThread.setInterval(200);
// Adds both threads to the controller
controll.add(&myThread); // & to pass the pointer to it
controll.add(&hisThread);
/*
If using DueTimer...
*/
// Timer1.attachInterrupt(timerCallback).start(20000);
/*
If using TimerOne...
*/
// Timer1.initialize(20000);
// Timer1.attachInterrupt(timerCallback);
// Timer1.start();
}
void waitSerial(){
while (!Serial.available());
delay(10);
while (Serial.available() && Serial.read());
}
void loop(){
while(1){
noInterrupts(); // Call to disable interrupts
Serial.println("Type anyting to stop myThread!");
interrupts(); // Call to enable interrupts
waitSerial();
myThread.enabled = false;
noInterrupts();
Serial.println("Type anyting to stop hisThread!");
interrupts();
waitSerial();
hisThread.enabled = false;
noInterrupts();
Serial.println("Type anyting to enable myThread!");
interrupts();
waitSerial();
myThread.enabled = true;
noInterrupts();
Serial.println("Type anyting to enable hisThread!");
interrupts();
waitSerial();
hisThread.enabled = true;
}
}

View File

@@ -0,0 +1,257 @@
/*
This is an example from ArduinoThread. You can find more information
in https://github.com/ivanseidel/ArduinoThread.
Coded by Ivan Seidel, Jun/2014 - ivanseidel@gmail.com
Dont be afraid. 90% is commented lines. READ them, they will teach you.
*/
#include <Thread.h>
#include <ThreadController.h>
/*
This example provides an object-oriented approach to
develop a custom Thread that overrides the 'shouldRun'
method, to only run the thread after a button was pushed.
After the push, it should 'keep' running for a desired time.
It should also provide us, a way to easily implement this
controll multiple times, without trouble.
We are giving this Custom Thread the name 'ButtonThread'.
Exemplifying what it does:
+ ButtonThread added to our mainController ThreadList
=> Instantiated with a custom Pin #,
=> and a time duration (in miliseconds)
+ ButtonThread is not running.
+ When the button is pressed:
+ Thread will start and keep running.
+ If the thread runned for our defined period,
we stop it.
================ HOW TO SETUP HARDWARE ==================
In order to make this example work with any arduino, hook up
the pins on the board to 3 buttons. You can change the inputs
if you need below here.
The Buttons are being SOFTWARE pulled UP (to VCC), and when
pushed, should go LOW. Connect like this:
(Arduino Input) <----> (Btn) <----> GND (-)
We are using digital pins 9, 10 and 11 as input.
It also uses a LED, but we are using the default one in the board.
=============== WHAT YO LEARN WITH THIS =================
1) Threads are actually running in 'parallel'.
Synce each thread process time is very tiny, they appear
as being runned in parallel.
Because of that, clicking multiple buttons at any time,
will looks like there is a program for each one of them.
2) If you keep the button 'pressed', it will continue to run.
Since we are 'enabling' the thread, and reseting the timer
flag (_lastButtonPushed) every time the button is pressed,
we should notice that in btn1Callback, where we print this
flag, it will never go beyond 0 if we keep pressing it.
3) The LED turns off, only because the Thread runs a last time
with the flag 'enabled' as false. This way, we can turn the
LED off and remain OFF until we press it egain.
I hope you enjoy, and learn some advanced-cool stuf with this tutorial.
Any feedback is apreciated!
*/
#define BTN1 9
#define BTN2 10
#define BTN3 11
#define LED 13
// ThreadController that will controll all button threads
ThreadController controll = ThreadController();
// Here we implement our custom ButtonThread, that Inherits from Thread
class ButtonThread: public Thread{
public:
// Our custom thread attributes
int pin;
long duration;
long _lastButtonPushed;
/*
Our Constructor. This will initialize the thread
with it's corresponding pin and duration after clicked.
*/
ButtonThread(int _pin, long _duration): Thread(){
// Set our attributes on construct
pin = _pin;
duration = _duration;
_lastButtonPushed = 0;
// Thread will start disabled
enabled = false;
// Configure the pin as INPUT and enable pull-up
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
}
/*
Override the method responsible for
checking if the thread should run.
It will first check if the button is pressed.
If so, we enable the thread, and then let the
"Old" default Thread method 'shouldRun' return if
it should run.
*/
bool shouldRun(long time){
// Override enabled on thread when pin goes LOW.
if(digitalRead(pin) == LOW){
enabled = true;
/*
Here, we save the current time in this object,
to compare it later.
the 'time' parameter in this method, is an override for the
'millis()' method. It allows who is checking the thread, to
pass a custom time.
This is sintax for writing an 'inline' if is very usefull,
it's the same as:
if(time > 0){
_lastButtonPushed = time;
}else{
_lastButtonPushed = millis();
}
*/
_lastButtonPushed = (time ? time : millis());
}
// Let default method check for it.
return Thread::shouldRun(time);
}
/*
We 'disable' the thread after the duration on the
'run' method.
What we should do here, is check if the time saved
in the _lastButtonPushed variable plus the duration,
is greater than our current time. If that's true, it
means we exceeded the thread time, and that we must
disable it and prevent from running.
*/
void run(){
// Check if time elapsed since last button push
if(millis() > _lastButtonPushed + duration){
// It exceeded time. We should disable it.
enabled = false;
}
/*
Run the thread.
Note that this method will only get called
from the ThreadList, IF the 'shouldRun' returns true.
If the thread is not enabled anymore, it will run a 'last'
time with the flag 'enabled' as false, meaning it's the last
run in the period. You can use it for doing something only
before it stops running.
*/
Thread::run();
}
};
/*
ButtonThreads objects instantiation
(we are instantiating 2 as a member, and one
as pointer in the setup, just to show you
different ways of doing it)
*/
// Thread 1 will be reading BTN1 pin, and will run for 3 secs
ButtonThread btn1Thread(BTN1, 3000);
// Thread 2 will be reading BTN1 pin, and will run for 5 secs
ButtonThread btn2Thread = ButtonThread(BTN2, 5000);
// Thread 3 will be instantiated in the setup()
ButtonThread *btn3Thread;
/*
Callback for ButtonThreads
*/
void btn1Callback(){
// When it's running, this thread will write to the serial.
/*
This math will print 'how long' the thread has been running,
since the button was/is pressed.
After pressing it, it should print as 0, and goes up untill
the thread duration (in this case, +-5000ms).
*/
Serial.print("BTN 1 Thread: ");
Serial.println(millis() - btn1Thread._lastButtonPushed);
}
void btn2Callback(){
/*
This thread will remain with the LED on pin 13 turned on
while it is running.
We detect that this method is called for the LAST time, if
the flag 'enabled' is FALSE on the btn2Thread object.
So, basically: If it's TRUE, we should turn ON the led, if not
we should turn OFF. We can simplify that into one line.
(Same 'inline' sintax as above)
*/
digitalWrite(LED, btn2Thread.enabled ? HIGH : LOW);
}
void btn3Callback(){
// When it's running, this thread will also write to the serial
Serial.println("BTN 3 Thread");
}
void setup(){
// Configure serial and output pins
Serial.begin(9600);
pinMode(LED, OUTPUT);
// Configure btn1Thread callback
// (During the 'enabled' time, it will run every 100ms, aka Interval)
btn1Thread.onRun(btn1Callback);
btn1Thread.setInterval(100);
// Configure btn2Thread callback and interval
btn2Thread.onRun(btn2Callback);
btn2Thread.setInterval(200);
// Instantiate btn3Thread
btn3Thread = new ButtonThread(BTN3, 4000);
// Configure btn3Thread callback and interval
btn3Thread->onRun(btn3Callback);
btn3Thread->setInterval(100);
// Adds all threads to the controller
controll.add(&btn1Thread); // & to pass the pointer to it
controll.add(&btn2Thread);
controll.add(btn3Thread); // Its already a pointer, no need for &
}
void loop(){
// Here we just run the main thread controller
controll.run();
}

View File

@@ -0,0 +1,105 @@
#include "Thread.h"
#include "ThreadController.h"
/*
This is a more "complex" for of using Threads.
You can also inherit from Thread, and do your entire code on the class.
This allows you, to create for example:
Sensor Readings (aquire, filter, and save localy values)
Custom Blinks, Beeps...
Anything you can imagine.
Threads are more "usefull" when used within Timer interrupts
This way of coding is more "reusable", and "correct" (Object Oriented)
*/
/*
This example, requires a Timer Interrupt Library.
If you are using Arduino NANO, UNO... (with ATmega168/328)
Please go to: http://playground.arduino.cc/code/timer1
If you are using Arduino DUE,
Please go to: https://github.com/ivanseidel/DueTimer
Include the library corresponding to your Arduino.
*/
#include <DueTimer.h>
// #include <TimerOne.h>
// Create a new Class, called SensorThread, that inherits from Thread
class SensorThread: public Thread
{
public:
int value;
int pin;
// No, "run" cannot be anything...
// Because Thread uses the method "run" to run threads,
// we MUST overload this method here. using anything other
// than "run" will not work properly...
void run(){
// Reads the analog pin, and saves it localy
value = map(analogRead(pin), 0,1023,0,255);
runned();
}
};
// Now, let's use our new class of Thread
SensorThread analog1 = SensorThread();
SensorThread analog2 = SensorThread();
// Instantiate a new ThreadController
ThreadController controller = ThreadController();
// This is the callback for the Timer
void timerCallback(){
controller.run();
}
void setup(){
Serial.begin(9600);
// Configures Thread analog1
analog1.pin = A1;
analog1.setInterval(100);
// Configures Thread analog2
analog2.pin = A2;
analog2.setInterval(100);
// Add the Threads to our ThreadController
controller.add(&analog1);
controller.add(&analog2);
/*
If using DueTimer...
*/
Timer1.attachInterrupt(timerCallback).start(10000);
/*
If using TimerOne...
*/
// Timer1.initialize(20000);
// Timer1.attachInterrupt(timerCallback);
// Timer1.start();
}
void loop(){
// Do complex-crazy-timeconsuming-tasks here
delay(1000);
// Get the fresh readings
Serial.print("Analog1 Thread: ");
Serial.println(analog1.value);
Serial.print("Analog2 Thread: ");
Serial.println(analog2.value);
// Do more complex-crazy-timeconsuming-tasks here
delay(1000);
}

View File

@@ -0,0 +1,35 @@
#include <Thread.h>
int ledPin = 13;
//My simple Thread
Thread myThread = Thread();
// callback for myThread
void niceCallback(){
static bool ledStatus = false;
ledStatus = !ledStatus;
digitalWrite(ledPin, ledStatus);
Serial.print("COOL! I'm running on: ");
Serial.println(millis());
}
void setup(){
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
myThread.onRun(niceCallback);
myThread.setInterval(500);
}
void loop(){
// checks if thread should run
if(myThread.shouldRun())
myThread.run();
// Other code...
int x = 0;
x = 1 + 2;
}

View File

@@ -0,0 +1,48 @@
#include <Thread.h>
#include <ThreadController.h>
// ThreadController that will controll all threads
ThreadController controll = ThreadController();
//My Thread (as a pointer)
Thread* myThread = new Thread();
//His Thread (not pointer)
Thread hisThread = Thread();
// callback for myThread
void niceCallback(){
Serial.print("COOL! I'm running on: ");
Serial.println(millis());
}
// callback for hisThread
void boringCallback(){
Serial.println("BORING...");
}
void setup(){
Serial.begin(9600);
// Configure myThread
myThread->onRun(niceCallback);
myThread->setInterval(500);
// Configure myThread
hisThread.onRun(boringCallback);
hisThread.setInterval(250);
// Adds both threads to the controller
controll.add(myThread);
controll.add(&hisThread); // & to pass the pointer to it
}
void loop(){
// run ThreadController
// this will check every thread inside ThreadController,
// if it should run. If yes, he will run it;
controll.run();
// Rest of code
float h = 3.1415;
h/=2;
}

View File

@@ -0,0 +1,56 @@
#include <Thread.h>
#include <StaticThreadController.h>
//My Thread (as a pointer)
Thread* myThread = new Thread();
//His Thread (not pointer)
Thread hisThread = Thread();
// callback for myThread
void niceCallback(){
Serial.print("COOL! I'm running on: ");
Serial.println(millis());
}
// callback for hisThread
void boringCallback(){
Serial.println("BORING...");
}
// callback for theThread
void justCallback(){
Serial.println("executing...");
}
//The Thread (as a pointer) with justCallback initialized
Thread* theThread = new Thread(justCallback);
// StaticThreadController that will controll all threads
// All non-pointers go with '&', but pointers go without '&',
StaticThreadController<3> controll (myThread, &hisThread, theThread);
void setup(){
Serial.begin(9600);
// Configure myThread
myThread->onRun(niceCallback);
myThread->setInterval(500);
// Configure hisThread
hisThread.onRun(boringCallback);
hisThread.setInterval(250);
// Set interval for theThread using StaticThreadController interface
controll[3].setInterval(375);
}
void loop(){
// run StaticThreadController
// this will check every thread inside ThreadController,
// if it should run. If yes, he will run it;
controll.run();
// Rest of code
float h = 3.1415;
h/=2;
}

View File

@@ -0,0 +1,32 @@
#######################################
# Syntax Coloring
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
Thread KEYWORD1
ThreadController KEYWORD1
StaticThreadController KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
runned KEYWORD2
setInterval KEYWORD2
shouldRun KEYWORD2
onRun KEYWORD2
run KEYWORD2
# Specific of ThreadController or StaticThreadController
add KEYWORD2
remove KEYWORD2
clear KEYWORD2
size KEYWORD2
get KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View File

@@ -0,0 +1,13 @@
{
"name": "ArduinoThread",
"keywords": "thread, task",
"description": "A library for managing the periodic execution of multiple tasks",
"repository": {
"type": "git",
"url": "https://github.com/ivanseidel/ArduinoThread.git"
},
"frameworks": "arduino",
//"platforms": "atmelavr", LK 2025
"platforms": "*"
"version": "2.1.1"
}

View File

@@ -0,0 +1,9 @@
name=ArduinoThread
version=2.1.1
author=Ivan Seidel <ivanseidel@gmail.com>
maintainer=Ivan Seidel <ivanseidel@gmail.com>
sentence=A simple way to run Threads on Arduino
paragraph=This Library helps to maintain organized and to facilitate the use of multiple tasks. We can use Timers Interrupts, and make it really powerfull, running "pseudo-background" tasks on the rug.
category=Timing
url=https://github.com/ivanseidel/ArduinoThread
architectures=*

View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015-2016 Libor Gabaj
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,858 @@
<a id="library"></a>
# LiquidCrystal_I2C
It is the reimplementation of the standard Arduino LCD library, configured to work with parallel HD44780 compatible LCDs, and interfaced via a Chinese PCF8574 I2C serial extender.
<a id="credit"></a>
## Credit
The reimplementation has been inspired by and credit goes to:
- Mario H. atmega@xs4all.nl LiquidCrystal_I2C V2.0
- Murray R. Van Luyn vanluynm@iinet.net.au Mods for Chinese I2C converter board
<a id="dependency"></a>
## Dependency
The library class extends the system library *Print* and includes following sytem header files.
- **inttypes.h**: Integer type conversions. This header file includes the exact-width integer definitions and extends them with additional facilities provided by the implementation.
- **Print.h**: Base class that provides *print()* and *println()*.
- **Wire.h**: TWI/I2C library for Arduino & Wiring.
<a id="interface"></a>
## Interface
Some of listed functions come out of Arduino [LCD API 1.0](http://playground.arduino.cc/Code/LCDAPI), some of them are specific for this library. It is possible to use functions from the system library [Print](#dependency), which is extended by the *LiquidCrystal_I2C*.
*) The function is an alias of another (usually previous) one.
##### Initialization
- [LiquidCrystal_I2C()](#LiquidCrystal_I2C)
- [begin()](#begin)
- [init()](#init)
- [clear()](#clear)
- [home()](#home)
##### Printing
- [print()](#print)
- [write()](#write)
##### Display control
- [noDisplay()](#noDisplay)
- *[off()](#noDisplay)
- [display()](#display)
- *[on()](#display)
- [scrollDisplayLeft()](#scrollDisplayLeft)
- [scrollDisplayRight()](#scrollDisplayRight)
- [leftToRight()](#leftToRight)
- [rightToLeft()](#rightToLeft)
- [noAutoscroll()](#noAutoscroll)
- [autoscroll()](#autoscroll)
- [noBacklight()](#noBacklight)
- [backlight()](#backlight)
- *[setBacklight()](#backlight)
##### Cursor manipulation
- [noCursor()](#noCursor)
- *[cursor_off()](#noCursor)
- [cursor()](#cursor)
- *[cursor_on()](#cursor)
- [noBlink()](#noBlink)
- *[blink_off()](#noBlink)
- [blink()](#blink)
- *[blink_on()](#blink)
- [setCursor()](#setCursor)
##### Graphs
- [init_bargraph()](#init_bargraph)
- [draw_horizontal_graph()](#draw_horizontal_graph)
- [draw_vertical_graph()](#draw_vertical_graph)
##### Utilities
- [createChar()](#createChar)
- *[load_custom_character()](#createChar)
- [command()](#command)
<a id="LiquidCrystal_I2C"></a>
## LiquidCrystal_I2C()
#### Description
Constructor of the object controlling an LCD. It defines address of the LCD and its geometry.
- More LCDs can be connected to the same I2C bus if they are hardware configured for different addresses.
- For each of LCDs the separate object has to be created.
- When the display powers up, it is configured as follows:
1. Display clear
1. Function set:
- DL = 1; 8-bit interface data
- N = 0; 1-line display
- F = 0; 5x8 dot character font
1. Display on/off control:
- D = 0; Display off
- C = 0; Cursor off
- B = 0; Blinking off
1. Entry mode set:
- I/D = 1; Increment by 1
- S = 0; No shift
- Note, however, that resetting the Arduino does not reset the LCD, so we cannot assume that it is in that state when a sketch starts (and the constructor is called).
#### Syntax
LiquidCrystal_I2C(uint8_t addr, uint8_t cols, uint8_t rows);
#### Parameters
- **addr**: I2C addres of the LCD predefined by the serial extender.
- *Valid values*: unsigned byte
- *Default value*: none
- *Usual values*:
- **0x3F** for LCDs *2004* with 20 columns and 4 rows.
- **0x27** for LCDs *1602* with 16 columns and 2 rows.
<a id="prm_cols"></a>
- **cols**: Number of characters in a row defined by the hardware construction of the LCD screen.
- *Valid values*: unsigned byte
- *Default value*: none
- *Usual values*: 20, 16, 8
<a id="prm_rows"></a>
- **rows**: Number of rows in the LCD screen defined by the hardware construction of the LCD.
- *Valid values*: unsigned byte
- *Default value*: none
- *Usual values*: 4, 2, 1
#### Returns
- **LCD object**: Object controlling the LCD communicating at defined address.
#### Example
``` cpp
lcd = LiquidCrystal_I2C(0x27, 16, 2);
```
[Back to interface](#interface)
<a id="begin"></a>
## begin()
#### Description
Initialize the LCD with its specific geometry parameters.
#### Syntax
void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
#### Parameters
- **cols**: Number of characters in a row defined by the hardware construction of the LCD screen.
- *Valid values*: unsigned byte
- *Default value*: none
- *Usual values*: 20, 16, 8
- **rows**: Number of rows in the LCD screen defined by the hardware construction of the LCD.
- *Valid values*: unsigned byte
- *Default value*: none
- *Usual values*: 4, 2, 1
- **charsize**: Geometry of the LCD's character defined by a library constant.
- *Valid values*: unsigned byte LCD_5x8DOTS, LCD_5x10DOT
- *Default value*: LCD_5x8DOTS
#### Returns
None
#### See also
[LiquidCrystal_I2C()](#LiquidCrystal_I2C)
[init()](#init)
[Back to interface](#interface)
<a id="init"></a>
## init()
#### Description
Initializes the display with values put to the [constructor](LiquidCrystal_I2C), clears the screen, and puts cursor to the upper left corner of the screen, i.e., to the home position 0,0. It is a wrapper function for function [begin()](#begin) with forgoing initialization of [Wire](#dependecy) library.
#### Syntax
void init();
#### Parameters
None
#### Returns
None
#### See also
[LiquidCrystal_I2C()](#LiquidCrystal_I2C)
[begin()](#begin)
[Back to interface](#interface)
<a id="clear"></a>
## clear()
#### Description
Overloaded function for clearing the entire LCD screen or just a part of a row.
- Using the function without any parameters clears the entire srceen.
- For clearing the entire row use the function just with the first parameter.
- The functions sets the cursor to the start column and row after clearing, i.e., after calling without parameters to the home position (0, 0), or after calling with parameters to the starts of cleared row segment.
#### Syntax
void clear();
void clear(uint8_t rowStart, uint8_t colStart = 0, uint8_t colCnt = 255);
#### Parameters
- **rowStart**: Number of a row to be cleared counting from 0.
- *Valid values*: unsigned byte 0 to [rows - 1](#prm_rows) of the [constructor](#LiquidCrystal_I2C)
- *Default value*: none
- **colStart**: Order number of the first character in a cleared row counting from 0, which the cleared segment starts from.
- *Valid values*: unsigned byte 0 to [cols - 1](#prm_cols) of the [constructor](#LiquidCrystal_I2C)
- *Default value*: 0 (start of a row)
- **colCnt**: Number of cleared characters in a cleard row.
- *Valid values*: unsigned byte 0 to [cols](#prm_cols) of the [constructor](#LiquidCrystal_I2C)
- *Default value*: 255, but internally limited to (*cols* - *colStart*)
#### Returns
None
#### See also
[LiquidCrystal_I2C()](#LiquidCrystal_I2C)
[Back to interface](#interface)
<a id="home"></a>
## home()
#### Description
Places the cursor to the home position (0, 0) and leaves displayed characters.
#### Syntax
void init();
#### Parameters
None
#### Returns
None
#### See also
[LiquidCrystal_I2C()](#LiquidCrystal_I2C)
[clear()](#clear)
[Back to interface](#interface)
<a id="print"></a>
## print()
#### Description
Prints text or number to the LCD. It is inhereted function from the parent system one. The function is overloaded and acts according the data type of the input data to be printed.
#### Syntax
byte print(char|byte|int|long|string data, int base);
#### Parameters
- **data**: String or number that should be printed on the LCD from current cursor position.
- *Valid values*: arbitrary
- *Default value*: none
- **base**: Optional base in which to print numbers.
- *Valid values*: integer in form of preprocesor constants
- BIN: binary base 2
- DEC: decimal base 10
- OCT: octal base 8
- HEX hexadecimal base 16
- *Default value*: string
#### Returns
- **ProcessBytes**: Number of successfully printed bytes.
#### Example
``` cpp
lcd = LiquidCrystal_I2C(0x27, 16, 2);
void setup()
{
lcd.print("Hello, world!");
lcd.setCursor(0, 1);
lcd.print(128, HEX);
}
void loop() {}
```
>Hello, world!
>80
#### See also
[write()](#write)
[setCursor()](#setCursor)
[LiquidCrystal_I2C()](#LiquidCrystal_I2C)
[Back to interface](#interface)
<a id="write"></a>
## write()
#### Description
Writes a raw value to the display.
#### Syntax
size_t write(uint8_t value);
#### Parameters
- **value**: Value that should be write to the LCD at address set before.
- *Valid values*: unsigned byte
- *Default value*: none
#### Returns
- **ProcessBytes**: Number of successfully processed bytes; always 1.
#### See also
[print()](#print)
[command()](#command)
[Back to interface](#interface)
<a id="noDisplay"></a>
## noDisplay()
#### Description
Turns the display off quickly. If the display does not have an option to turn on the display, the function just turns backlight on.
#### Syntax
void noDisplay();
#### Alias
void off();
#### Parameters
None
#### Returns
None
#### See also
[display()](#display)
[Back to interface](#interface)
<a id="display"></a>
## display()
#### Description
Turns the display on quickly. If the display does not have an option to turn off the display, the function just turns backlight off.
#### Syntax
void display();
#### Alias
void on();
#### Parameters
None
#### Returns
None
#### See also
[noDisplay()](#noDisplay)
[Back to interface](#interface)
<a id="scrollDisplayLeft"></a>
## scrollDisplayLeft()
#### Description
Scrolls the display text to the left without changing the RAM. The function scrolls entire 40 character buffer. If you print 40 characters to a row and start scrolling, you get continuous moving banner in a row especially on 1602 LCDs.
#### Syntax
void scrollDisplayLeft();
#### Parameters
None
#### Returns
None
#### See also
[scrollDisplayRight()](#scrollDisplayRight)
[Back to interface](#interface)
<a id="scrollDisplayRight"></a>
## scrollDisplayRight()
#### Description
Scrolls the display text to the right without changing the RAM. The function scrolls entire 40 character buffer. If you print 40 characters to a row and start scrolling, you get continuous moving banner in a row especially on 1602 LCDs.
#### Syntax
void scrollDisplayRight();
#### Parameters
None
#### Returns
None
#### See also
[scrollDisplayLeft()](#scrollDisplayLeft)
[Back to interface](#interface)
<a id="leftToRight"></a>
## leftToRight()
#### Description
Sets the flow of text from left to right as it is normal for Latin languages.
#### Syntax
void leftToRight();
#### Parameters
None
#### Returns
None
#### See also
[rightToLeft()](#rightToLeft)
[Back to interface](#interface)
<a id="rightToLeft"></a>
## rightToLeft()
#### Description
Sets the flow of text from right to left as it is normal for Arabic languages.
#### Syntax
void rightToLeft();
#### Parameters
None
#### Returns
None
#### See also
[leftToRight()](#leftToRight)
[Back to interface](#interface)
<a id="noAutoscroll"></a>
## noAutoscroll()
#### Description
Justifies the text from the cursor to the left.
#### Syntax
void noAutoscroll();
#### Parameters
None
#### Returns
None
#### See also
[autoscroll()](#autoscroll)
[Back to interface](#interface)
<a id="autoscroll"></a>
## autoscroll()
#### Description
Justifies the text from the cursor to the right.
#### Syntax
void autoscroll();
#### Parameters
None
#### Returns
None
#### See also
[noAutoscroll()](#noAutoscroll)
[Back to interface](#interface)
<a id="noBacklight"></a>
## noBacklight()
#### Description
Turns the backlight off.
#### Syntax
void noBacklight();
#### Alias
void setBacklight(0);
#### Parameters
None
#### Returns
None
#### See also
[backlight()](#backlight)
[Back to interface](#interface)
<a id="backlight"></a>
## backlight()
#### Description
Turns the backlight on.
#### Syntax
void backlight();
#### Alias
void setBacklight(1);
#### Parameters
None
#### Returns
None
#### See also
[noBacklight()](#noBacklight)
[Back to interface](#interface)
<a id="noCursor"></a>
## noCursor()
#### Description
Turns the block cursor off.
#### Syntax
void noCursor();
#### Alias
void cursor_off();
#### Parameters
None
#### Returns
None
#### See also
[cursor()](#cursor)
[Back to interface](#interface)
<a id="cursor"></a>
## cursor()
#### Description
Turns the block cursor on.
#### Syntax
void cursor();
#### Alias
void cursor_on();
#### Parameters
None
#### Returns
None
#### See also
[noCursor()](#noCursor)
[Back to interface](#interface)
<a id="noBlink"></a>
## noBlink()
#### Description
Turns on the blinking underline cursor.
#### Syntax
void noBlink();
#### Alias
void blink_off();
#### Parameters
None
#### Returns
None
#### See also
[blink()](#blink)
[Back to interface](#interface)
<a id="blink"></a>
## blink()
#### Description
Turns off the blinking underline cursor.
#### Syntax
void blink();
#### Alias
void blink_on();
#### Parameters
None
#### Returns
None
#### See also
[noBlink()](#noBlink)
[Back to interface](#interface)
<a id="setCursor"></a>
## setCursor()
#### Description
Fills the first 8 character generator RAM (CGRAM) locations with custom characters.
#### Syntax
void setCursor(uint8_t col, uint8_t row);
#### Parameters
- **col**: Number of a column where the cursor will be located counting from 0.
- *Valid values*: unsigned byte 0 to [cols - 1](#prm_cols) of the [constructor](#LiquidCrystal_I2C)
- *Default value*: none
- **row**: Number of a row where the cursor will be located counting from 0.
- *Valid values*: unsigned byte 0 to [rows - 1](#prm_rows) of the [constructor](#LiquidCrystal_I2C)
- *Default value*: none
#### Returns
None
#### See also
[home()](#home)
[Back to interface](#interface)
<a id="init_bargraph"></a>
## init_bargraph()
#### Description
Initializes particular bar graph. The function creates a set of custom
characters for displaying bar graphs. Some number of first current custom
characters (5 or 8) will be overwritten according to the type of graph.
#### Syntax
uint8_t init_bargraph(uint8_t graphtype);
#### Parameters
- **graphtype**: Type of a graph.
- *Valid values*: unsigned integer
- LCDI2C_VERTICAL_BAR_GRAPH - rewrites all 8 custom characters
- LCDI2C_HORIZONTAL_BAR_GRAPH - rewrites first 5 custom characters
- LCDI2C_HORIZONTAL_LINE_GRAPH - rewrites first 5 custom characters
- *Default value*: none
#### Returns
- **ResultCode**: Numeric code determining processing of the initialization.
- 0: success
- 1: failure, e.g., not recognized graph type
#### See also
[draw_horizontal_graph()](#draw_horizontal_graph)
[draw_vertical_graph()](#draw_vertical_graph)
[Back to interface](#interface)
<a id="draw_horizontal_graph"></a>
## draw_horizontal_graph()
#### Description
Displays horizontal graph from desired cursor position with input value.
- The bar graph is composed of solid, full rectangle characters eventually except final character with reduced vertical pipes. Value of the bar graph is displayed as equivalent number of pipes in the graph segment.
- The line graph is composed of one pipe running across a LCD row. Value
of the bar graph is displayed as a pipe at equivalent dot position in the graph segment.
- The function is overloaded by data type of a displayed graph value, which
determines its form.
- Zero value of the graph is displayed as the very left pipe in the graph segment due to counting from 0, so that the graph always displays something.
#### Syntax
void draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end);
void draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint16_t percentage);
void draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, float ratio);
#### Parameters
- **row**: Row positon of graph segment counting from 0 to physical number of rows.
- *Valid values*: non-negative integer 0 to [rows - 1](#prm_rows) of the [constructor](#LiquidCrystal_I2C)
- *Default value*: none
- **col**: Column position of graph segment counting from 0 physical number of columns on a row.
- *Valid values*: non-negative integer 0 to [cols - 1](#prm_cols) of the [constructor](#LiquidCrystal_I2C)
- *Default value*: none
- **len**: Length of a graph segment in characters limited to remaining physical columns from starting *col* position.
- *Valid values*: non-negative integer 0 to [cols - col](#prm_cols) of the [constructor](#LiquidCrystal_I2C)
- *Default value*: none
- **pixel_col_end**: Displayed value in pipes (horizontal dots) counting from 0 to number of pipes of the graph segment. A sketch should calculate the number of segment pipes in order to map an application value to displayed value.
- *Valid values*: non-negative integer 0 to 5 * *len*
- *Default value*: none
- **percentage**: Displayed value in percentage of a graph segment length. Accepted value is rounded to integer per cents.
- *Valid values*: non-negative integer 0 to 100
- *Default value*: none
- **ratio**: Displayed value as a fragment of a graph segment length.
- *Valid values*: non-negative decimal 0. to 1.
- *Default value*: none
#### Returns
None
#### See also
[init_bargraph()](#init_bargraph)
[draw_vertical_graph()](#draw_vertical_graph)
[Back to interface](#interface)
<a id="draw_vertical_graph"></a>
## draw_vertical_graph()
#### Description
Displays vertical bar from desired cursor position with input value.
- The bar graph is composed of solid, full rectangle characters eventually except final character with reduced horizontal dashes. Value of the bar graph is displayed as equivalent number of dashes in the graph segment.
- The function is overloaded by data type of a displayed graph value, which
determines its form.
#### Syntax
void draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_row_end);
void draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint16_t percentage);
void draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, float ratio);
#### Parameters
- **row**: Row positon of graph segment counting from 0 to physical limit.
- *Valid values*: non-negative integer 0 to [rows - 1](#prm_rows) of the [constructor](#LiquidCrystal_I2C)
- *Default value*: none
- **col**: Column position of graph segment counting from 0 physical limit.
- *Valid values*: non-negative integer 0 to [cols - 1](#prm_cols) of the [constructor](#LiquidCrystal_I2C)
- *Default value*: none
- **len**: Length of a graph segment in rows limited to remaining physical rows from starting *row* position.
- *Valid values*: non-negative integer 0 to [row + 1](#prm_rows) of the [constructor](#LiquidCrystal_I2C)
- *Default value*: none
- **pixel_col_end**: Displayed value in dashes (vertical dots) counting from 0 to number of dashes of the graph segment. A sketch should calculate the number of segment dashes in order to map an application value to displayed value.
- *Valid values*: non-negative integer 0 to 8 * *len* or 10 * *len*
- *Default value*: none
- **percentage**: Displayed value in percentage of a graph segment length. Accepted value is rounded to integer per cents.
- *Valid values*: non-negative integer 0 to 100
- *Default value*: none
- **ratio**: Displayed value as a fragment of a graph segment length.
- *Valid values*: non-negative decimal 0. to 1.
- *Default value*: none
#### Returns
None
#### See also
[init_bargraph()](#init_bargraph)
[draw_horizontal_graph()](#draw_horizontal_graph)
[Back to interface](#interface)
<a id="createChar"></a>
## createChar()
#### Description
Fills the first 8 character generator RAM (CGRAM) locations with custom characters.
#### Syntax
void createChar(uint8_t, uint8_t[]);
#### Alias
void load_custom_character(uint8_t char_num, uint8_t *rows);
#### Parameters
- **char_num**: Position of a custom character in CGRAM for custom chars.
- *Valid values*: 0 - 7
- *Default value*: none
- **uint8_t[]**: Array of custom characters definitions.
- *Valid values*: Character row byte patterns from the top of the char.
- Array length 8 bytes for 5x8 characters.
- Array length 10 bytes for 5x10 characters.
- *Default value*: none
- **rows**: Pointer to the array of custom characters definitions.
#### Returns
None
#### See also
[init_bargraph()](#init_bargraph)
[Back to interface](#interface)
<a id="command"></a>
## command()
#### Description
Sends a command to the display. It is useful for commands not supported
by the library.
#### Syntax
void command(uint8_t value);
#### Parameters
- **value**: Command code that should be send to the LCD.
- *Valid values*: unsigned byte
- *Default value*: none
#### Returns
None
#### See also
[write()](#write)
[Back to interface](#interface)

View File

@@ -0,0 +1,67 @@
/*
NAME:
Demonstration of Autoscroll function
DESCRIPTION:
This sketch demonstrates the use of the autoscroll() and noAutoscroll()
functions to make new text scroll or not.
* The sketch is intended preferrably for 16x2 LCD, but can be configured
for 20x4 LCDs just by uncommenting and commenting related sections.
* The sketch is just for demonstration purposes, so that it is not
optimized for memory usage.
LICENSE:
This program is free software; you can redistribute it and/or modify
it under the terms of the MIT License (MIT).
CREDENTIALS:
Author: Libor Gabaj
Version: 1.0.0
Updated: 20.03.2016
CREDIT:
The example taken and rewritten for I2C from official Arduino standard library
(https://github.com/arduino/Arduino/tree/master/libraries/LiquidCrystal)
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// LCD address and geometry and library initialization
const byte lcdAddr = 0x27; // Address of I2C backpack
const byte lcdCols = 16; // Number of character in a row
const byte lcdRows = 2; // Number of lines
//const byte lcdAddr = 0x3F; // Address of I2C backpack
//const byte lcdCols = 20; // Number of character in a row
//const byte lcdRows = 4; // Number of lines
LiquidCrystal_I2C lcd(lcdAddr, lcdCols, lcdRows);
// Demo parameters
const byte lcdScrollRow = 0; // Number of a demo row counting from 0
const unsigned int digitDelay = 500; // Miliseconds before displaying next digit
// Function for displaying demo digits
void printDigits() {
for (byte thisChar = 0; thisChar < 10; thisChar++) {
lcd.print(thisChar);
delay(digitDelay);
}
}
void setup() {
lcd.init();
lcd.backlight();
}
void loop() {
lcd.setCursor(0, lcdScrollRow);
printDigits();
// Set the cursor to the last column of the demo row and turn on autoscroll
lcd.setCursor(lcdCols, lcdScrollRow);
lcd.autoscroll();
printDigits();
lcd.noAutoscroll();
lcd.clear();
}

View File

@@ -0,0 +1,162 @@
/*
NAME:
Demo sketch for complete printing test of LCD
DESCRIPTION:
The sketch demonstrates capabalities of the LCD by displaying several
test.
* The sketch is intended preferrably for 16x2 LCD, but can be configured
for 20x4 LCDs just by uncommenting and commenting related sections.
* The sketch is just for demonstration purposes, so that it is not
optimized for memory usage.
LICENSE:
This program is free software; you can redistribute it and/or modify
it under the terms of the MIT License (MIT).
CREDITS:
Inspired by the example LCD_Test in the library LCDi2cW
from "4-2-2009 dale@wentztech.com".
CREDENTIALS:
Author: Libor Gabaj
Version: 1.1.0
Updated: 04.03.2015
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// LCD address and geometry for LCD 1602
const byte lcdAddr = 0x27; // Typical address of I2C backpack for 1602
const byte lcdCols = 16; // Number of characters in a row of display
const byte lcdRows = 2; // Number of lines of display
// LCD address and geometry for LCD 2004
//const byte lcdAddr = 0x3F; // Typical address of I2C backpack for 2004
//const byte lcdCols = 20; // Number of characters in a row of display
//const byte lcdRows = 4; // Number of lines of display
// Initialize library and setting LCD geometry
LiquidCrystal_I2C lcd(lcdAddr, lcdCols, lcdRows);
// Demo constants
const int testDelay = 500; // Delay between tests in ms
const int demoDelay = 3000; // Delay between demos in ms
const byte demoNumMin = 1; // Range of demo tests
const byte demoNumMax = 255;
const byte charNumMin = 0; // Code of first displayed character
const byte charNumMax = 255; // Code of last displayed character
// Demo variables
byte col, row;
unsigned int demoNum, charNum;
char buffer[lcdCols + 1];
void setup() {
// Initialize LCD
lcd.init();
lcd.backlight(); // Switch on the backlight LED, if any or wired
}
void loop()
{
demoNum = max(demoNumMin, 1);
while(demoNum >= demoNumMin && demoNum <= demoNumMax) {
lcd.clear();
lcd.cursor_off();
lcd.blink_off();
sprintf(buffer, "%u.", demoNum);
lcd.print(buffer);
switch (demoNum) {
case 1:
lcd.print(F("Hello World!"));
break;
case 2:
lcd.print(F("Dash Cursor"));
lcd.setCursor(0, 1);
lcd.cursor_on();
break;
case 3:
lcd.print (F("Block Cursor"));
lcd.setCursor(0, 1);
lcd.blink_on();
break;
case 4:
lcd.print(F("No Cursor"));
lcd.setCursor(0, 1);
break;
case 5:
lcd.print(F("Characters"));
lcd.cursor_on();
charNum = charNumMin;
while(charNum <= charNumMax) {
row = 1;
do {
lcd.clear(row);
col = 0;
lcd.setCursor(col, row);
do {
lcd.write(char(charNum++));
delay(testDelay);
} while(++col < lcdCols && charNum <= charNumMax);
} while(++row < lcdRows && charNum <= charNumMax);
}
lcd.cursor_off();
break;
case 6:
for (byte row=0; row < lcdRows; row++) {
lcd.print(F("Line "));
lcd.print(row);
delay(testDelay);
lcd.setCursor(0, row + 1);
}
break;
case 7:
lcd.print(F("Count to 255"));
for (unsigned int i = 0; i < 256; i++) {
lcd.clear(1);
sprintf(buffer, "%03u 0x%02X %c", i, i, i);
lcd.print(buffer);
if (lcdCols >= 20) {
lcd.print(" B");
lcd.print(i, BIN);
}
delay(testDelay);
}
break;
case 8:
lcd.print(F("Positions"));
lcd.setCursor(0, 1);
for (byte col = 0; col < lcdCols; col++) {
lcd.write(col%10 + char('0'));
delay(testDelay);
}
break;
case 9:
lcd.print(F("Clearing"));
for (byte row = 1; row < lcdRows; row++) {
// Fill row
lcd.setCursor(0, row);
for (byte col = 0; col < lcdCols; col++) {
lcd.write(col%10 + char('0'));
}
delay(testDelay);
// Clear row
for (byte i = 0; i < lcdCols / 2; i++) {
lcd.setCursor(lcdCols / 2 - i - 1, row);
lcd.write(' ');
lcd.setCursor(lcdCols / 2 + i, row);
lcd.write(' ');
delay(testDelay);
}
}
break;
default:
demoNum = 0;
continue;
}
delay(demoDelay);
demoNum++;
}
}

View File

@@ -0,0 +1,60 @@
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
uint8_t bell[8] = {0x4,0xe,0xe,0xe,0x1f,0x0,0x4};
uint8_t note[8] = {0x2,0x3,0x2,0xe,0x1e,0xc,0x0};
uint8_t clock[8] = {0x0,0xe,0x15,0x17,0x11,0xe,0x0};
uint8_t heart[8] = {0x0,0xa,0x1f,0x1f,0xe,0x4,0x0};
uint8_t duck[8] = {0x0,0xc,0x1d,0xf,0xf,0x6,0x0};
uint8_t check[8] = {0x0,0x1,0x3,0x16,0x1c,0x8,0x0};
uint8_t cross[8] = {0x0,0x1b,0xe,0x4,0xe,0x1b,0x0};
uint8_t retarrow[8] = { 0x1,0x1,0x5,0x9,0x1f,0x8,0x4};
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
void setup()
{
lcd.init(); // initialize the lcd
lcd.backlight();
lcd.createChar(0, bell);
lcd.createChar(1, note);
lcd.createChar(2, clock);
lcd.createChar(3, heart);
lcd.createChar(4, duck);
lcd.createChar(5, check);
lcd.createChar(6, cross);
lcd.createChar(7, retarrow);
lcd.home();
lcd.print("Hello world...");
lcd.setCursor(0, 1);
lcd.print(" i ");
lcd.write(3);
lcd.print(" arduinos!");
delay(5000);
displayKeyCodes();
}
// display all keycodes
void displayKeyCodes(void) {
uint8_t i = 0;
while (1) {
lcd.clear();
lcd.print("Codes 0x"); lcd.print(i, HEX);
lcd.print("-0x"); lcd.print(i+16, HEX);
lcd.setCursor(0, 1);
for (int j=0; j<16; j++) {
lcd.write(i+j);
}
i+=16;
delay(4000);
}
}
void loop()
{
}

View File

@@ -0,0 +1,17 @@
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 20 chars and 4 line display
void setup()
{
lcd.init(); // initialize the lcd
// Print a message to the LCD.
lcd.backlight();
lcd.print("Hello, world!");
}
void loop()
{
}

View File

@@ -0,0 +1,95 @@
/*
NAME:
Demo sketch for Histogram composed of Vertical Bar Graphs
DESCRIPTION:
The sketch demonstrates usage of LiquidCrystal_I2C library version 2.x
for programing histograms with help of vertical graphs.
* The sketch is intended preferrably for 16x2 LCD, but can be configured
for 20x4 LCDs just by uncommenting and commenting related sections.
* All graph values are displayed in number of vertical pixels.
* The sketch demostrates a histogram
- in second row with one row height
- in full display are with
with values changed randomly.
* The sketch is just for demonstration purposes, so that it is not
optimized for memory usage.
LICENSE:
This program is free software; you can redistribute it and/or modify
it under the terms of the MIT License (MIT).
CREDENTIALS:
Author: Libor Gabaj
Version: 1.0.0
Updated: 01.03.2015
*/
/* Needed libraries
Dispite the LCD library includes Wire library, the ArduinoIDE does not
includes nested libraries, if they are not in the same folder.
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// LCD address and geometry for LCD 1602
const byte lcdAddr = 0x27; // Typical address of I2C backpack for 1602
const byte lcdCols = 16; // Number of characters in a row of display
const byte lcdRows = 2; // Number of lines of display
// LCD address and geometry for LCD 2004
//const byte lcdAddr = 0x3F; // Typical address of I2C backpack for 2004
//const byte lcdCols = 20; // Number of characters in a row of display
//const byte lcdRows = 4; // Number of lines of display
// Initialize library and setting LCD geometry
LiquidCrystal_I2C lcd(lcdAddr, lcdCols, lcdRows);
// Demo constants
const int graphDelay = 100; // Delay between histograms
const int demoTime = 5000; // Showing time of a demo
// Demo variables
byte graphPixelsCur, graphPixelsMax;
unsigned long demoStart;
void setup()
{
// Initialize LCD
lcd.init();
lcd.backlight(); // Switch on the backlight LED, if any or wired
/* Initialize graph
* Macro is defined in LiquidCrystal_I2C library.
* Function uses all 8 custom character positions (0-7)
and creates custom characters for displaying vertical bar.
*/
lcd.init_bargraph(LCDI2C_VERTICAL_BAR_GRAPH);
}
void loop()
{
// Demo 1: One row histogram
lcd.clear();
lcd.print("Histogram");
graphPixelsMax = LCD_CHARACTER_VERTICAL_DOTS;
demoStart = millis();
while(millis() - demoStart < demoTime) {
for(byte graphCol = 0; graphCol < lcdCols; graphCol++) {
graphPixelsCur = random(0, graphPixelsMax);
lcd.draw_vertical_graph(1, graphCol, 1, graphPixelsCur);
}
delay(graphDelay);
}
// Demo 2: Full display histogram
lcd.clear();
graphPixelsMax = lcdRows * LCD_CHARACTER_VERTICAL_DOTS;
demoStart = millis();
while(millis() - demoStart < demoTime) {
for(byte graphCol = 0; graphCol < lcdCols; graphCol++) {
graphPixelsCur = random(0, graphPixelsMax);
lcd.draw_vertical_graph(lcdRows - 1, graphCol, lcdRows, graphPixelsCur);
}
delay(graphDelay);
}
}

View File

@@ -0,0 +1,135 @@
/*
NAME:
Demo sketch for Horizontal Bar Graph
DESCRIPTION:
The sketch demonstrates usage of LiquidCrystal_I2C library version 2.x
for programing horizontal graphs, which mimics progress bar.
* The sketch is intended preferrably for 16x2 LCD, but can be configured
for 20x4 LCDs just by uncommenting and commenting related sections.
* All graph values are displayed in number of horizontal pixels.
* The sketch demostrates
- 1. Continues full row progress bar
- 2. Continues half row central progress bar
- 3. Random full row progress bar
* The sketch is just for demonstration purposes, so that it is not
optimized for memory usage.
LICENSE:
This program is free software; you can redistribute it and/or modify
it under the terms of the MIT License (MIT).
CREDENTIALS:
Author: Libor Gabaj
Version: 1.0.0
Updated: 01.03.2015
*/
/* Needed libraries
Dispite the LCD library includes Wire library, the ArduinoIDE does not
includes nested libraries, if they are not in the same folder.
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// LCD address and geometry for LCD 1602
const byte lcdAddr = 0x27; // Typical address of I2C backpack for 1602
const byte lcdCols = 16; // Number of characters in a row of display
const byte lcdRows = 2; // Number of lines of display
// LCD address and geometry for LCD 2004
//const byte lcdAddr = 0x3F; // Typical address of I2C backpack for 2004
//const byte lcdCols = 20; // Number of characters in a row of display
//const byte lcdRows = 4; // Number of lines of display
// Initialize library and setting LCD geometry
LiquidCrystal_I2C lcd(lcdAddr, lcdCols, lcdRows);
// Cursor coordinates and character row pattern for progress bar
const byte graphRow = 1; // In this row the graph is displayed
const byte labelRow = 0; // In this row the label is displayed
const byte valueCol = lcdCols - 2; // In this column starts graph value
const int graphDelay = 100; // Delay between graph values in ms
const int demoDelay = 3000; // Delay between demos in ms
// Demo parameters
const char graphType[] = " Bar";
const char* graphLbls[] = {"Full", "Half", "Random"};
const byte graphLens[] = {lcdCols, lcdCols / 2, lcdCols};
const byte graphCols[] = {0, lcdCols / 4, 0};
// Demo variables
byte graphPixelsCur, graphPixelsMax;
// Function for displaying graph label
void printLabel(byte demo) {
// Create label
char labelText[valueCol];
sprintf(labelText, "%1u.%s%s", demo + 1, graphLbls[demo], graphType);
// Display label on clear display
lcd.clear();
lcd.setCursor(0, labelRow);
lcd.print(labelText);
}
// Function for displaying graph value
void printValue(byte value) {
lcd.clear(labelRow, valueCol); // Clear value space
lcd.setCursor(valueCol, labelRow);
lcd.print(value);
}
void setup()
{
// Initialize LCD
lcd.init();
lcd.backlight(); // Switch on the backlight LED, if any or wired
/* Initialize graph
* Macro is defined in LiquidCrystal_I2C library.
* Function uses the first 5 custom character positions (0-4)
and creates custom characters for displaying progress bar.
*/
lcd.init_bargraph(LCDI2C_HORIZONTAL_BAR_GRAPH);
}
void loop()
{
for(byte demoNum = 0; demoNum < sizeof(graphLens)/sizeof(graphLens[0]); demoNum++) {
graphPixelsMax = graphLens[demoNum] * LCD_CHARACTER_HORIZONTAL_DOTS;
printLabel(demoNum);
switch (demoNum) {
case 0:
case 1:
// Demo 1: Graph in full row with sequence values
// Demo 2: Graph in half row with sequence values
// Descending graph values
for (byte i = graphPixelsMax; i > 0; i--) {
graphPixelsCur = i - 1;
printValue(graphPixelsCur);
lcd.draw_horizontal_graph(graphRow, graphCols[demoNum], graphLens[demoNum], graphPixelsCur);
delay(graphDelay);
}
// Ascending graph values
for (byte i = 0; i < graphPixelsMax; i++) {
graphPixelsCur = i;
printValue(graphPixelsCur);
lcd.draw_horizontal_graph(graphRow, graphCols[demoNum], graphLens[demoNum], graphPixelsCur);
delay(graphDelay);
}
break;
case 2:
// Demo 3: Graph in full row with random values
for (byte i = 0; i < graphPixelsMax; i++) {
graphPixelsCur = random(0, graphPixelsMax);
printValue(graphPixelsCur);
lcd.draw_horizontal_graph(graphRow, graphCols[demoNum], graphLens[demoNum], graphPixelsCur);
delay(graphDelay);
}
break;
}
delay(demoDelay);
}
}

View File

@@ -0,0 +1,135 @@
/*
NAME:
Demo sketch for Horizontal Line Graph
DESCRIPTION:
The sketch demonstrates usage of LiquidCrystal_I2C library version 2.x
for programing horizontal graphs, which mimics scale graphs.
* The sketch is intended preferrably for 16x2 LCD, but can be configured
for 20x4 LCDs just by uncommenting and commenting related sections.
* All graph values are displayed in number of horizontal pixels.
* The sketch demostrates
- 1. Continues full row scale graph
- 2. Continues half row central scale graph
- 3. Random full row scale graph
* The sketch is just for demonstration purposes, so that it is not
optimized for memory usage.
LICENSE:
This program is free software; you can redistribute it and/or modify
it under the terms of the MIT License (MIT).
CREDENTIALS:
Author: Libor Gabaj
Version: 1.0.0
Updated: 01.03.2015
*/
/* Needed libraries
Dispite the LCD library includes Wire library, the ArduinoIDE does not
includes nested libraries, if they are not in the same folder.
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// LCD address and geometry for LCD 1602
const byte lcdAddr = 0x27; // Typical address of I2C backpack for 1602
const byte lcdCols = 16; // Number of characters in a row of display
const byte lcdRows = 2; // Number of lines of display
// LCD address and geometry for LCD 2004
//const byte lcdAddr = 0x3F; // Typical address of I2C backpack for 2004
//const byte lcdCols = 20; // Number of characters in a row of display
//const byte lcdRows = 4; // Number of lines of display
// Initialize library and setting LCD geometry
LiquidCrystal_I2C lcd(lcdAddr, lcdCols, lcdRows);
// Cursor coordinates and character row pattern for progress bar
const byte graphRow = 1; // In this row the graph is displayed
const byte labelRow = 0; // In this row the label is displayed
const byte valueCol = lcdCols - 2; // In this column starts graph value
const int graphDelay = 200; // Delay between graph values in ms
const int demoDelay = 3000; // Delay between demos in ms
// Demo parameters
const char graphType[] = "Scale";
const char* graphLbls[] = {"Full ", "Half ", "Random"};
const byte graphLens[] = {lcdCols, lcdCols / 2, lcdCols};
const byte graphCols[] = {0, lcdCols / 4, 0};
// Demo variables
byte graphPixelsCur, graphPixelsMax;
// Function for displaying graph label
void printLabel(byte demo) {
// Create label
char labelText[valueCol];
sprintf(labelText, "%1u.%s%s", demo + 1, graphLbls[demo], graphType);
// Display label on clear display
lcd.clear();
lcd.setCursor(0, labelRow);
lcd.print(labelText);
}
// Function for displaying graph value
void printValue(byte value) {
lcd.clear(labelRow, valueCol); // Clear value space
lcd.setCursor(valueCol, labelRow);
lcd.print(value);
}
void setup()
{
// Initialize LCD
lcd.init();
lcd.backlight(); // Switch on the backlight LED, if any or wired
/* Initialize graph
* Macro is defined in LiquidCrystal_I2C library.
* Function uses the first 5 custom character positions (0-4)
and creates custom characters for displaying progress bar.
*/
lcd.init_bargraph(LCDI2C_HORIZONTAL_LINE_GRAPH);
}
void loop()
{
for(byte demoNum = 0; demoNum < sizeof(graphLens)/sizeof(graphLens[0]); demoNum++) {
graphPixelsMax = graphLens[demoNum] * LCD_CHARACTER_HORIZONTAL_DOTS;
printLabel(demoNum);
switch (demoNum) {
case 0:
case 1:
// Demo 1: Graph in full row with sequence values
// Demo 2: Graph in half row with sequence values
// Descending graph values
for (byte i = graphPixelsMax; i > 0; i--) {
graphPixelsCur = i - 1;
printValue(graphPixelsCur);
lcd.draw_horizontal_graph(graphRow, graphCols[demoNum], graphLens[demoNum], graphPixelsCur);
delay(graphDelay);
}
// Ascending graph values
for (byte i = 0; i < graphPixelsMax; i++) {
graphPixelsCur = i;
printValue(graphPixelsCur);
lcd.draw_horizontal_graph(graphRow, graphCols[demoNum], graphLens[demoNum], graphPixelsCur);
delay(graphDelay);
}
break;
case 2:
// Demo 3: Graph in full row with random values
for (byte i = 0; i < graphPixelsMax; i++) {
graphPixelsCur = random(0, graphPixelsMax);
printValue(graphPixelsCur);
lcd.draw_horizontal_graph(graphRow, graphCols[demoNum], graphLens[demoNum], graphPixelsCur);
delay(graphDelay);
}
break;
}
delay(demoDelay);
}
}

View File

@@ -0,0 +1,24 @@
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd1(0x26,16,2); // set the LCD address of the first lcd to 0x26 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd2(0x27,16,2); // set the LCD address of the second lcd to 0x27 for a 16 chars and 2 line display
void setup()
{
lcd1.init(); // initialize the first lcd
lcd2.init(); // initialize the second lcd
// Print a message on the first LCD.
lcd1.backlight();
lcd1.print("Hello, #1 world!");
// Print a message on the second LCD.
lcd2.backlight();
lcd2.print("Hello, #2 world!");
}
void loop()
{
}

View File

@@ -0,0 +1,46 @@
<a id="library"></a>
# LiquidCrystal_I2C
It is the reimplementation of the standard Arduino LCD library, configured to work with parallel HD44780 compatible LCDs, and interfaced via a Chinese PCF8574 I2C serial extender.
<a id="examples"></a>
## Examples
##### Autoscroll
Demonstrates autoscroll function.
##### CompleteTest
Demo sketch for complete printing test of the LCD. The test suit consist of 9 tests each labeled in the first row.
##### CustomChars
Creation of 8 custom characters in form of graphical symbols.
##### HelloWorld
Standard initial example. Use it for checking basic functionality and address of the LCD.
##### Histogram
Demo sketch for several histograms composed of vertical bar graphs. The values for graphs are generated randomly.
1. The first demo histogram is displayed in one row only.
1. The second demo histogram display across all rows of the LCD and uses its entire screen.
##### HorizontalBarGraph
Demo sketch for horizontal bar graphs.
1. The first demo histogram uses full row for continues increasing and decreasing values (breathing graph).
1. The second demo histogram is a breathing graph using just one half of a row.
1. The third demo histogram displays values generated randomly.
##### HorizontalLineGraph
Demo sketch for horizontal line graphs. A value is represented just with a pipe on a row.
1. The first demo histogram uses full row for continues increasing and decreasing values (running graph).
1. The second demo histogram is a running graph using just one half of a row.
1. The third demo histogram displays values generated randomly.
##### MultipleLcd
Using multiple LCD on the same I2C bus but communicating on different addresses.
##### Scroll
Demonstrates scrolling text to the left and right without changing text.
##### SerialDisplay
Sketch receives characters from the serial port and displays them on the LCD one by one.
##### VerticalBarGraph
Demo sketch for vertical bar graph. The graph uses all rows in the last column for continues increasing and decreasing values (breathing graph).

View File

@@ -0,0 +1,71 @@
/*
NAME:
Demonstration scrolling text to the left and right without changing text.
DESCRIPTION:
This sketch demonstrates the use of the scrollDisplayLeft() and
scrollDisplayRight() functions to make new text scroll to the left and right.
* The sketch is intended preferrably for 16x2 LCD, but can be configured
for 20x4 LCDs just by uncommenting and commenting related sections.
* The sketch is just for demonstration purposes, so that it is not
optimized for memory usage.
LICENSE:
This program is free software; you can redistribute it and/or modify
it under the terms of the MIT License (MIT).
CREDENTIALS:
Author: Libor Gabaj
Version: 1.0.0
Updated: 20.03.2016
CREDIT:
The example taken and rewritten for I2C from official Arduino standard library
(https://github.com/arduino/Arduino/tree/master/libraries/LiquidCrystal)
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// LCD address and geometry and library initialization
const byte lcdAddr = 0x27; // Address of I2C backpack
const byte lcdCols = 16; // Number of character in a row
const byte lcdRows = 2; // Number of lines
//const byte lcdAddr = 0x3F; // Address of I2C backpack
//const byte lcdCols = 20; // Number of character in a row
//const byte lcdRows = 4; // Number of lines
LiquidCrystal_I2C lcd(lcdAddr, lcdCols, lcdRows);
// Demo parameters
const char demoText[]= "Hello World!";
const unsigned int scrollDelay = 500; // Miliseconds before scrolling next char
const unsigned int demoDelay = 2000; // Miliseconds between demo loops
byte textLen; // Number of visible characters in the text
void setup() {
textLen = sizeof(demoText) - 1;
lcd.init();
lcd.backlight();
lcd.print(demoText);
delay(demoDelay);
}
void loop() {
// Scroll entire text in a row to the left outside the screen
for (byte positionCounter = 0; positionCounter < textLen; positionCounter++) {
lcd.scrollDisplayLeft();
delay(scrollDelay);
}
// Scroll hidden text through entire row to the right outside the screen
for (byte positionCounter = 0; positionCounter < textLen + lcdCols; positionCounter++) {
lcd.scrollDisplayRight();
delay(scrollDelay);
}
// Scroll text to the right back to original position
for (byte positionCounter = 0; positionCounter < lcdCols; positionCounter++) {
lcd.scrollDisplayLeft();
delay(scrollDelay);
}
delay(demoDelay);
}

View File

@@ -0,0 +1,31 @@
/*
* Displays text sent over the serial port (e.g. from the Serial Monitor) on
* an attached LCD.
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
void setup()
{
lcd.init(); // initialize the lcd
lcd.backlight();
Serial.begin(9600);
}
void loop()
{
// when characters arrive over the serial port...
if (Serial.available()) {
// wait a bit for the entire message to arrive
delay(100);
// clear the screen
lcd.clear();
// read all the available characters
while (Serial.available() > 0) {
// display each character to the LCD
lcd.write(Serial.read());
}
}
}

View File

@@ -0,0 +1,120 @@
/*
NAME:
Demo sketch for Vertical Bar Graph
DESCRIPTION:
The sketch demonstrates usage of LiquidCrystal_I2C library version 2.x
for programing vertical graphs, which mimics histogram.
* The sketch is intended preferrably for 16x2 LCD, but can be configured
for 20x4 LCDs just by uncommenting and commenting related sections.
* All graph values are displayed in number of vertical pixels.
* The sketch demostrates vertical graphs from one row graph to full rows
graph of the display.
* The sketch is just for demonstration purposes, so that it is not
optimized for memory usage.
LICENSE:
This program is free software; you can redistribute it and/or modify
it under the terms of the MIT License (MIT).
CREDENTIALS:
Author: Libor Gabaj
Version: 1.0.0
Updated: 01.03.2015
*/
/* Needed libraries
Dispite the LCD library includes Wire library, the ArduinoIDE does not
includes nested libraries, if they are not in the same folder.
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// LCD address and geometry for LCD 1602
const byte lcdAddr = 0x27; // Typical address of I2C backpack for 1602
const byte lcdCols = 16; // Number of characters in a row of display
const byte lcdRows = 2; // Number of lines of display
// LCD address and geometry for LCD 2004
//const byte lcdAddr = 0x3F; // Typical address of I2C backpack for 2004
//const byte lcdCols = 20; // Number of characters in a row of display
//const byte lcdRows = 4; // Number of lines of display
// Initialize library and setting LCD geometry
LiquidCrystal_I2C lcd(lcdAddr, lcdCols, lcdRows);
// Cursor coordinates and character row pattern for progress bar
const byte graphCol = lcdCols - 1; // In this column the graph is displayed
const int graphDelay = 200; // Delay between graph values in ms
const int demoDelay = 3000; // Delay between demos in ms
// Demo parameters
const char graphType[] = " Col(s) Graph";
// Demo variables
byte graphPixelsCur, graphPixelsMax;
// Function for displaying graph label
void printLabel(byte rows) {
const byte labelCol = 0;
const byte labelRow = 0;
// Create label
char labelText[graphCol];
sprintf(labelText, "%1u%s", rows, graphType);
// Display label on clear display
lcd.clear();
lcd.setCursor(labelCol, labelRow);
lcd.print(labelText);
}
// Function for displaying graph value
void printValue(byte value) {
const byte valueWidth = 2; // Max. digits in value
const byte valueCol = graphCol - valueWidth - 1;
const byte valueRow = 1;
// Create value
char valueFormat[4], valueText[valueWidth + 1];
sprintf(valueFormat, "%%%1uu", valueWidth);
sprintf(valueText, valueFormat, value);
// Display label on clear display
lcd.clear(valueRow, valueCol, valueWidth);
lcd.setCursor(valueCol, valueRow);
lcd.print(valueText);
}
void setup()
{
// Initialize LCD
lcd.init();
lcd.backlight(); // Switch on the backlight LED, if any or wired
/* Initialize graph
* Macro is defined in LiquidCrystal_I2C library.
* Function uses all 8 custom character positions (0-7)
and creates custom characters for displaying vertical bar.
*/
lcd.init_bargraph(LCDI2C_VERTICAL_BAR_GRAPH);
}
void loop()
{
for(byte graphHight = 1; graphHight <= lcdRows; graphHight++) {
graphPixelsMax = graphHight * LCD_CHARACTER_VERTICAL_DOTS;
printLabel(graphHight);
for (byte i = graphPixelsMax; i > 0; i--) {
graphPixelsCur = i - 1;
printValue(graphPixelsCur);
lcd.draw_vertical_graph(graphHight - 1, graphCol, graphHight, graphPixelsCur);
delay(graphDelay);
}
// Ascending graph values
for (byte i = 0; i < graphPixelsMax; i++) {
graphPixelsCur = i;
printValue(graphPixelsCur);
lcd.draw_vertical_graph(graphHight - 1, graphCol, graphHight, graphPixelsCur);
delay(graphDelay);
}
delay(demoDelay);
}
}

View File

@@ -0,0 +1,5 @@
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=http://www.banggood.com/IIC-Or-I2C-Or-TWI-SPI-LCD1602-Character-LCD-Module-For-Arduino-p-88316.html?p=5G0704100426201212C9
IDList=

View File

@@ -0,0 +1,5 @@
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=http://www.banggood.com/IIC-Or-I2C-2004-204-20-X-4-Character-LCD-Display-Module-Blue-p-908616.html?p=5G0704100426201212C9
IDList=

View File

@@ -0,0 +1,5 @@
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=http://www.banggood.com/IIC-Or-I2C-Or-TWI-Or-SP-Serial-Interface-Module-Port-For-5V-Arduino-1602LCD-p-80365.html?p=5G0704100426201212C9
IDList=

View File

@@ -0,0 +1,5 @@
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=http://www.banggood.com/IIC-Or-I2C-2004-204-20-X-4-Character-LCD-Display-Module-Yellow-Green-p-908821.html?p=5G0704100426201212C9
IDList=

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

View File

@@ -0,0 +1,7 @@
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=http://playground.arduino.cc/Code/LCDi2c
IDList=
IconFile=http://playground.arduino.cc/favicon.png
IconIndex=1

View File

@@ -0,0 +1,5 @@
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=http://playground.arduino.cc/Code/LCDAPI
IDList=

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,47 @@
// LiquidCrystal_I2C V2.0 - Mario H. atmega@xs4all.nl
// Mods for Chinese I2C converter board - Murray R. Van Luyn. vanluynm@iinet.net.au
The LiquidCrystal_I2C library is a modified version of the standard LiquidCrystal library as found on
the Arduino website.
This library is intended to be used when a parallel HD44780 compatible LCD is controlled over I2C using
a Chinese PCF8574 extender.
4 of the 8 outputs are used for LCD data lines 4 to 7.
4 outputs are used for the Enable, register-select, Read/Write and backlight control lines.
The Chinese PCF8574 extender is available in two versions, the PCF8574 and the PCF8574A.
The only difference between the two is the I2C base address.
The base address for the PCF8574 is 0x27 and the base address for the PCF8574A is 0x4E.
The examples included in this zip file assume the use of an PCF8574 set for address 0x27
(A0, A1 and A3 un-linked, so pulled high).
For PCF8574 the addressing is:
Jp3 Jp2 Jp1
A2 A1 A0 Dec Hex
L L L 32 0x20
L L H 33 0x21
L H L 34 0x22
L H H 35 0x23
H L L 36 0x24
H L H 37 0x25
H H L 38 0x26
H H H 39 0x27
For PCF8574A the addressing is:
Jp3 Jp2 Jp1
A2 A1 A0 Dec Hex
L L L 56 0x38
L L H 57 0x39
L H L 64 0x40
L H H 74 0x4A
H L L 75 0x4B
H L H 76 0x4C
H H L 77 0x4D
H H H 78 0x4E
For compatibility reasons this library contains some aliases for functions that are known under different
names in other libraries. This should make it fairly easy to implement the library in existing sketches
without changing to much code.
Functions not supported by this library will return nothing at all and in case a return value is expected
the function will return 0.

View File

@@ -0,0 +1,50 @@
###########################################
# Syntax Coloring Map For LiquidCrystal_I2C
###########################################
###########################################
# Datatypes (KEYWORD1)
###########################################
LiquidCrystal_I2C KEYWORD1
###########################################
# Methods and Functions (KEYWORD2)
###########################################
init KEYWORD2
begin KEYWORD2
clear KEYWORD2
home KEYWORD2
noDisplay KEYWORD2
display KEYWORD2
noBlink KEYWORD2
blink KEYWORD2
noCursor KEYWORD2
cursor KEYWORD2
scrollDisplayLeft KEYWORD2
scrollDisplayRight KEYWORD2
leftToRight KEYWORD2
rightToLeft KEYWORD2
shiftIncrement KEYWORD2
shiftDecrement KEYWORD2
noBacklight KEYWORD2
backlight KEYWORD2
autoscroll KEYWORD2
noAutoscroll KEYWORD2
createChar KEYWORD2
setCursor KEYWORD2
print KEYWORD2
blink_on KEYWORD2
blink_off KEYWORD2
cursor_on KEYWORD2
cursor_off KEYWORD2
setBacklight KEYWORD2
load_custom_character KEYWORD2
printstr KEYWORD2
init_bargraph KEYWORD2
draw_horizontal_graph KEYWORD2
graphHorizontalChars KEYWORD2
graphVerticalChars KEYWORD2
###########################################
# Constants (LITERAL1)
###########################################
LIQUIDCRYSTAL_I2C_VERSION LITERAL1

View File

@@ -0,0 +1,9 @@
name=LiquidCrystal_I2C
version=2.6.1
author=Libor Gabaj <libor.gabaj@gmail.com>
maintainer=Libor Gabaj <libor.gabaj@gmail.com>
sentence=Library for parallel HD44780 compatible LCDs interfaced via a Chinese PCF8574 I2C serial extender.
paragraph=Library for parallel HD44780 compatible LCDs interfaced via a Chinese PCF8574 I2C serial extender. It adds overloaded clear() function for clearing particular segment of an input row. Library also implements extended graph functions with help of custom characters and adds overloaded graph functions for expressing graph value in percentage or ration instead of pixels.
category=Display
url=https://github.com/mrkaleArduinoLib/LiquidCrystal_I2C.git
architectures=avr

View File

@@ -0,0 +1,444 @@
#include "LiquidCrystal_I2C.h"
// When the display powers up, it is configured as follows:
//
// 1. Display clear
// 2. Function set:
// DL = 1; 8-bit interface data
// N = 0; 1-line display
// F = 0; 5x8 dot character font
// 3. Display on/off control:
// D = 0; Display off
// C = 0; Cursor off
// B = 0; Blinking off
// 4. Entry mode set:
// I/D = 1; Increment by 1
// S = 0; No shift
//
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
// can't assume that its in that state when a sketch starts (and the
// LiquidCrystal constructor is called).
LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t addr, uint8_t cols, uint8_t rows)
{
_Addr = addr;
_cols = cols;
_rows = rows;
_backlightval = LCD_NOBACKLIGHT;
}
void LiquidCrystal_I2C::init(){
init_priv();
}
void LiquidCrystal_I2C::init_priv()
{
Wire.begin();
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
begin(_cols, _rows);
}
void LiquidCrystal_I2C::begin(uint8_t cols, uint8_t lines, uint8_t charsize) {
if (lines > 1) {
_displayfunction |= LCD_2LINE;
}
_numlines = lines;
// for some 1 line displays you can select a 10 pixel high font
if ((charsize != 0) && (lines == 1)) {
_displayfunction |= LCD_5x10DOTS;
}
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
// according to datasheet, we need at least 40ms after power rises above 2.7V
// before sending commands. Arduino can turn on way before 4.5V so we'll wait 50
delayMicroseconds(50000);
// Now we pull both RS and R/W low to begin commands
expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)
delay(1000);
// put the LCD into 4 bit mode
// this is according to the hitachi HD44780 datasheet
// figure 24, pg 46
// we start in 8bit mode, try to set 4 bit mode
write4bits(0x30);
delayMicroseconds(4500); // wait min 4.1ms
// second try
write4bits(0x30);
delayMicroseconds(4500); // wait min 4.1ms
// third go!
write4bits(0x30);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x20);
// set # lines, font size, etc.
command(LCD_FUNCTIONSET | _displayfunction);
// turn the display on with no cursor or blinking default
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
display();
// clear it off
clear();
// Initialize to default text direction (for roman languages)
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
// set the entry mode
command(LCD_ENTRYMODESET | _displaymode);
home();
}
/********** high level commands, for the user! */
void LiquidCrystal_I2C::clear(){
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
}
// Clear particular segment of a row
void LiquidCrystal_I2C::clear(uint8_t rowStart, uint8_t colStart, uint8_t colCnt) {
// Maintain input parameters
rowStart = constrain(rowStart, 0, _rows - 1);
colStart = constrain(colStart, 0, _cols - 1);
colCnt = constrain(colCnt, 0, _cols - colStart);
// Clear segment
setCursor(colStart, rowStart);
for (uint8_t i = 0; i < colCnt; i++) write(' ');
// Go to segment start
setCursor(colStart, rowStart);
}
void LiquidCrystal_I2C::home(){
command(LCD_RETURNHOME); // set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
}
void LiquidCrystal_I2C::setCursor(uint8_t col, uint8_t row){
int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
if ( row > _numlines ) {
row = _numlines-1; // we count rows starting w/0
}
command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}
// Turn the display on/off (quickly)
void LiquidCrystal_I2C::noDisplay() {
_displaycontrol &= ~LCD_DISPLAYON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal_I2C::display() {
_displaycontrol |= LCD_DISPLAYON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// Turns the underline cursor on/off
void LiquidCrystal_I2C::noCursor() {
_displaycontrol &= ~LCD_CURSORON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal_I2C::cursor() {
_displaycontrol |= LCD_CURSORON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// Turn on and off the blinking cursor
void LiquidCrystal_I2C::noBlink() {
_displaycontrol &= ~LCD_BLINKON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal_I2C::blink() {
_displaycontrol |= LCD_BLINKON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// These commands scroll the display without changing the RAM
void LiquidCrystal_I2C::scrollDisplayLeft(void) {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
void LiquidCrystal_I2C::scrollDisplayRight(void) {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}
// This is for text that flows Left to Right
void LiquidCrystal_I2C::leftToRight(void) {
_displaymode |= LCD_ENTRYLEFT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This is for text that flows Right to Left
void LiquidCrystal_I2C::rightToLeft(void) {
_displaymode &= ~LCD_ENTRYLEFT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This will 'right justify' text from the cursor
void LiquidCrystal_I2C::autoscroll(void) {
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This will 'left justify' text from the cursor
void LiquidCrystal_I2C::noAutoscroll(void) {
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
command(LCD_ENTRYMODESET | _displaymode);
}
// Allows us to fill the first 8 CGRAM locations
// with custom characters
void LiquidCrystal_I2C::createChar(uint8_t location, uint8_t charmap[]) {
location &= 0x7; // we only have 8 locations 0-7
command(LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++) {
write(charmap[i]);
}
}
// Turn the (optional) backlight off/on
void LiquidCrystal_I2C::noBacklight(void) {
_backlightval=LCD_NOBACKLIGHT;
expanderWrite(0);
}
void LiquidCrystal_I2C::backlight(void) {
_backlightval=LCD_BACKLIGHT;
expanderWrite(0);
}
/*********** mid level commands, for sending data/cmds */
inline void LiquidCrystal_I2C::command(uint8_t value) {
send(value, 0);
}
inline size_t LiquidCrystal_I2C::write(uint8_t value) {
send(value, Rs);
return 1; // Number of processed bytes
}
/************ low level data pushing commands **********/
// write either command or data
void LiquidCrystal_I2C::send(uint8_t value, uint8_t mode) {
uint8_t highnib = value & 0xF0;
uint8_t lownib = value << 4;
write4bits((highnib)|mode);
write4bits((lownib)|mode);
}
void LiquidCrystal_I2C::write4bits(uint8_t value) {
expanderWrite(value);
pulseEnable(value);
}
void LiquidCrystal_I2C::expanderWrite(uint8_t _data){
Wire.beginTransmission(_Addr);
Wire.write((int)(_data) | _backlightval);
Wire.endTransmission();
}
void LiquidCrystal_I2C::pulseEnable(uint8_t _data){
expanderWrite(_data | En); // En high
delayMicroseconds(1); // enable pulse must be >450ns
expanderWrite(_data & ~En); // En low
delayMicroseconds(50); // commands need > 37us to settle
}
// Create custom characters for horizontal graphs
uint8_t LiquidCrystal_I2C::graphHorizontalChars(uint8_t rowPattern) {
uint8_t cc[LCD_CHARACTER_VERTICAL_DOTS];
for (uint8_t idxCol = 0; idxCol < LCD_CHARACTER_HORIZONTAL_DOTS; idxCol++) {
for (uint8_t idxRow = 0; idxRow < LCD_CHARACTER_VERTICAL_DOTS; idxRow++) {
cc[idxRow] = rowPattern << (LCD_CHARACTER_HORIZONTAL_DOTS - 1 - idxCol);
}
createChar(idxCol, cc);
}
return LCD_CHARACTER_HORIZONTAL_DOTS;
}
// Create custom characters for vertical graphs
uint8_t LiquidCrystal_I2C::graphVerticalChars(uint8_t rowPattern) {
uint8_t cc[LCD_CHARACTER_VERTICAL_DOTS];
for (uint8_t idxChr = 0; idxChr < LCD_CHARACTER_VERTICAL_DOTS; idxChr++) {
for (uint8_t idxRow = 0; idxRow < LCD_CHARACTER_VERTICAL_DOTS; idxRow++) {
cc[LCD_CHARACTER_VERTICAL_DOTS - idxRow - 1] = idxRow > idxChr ? B00000 : rowPattern;
}
createChar(idxChr, cc);
}
return LCD_CHARACTER_VERTICAL_DOTS;
}
// Initializes custom characters for input graph type
uint8_t LiquidCrystal_I2C::init_bargraph(uint8_t graphtype) {
// Initialize row state vector
for(byte i = 0; i < _rows; i++) {
_graphstate[i] = 255;
}
switch (graphtype) {
case LCDI2C_VERTICAL_BAR_GRAPH:
graphVerticalChars(B11111);
// Initialize column state vector
for(byte i = _rows; i < _cols; i++) {
_graphstate[i] = 255;
}
break;
case LCDI2C_HORIZONTAL_BAR_GRAPH:
graphHorizontalChars(B11111);
break;
case LCDI2C_HORIZONTAL_LINE_GRAPH:
graphHorizontalChars(B00001);
break;
default:
return 1;
}
_graphtype = graphtype;
return 0;
}
// Display horizontal graph from desired cursor position with input value
void LiquidCrystal_I2C::draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end) {
// Maintain input parameters
row = constrain(row, 0, _rows - 1);
column = constrain(column, 0, _cols - 1);
len = constrain(len, 0, _cols - column);
pixel_col_end = constrain(pixel_col_end, 0, (len * LCD_CHARACTER_HORIZONTAL_DOTS) - 1);
_graphstate[row] = constrain(_graphstate[row], column, column + len - 1);
// Display graph
switch (_graphtype) {
case LCDI2C_HORIZONTAL_BAR_GRAPH:
setCursor(column, row);
// Display full characters
for (uint8_t i = 0; i < pixel_col_end / LCD_CHARACTER_HORIZONTAL_DOTS; i++) {
write(LCD_CHARACTER_HORIZONTAL_DOTS - 1);
column++;
}
// Display last character
write(pixel_col_end % LCD_CHARACTER_HORIZONTAL_DOTS);
// Clear remaining chars in segment
for (uint8_t i = column; i < _graphstate[row]; i++) write(' ');
// Last drawn column as graph state
_graphstate[row] = column;
break;
case LCDI2C_HORIZONTAL_LINE_GRAPH:
// Drawn column as graph state
column += pixel_col_end / LCD_CHARACTER_HORIZONTAL_DOTS;
// Clear previous drawn character if differs from new one
if (_graphstate[row] != column) {
setCursor(_graphstate[row], row);
write(' ');
_graphstate[row] = column;
}
// Display graph character
setCursor(column, row);
write(pixel_col_end % LCD_CHARACTER_HORIZONTAL_DOTS);
break;
default:
return;
}
}
// Display horizontal graph from desired cursor position with input value
void LiquidCrystal_I2C::draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_row_end) {
// Maintain input parameters
row = constrain(row, 0, _rows - 1);
column = constrain(column, 0, _cols - 1);
len = constrain(len, 0, row + 1);
pixel_row_end = constrain(pixel_row_end, 0, (len * LCD_CHARACTER_VERTICAL_DOTS) - 1);
_graphstate[column] = constrain(_graphstate[column], row - len + 1, row);
// Display graph
switch (_graphtype) {
case LCDI2C_VERTICAL_BAR_GRAPH:
// Display full characters
for (uint8_t i = 0; i < pixel_row_end / LCD_CHARACTER_VERTICAL_DOTS; i++) {
setCursor(column, row--);
write(LCD_CHARACTER_VERTICAL_DOTS - 1);
}
// Display the highest character
setCursor(column, row);
write(pixel_row_end % LCD_CHARACTER_VERTICAL_DOTS);
// Clear remaining top chars in column
for (uint8_t i = _graphstate[column]; i < row; i++) {
setCursor(column, i);
write(' ');
}
_graphstate[column] = row; // Last drawn row as its state
break;
default:
return;
}
}
// Overloaded methods
void LiquidCrystal_I2C::draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint16_t percentage) {
percentage = (percentage * len * LCD_CHARACTER_HORIZONTAL_DOTS / 100) - 1;
draw_horizontal_graph(row, column, len, (uint8_t) percentage);
}
void LiquidCrystal_I2C::draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, float ratio) {
ratio = (ratio * len * LCD_CHARACTER_HORIZONTAL_DOTS) - 1;
draw_horizontal_graph(row, column, len, (uint8_t) ratio);
}
void LiquidCrystal_I2C::draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint16_t percentage) {
percentage = (percentage * len * LCD_CHARACTER_VERTICAL_DOTS / 100) - 1;
draw_vertical_graph(row, column, len, (uint8_t) percentage);
}
void LiquidCrystal_I2C::draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, float ratio) {
ratio = (ratio * len * LCD_CHARACTER_VERTICAL_DOTS) - 1;
draw_vertical_graph(row, column, len, (uint8_t) ratio);
}
// Alias functions
void LiquidCrystal_I2C::on(){
display();
}
void LiquidCrystal_I2C::off(){
noDisplay();
}
void LiquidCrystal_I2C::cursor_on(){
cursor();
}
void LiquidCrystal_I2C::cursor_off(){
noCursor();
}
void LiquidCrystal_I2C::blink_on(){
blink();
}
void LiquidCrystal_I2C::blink_off(){
noBlink();
}
void LiquidCrystal_I2C::load_custom_character(uint8_t char_num, uint8_t *rows){
createChar(char_num, rows);
}
void LiquidCrystal_I2C::setBacklight(uint8_t new_val){
if(new_val){
backlight(); // turn backlight on
}else{
noBacklight(); // turn backlight off
}
}
void LiquidCrystal_I2C::printstr(const char c[]){
//This function is not identical to the function used for "real" I2C displays
//it's here so the user sketch doesn't have to be changed
print(c);
}

View File

@@ -0,0 +1,303 @@
/*
NAME:
LiquidCrystal_I2C
DESCRIPTION:
Library for parallel HD44780 compatible LCDs interfaced via a Chinese
PCF8574 I2C serial extender.
- Library implements LCD API 1.0 to the extend the appropriate LCDs
support functionality expected by the API.
- Library adds overloaded clear() function for clearing particular
segment of an input row.
- Library implements extended graph functions with help of custom
characters, so that do not use your custom characters concurrently
with graph function. Your custom characters will be overwritten by
graph initialization.
- Library adds overloaded graph functions for expression graph value
in percentage instead of pixels.
LICENSE:
This program is free software; you can redistribute it and/or modify
it under the terms of the MIT License (MIT).
CREDENTIALS:
Author: Libor Gabaj
GitHub: https://github.com/mrkaleArduinoLib/LiquidCrystal_I2C.git
CREDITS:
Mario H. atmega@xs4all.nl - LiquidCrystal_I2C V2.0
Murray R. Van Luyn. vanluynm@iinet.net.au - Mods for Chinese I2C converter board
*/
#ifndef LIQUIDCRYSTAL_I2C_H
#define LIQUIDCRYSTAL_I2C_H
#define LIQUIDCRYSTAL_I2C_VERSION "LiquidCrystal_I2C 2.6.1"
#include <Arduino.h>
#include <inttypes.h>
#include <Wire.h>
// commands
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// flags for display entry mode
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// flags for display on/off control
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// flags for display/cursor shift
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// flags for function set
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// flags for backlight control
//#define LCD_BACKLIGHT B00001000
//#define LCD_NOBACKLIGHT B00000000
// LK ESP32
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00
// values for graphtype in calls to init_bargraph and character geometry
#define LCDI2C_VERTICAL_BAR_GRAPH 1
#define LCDI2C_HORIZONTAL_BAR_GRAPH 2
#define LCDI2C_HORIZONTAL_LINE_GRAPH 3
#define LCD_CHARACTER_HORIZONTAL_DOTS 5
#define LCD_CHARACTER_VERTICAL_DOTS 8
#define En B00000100 // Enable bit
#define Rw B00000010 // Read/Write bit
#define Rs B00000001 // Register select bit
class LiquidCrystal_I2C : public Print {
public:
LiquidCrystal_I2C(uint8_t addr, uint8_t cols, uint8_t rows);
void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
void init();
/*
Clear particular segment of a row
DESCRIPTION:
Overloaded original function clear().
* Thanks to default parameters, for clearing the entire row
use just clear(rowStart).
* The functions sets the cursor to start column and row after clearing.
PARAMETERS:
rowStart - row number to be cleared counting from 0.
Limited to the last row.
colStart - column number of the cleared segment counting from 0.
Defaulted to the very begining of the row.
Limited to the last character.
colCnt - number of cleared characters.
Defaulted to 255.
Limited to remaining characters on the row.
RETURN: none
*/
void clear();
void clear(uint8_t rowStart, uint8_t colStart = 0, uint8_t colCnt = 255);
void home();
void noDisplay();
void display();
void noBlink();
void blink();
void noCursor();
void cursor();
void scrollDisplayLeft();
void scrollDisplayRight();
void leftToRight();
void rightToLeft();
void noBacklight();
void backlight();
void noAutoscroll();
void autoscroll();
void createChar(uint8_t location, uint8_t charmap[]);
void setCursor(uint8_t col, uint8_t row);
virtual size_t write(uint8_t value);
void command(uint8_t value);
/*
Initialize particular bar graph
DESCRIPTION:
Creates a set of custom characters for displaying bar graphs.
Some number of first current custom characters will be overwritten
according to the type of graph.
PARAMETERS:
uint8_t graphtype - type of graph
LCDI2C_VERTICAL_BAR_GRAPH - rewrites all 8 custom characters
LCDI2C_HORIZONTAL_BAR_GRAPH - rewrites first 5 custom characters
LCDI2C_HORIZONTAL_LINE_GRAPH - rewrites first 5 custom characters
RETURN: error code
0 - at success
1 - at failure, e.g., graph type not recognized
*/
uint8_t init_bargraph(uint8_t graphtype);
/*
Display horizontal graph from desired cursor position with input value
DESCRIPTION:
Displays horizontal bar or running pipe starting at input cursor position
composed of custom characters.
* For graph is reserved "len" characters long segment on the "row" starting
on "column".
* Current value of the bar graph is displayed as "pixel_col_end" pipes
in the graph segment.
* Current value of the line graph is displayed as pipe on "pixel_col_end"
dot position in the graph segment.
* Zero value of the graph is displayed as the very left pipe in the
graph segment, so that the graph always displays something.
PARAMETERS:
uint8_t row - row position of graph segment counting from 0
Limited to physical rows.
uint8_t column - column position of graph segment counting from 0
Limited to physical columns.
uint8_t len - length of graph segment in characters
Limited to remaining physical columns from col position.
uint8_t pixel_col_end - value of graph in pipes counting from 0
Limited to physical horizontal dots of graph segment.
RETURN: none
*/
void draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end);
/*
Display vertical graph from desired cursor position with input value
DESCRIPTION:
Displays vertical bar starting at "row", "column" position composed
of custom characters.
For bar is reserved "len" rows long segment on the "column" starting on
"row".
Current value of the bar graph is displayed as "pixel_row_end" dashes
from bottom to top of the graph segment.
PARAMETERS:
uint8_t row - row positon of the bottom of a graph segment
counting from 0
Limited to physical rows.
uint8_t column - column position of graph segment counting from 0
Limited to physical columns.
uint8_t len - length of graph segment in rows
Limited to remaining physical rows from row position.
uint8_t pixel_row_end - value of graph in dashes counting from 0
Limited to physical vertical dots of graph segment.
RETURN: none
*/
void draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_row_end);
/*
Overloaded methods with type difference of graph value
PARAMETERS:
uint16_t percentage - percentage of graph segment as graph value
Although expected range is 0 to 100, uint8_t has been reserved
by official API already.
float ratio - fraction of graph segment as graph value
Expected range is 0.0 to 1.0
*/
void draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint16_t percentage);
void draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, float ratio);
void draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint16_t percentage);
void draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, float ratio);
////compatibility API function aliases
void on(); // alias for display()
void off(); // alias for noDisplay()
void blink_on(); // alias for blink()
void blink_off(); // alias for noBlink()
void cursor_on(); // alias for cursor()
void cursor_off(); // alias for noCursor()
void setBacklight(uint8_t new_val); // alias for backlight() and nobacklight()
void load_custom_character(uint8_t char_num, uint8_t *rows); // alias for createChar()
void printstr(const char[]);
/* Unsupported API functions (not implemented in this library)
uint8_t status();
void setContrast(uint8_t new_val);
uint8_t keypad();
void setDelay(int, int);
*/
private:
void init_priv();
void send(uint8_t, uint8_t);
void write4bits(uint8_t);
void expanderWrite(uint8_t);
void pulseEnable(uint8_t);
/*
Create custom characters for horizontal graphs
DESCRIPTION:
Creates the set of custom characters for displaying horizontal graphs.
The first 5 current custom characters will be overwritten.
Particular custom characters are filled by bit shifting fullCharRowPattern
from the right to the left.
PARAMETERS:
uint8_t rowPattern - row pattern of the full character
RETURN: uint8_t - number of created custom characters
*/
uint8_t graphHorizontalChars(uint8_t rowPattern);
/*
Create custom characters for vertical graphs
DESCRIPTION:
Creates the set of custom characters for displaying vertical graphs.
All 8 current custom characters will be overwritten.
Particular custom characters are filled with rowPattern from the very
bottom pixel line.
PARAMETERS:
uint8_t rowPattern - row pattern of the pixel line
RETURN: uint8_t - number of created custom characters
*/
uint8_t graphVerticalChars(uint8_t rowPattern);
// Private attributes
uint8_t _Addr;
uint8_t _displayfunction;
uint8_t _displaycontrol;
uint8_t _displaymode;
uint8_t _numlines;
uint8_t _cols;
uint8_t _rows;
uint8_t _backlightval;
uint8_t _graphtype; // Internal code for graph type
uint8_t _graphstate[20]; // Internal last graph column/row state
};
#endif

4
lib/README Normal file
View File

@@ -0,0 +1,4 @@
# Biblioteki
Ten folder zawiera biblioteki wykorzystane w projekcie.

46
lib/RTClib/.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,46 @@
Thank you for opening an issue on an Adafruit Arduino library repository. To
improve the speed of resolution please review the following guidelines and
common troubleshooting steps below before creating the issue:
- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use
the forums at http://forums.adafruit.com to ask questions and troubleshoot why
something isn't working as expected. In many cases the problem is a common issue
that you will more quickly receive help from the forum community. GitHub issues
are meant for known defects in the code. If you don't know if there is a defect
in the code then start with troubleshooting on the forum first.
- **If following a tutorial or guide be sure you didn't miss a step.** Carefully
check all of the steps and commands to run have been followed. Consult the
forum if you're unsure or have questions about steps in a guide/tutorial.
- **For Arduino projects check these very common issues to ensure they don't apply**:
- For uploading sketches or communicating with the board make sure you're using
a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes
very hard to tell the difference between a data and charge cable! Try using the
cable with other devices or swapping to another cable to confirm it is not
the problem.
- **Be sure you are supplying adequate power to the board.** Check the specs of
your board and plug in an external power supply. In many cases just
plugging a board into your computer is not enough to power it and other
peripherals.
- **Double check all soldering joints and connections.** Flakey connections
cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints.
- **Ensure you are using an official Arduino or Adafruit board.** We can't
guarantee a clone board will have the same functionality and work as expected
with this code and don't support them.
If you're sure this issue is a defect in the code and checked the steps above
please fill in the following fields to provide enough troubleshooting information.
You may delete the guideline and text above to just leave the following details:
- Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE**
- Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO
VERSION HERE**
- List the steps to reproduce the problem below (if possible attach a sketch or
copy the sketch code in too): **LIST REPRO STEPS BELOW**

View File

@@ -0,0 +1,26 @@
Thank you for creating a pull request to contribute to Adafruit's GitHub code!
Before you open the request please review the following guidelines and tips to
help it be more easily integrated:
- **Describe the scope of your change--i.e. what the change does and what parts
of the code were modified.** This will help us understand any risks of integrating
the code.
- **Describe any known limitations with your change.** For example if the change
doesn't apply to a supported platform of the library please mention it.
- **Please run any tests or examples that can exercise your modified code.** We
strive to not break users of the code and running tests/examples helps with this
process.
Thank you again for contributing! We will try to test and integrate the change
as soon as we can, but be aware we have many GitHub repositories to manage and
can't immediately respond to every request. There is no need to bump or check in
on a pull request (it will clutter the discussion of the request).
Also don't be worried if the request is closed or not integrated--sometimes the
priorities of Adafruit's GitHub code (education, ease of use) might not match the
priorities of the pull request. Don't fret, the open source community thrives on
forks and GitHub makes it easy to keep your changes in a forked repo.
After reviewing the guidelines above you can delete this text from the pull request.

View File

@@ -0,0 +1,32 @@
name: Arduino Library CI
on: [pull_request, push, repository_dispatch]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-python@v4
with:
python-version: '3.x'
- uses: actions/checkout@v3
- uses: actions/checkout@v3
with:
repository: adafruit/ci-arduino
path: ci
- name: pre-install
run: bash ci/actions_install.sh
- name: test platforms
run: python3 ci/build_platform.py main_platforms
- name: clang
run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r .
- name: doxygen
env:
GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }}
PRETTYNAME : "RTClib"
run: bash ci/doxy_gen_and_deploy.sh src

4
lib/RTClib/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
*~
html
Doxyfile*
doxygen_sqlite3.db

1
lib/RTClib/.piopm Normal file
View File

@@ -0,0 +1 @@
{"type": "library", "name": "RTClib", "version": "2.1.4", "spec": {"owner": "adafruit", "id": 83, "name": "RTClib", "requirements": null, "uri": null}}

77
lib/RTClib/README.md Normal file
View File

@@ -0,0 +1,77 @@
# RTClib [![Build Status](https://github.com/adafruit/RTClib/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/RTClib/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/RTClib/html/index.html)
This is a fork of JeeLab's fantastic real time clock library for Arduino.
Works great with Adafruit RTC breakouts:
- [DS3231 Precision RTC](https://www.adafruit.com/product/3013) (breakout) and [Stemma QT version](https://www.adafruit.com/product/5188)
- [PCF8523 RTC](https://www.adafruit.com/product/3295)
- [DS1307 RTC](https://www.adafruit.com/product/3296)
Please note that dayOfTheWeek() ranges from 0 to 6 inclusive with 0 being 'Sunday'.
<!-- START COMPATIBILITY TABLE -->
## Compatibility
MCU | Tested Works | Doesn't Work | Not Tested | Notes
------------------ | :----------: | :----------: | :---------: | -----
Atmega328 @ 16MHz | X | | |
Atmega328 @ 12MHz | X | | |
Atmega32u4 @ 16MHz | X | | | Use SDA/SCL on pins D3 &amp; D2
Atmega32u4 @ 8MHz | X | | | Use SDA/SCL on pins D3 &amp; D2
ESP8266 | X | | | SDA/SCL default to pins 4 &amp; 5 but any two pins can be assigned as SDA/SCL using Wire.begin(SDA,SCL)
Atmega2560 @ 16MHz | X | | | Use SDA/SCL on Pins 20 &amp; 21
ATSAM3X8E | X | | | Use SDA1 and SCL1
ATSAM21D | X | | |
ATtiny85 @ 16MHz | X | | |
ATtiny85 @ 8MHz | X | | |
Intel Curie @ 32MHz | | | X |
STM32F2 | | | X |
* ATmega328 @ 16MHz : Arduino UNO, Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini
* ATmega328 @ 12MHz : Adafruit Pro Trinket 3V
* ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0
* ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro
* ESP8266 : Adafruit Huzzah
* ATmega2560 @ 16MHz : Arduino Mega
* ATSAM3X8E : Arduino Due
* ATSAM21D : Arduino Zero, M0 Pro
* ATtiny85 @ 16MHz : Adafruit Trinket 5V
* ATtiny85 @ 8MHz : Adafruit Gemma, Arduino Gemma, Adafruit Trinket 3V
<!-- END COMPATIBILITY TABLE -->
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
# Dependencies
* [Adafruit BusIO](https://github.com/adafruit/Adafruit_BusIO)
# Contributing
Contributions are welcome! Please read our [Code of Conduct](https://github.com/adafruit/RTClib/blob/master/code-of-conduct.md)
before contributing to help this project stay welcoming.
## Documentation and doxygen
For the detailed API documentation, see https://adafruit.github.io/RTClib/html/index.html
Documentation is produced by doxygen. Contributions should include documentation for any new code added.
Some examples of how to use doxygen can be found in these guide pages:
https://learn.adafruit.com/the-well-automated-arduino-library/doxygen
https://learn.adafruit.com/the-well-automated-arduino-library/doxygen-tips
## Code formatting and clang-format
The code should be formatted according to the [LLVM Coding Standards](https://llvm.org/docs/CodingStandards.html), which is the default of the clang-format tool. The easiest way to ensure conformance is to [install clang-format](https://llvm.org/builds/) and run
```shell
clang-format -i <source_file>
```
See [Formatting with clang-format](https://learn.adafruit.com/the-well-automated-arduino-library/formatting-with-clang-format) for details.
Written by JeeLabs
MIT license, check license.txt for more information
All text above must be included in any redistribution
To install, use the Arduino Library Manager and search for "RTClib" and install the library.

View File

@@ -0,0 +1,127 @@
# Adafruit Community Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and leaders pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level or type of
experience, education, socio-economic status, nationality, personal appearance,
race, religion, or sexual identity and orientation.
## Our Standards
We are committed to providing a friendly, safe and welcoming environment for
all.
Examples of behavior that contributes to creating a positive environment
include:
* Be kind and courteous to others
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Collaborating with other community members
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and sexual attention or advances
* The use of inappropriate images, including in a community member's avatar
* The use of inappropriate language, including in a community member's nickname
* Any spamming, flaming, baiting or other attention-stealing behavior
* Excessive or unwelcome helping; answering outside the scope of the question
asked
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate
The goal of the standards and moderation guidelines outlined here is to build
and maintain a respectful community. We ask that you dont just aim to be
"technically unimpeachable", but rather try to be your best self.
We value many things beyond technical expertise, including collaboration and
supporting others within our community. Providing a positive experience for
other community members can have a much more significant impact than simply
providing the correct answer.
## Our Responsibilities
Project leaders are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project leaders have the right and responsibility to remove, edit, or
reject messages, comments, commits, code, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any community member for other behaviors that they deem
inappropriate, threatening, offensive, or harmful.
## Moderation
Instances of behaviors that violate the Adafruit Community Code of Conduct
may be reported by any member of the community. Community members are
encouraged to report these situations, including situations they witness
involving other community members.
You may report in the following ways:
In any situation, you may send an email to <support@adafruit.com>.
On the Adafruit Discord, you may send an open message from any channel
to all Community Helpers by tagging @community helpers. You may also send an
open message from any channel, or a direct message to @kattni#1507,
@tannewt#4653, @Dan Halbert#1614, @cater#2442, @sommersoft#0222, or
@Andon#8175.
Email and direct message reports will be kept confidential.
In situations on Discord where the issue is particularly egregious, possibly
illegal, requires immediate action, or violates the Discord terms of service,
you should also report the message directly to Discord.
These are the steps for upholding our communitys standards of conduct.
1. Any member of the community may report any situation that violates the
Adafruit Community Code of Conduct. All reports will be reviewed and
investigated.
2. If the behavior is an egregious violation, the community member who
committed the violation may be banned immediately, without warning.
3. Otherwise, moderators will first respond to such behavior with a warning.
4. Moderators follow a soft "three strikes" policy - the community member may
be given another chance, if they are receptive to the warning and change their
behavior.
5. If the community member is unreceptive or unreasonable when warned by a
moderator, or the warning goes unheeded, they may be banned for a first or
second offense. Repeated offenses will result in the community member being
banned.
## Scope
This Code of Conduct and the enforcement policies listed above apply to all
Adafruit Community venues. This includes but is not limited to any community
spaces (both public and private), the entire Adafruit Discord server, and
Adafruit GitHub repositories. Examples of Adafruit Community spaces include
but are not limited to meet-ups, audio chats on the Adafruit Discord, or
interaction at a conference.
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. As a community
member, you are representing our community, and are expected to behave
accordingly.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.4, available at
<https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>,
and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html).
For other projects adopting the Adafruit Community Code of
Conduct, please contact the maintainers of those projects for enforcement.
If you wish to use this code of conduct for your own project, consider
explicitly mentioning your moderation policy or making a copy with your
own moderation policy so as to avoid confusion.

View File

@@ -0,0 +1,122 @@
/* Example implementation of an alarm using DS3231
*
* VCC and GND of RTC should be connected to some power source
* SDA, SCL of RTC should be connected to SDA, SCL of arduino
* SQW should be connected to CLOCK_INTERRUPT_PIN
* CLOCK_INTERRUPT_PIN needs to work with interrupts
*/
#include <RTClib.h>
// #include <Wire.h>
RTC_DS3231 rtc;
// the pin that is connected to SQW
#define CLOCK_INTERRUPT_PIN 2
void setup() {
Serial.begin(9600);
// initializing the rtc
if(!rtc.begin()) {
Serial.println("Couldn't find RTC!");
Serial.flush();
while (1) delay(10);
}
if(rtc.lostPower()) {
// this will adjust to the date and time at compilation
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
//we don't need the 32K Pin, so disable it
rtc.disable32K();
// Making it so, that the alarm will trigger an interrupt
pinMode(CLOCK_INTERRUPT_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN), onAlarm, FALLING);
// set alarm 1, 2 flag to false (so alarm 1, 2 didn't happen so far)
// if not done, this easily leads to problems, as both register aren't reset on reboot/recompile
rtc.clearAlarm(1);
rtc.clearAlarm(2);
// stop oscillating signals at SQW Pin
// otherwise setAlarm1 will fail
rtc.writeSqwPinMode(DS3231_OFF);
// turn off alarm 2 (in case it isn't off already)
// again, this isn't done at reboot, so a previously set alarm could easily go overlooked
rtc.disableAlarm(2);
// schedule an alarm 10 seconds in the future
if(!rtc.setAlarm1(
rtc.now() + TimeSpan(10),
DS3231_A1_Second // this mode triggers the alarm when the seconds match. See Doxygen for other options
)) {
Serial.println("Error, alarm wasn't set!");
}else {
Serial.println("Alarm will happen in 10 seconds!");
}
}
void loop() {
// print current time
char date[10] = "hh:mm:ss";
rtc.now().toString(date);
Serial.print(date);
// the stored alarm value + mode
DateTime alarm1 = rtc.getAlarm1();
Ds3231Alarm1Mode alarm1mode = rtc.getAlarm1Mode();
char alarm1Date[12] = "DD hh:mm:ss";
alarm1.toString(alarm1Date);
Serial.print(" [Alarm1: ");
Serial.print(alarm1Date);
Serial.print(", Mode: ");
switch (alarm1mode) {
case DS3231_A1_PerSecond: Serial.print("PerSecond"); break;
case DS3231_A1_Second: Serial.print("Second"); break;
case DS3231_A1_Minute: Serial.print("Minute"); break;
case DS3231_A1_Hour: Serial.print("Hour"); break;
case DS3231_A1_Date: Serial.print("Date"); break;
case DS3231_A1_Day: Serial.print("Day"); break;
}
// the value at SQW-Pin (because of pullup 1 means no alarm)
Serial.print("] SQW: ");
Serial.print(digitalRead(CLOCK_INTERRUPT_PIN));
// whether a alarm fired
Serial.print(" Fired: ");
Serial.print(rtc.alarmFired(1));
// Serial.print(" Alarm2: ");
// Serial.println(rtc.alarmFired(2));
// control register values (see https://datasheets.maximintegrated.com/en/ds/DS3231.pdf page 13)
// Serial.print(" Control: 0b");
// Serial.println(read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL), BIN);
// resetting SQW and alarm 1 flag
// using setAlarm1, the next alarm could now be configurated
if (rtc.alarmFired(1)) {
rtc.clearAlarm(1);
Serial.print(" - Alarm cleared");
}
Serial.println();
delay(2000);
}
void onAlarm() {
Serial.println("Alarm occured!");
}
/*static uint8_t read_i2c_register(uint8_t addr, uint8_t reg) {
Wire.beginTransmission(addr);
Wire.write((byte)reg);
Wire.endTransmission();
Wire.requestFrom(addr, (byte)1);
return Wire.read();
}*/

View File

@@ -0,0 +1,120 @@
/* Using DS3231 (or other supported RTC) with a custom TwoWire instance
*
* If using a microcontroller which supports additional i2c ports,
* such as the SAMD21's SERCOMX, a user can define a custom i2c bus
* to use with an RTC.
* This example builds the custom i2c bus using SERCOM0 and leverages the "wiring_private.h" APIs
*
* Connecting the device:
* VCC and GND of RTC should be connected to some power source
* SDA, SCL of RTC should be connected to the custom SDA and SCL pins.
* In this particular example we are using a Nano 33 IoT and routing
* the custom Wire instance over pins 6 (SDA) and 5 (SCL)
*
* This example will work with Arduino Zero, any Arduino MKR board based on SAMD21, Nano 33 IoT
* and any board by Adafruit, Sparkfun, Seeed Studio based on the same microcontroller
*
*/
#include <Wire.h>
#include "wiring_private.h"
#include <RTClib.h>
/* Defining the custom TwoWire instance for SAMD21 */
TwoWire myWire(&sercom0, 6, 5); // Create the new wire instance assigning it to pin 0 and 1
extern "C"{
void SERCOM0_Handler(void);
void SERCOM0_Handler(void) {
myWire.onService();
}
}
/* Creating a new DS3231 object */
RTC_DS3231 myRTC;
String daysNames[] = {
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
};
String monthsNames[] = {
"-",
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
};
void setup() {
Serial.begin(57600);
Serial.println("start");
unsigned long setupStartTime = millis();
/*** Waiting for Serial to be ready or timeout ***/
while(!Serial && millis() - setupStartTime < 3000);
/*
* Initialising pins 6 and 5 to be routed to the SERCOM0 pads 0 and 1 in order
* to be used as SDA and SCL. Without this step the periphearl won't be patched through
*/
pinPeripheral(6, PIO_SERCOM_ALT); // PAD[0] //Assign SDA function to pin 0
pinPeripheral(5, PIO_SERCOM_ALT); // PAD[1] //Assign SCL function to pin 1
/* We now pass our custom TwoWire object to the RTC instance */
myRTC.begin(&myWire);
/*
* From this moment on every operation on the RTC will work as expected
* But the i2c bus being used will be the one we manually created using SERCOM0
*/
/*
* Creating a Date object with
* YEAR, MONTH, DAY (2021, January, 1)
* HOUR, MINUTE, SECONDS (0, 0, 0)
* Midnight of January 1st, 2021
*/
DateTime newDT = DateTime(2021, 1, 1, 0, 0, 0);
/* Pushing that date/time to the RTC */
myRTC.adjust(newDT);
Serial.println("setup done");
}
void loop() {
/* creating a temporary date/time object to store the data coming from the RTC */
DateTime dt = myRTC.now();
/* printing that data to the Serial port in a meaningful format */
Serial.println("************");
Serial.print(daysNames[dt.dayOfTheWeek()]);
Serial.print(" ");
Serial.print(monthsNames[dt.month()]);
Serial.print(" ");
Serial.print(dt.day());
Serial.print(", ");
Serial.println(dt.year());
Serial.print(dt.hour());
Serial.print(":");
Serial.print(dt.minute());
Serial.print(":");
Serial.println(dt.second());
/* Delays are bad, but let's not flood the Serial for this silly example */
delay(500);
}

Some files were not shown because too many files have changed in this diff Show More