Compare commits

...

33 Commits

Author SHA1 Message Date
Martin Brodbeck 76d464c8cc more build info 2022-06-01 21:53:44 +02:00
Martin Brodbeck c9a6729ba7 readme updated 2022-06-01 21:50:39 +02:00
Martin Brodbeck 44a00db6b9 only enable uart for debug mode 2022-06-01 21:36:10 +02:00
Martin Brodbeck d6ea24685b Fixed logic error in relais 2022-06-01 21:14:22 +02:00
Martin Brodbeck bde19fd2b7 button logic finished
Now on par with Python implementation
2022-06-01 14:56:02 +02:00
Martin Brodbeck 278de69a16 button logic (WIP) 2022-06-01 14:31:17 +02:00
Martin Brodbeck 684ac6f884 code cleanup 2022-06-01 13:42:47 +02:00
Martin Brodbeck 48b9fb5015 sleep logic implemented 2022-06-01 13:38:22 +02:00
Martin Brodbeck 8bde85723d use 3rd party lib for ds18b20 2022-06-01 13:10:01 +02:00
Martin Brodbeck 9f261ddac7 use 3rd party lib for ds18b20 2022-06-01 13:09:17 +02:00
Martin Brodbeck dfa5713fb5 move sleep to convert method 2022-05-31 16:06:48 +02:00
Martin Brodbeck 39bac21110 use more descriptive constant 2022-05-31 15:59:22 +02:00
Martin Brodbeck 5e7877b5d8 typo 2022-05-31 15:31:18 +02:00
Martin Brodbeck ba95eeebb9 make mode invisible 2022-05-31 15:25:59 +02:00
Martin Brodbeck d6d91f4cb2 cmake improved 2022-05-31 15:22:04 +02:00
Martin Brodbeck 91e1a7d424 restructured 2022-05-31 15:13:00 +02:00
Martin Brodbeck 2f7d1dd921 code beautifying 2022-05-31 14:28:15 +02:00
Martin Brodbeck d354be1077 relais added 2022-05-31 13:53:19 +02:00
Martin Brodbeck 8b58b3a443 heating logic 2022-05-31 13:01:10 +02:00
Martin Brodbeck 7ca6b69f9d version info added 2022-05-31 13:00:33 +02:00
Martin Brodbeck cbbf0b77e7 some basic work implemented 2022-05-31 12:31:29 +02:00
Martin Brodbeck efee152c5c cursor positioning 2022-05-31 12:29:45 +02:00
Martin Brodbeck 5c68445c4d format fallback 2022-05-31 09:47:59 +02:00
Martin Brodbeck 440359d775 clang-format 2022-05-31 09:47:43 +02:00
Martin Brodbeck 275e012695 ds18b20 code added 2022-05-31 09:47:29 +02:00
Martin Brodbeck b1c0b0292b clang-format added 2022-05-31 09:47:03 +02:00
Martin Brodbeck a52c1b94b8 More on LCD 2022-05-30 21:36:56 +02:00
Martin Brodbeck 0a48d09436 More on LCD class 2022-05-30 21:33:48 +02:00
Martin Brodbeck b084a2df64 using LCD class 2022-05-30 16:09:42 +02:00
Martin Brodbeck 165e9912dd LCD class 2022-05-30 16:09:23 +02:00
Martin Brodbeck 55c3b0f80a LCD class introduced 2022-05-30 16:09:09 +02:00
Martin Brodbeck a5e3e3c671 using environment variable (portability) 2022-05-30 14:16:10 +02:00
Martin Brodbeck 6707c4d19f Starting work on C++ 2022-05-30 14:10:48 +02:00
26 changed files with 844 additions and 3 deletions

179
.clang-format Normal file
View 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
View File

@ -0,0 +1 @@
build/

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "modules/pico-onewire"]
path = modules/pico-onewire
url = https://github.com/adamboardman/pico-onewire.git

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

18
.vscode/c_cpp_properties.json vendored Normal file
View 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
View File

@ -0,0 +1,7 @@
{
"recommendations": [
"marus25.cortex-debug",
"ms-vscode.cmake-tools",
"ms-vscode.cpptools"
]
}

31
.vscode/launch.json vendored Normal file
View 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
View 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
View 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)

View File

@ -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.
### 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
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
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.
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.

View 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

@ -0,0 +1 @@
Subproject commit d5af2a1e1d81c3cb21805e332c8185607ee74b1d

34
src/CMakeLists.txt Normal file
View 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
View File

@ -0,0 +1,6 @@
#ifndef CONFIG_H
#define CONFIG_H
#cmakedefine PROJECT_VERSION "@PROJECT_VERSION@"
#endif

73
src/ds18b20.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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