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.

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