Compare commits
33 commits
12560f784e
...
76d464c8cc
Author | SHA1 | Date | |
---|---|---|---|
Martin Brodbeck | 76d464c8cc | ||
Martin Brodbeck | c9a6729ba7 | ||
Martin Brodbeck | 44a00db6b9 | ||
Martin Brodbeck | d6ea24685b | ||
Martin Brodbeck | bde19fd2b7 | ||
Martin Brodbeck | 278de69a16 | ||
Martin Brodbeck | 684ac6f884 | ||
Martin Brodbeck | 48b9fb5015 | ||
Martin Brodbeck | 8bde85723d | ||
Martin Brodbeck | 9f261ddac7 | ||
Martin Brodbeck | dfa5713fb5 | ||
Martin Brodbeck | 39bac21110 | ||
Martin Brodbeck | 5e7877b5d8 | ||
Martin Brodbeck | ba95eeebb9 | ||
Martin Brodbeck | d6d91f4cb2 | ||
Martin Brodbeck | 91e1a7d424 | ||
Martin Brodbeck | 2f7d1dd921 | ||
Martin Brodbeck | d354be1077 | ||
Martin Brodbeck | 8b58b3a443 | ||
Martin Brodbeck | 7ca6b69f9d | ||
Martin Brodbeck | cbbf0b77e7 | ||
Martin Brodbeck | efee152c5c | ||
Martin Brodbeck | 5c68445c4d | ||
Martin Brodbeck | 440359d775 | ||
Martin Brodbeck | 275e012695 | ||
Martin Brodbeck | b1c0b0292b | ||
Martin Brodbeck | a52c1b94b8 | ||
Martin Brodbeck | 0a48d09436 | ||
Martin Brodbeck | b084a2df64 | ||
Martin Brodbeck | 165e9912dd | ||
Martin Brodbeck | 55c3b0f80a | ||
Martin Brodbeck | a5e3e3c671 | ||
Martin Brodbeck | 6707c4d19f |
179
.clang-format
Normal file
179
.clang-format
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
# BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -2
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignArrayOfStructures: None
|
||||||
|
AlignConsecutiveMacros: None
|
||||||
|
AlignConsecutiveAssignments: None
|
||||||
|
AlignConsecutiveBitFields: None
|
||||||
|
AlignConsecutiveDeclarations: None
|
||||||
|
AlignEscapedNewlines: Right
|
||||||
|
AlignOperands: Align
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
AllowAllConstructorInitializersOnNextLine: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortEnumsOnASingleLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: Never
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: MultiLine
|
||||||
|
AttributeMacros:
|
||||||
|
- __capability
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: false
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: Never
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
AfterExternBlock: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
BeforeLambdaBody: false
|
||||||
|
BeforeWhile: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
SplitEmptyNamespace: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeConceptDeclarations: true
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ColumnLimit: 80
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DeriveLineEnding: 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
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentCaseBlocks: false
|
||||||
|
IndentGotoLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentExternBlock: AfterExternBlock
|
||||||
|
IndentRequires: false
|
||||||
|
#IndentWidth: 2
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
InsertTrailingCommas: None
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
LambdaBodyIndentation: Signature
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBinPackProtocolList: Auto
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCBreakBeforeNestedBlockParam: true
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakAssignment: 2
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyBreakTemplateDeclaration: 10
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
PenaltyIndentedWhitespace: 0
|
||||||
|
PointerAlignment: Right
|
||||||
|
PPIndentWidth: -1
|
||||||
|
ReferenceAlignment: Pointer
|
||||||
|
ReflowComments: true
|
||||||
|
ShortNamespaceLines: 1
|
||||||
|
SortIncludes: CaseSensitive
|
||||||
|
SortJavaStaticImport: Before
|
||||||
|
SortUsingDeclarations: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCaseColon: false
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceAroundPointerQualifiers: Default
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyBlock: false
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: Never
|
||||||
|
SpacesInConditionalStatement: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInLineCommentPrefix:
|
||||||
|
Minimum: 1
|
||||||
|
Maximum: -1
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
SpaceBeforeSquareBrackets: false
|
||||||
|
BitFieldColonSpacing: Both
|
||||||
|
Standard: Latest
|
||||||
|
StatementAttributeLikeMacros:
|
||||||
|
- Q_EMIT
|
||||||
|
StatementMacros:
|
||||||
|
- Q_UNUSED
|
||||||
|
- QT_REQUIRE_VERSION
|
||||||
|
TabWidth: 8
|
||||||
|
UseCRLF: false
|
||||||
|
UseTab: Never
|
||||||
|
WhitespaceSensitiveMacros:
|
||||||
|
- STRINGIZE
|
||||||
|
- PP_STRINGIZE
|
||||||
|
- BOOST_PP_STRINGIZE
|
||||||
|
- NS_SWIFT_NAME
|
||||||
|
- CF_SWIFT_NAME
|
||||||
|
...
|
||||||
|
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
build/
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "modules/pico-onewire"]
|
||||||
|
path = modules/pico-onewire
|
||||||
|
url = https://github.com/adamboardman/pico-onewire.git
|
1
.vscode/.cortex-debug.peripherals.state.json
vendored
Normal file
1
.vscode/.cortex-debug.peripherals.state.json
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
[]
|
1
.vscode/.cortex-debug.registers.state.json
vendored
Normal file
1
.vscode/.cortex-debug.registers.state.json
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
[]
|
18
.vscode/c_cpp_properties.json
vendored
Normal file
18
.vscode/c_cpp_properties.json
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Linux",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/**",
|
||||||
|
"${env:PICO_SDK_PATH}/**"
|
||||||
|
],
|
||||||
|
"defines": [],
|
||||||
|
"compilerPath": "/usr/bin/arm-none-eabi-gcc",
|
||||||
|
"cStandard": "gnu17",
|
||||||
|
"cppStandard": "gnu++14",
|
||||||
|
"intelliSenseMode": "linux-gcc-arm",
|
||||||
|
"configurationProvider" : "ms-vscode.cmake-tools"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
7
.vscode/extensions.json
vendored
Normal file
7
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"marus25.cortex-debug",
|
||||||
|
"ms-vscode.cmake-tools",
|
||||||
|
"ms-vscode.cpptools"
|
||||||
|
]
|
||||||
|
}
|
31
.vscode/launch.json
vendored
Normal file
31
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Cortex Debug",
|
||||||
|
"cwd": "${workspaceRoot}",
|
||||||
|
"executable": "${command:cmake.launchTargetPath}",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "cortex-debug",
|
||||||
|
"servertype": "openocd",
|
||||||
|
"gdbPath" : "arm-none-eabi-gdb",
|
||||||
|
"device": "RP2040",
|
||||||
|
//"showDevDebugOutput": "parsed",
|
||||||
|
"configFiles": [
|
||||||
|
"interface/picoprobe.cfg",
|
||||||
|
"target/rp2040.cfg"
|
||||||
|
],
|
||||||
|
"svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd",
|
||||||
|
"runToEntryPoint": "main",
|
||||||
|
// Give restart the same functionality as runToMain
|
||||||
|
//"postRestartCommands": [
|
||||||
|
// "break main",
|
||||||
|
// "continue"
|
||||||
|
//],
|
||||||
|
"searchDir": ["${env:HOME}/src/openocd/tcl"],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
20
.vscode/settings.json
vendored
Normal file
20
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"cmake.configureOnOpen": false,
|
||||||
|
"cmake.buildBeforeRun": true,
|
||||||
|
"cmake.statusbar.advanced": {
|
||||||
|
"debug" : {
|
||||||
|
"visibility": "hidden"
|
||||||
|
}, "launch" : {
|
||||||
|
"visibility": "hidden"
|
||||||
|
},
|
||||||
|
"build" : {
|
||||||
|
"visibility": "hidden"
|
||||||
|
},
|
||||||
|
"buildTarget" : {
|
||||||
|
"visibility": "hidden"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"cortex-debug.openocdPath": "${env:HOME}/src/openocd/src/openocd",
|
||||||
|
"cmake.generator": "Unix Makefiles",
|
||||||
|
"C_Cpp.clang_format_fallbackStyle": "LLVM",
|
||||||
|
}
|
22
CMakeLists.txt
Normal file
22
CMakeLists.txt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-volatile")
|
||||||
|
|
||||||
|
# Initialise pico_sdk from installed location
|
||||||
|
# (note this can come from environment, CMake cache etc)
|
||||||
|
set(PICO_SDK_PATH "/usr/share/pico-sdk")
|
||||||
|
|
||||||
|
# Pull in Raspberry Pi Pico SDK (must be before project)
|
||||||
|
include("cmake/pico_sdk_import.cmake")
|
||||||
|
|
||||||
|
project(gbmanager VERSION "1.0.0" LANGUAGES C CXX ASM)
|
||||||
|
|
||||||
|
|
||||||
|
# Initialise the Raspberry Pi Pico SDK
|
||||||
|
pico_sdk_init()
|
||||||
|
|
||||||
|
add_subdirectory(modules/pico-onewire)
|
||||||
|
add_subdirectory(src)
|
23
README.md
23
README.md
|
@ -20,10 +20,27 @@ Die Kosten für die Bauteile belaufen sich auf ca. 23 €.
|
||||||
Die Software ist derzeit noch rudimentär gehalten. Die Temperatur wird perodisch ausgelesen und die Heizmatte entsprechend der Zieltemperatur an- oder ausgeschaltet. Über Interrupts wird auf drei Drucktaster reagiert. Dadurch können (derzeit) die Zieltemperatur eingestellt sowie die Heizungsregelung (de)aktiviert werden.
|
Die Software ist derzeit noch rudimentär gehalten. Die Temperatur wird perodisch ausgelesen und die Heizmatte entsprechend der Zieltemperatur an- oder ausgeschaltet. Über Interrupts wird auf drei Drucktaster reagiert. Dadurch können (derzeit) die Zieltemperatur eingestellt sowie die Heizungsregelung (de)aktiviert werden.
|
||||||
|
|
||||||
### Verwendete Bibliotheken
|
### Verwendete Bibliotheken
|
||||||
Für die Ansteuerung des LCD wird `rpi-pico-i2c-lcd` von _T-622_ ([Github](https://github.com/t-622/rpi-pico-i2c-lcd)) verwendet, das wiederum auf `python_lcd` von _dhylands_ ([Github](https://github.com/dhylands/python_lcd)) basiert. Letzteres steht unter der MIT-Lizenz. `rpi-pico-i2c-lcd` ist ohne Lizenzangabe. Die entspechenden Dateien liegen der Einfachheit halber im `lib` Unterverzeichnis.
|
Die C++-Implementierung, die bei Bedarf weiterentwickelt wird, verwendet zur Ansteuerung des Temperatursensors die `pico-onewire` Bibliothek von Adam Boardman ([Github](https://github.com/adamboardman/pico-onewire)).
|
||||||
|
|
||||||
|
_Hinweis_: Die ältere Python-Implementierung ist zu Dokumentationszwecken noch im Unterverzeichnis "micropython" zu finden. Wahrscheinlich wird diese nicht mehr weiterentwickelt.
|
||||||
|
Für die Ansteuerung des LCD wird `rpi-pico-i2c-lcd` von _T-622_ ([Github](https://github.com/t-622/rpi-pico-i2c-lcd)) verwendet, das wiederum auf `python_lcd` von _dhylands_ ([Github](https://github.com/dhylands/python_lcd)) basiert. Die entspechenden Dateien liegen der Einfachheit halber im `lib` Unterverzeichnis.
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
Am einfachsten ist es, mittels [Thonny](https://thonny.org/) die Datei `main.py` sowie den `lib`-Ordner ins Hauptverzichnis des Picos zu kopieren. Auf dem Pico muss natürlich MicroPython installiert sein. Fertig.
|
Zunächst wird das Repository geklont sowie die Submodules initialisiert:
|
||||||
|
```
|
||||||
|
$ git clone https://git.rustysoft.de/martin/gbmanager.git
|
||||||
|
$ cd gbmanager
|
||||||
|
$ git submodule init
|
||||||
|
$ git submodule update
|
||||||
|
```
|
||||||
|
|
||||||
|
Mit den folgenden Kommandos wird die Firmware compiliert:
|
||||||
|
```
|
||||||
|
$ mkdir build && cd build
|
||||||
|
$ cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||||
|
$ make
|
||||||
|
```
|
||||||
|
Im src-Unterverzeichnis (des build-Verzeichnisses!) ist nun UF2-Datei `gbmanager.uf2` vorhanden. Diese muss nun nur noch auf den Pico kopiert werden.
|
||||||
|
|
||||||
# Aufbau
|
# Aufbau
|
||||||
Die zum Aufbau notwendigen Informationen bzw. Dateien befinden sich in diesem Repository.
|
Die zum Aufbau notwendigen Informationen bzw. Dateien befinden sich in diesem Repository.
|
||||||
|
@ -41,4 +58,4 @@ Im Verzeichnis _FreeCAD_ befindet sich das entsprechende CAD-Projekt sowie die d
|
||||||
|
|
||||||
Das Gerät wird über ein microUSB-Kabel mit einem 5V Netzteil, wie man es zum Aufladen von Smartphones verwendet, verbunden. Der Raspberry Pi Pico benötigt sehr wenig Strom, es genügt daher ein "schwaches" Netzteil. Der Euro-Stromstecker kommt an die Steckdose. Damit ist (über ein Relais) das andere Stromkabel, das mit einer Euro-Buchse versehen ist, verbunden. An diese Buchse wiederum kommt die Heizmatte. Das letzte Kabel – in meinem Fall das hellgraue – ist der Temperaturfühler. Dieses muss über eine Bohrung o. ä. in die Gärbox eingeführt werden, so dass eine Temperaturerfassung des Innenraums möglich ist.
|
Das Gerät wird über ein microUSB-Kabel mit einem 5V Netzteil, wie man es zum Aufladen von Smartphones verwendet, verbunden. Der Raspberry Pi Pico benötigt sehr wenig Strom, es genügt daher ein "schwaches" Netzteil. Der Euro-Stromstecker kommt an die Steckdose. Damit ist (über ein Relais) das andere Stromkabel, das mit einer Euro-Buchse versehen ist, verbunden. An diese Buchse wiederum kommt die Heizmatte. Das letzte Kabel – in meinem Fall das hellgraue – ist der Temperaturfühler. Dieses muss über eine Bohrung o. ä. in die Gärbox eingeführt werden, so dass eine Temperaturerfassung des Innenraums möglich ist.
|
||||||
|
|
||||||
Mit den blauen Tasten stellt man die gewünschte Temperatur ein. Rot schaltet die Heizungssteuerung ein/aus. Ein ">H<" zeigt an, ob gerade geheizt wird.
|
Mit den blauen Tasten stellt man die gewünschte Temperatur ein. Rot schaltet die Heizungssteuerung ein/aus. Ein ">H<" zeigt an, ob gerade geheizt wird.
|
||||||
|
|
73
cmake/pico_sdk_import.cmake
Normal file
73
cmake/pico_sdk_import.cmake
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
|
||||||
|
|
||||||
|
# This can be dropped into an external project to help locate this SDK
|
||||||
|
# It should be include()ed prior to project()
|
||||||
|
|
||||||
|
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
|
||||||
|
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
|
||||||
|
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
|
||||||
|
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
|
||||||
|
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
|
||||||
|
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
|
||||||
|
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
|
||||||
|
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
|
||||||
|
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
|
||||||
|
|
||||||
|
if (NOT PICO_SDK_PATH)
|
||||||
|
if (PICO_SDK_FETCH_FROM_GIT)
|
||||||
|
include(FetchContent)
|
||||||
|
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
|
||||||
|
if (PICO_SDK_FETCH_FROM_GIT_PATH)
|
||||||
|
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
|
||||||
|
endif ()
|
||||||
|
# GIT_SUBMODULES_RECURSE was added in 3.17
|
||||||
|
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
|
||||||
|
FetchContent_Declare(
|
||||||
|
pico_sdk
|
||||||
|
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||||
|
GIT_TAG master
|
||||||
|
GIT_SUBMODULES_RECURSE FALSE
|
||||||
|
)
|
||||||
|
else ()
|
||||||
|
FetchContent_Declare(
|
||||||
|
pico_sdk
|
||||||
|
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||||
|
GIT_TAG master
|
||||||
|
)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (NOT pico_sdk)
|
||||||
|
message("Downloading Raspberry Pi Pico SDK")
|
||||||
|
FetchContent_Populate(pico_sdk)
|
||||||
|
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
|
||||||
|
endif ()
|
||||||
|
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
|
||||||
|
else ()
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
|
||||||
|
)
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||||
|
if (NOT EXISTS ${PICO_SDK_PATH})
|
||||||
|
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
|
||||||
|
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
|
||||||
|
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
|
||||||
|
|
||||||
|
include(${PICO_SDK_INIT_CMAKE_FILE})
|
1
modules/pico-onewire
Submodule
1
modules/pico-onewire
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit d5af2a1e1d81c3cb21805e332c8185607ee74b1d
|
34
src/CMakeLists.txt
Normal file
34
src/CMakeLists.txt
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
configure_file(${CMAKE_CURRENT_LIST_DIR}/config.h.in ${PROJECT_BINARY_DIR}/src/config.h)
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
gbmanager.cpp
|
||||||
|
lcd.cpp
|
||||||
|
relais.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add executable. Default name is the project name, version 0.1
|
||||||
|
add_executable(${CMAKE_PROJECT_NAME} ${SOURCES})
|
||||||
|
|
||||||
|
pico_set_program_name(${CMAKE_PROJECT_NAME} "gbmanager")
|
||||||
|
pico_set_program_version(${CMAKE_PROJECT_NAME} ${PROJECT_VERSION})
|
||||||
|
|
||||||
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
|
pico_enable_stdio_uart(${CMAKE_PROJECT_NAME} 1)
|
||||||
|
pico_enable_stdio_usb(${CMAKE_PROJECT_NAME} 0)
|
||||||
|
else()
|
||||||
|
pico_enable_stdio_uart(${CMAKE_PROJECT_NAME} 0)
|
||||||
|
pico_enable_stdio_usb(${CMAKE_PROJECT_NAME} 0)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
pico_generate_pio_header(${CMAKE_PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/ds18b20.pio)
|
||||||
|
|
||||||
|
# Add the standard library to the build
|
||||||
|
target_link_libraries(${CMAKE_PROJECT_NAME} pico_stdlib pico_one_wire)
|
||||||
|
|
||||||
|
# Add any user requested libraries
|
||||||
|
target_link_libraries(${CMAKE_PROJECT_NAME}
|
||||||
|
hardware_i2c
|
||||||
|
hardware_gpio
|
||||||
|
)
|
||||||
|
|
||||||
|
pico_add_extra_outputs(${CMAKE_PROJECT_NAME})
|
6
src/config.h.in
Normal file
6
src/config.h.in
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef CONFIG_H
|
||||||
|
#define CONFIG_H
|
||||||
|
|
||||||
|
#cmakedefine PROJECT_VERSION "@PROJECT_VERSION@"
|
||||||
|
|
||||||
|
#endif
|
73
src/ds18b20.cpp
Normal file
73
src/ds18b20.cpp
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#include "ds18b20.h"
|
||||||
|
|
||||||
|
DS18B20::DS18B20(PIO pio, uint8_t gpio) : pio{pio}, gpio{gpio} {
|
||||||
|
uint offset = pio_add_program(pio, &ds18b20_program);
|
||||||
|
stateMachineIndex = pio_claim_unused_sm(pio, true);
|
||||||
|
pio_gpio_init(pio, gpio);
|
||||||
|
pio_sm_config c = ds18b20_program_get_default_config(offset);
|
||||||
|
sm_config_set_clkdiv_int_frac(&c, 255, 0);
|
||||||
|
sm_config_set_set_pins(&c, gpio, 1);
|
||||||
|
sm_config_set_out_pins(&c, gpio, 1);
|
||||||
|
sm_config_set_in_pins(&c, gpio);
|
||||||
|
sm_config_set_in_shift(&c, true, true, 8);
|
||||||
|
pio_sm_init(pio0, stateMachineIndex, offset, &c);
|
||||||
|
pio_sm_set_enabled(pio0, stateMachineIndex, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DS18B20::writeBytes(uint8_t bytes[], int len) {
|
||||||
|
pio_sm_put_blocking(pio, stateMachineIndex, 250);
|
||||||
|
pio_sm_put_blocking(pio, stateMachineIndex, len - 1);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
pio_sm_put_blocking(pio, stateMachineIndex, bytes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DS18B20::readBytes(uint8_t bytes[], int len) {
|
||||||
|
pio_sm_put_blocking(pio, stateMachineIndex, 0);
|
||||||
|
pio_sm_put_blocking(pio, stateMachineIndex, len - 1);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
bytes[i] = pio_sm_get_blocking(pio, stateMachineIndex) >> 24;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DS18B20::convert() {
|
||||||
|
uint8_t d[2] = {0xCC, 0x44};
|
||||||
|
writeBytes(d, 2);
|
||||||
|
sleep_ms(750);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DS18B20::crc8(uint8_t *data, uint8_t len) {
|
||||||
|
uint8_t i;
|
||||||
|
uint8_t j;
|
||||||
|
uint8_t temp;
|
||||||
|
uint8_t databyte;
|
||||||
|
uint8_t crc = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
databyte = data[i];
|
||||||
|
for (j = 0; j < 8; j++) {
|
||||||
|
temp = (crc ^ databyte) & 0x01;
|
||||||
|
crc >>= 1;
|
||||||
|
if (temp)
|
||||||
|
crc ^= 0x8C;
|
||||||
|
databyte >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
float DS18B20::getTemperature() {
|
||||||
|
uint8_t d[2] = {0xCC, 0xBE};
|
||||||
|
writeBytes(d, 2);
|
||||||
|
uint8_t data[9];
|
||||||
|
readBytes(data, 9);
|
||||||
|
uint8_t crc = crc8(data, 9);
|
||||||
|
if (crc != 0)
|
||||||
|
return -2000;
|
||||||
|
int t1 = data[0];
|
||||||
|
int t2 = data[1];
|
||||||
|
int16_t temp1 = (t2 << 8 | t1);
|
||||||
|
volatile float temp = (float)temp1 / 16;
|
||||||
|
return temp;
|
||||||
|
}
|
23
src/ds18b20.h
Normal file
23
src/ds18b20.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef DS18B20_H
|
||||||
|
#define DS18B20_H
|
||||||
|
|
||||||
|
#include "ds18b20.pio.h"
|
||||||
|
#include "hardware/gpio.h"
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
|
class DS18B20 {
|
||||||
|
public:
|
||||||
|
DS18B20(PIO pio, uint8_t gpio);
|
||||||
|
float getTemperature();
|
||||||
|
void convert();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t crc8(uint8_t *data, uint8_t len);
|
||||||
|
void writeBytes(uint8_t bytes[], int len);
|
||||||
|
void readBytes(uint8_t bytes[], int len);
|
||||||
|
PIO pio;
|
||||||
|
uint8_t gpio;
|
||||||
|
uint stateMachineIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
44
src/ds18b20.pio
Normal file
44
src/ds18b20.pio
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
|
||||||
|
.program ds18b20
|
||||||
|
.wrap_target
|
||||||
|
again:
|
||||||
|
pull block
|
||||||
|
mov x, osr
|
||||||
|
jmp !x, read
|
||||||
|
|
||||||
|
write: set pindirs, 1
|
||||||
|
set pins, 0
|
||||||
|
loop1:
|
||||||
|
jmp x--,loop1
|
||||||
|
set pindirs, 0 [31]
|
||||||
|
wait 1 pin 0 [31]
|
||||||
|
|
||||||
|
pull block
|
||||||
|
mov x, osr
|
||||||
|
bytes1:
|
||||||
|
pull block
|
||||||
|
set y, 7
|
||||||
|
set pindirs, 1
|
||||||
|
bit1:
|
||||||
|
set pins, 0 [1]
|
||||||
|
out pins,1 [31]
|
||||||
|
set pins, 1 [20]
|
||||||
|
jmp y--,bit1
|
||||||
|
jmp x--,bytes1
|
||||||
|
|
||||||
|
set pindirs, 0 [31]
|
||||||
|
jmp again
|
||||||
|
|
||||||
|
read:
|
||||||
|
pull block
|
||||||
|
mov x, osr
|
||||||
|
bytes2:
|
||||||
|
set y, 7
|
||||||
|
bit2:
|
||||||
|
set pindirs, 1
|
||||||
|
set pins, 0 [1]
|
||||||
|
set pindirs, 0 [5]
|
||||||
|
in pins,1 [10]
|
||||||
|
jmp y--,bit2
|
||||||
|
jmp x--,bytes2
|
||||||
|
.wrap
|
125
src/gbmanager.cpp
Normal file
125
src/gbmanager.cpp
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "../modules/pico-onewire/api/one_wire.h"
|
||||||
|
#include "hardware/i2c.h"
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "lcd.h"
|
||||||
|
#include "relais.h"
|
||||||
|
|
||||||
|
// GPIOs used
|
||||||
|
constexpr uint I2C_SDA_PIN = 26;
|
||||||
|
constexpr uint I2C_SCL_PIN = 27;
|
||||||
|
constexpr uint DS18B20_PIN = 28;
|
||||||
|
constexpr uint RELAIS_PIN = 18;
|
||||||
|
constexpr uint BUTTON_1_PIN = 17;
|
||||||
|
constexpr uint BUTTON_2_PIN = 16;
|
||||||
|
constexpr uint BUTTON_3_PIN = 15;
|
||||||
|
|
||||||
|
// Custom chars for the LCD
|
||||||
|
constexpr char CUSTOM_CHAR_DEG = 0xDF;
|
||||||
|
constexpr char CUSTOM_CHAR_AE = 0xE1;
|
||||||
|
|
||||||
|
// Global variables which have to be accessed by callback function
|
||||||
|
bool isSystemOn = false;
|
||||||
|
float temp_tgt{28.0};
|
||||||
|
absolute_time_t lastPressed = get_absolute_time();
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
void buttonPressedCallback(uint gpio, uint32_t events) {
|
||||||
|
if (absolute_time_diff_us(lastPressed, get_absolute_time()) < 750000) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
lastPressed = get_absolute_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (gpio) {
|
||||||
|
case BUTTON_1_PIN:
|
||||||
|
temp_tgt -= 0.5;
|
||||||
|
break;
|
||||||
|
case BUTTON_2_PIN:
|
||||||
|
temp_tgt += 0.5;
|
||||||
|
break;
|
||||||
|
case BUTTON_3_PIN:
|
||||||
|
isSystemOn = !isSystemOn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Enable UART so we can print status output
|
||||||
|
stdio_init_all();
|
||||||
|
|
||||||
|
// Initialize the LCD
|
||||||
|
auto myLCD = LCD(i2c1, I2C_SDA_PIN, I2C_SCL_PIN);
|
||||||
|
myLCD.clear();
|
||||||
|
|
||||||
|
// Initialize the temp sensor
|
||||||
|
One_wire oneWire(DS18B20_PIN);
|
||||||
|
oneWire.init();
|
||||||
|
rom_address_t address{};
|
||||||
|
oneWire.single_device_read_rom(address);
|
||||||
|
|
||||||
|
// Initialize the relais
|
||||||
|
Relais relais(RELAIS_PIN);
|
||||||
|
|
||||||
|
// Initialize the Buttons
|
||||||
|
gpio_set_irq_enabled_with_callback(BUTTON_1_PIN, GPIO_IRQ_EDGE_FALL, true,
|
||||||
|
&buttonPressedCallback);
|
||||||
|
gpio_set_irq_enabled_with_callback(BUTTON_2_PIN, GPIO_IRQ_EDGE_FALL, true,
|
||||||
|
&buttonPressedCallback);
|
||||||
|
gpio_set_irq_enabled_with_callback(BUTTON_3_PIN, GPIO_IRQ_EDGE_FALL, true,
|
||||||
|
&buttonPressedCallback);
|
||||||
|
|
||||||
|
float temp_act{0};
|
||||||
|
float temp_diff{0.5};
|
||||||
|
std::stringstream lcdText{};
|
||||||
|
bool isHeating = false;
|
||||||
|
string heatInfo{""};
|
||||||
|
string systemInfo{""};
|
||||||
|
|
||||||
|
lcdText << " G" << CUSTOM_CHAR_AE << "rbox Manager\n (Ver. "
|
||||||
|
<< PROJECT_VERSION << ")";
|
||||||
|
myLCD.sendString(lcdText.str());
|
||||||
|
sleep_ms(3000);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
absolute_time_t start = get_absolute_time();
|
||||||
|
oneWire.convert_temperature(address, true, false);
|
||||||
|
temp_act = oneWire.temperature(address);
|
||||||
|
|
||||||
|
if (isSystemOn && temp_act < temp_tgt - temp_diff) {
|
||||||
|
isHeating = true;
|
||||||
|
} else if (isSystemOn && temp_act > temp_tgt + temp_diff) {
|
||||||
|
isHeating = false;
|
||||||
|
} else if (!isSystemOn) {
|
||||||
|
isHeating = false;
|
||||||
|
}
|
||||||
|
isHeating ? heatInfo = ">H<" : heatInfo = " ";
|
||||||
|
isSystemOn ? systemInfo = "ON " : systemInfo = "OFF";
|
||||||
|
|
||||||
|
relais.activate(isHeating);
|
||||||
|
|
||||||
|
lcdText.str("");
|
||||||
|
lcdText.clear();
|
||||||
|
lcdText.precision(4);
|
||||||
|
lcdText << "ACT: " << temp_act << CUSTOM_CHAR_DEG << "C " << heatInfo
|
||||||
|
<< "\n"
|
||||||
|
<< "TGT: " << temp_tgt << CUSTOM_CHAR_DEG << "C " << systemInfo;
|
||||||
|
|
||||||
|
myLCD.setCursor(0, 0);
|
||||||
|
myLCD.sendString(lcdText.str());
|
||||||
|
|
||||||
|
absolute_time_t stop = get_absolute_time();
|
||||||
|
|
||||||
|
int64_t duration_ms = absolute_time_diff_us(start, stop) / 1000;
|
||||||
|
int64_t timeToSleep = 1000 - duration_ms;
|
||||||
|
|
||||||
|
if (timeToSleep > 0)
|
||||||
|
sleep_ms(timeToSleep);
|
||||||
|
}
|
||||||
|
}
|
98
src/lcd.cpp
Normal file
98
src/lcd.cpp
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
#include "lcd.h"
|
||||||
|
|
||||||
|
// commands
|
||||||
|
constexpr int LCD_CLEARDISPLAY = 0x01;
|
||||||
|
constexpr int LCD_RETURNHOME = 0x02;
|
||||||
|
constexpr int LCD_ENTRYMODESET = 0x04;
|
||||||
|
constexpr int LCD_DISPLAYCONTROL = 0x08;
|
||||||
|
constexpr int LCD_CURSORSHIFT = 0x10;
|
||||||
|
constexpr int LCD_FUNCTIONSET = 0x20;
|
||||||
|
constexpr int LCD_SETCGRAMADDR = 0x40;
|
||||||
|
constexpr int LCD_SETDDRAMADDR = 0x80;
|
||||||
|
|
||||||
|
// flags for display entry mode
|
||||||
|
constexpr int LCD_ENTRYSHIFTINCREMENT = 0x01;
|
||||||
|
constexpr int LCD_ENTRYLEFT = 0x02;
|
||||||
|
|
||||||
|
// flags for display and cursor control
|
||||||
|
constexpr int LCD_BLINKON = 0x01;
|
||||||
|
constexpr int LCD_CURSORON = 0x02;
|
||||||
|
constexpr int LCD_DISPLAYON = 0x04;
|
||||||
|
|
||||||
|
// flags for function set
|
||||||
|
constexpr int LCD_5x10DOTS = 0x04;
|
||||||
|
constexpr int LCD_2LINE = 0x08;
|
||||||
|
constexpr int LCD_8BITMODE = 0x10;
|
||||||
|
|
||||||
|
constexpr int LCD_BACKLIGHT = 0x08;
|
||||||
|
constexpr int LCD_ENABLE_BIT = 0x04;
|
||||||
|
|
||||||
|
LCD::LCD(i2c_inst_t *i2c, const uint gpio_sda, const uint gpio_scl,
|
||||||
|
const uint8_t i2c_addr, uint8_t num_cols, uint8_t num_lines)
|
||||||
|
: i2c{i2c}, i2c_addr{i2c_addr}, num_cols{num_cols}, num_lines{num_lines} {
|
||||||
|
i2c_init(i2c1, 100 * 1000);
|
||||||
|
gpio_set_function(gpio_sda, GPIO_FUNC_I2C);
|
||||||
|
gpio_set_function(gpio_scl, GPIO_FUNC_I2C);
|
||||||
|
gpio_pull_up(gpio_sda);
|
||||||
|
gpio_pull_up(gpio_scl);
|
||||||
|
|
||||||
|
sendByte(0x03, Mode::COMMAND);
|
||||||
|
sendByte(0x03, Mode::COMMAND);
|
||||||
|
sendByte(0x03, Mode::COMMAND);
|
||||||
|
sendByte(0x02, Mode::COMMAND);
|
||||||
|
|
||||||
|
sendByte(LCD_ENTRYMODESET | LCD_ENTRYLEFT, Mode::COMMAND);
|
||||||
|
sendByte(LCD_FUNCTIONSET | LCD_2LINE, Mode::COMMAND);
|
||||||
|
sendByte(LCD_DISPLAYCONTROL | LCD_DISPLAYON, Mode::COMMAND);
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go to location on LCD
|
||||||
|
void LCD::setCursor(int line, int position) {
|
||||||
|
int val = (line == 0) ? 0x80 + position : 0xC0 + position;
|
||||||
|
sendByte(val, Mode::COMMAND);
|
||||||
|
cursor_x = line;
|
||||||
|
cursor_y = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LCD::sendChar(char val) { sendByte(val, Mode::CHARACTER); }
|
||||||
|
|
||||||
|
void LCD::sendString(const std::string &str) {
|
||||||
|
for (const char &c : str) {
|
||||||
|
if (c == '\n') {
|
||||||
|
cursor_y++;
|
||||||
|
setCursor(cursor_y, 0);
|
||||||
|
} else {
|
||||||
|
sendChar(c);
|
||||||
|
cursor_x++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LCD::clear() { sendByte(LCD_CLEARDISPLAY, Mode::COMMAND); }
|
||||||
|
|
||||||
|
void LCD::i2cWriteByte(uint8_t val) {
|
||||||
|
i2c_write_blocking(i2c, i2c_addr, &val, 1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LCD::toggleEnable(uint8_t val) {
|
||||||
|
// Toggle enable pin on LCD display
|
||||||
|
// We cannot do this too quickly or things don't work
|
||||||
|
constexpr uint64_t DELAY_US = 600;
|
||||||
|
sleep_us(DELAY_US);
|
||||||
|
i2cWriteByte(val | LCD_ENABLE_BIT);
|
||||||
|
sleep_us(DELAY_US);
|
||||||
|
i2cWriteByte(val & ~LCD_ENABLE_BIT);
|
||||||
|
sleep_us(DELAY_US);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The display is sent a byte as two separate nibble transfers
|
||||||
|
void LCD::sendByte(uint8_t val, Mode mode) {
|
||||||
|
uint8_t high = static_cast<int>(mode) | (val & 0xF0) | LCD_BACKLIGHT;
|
||||||
|
uint8_t low = static_cast<int>(mode) | ((val << 4) & 0xF0) | LCD_BACKLIGHT;
|
||||||
|
|
||||||
|
i2cWriteByte(high);
|
||||||
|
toggleEnable(high);
|
||||||
|
i2cWriteByte(low);
|
||||||
|
toggleEnable(low);
|
||||||
|
}
|
33
src/lcd.h
Normal file
33
src/lcd.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef LCD_H
|
||||||
|
#define LCD_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "hardware/i2c.h"
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
|
class LCD {
|
||||||
|
public:
|
||||||
|
LCD(i2c_inst_t *i2c, const uint gpio_sda, const uint gpio_scl,
|
||||||
|
const uint8_t i2c_addr = 0x27, uint8_t num_cols = 16,
|
||||||
|
uint8_t num_lines = 2);
|
||||||
|
|
||||||
|
void sendString(const std::string &str);
|
||||||
|
void setCursor(int line, int position);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class Mode { COMMAND, CHARACTER };
|
||||||
|
void sendByte(uint8_t val, Mode mode);
|
||||||
|
void toggleEnable(uint8_t val);
|
||||||
|
void i2cWriteByte(uint8_t val);
|
||||||
|
void sendChar(char val);
|
||||||
|
i2c_inst_t *i2c;
|
||||||
|
uint8_t i2c_addr;
|
||||||
|
uint8_t num_cols;
|
||||||
|
uint8_t num_lines;
|
||||||
|
uint8_t cursor_x{0};
|
||||||
|
uint8_t cursor_y{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
13
src/relais.cpp
Normal file
13
src/relais.cpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#include "relais.h"
|
||||||
|
|
||||||
|
Relais::Relais(uint gpio) : gpio{gpio} {
|
||||||
|
gpio_init(gpio);
|
||||||
|
gpio_set_dir(gpio, GPIO_OUT);
|
||||||
|
off();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Relais::activate(bool active) { gpio_put(gpio, !active); }
|
||||||
|
|
||||||
|
void Relais::on() { activate(true); }
|
||||||
|
|
||||||
|
void Relais::off() { activate(false); }
|
18
src/relais.h
Normal file
18
src/relais.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef RELAIS_H
|
||||||
|
#define RELAIS_H
|
||||||
|
|
||||||
|
#include "hardware/gpio.h"
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
|
class Relais {
|
||||||
|
public:
|
||||||
|
Relais(uint gpio);
|
||||||
|
void activate(bool active);
|
||||||
|
void on();
|
||||||
|
void off();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint gpio;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue