Initial Comit

This commit is contained in:
tobid7 2025-06-12 10:04:45 +02:00
commit abffaf43ec
28 changed files with 14670 additions and 0 deletions

4
.gitignore vendored Executable file
View File

@ -0,0 +1,4 @@
build
!.vscode/*
include/wifi.hpp
.DS_Store

6
.gitmodules vendored Normal file
View File

@ -0,0 +1,6 @@
[submodule "vendor/bme280"]
path = vendor/bme280
url = https://dev.npid7.de/pico_stuff/bme280
[submodule "vendor/pico-fatfs"]
path = vendor/pico-fatfs
url = https://github.com/carlk3/no-OS-FatFS-SD-SDIO-SPI-RPi-Pico

22
.vscode/c_cpp_properties.json vendored Executable file
View File

@ -0,0 +1,22 @@
{
"configurations": [
{
"name": "Pico",
"includePath": [
"${workspaceFolder}/**",
"${userHome}/.pico-sdk/sdk/2.1.1/**"
],
"forcedInclude": [
"${userHome}/.pico-sdk/sdk/2.1.1/src/common/pico_base_headers/include/pico.h",
"${workspaceFolder}/build/generated/pico_base/pico/config_autogen.h"
],
"defines": [],
"compilerPath": "${userHome}/.pico-sdk/toolchain/14_2_Rel1/bin/arm-none-eabi-gcc",
"compileCommands": "${workspaceFolder}/build/compile_commands.json",
"cStandard": "c17",
"cppStandard": "c++14",
"intelliSenseMode": "linux-gcc-arm"
}
],
"version": 4
}

15
.vscode/cmake-kits.json vendored Executable file
View File

@ -0,0 +1,15 @@
[
{
"name": "Pico",
"compilers": {
"C": "${command:raspberry-pi-pico.getCompilerPath}",
"CXX": "${command:raspberry-pi-pico.getCxxCompilerPath}"
},
"environmentVariables": {
"PATH": "${command:raspberry-pi-pico.getEnvPath};${env:PATH}"
},
"cmakeSettings": {
"Python3_EXECUTABLE": "${command:raspberry-pi-pico.getPythonPath}"
}
}
]

9
.vscode/extensions.json vendored Executable file
View File

@ -0,0 +1,9 @@
{
"recommendations": [
"marus25.cortex-debug",
"ms-vscode.vscode-serial-monitor",
"raspberry-pi.raspberry-pi-pico",
"ms-vscode.cpptools",
"ms-vscode.cpptools-extension-pack"
]
}

70
.vscode/launch.json vendored Executable file
View File

@ -0,0 +1,70 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Pico Debug (Cortex-Debug)",
"cwd": "${userHome}/.pico-sdk/openocd/0.12.0+dev/scripts",
"executable": "${command:raspberry-pi-pico.launchTargetPath}",
"request": "launch",
"type": "cortex-debug",
"servertype": "openocd",
"serverpath": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
"gdbPath": "${command:raspberry-pi-pico.getGDBPath}",
"device": "${command:raspberry-pi-pico.getChipUppercase}",
"configFiles": [
"interface/cmsis-dap.cfg",
"target/${command:raspberry-pi-pico.getTarget}.cfg"
],
"svdFile": "${userHome}/.pico-sdk/sdk/2.1.1/src/${command:raspberry-pi-pico.getChip}/hardware_regs/${command:raspberry-pi-pico.getChipUppercase}.svd",
"runToEntryPoint": "main",
// Fix for no_flash binaries, where monitor reset halt doesn't do what is expected
// Also works fine for flash binaries
"overrideLaunchCommands": [
"monitor reset init",
"load \"${command:raspberry-pi-pico.launchTargetPath}\""
],
"openOCDLaunchCommands": [
"adapter speed 5000"
]
},
{
"name": "Pico Debug (Cortex-Debug with external OpenOCD)",
"cwd": "${workspaceRoot}",
"executable": "${command:raspberry-pi-pico.launchTargetPath}",
"request": "launch",
"type": "cortex-debug",
"servertype": "external",
"gdbTarget": "localhost:3333",
"gdbPath": "${command:raspberry-pi-pico.getGDBPath}",
"device": "${command:raspberry-pi-pico.getChipUppercase}",
"svdFile": "${userHome}/.pico-sdk/sdk/2.1.1/src/${command:raspberry-pi-pico.getChip}/hardware_regs/${command:raspberry-pi-pico.getChipUppercase}.svd",
"runToEntryPoint": "main",
// Fix for no_flash binaries, where monitor reset halt doesn't do what is expected
// Also works fine for flash binaries
"overrideLaunchCommands": [
"monitor reset init",
"load \"${command:raspberry-pi-pico.launchTargetPath}\""
]
},
{
"name": "Pico Debug (C++ Debugger)",
"type": "cppdbg",
"request": "launch",
"cwd": "${workspaceRoot}",
"program": "${command:raspberry-pi-pico.launchTargetPath}",
"MIMode": "gdb",
"miDebuggerPath": "${command:raspberry-pi-pico.getGDBPath}",
"miDebuggerServerAddress": "localhost:3333",
"debugServerPath": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
"debugServerArgs": "-f interface/cmsis-dap.cfg -f target/${command:raspberry-pi-pico.getTarget}.cfg -c \"adapter speed 5000\"",
"serverStarted": "Listening on port .* for gdb connections",
"filterStderr": true,
"hardwareBreakpoints": {
"require": true,
"limit": 4
},
"preLaunchTask": "Flash",
"svdPath": "${userHome}/.pico-sdk/sdk/2.1.1/src/${command:raspberry-pi-pico.getChip}/hardware_regs/${command:raspberry-pi-pico.getChipUppercase}.svd"
},
]
}

40
.vscode/settings.json vendored Executable file
View File

@ -0,0 +1,40 @@
{
"cmake.showSystemKits": false,
"cmake.options.statusBarVisibility": "hidden",
"cmake.options.advanced": {
"build": {
"statusBarVisibility": "hidden"
},
"launch": {
"statusBarVisibility": "hidden"
},
"debug": {
"statusBarVisibility": "hidden"
}
},
"cmake.configureOnEdit": false,
"cmake.automaticReconfigure": false,
"cmake.configureOnOpen": false,
"cmake.generator": "Ninja",
"cmake.cmakePath": "${userHome}/.pico-sdk/cmake/v3.31.5/bin/cmake",
"C_Cpp.debugShortcut": false,
"terminal.integrated.env.windows": {
"PICO_SDK_PATH": "${env:USERPROFILE}/.pico-sdk/sdk/2.1.1",
"PICO_TOOLCHAIN_PATH": "${env:USERPROFILE}/.pico-sdk/toolchain/14_2_Rel1",
"Path": "${env:USERPROFILE}/.pico-sdk/toolchain/14_2_Rel1/bin;${env:USERPROFILE}/.pico-sdk/picotool/2.1.1/picotool;${env:USERPROFILE}/.pico-sdk/cmake/v3.31.5/bin;${env:USERPROFILE}/.pico-sdk/ninja/v1.12.1;${env:PATH}"
},
"terminal.integrated.env.osx": {
"PICO_SDK_PATH": "${env:HOME}/.pico-sdk/sdk/2.1.1",
"PICO_TOOLCHAIN_PATH": "${env:HOME}/.pico-sdk/toolchain/14_2_Rel1",
"PATH": "${env:HOME}/.pico-sdk/toolchain/14_2_Rel1/bin:${env:HOME}/.pico-sdk/picotool/2.1.1/picotool:${env:HOME}/.pico-sdk/cmake/v3.31.5/bin:${env:HOME}/.pico-sdk/ninja/v1.12.1:${env:PATH}"
},
"terminal.integrated.env.linux": {
"PICO_SDK_PATH": "${env:HOME}/.pico-sdk/sdk/2.1.1",
"PICO_TOOLCHAIN_PATH": "${env:HOME}/.pico-sdk/toolchain/14_2_Rel1",
"PATH": "${env:HOME}/.pico-sdk/toolchain/14_2_Rel1/bin:${env:HOME}/.pico-sdk/picotool/2.1.1/picotool:${env:HOME}/.pico-sdk/cmake/v3.31.5/bin:${env:HOME}/.pico-sdk/ninja/v1.12.1:${env:PATH}"
},
"raspberry-pi-pico.cmakeAutoConfigure": true,
"raspberry-pi-pico.useCmakeTools": false,
"raspberry-pi-pico.cmakePath": "${HOME}/.pico-sdk/cmake/v3.31.5/bin/cmake",
"raspberry-pi-pico.ninjaPath": "${HOME}/.pico-sdk/ninja/v1.12.1/ninja"
}

58
.vscode/tasks.json vendored Executable file
View File

@ -0,0 +1,58 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Compile Project",
"type": "process",
"isBuildCommand": true,
"command": "${userHome}/.pico-sdk/ninja/v1.12.1/ninja",
"args": ["-C", "${workspaceFolder}/build"],
"group": "build",
"presentation": {
"reveal": "always",
"panel": "dedicated"
},
"problemMatcher": "$gcc",
"windows": {
"command": "${env:USERPROFILE}/.pico-sdk/ninja/v1.12.1/ninja.exe"
}
},
{
"label": "Run Project",
"type": "process",
"command": "${env:HOME}/.pico-sdk/picotool/2.1.1/picotool/picotool",
"args": [
"load",
"${command:raspberry-pi-pico.launchTargetPath}",
"-fx"
],
"presentation": {
"reveal": "always",
"panel": "dedicated"
},
"problemMatcher": [],
"windows": {
"command": "${env:USERPROFILE}/.pico-sdk/picotool/2.1.1/picotool/picotool.exe"
}
},
{
"label": "Flash",
"type": "process",
"command": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
"args": [
"-s",
"${userHome}/.pico-sdk/openocd/0.12.0+dev/scripts",
"-f",
"interface/cmsis-dap.cfg",
"-f",
"target/${command:raspberry-pi-pico.getTarget}.cfg",
"-c",
"adapter speed 5000; program \"${command:raspberry-pi-pico.launchTargetPath}\" verify reset exit"
],
"problemMatcher": [],
"windows": {
"command": "${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
}
}
]
}

94
CMakeLists.txt Executable file
View File

@ -0,0 +1,94 @@
# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work ==
if(WIN32)
set(USERHOME $ENV{USERPROFILE})
else()
set(USERHOME $ENV{HOME})
endif()
set(sdkVersion 2.1.1)
set(toolchainVersion 14_2_Rel1)
set(picotoolVersion 2.1.1)
set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake)
if(EXISTS ${picoVscode})
include(${picoVscode})
endif()
# ====================================================================================
cmake_minimum_required(VERSION 3.23)
# Set C++ and C Standard
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED true)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# SDK Config dstuff
if(WIN32)
set(USERHOME $ENV{USERPROFILE})
else()
set(USERHOME $ENV{HOME})
endif()
set(sdkVersion 2.1.1)
set(toolchainVersion 14_2_Rel1)
set(picotoolVersion 2.1.1)
set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake)
if(EXISTS ${picoVscode})
include(${picoVscode})
endif()
# ====================================================================================
set(PICO_BOARD pico_w CACHE STRING "Board type")
# Pull in Raspberry Pi Pico SDK (must be before project)
include(cmake/pico_sdk_import.cmake)
project(Test LANGUAGES C CXX ASM)
# Disable std::format note during compiling
add_compile_options(-Wno-psabi)
# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()
# Include BME280 Library
add_subdirectory(vendor/bme280)
# Include FatFS
add_subdirectory(vendor/pico-fatfs/src)
add_executable(Test
source/main.cpp
source/hw_config.c
)
pico_set_program_name(Test "Test")
pico_set_program_version(Test "0.1")
# Modify the below lines to enable/disable output over UART/USB
pico_enable_stdio_uart(Test 0)
pico_enable_stdio_usb(Test 1)
# Add the standard include files to the build
target_include_directories(Test PRIVATE
${CMAKE_CURRENT_LIST_DIR}
include
include/configs
${PICO_LWIP_CONTRIB_PATH}/apps/httpd
)
# Add any user requested libraries
target_link_libraries(Test
pico_cyw43_arch_lwip_threadsafe_background
pico_lwip_http
pico_lwip_mdns
pico_stdlib
hardware_i2c
hardware_spi
bme280 # Link BME280 Library
no-OS-FatFS-SD-SDIO-SPI-RPi-Pico # Link FatFS
)
pico_add_extra_outputs(Test)

37
README.md Normal file
View File

@ -0,0 +1,37 @@
# Raspi Pico Temperaturüberwachung
## Doku
Docs and stuff can be found [here](doku/README.md)
## Hardware
- Raspiberry PI Pico
- BME/BMP 280 Sensor
- TFT Display (128x160)
- SD Reader (no card detect)
## Usage
Create a wifi.hpp in includes
```cpp
#pragma once
// Change this Data
#define WIFI_SSID "Zensiert"
#define WIFI_PASSWORD "ZensiertOderSo"
```
You also need to change the `CONFIG` Section in `main.cpp` if you changed the pin layout
### Build
```bash
cmake -B build --toolchain cmake/pico_sdk_import.cmake -G Ninja
cmake --build build
```
## External Dpendencies
- [BME280LIB](https://dev.npid7.de/pico_stuff/bme280)
- [FatFS](https://github.com/carlk3/no-OS-FatFS-SD-SDIO-SPI-RPi-Pico)

121
cmake/pico_sdk_import.cmake Executable file
View File

@ -0,0 +1,121 @@
# 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()
# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
# following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG))
set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG})
message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')")
endif ()
if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG)
set(PICO_SDK_FETCH_FROM_GIT_TAG "master")
message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG")
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")
set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for 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 ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
)
if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK")
# GIT_SUBMODULES_RECURSE was added in 3.17
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
FetchContent_Populate(
pico_sdk
QUIET
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
GIT_SUBMODULES_RECURSE FALSE
SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src
BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build
SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild
)
else ()
FetchContent_Populate(
pico_sdk
QUIET
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src
BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build
SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild
)
endif ()
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})

BIN
data/boot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

92
doku/README.md Executable file
View File

@ -0,0 +1,92 @@
# Doku Rapi Temperatur / Luftfeuchtigkeit
## Verkabelung
| Raspi | Sensor |
|---|---|
| 6 (I2C SDA) | SDA |
| 7 (I2C SCL) | SCL |
| 38 (GND) | GND |
| 36 (3V) | VIN |
## Idee
Auslesen des Sensors und anzeigen der Werte / Verlauf im Browser über HTML
## Umsetzung
- Raspi Pico verkabeln mit Sensor
- Eigende Library fpr BME280 Sensor schreiben (Gab keine)
- Ausgeben der Werte in Konsole
- TCP Sevrer auf Port 80 Starten und bei abfrage den HTML Code der Seite senden.
- /data API endpunkt einbauen, der die Sensordaten in json antwortet.
## Problem
Durch den komplexen aufbau des des PicoSDK TCP examples, konnte die umsetzung der Daten in einer HTML seite nicht erfolgen
Es gab eine 1/100 chance das die Daten in HTML sichtbar waren, da die verbindung zu früh geschlossen wurde und der Browser dann in einen fehler läuft obwohl die daten vorhanden sind.
### Was funktioniert hat
Ausgabe über usb ins terminal (minicom)
![Bild](bilderoderso/setp1.png)
## Erweiterung
### Neue Verkabelung
#### Display
| Pin | Type | Pico |
| --- | ---- | ---- |
| 1 | GND | 38 |
| 2 | VCC | 36 |
| 3 | SCK | 24 |
| 4 | SDA | 25 |
| 5 | RES | 26 |
| 6 | RS | 27 |
| 7 | CS | 29 |
| 8 | VCC (BACKLIGHT) | 36 |
#### SD Leser
| Pin | Type | Pico |
| --- | ---- | ---- |
| 1 | GND | 38 |
| 2 | VCC | 36 |
| 3 | MISO | 21 |
| 4 | SDA/MOSI | 25 |
| 5 | SCK | 24 |
| 6 | CS | 9 |
### HTTP Fehler
HTTP Fehler wurde behoben. Die Connection wird nun richtig geschlossen. Dadurch gibt es auch die möglichkeit die Daten in Charts anzuzeigen (Ein Datensatz alle 10 Sekunden)
![Bild](bilderoderso/site.png)
### Display Erweiterung
Zusätzlich gibe es ein Display, welches Live Daten, IP, Durchschnittliche Date der letzten 1000 Datensätze. Zusätlich gibt es einen BLUE Screen, wenn ein fehler auftritt mit eingebauter fehlermeldung und automatischem reboot nach 10 Sekunden.
Der fehlerbildschirm macht auch die WIFI Error LED auf gpio 15 überflüssig.
Des weiteren gibt es noch einen 16 Stelligen Hexadezimal fehlerzehler für den TCP (HTTP) Server, als debug info durch die man erkennt, wenn sich der server villeicht komplett aufgehangen hat. 16 Stellig Hexadecimal liegt daran, das der fehlerwert in einer 64 bit zahl gespeichert wird
### Input Pins
Zusätlich gibt es noch die möglich keit, mithilfe von Pin14, wenn man strom drauf gibt, ohne Wifi zu booten, was nütulich ist für lokale tests, ohne dauernd daraud zu warten das der Pi Pico sich verbindet.
Auf Pin13 Gibt es die möglichkeit einen reboot auszulösen, welchen man z.B nutzen kann, um einmal alles zurüclzusetzen oder in den BOOTSEL (Flash) Mode zu booten
### SD Karte
SD Karten erweiterung funktioniert noch nicht.
Die Idee dahinter ist, daten auf der SD Karte zu speichern und dadurch eine größere Zeitspane auf der Seite anzeigen zu können, ohne das die Daten bei einem Reboot verloren gehen und ohne Limitation durch die größe des RAM Chips

BIN
doku/bilderoderso/setp1.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
doku/bilderoderso/site.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

34
doku/testfile/test.html Normal file
View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Pico Webserver</title>
<style>
body { font-family: sans-serif; background: #f0f0f0; text-align:center; margin-top: 50px; }
#data { font-size: 1.5rem; white-space: pre-line; }
</style>
</head>
<body>
<h1>Temperaturüberwachung</h1>
<div id="data">Temperatur: 24.2°C<br>Luftfeuchtigkeit:42.2%</div>
<script>
/*async function fetchSensorData() {
try {
const res = await fetch("/data");
const json = await res.json();
document.getElementById("data").innerText =
`Temperature: ${json.temp.toFixed(2)} °C\nHumidity: ${json.humidity.toFixed(2)} %`;
} catch(e) {
document.getElementById("data").innerText = "Error fetching sensor data.";
}
}
fetchSensorData();
setInterval(fetchSensorData, 2000);*/
</script>
</body>
</html>

1828
include/boot.h Normal file

File diff suppressed because it is too large Load Diff

91
include/configs/lwipopts.h Executable file
View File

@ -0,0 +1,91 @@
#ifndef _LWIPOPTS_H
#define _LWIPOPTS_H
// Common settings used in most of the pico_w examples
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details)
// allow override in some examples
#ifndef NO_SYS
#define NO_SYS 1
#endif
// allow override in some examples
#ifndef LWIP_SOCKET
#define LWIP_SOCKET 0
#endif
#if PICO_CYW43_ARCH_POLL
#define MEM_LIBC_MALLOC 1
#else
// MEM_LIBC_MALLOC is incompatible with non polling versions
#define MEM_LIBC_MALLOC 0
#endif
#define MEM_ALIGNMENT 4
#ifndef MEM_SIZE
#define MEM_SIZE 16384 // 4000
#endif
#define MEMP_NUM_TCP_SEG 32
#define MEMP_NUM_ARP_QUEUE 10
#define PBUF_POOL_SIZE 24
#define LWIP_ARP 1
#define LWIP_ETHERNET 1
#define LWIP_ICMP 1
#define LWIP_RAW 1
#define TCP_WND (8 * TCP_MSS)
#define TCP_MSS 1460
#define TCP_SND_BUF (8 * TCP_MSS) // (8 * TCP_MSS)
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
#define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1
#define LWIP_NETIF_HOSTNAME 1
#define LWIP_NETCONN 0
#define MEM_STATS 0
#define SYS_STATS 0
#define MEMP_STATS 0
#define LINK_STATS 0
// #define ETH_PAD_SIZE 2
#define LWIP_CHKSUM_ALGORITHM 3
#define LWIP_DHCP 1
#define LWIP_IPV4 1
#define LWIP_TCP 1
#define LWIP_UDP 1
#define LWIP_DNS 1
#define LWIP_TCP_KEEPALIVE 1
#define LWIP_NETIF_TX_SINGLE_PBUF 1
#define DHCP_DOES_ARP_CHECK 0
#define LWIP_DHCP_DOES_ACD_CHECK 0
#ifndef NDEBUG
#define LWIP_DEBUG 1
#define LWIP_STATS 1
#define LWIP_STATS_DISPLAY 1
#endif
#define ETHARP_DEBUG LWIP_DBG_OFF
#define NETIF_DEBUG LWIP_DBG_OFF
#define PBUF_DEBUG LWIP_DBG_OFF
#define API_LIB_DEBUG LWIP_DBG_OFF
#define API_MSG_DEBUG LWIP_DBG_OFF
#define SOCKETS_DEBUG LWIP_DBG_OFF
#define ICMP_DEBUG LWIP_DBG_OFF
#define INET_DEBUG LWIP_DBG_OFF
#define IP_DEBUG LWIP_DBG_OFF
#define IP_REASS_DEBUG LWIP_DBG_OFF
#define RAW_DEBUG LWIP_DBG_OFF
#define MEM_DEBUG LWIP_DBG_OFF
#define MEMP_DEBUG LWIP_DBG_OFF
#define SYS_DEBUG LWIP_DBG_OFF
#define TCP_DEBUG LWIP_DBG_OFF
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
#define TCP_RTO_DEBUG LWIP_DBG_OFF
#define TCP_CWND_DEBUG LWIP_DBG_OFF
#define TCP_WND_DEBUG LWIP_DBG_OFF
#define TCP_FR_DEBUG LWIP_DBG_OFF
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
#define TCP_RST_DEBUG LWIP_DBG_OFF
#define UDP_DEBUG LWIP_DBG_OFF
#define TCPIP_DEBUG LWIP_DBG_OFF
#define PPP_DEBUG LWIP_DBG_OFF
#define SLIP_DEBUG LWIP_DBG_OFF
#define DHCP_DEBUG LWIP_DBG_OFF
#endif /* __LWIPOPTS_H__ */

3083
include/font.hpp Normal file

File diff suppressed because it is too large Load Diff

460
include/server.h Executable file
View File

@ -0,0 +1,460 @@
#include <stdlib.h>
#include <string.h>
#include "bme280.h" // Deine BME280 Sensor-Bibliothek
#include "hardware/i2c.h" // Nötig für I2C-Definitionen, falls bme280.h sie nicht enthält
#include "lwip/pbuf.h"
#include "lwip/tcp.h"
#include "pico/cyw43_arch.h"
#include "pico/stdlib.h"
#define TCP_PORT 80
#define DEBUG_printf printf
#define BUF_SIZE 8192 * 4 // Kann angepasst werden für größere HTML/JSON
#define POLL_TIME_S 5
static uint64_t __tcp_errors = 0;
// Deklariere den BME280 Kontext als externe globale Variable.
// Dieser wird in main.cpp initialisiert und hier verwendet.
extern bme280_ctx *ctx; // WICHTIG: Nutzt jetzt denselben Namen wie in main.cpp
struct data {
float t;
float h;
};
extern struct data _list[1000];
extern int list_index;
extern int list_count;
const char *html_page = R"rawliteral(
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Dashboard oder so</title>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body {
background: #f4f6f8;
font-family: 'Montserrat', sans-serif;
padding: 20px;
color: #333;
}
h1, h2 {
font-weight: 600;
text-align: center;
}
.chart-container {
width: 100%;
max-width: 800px;
margin: 20px auto;
background: #fff;
padding: 20px;
border-radius: 12px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
}
.live-data {
display: flex;
justify-content: center;
gap: 30px;
font-size: 1.5em;
margin-top: 10px;
}
canvas {
width: 100% !important;
height: 300px !important;
}
</style>
</head>
<body>
<h1>Dashboard oder so</h1>
<div class="chart-container live-data">
<div>🌡 Temp: <span id="liveTemp">--</span> °C</div>
<div>💧 Humidity: <span id="liveHumidity">--</span> %</div>
</div>
<div class="chart-container">
<h2>Temperature History</h2>
<canvas id="tempChart"></canvas>
</div>
<div class="chart-container">
<h2>Humidity History</h2>
<canvas id="humChart"></canvas>
</div>
<script>
let tempChart, humChart;
function initCharts() {
const tempCtx = document.getElementById('tempChart').getContext('2d');
const humCtx = document.getElementById('humChart').getContext('2d');
const options = {
type: 'line',
options: {
responsive: true,
animation: false,
scales: {
x: {
title: { display: true, text: 'Time' },
ticks: { autoSkip: true, maxTicksLimit: 10 }
},
y: { beginAtZero: false }
}
}
};
tempChart = new Chart(tempCtx, {
...options,
data: {
labels: [],
datasets: [{
label: 'Temperature (°C)',
data: [],
borderColor: '#e74c3c',
backgroundColor: 'rgba(231, 76, 60, 0.2)',
tension: 0.3,
fill: true,
pointRadius: 2
}]
}
});
humChart = new Chart(humCtx, {
...options,
data: {
labels: [],
datasets: [{
label: 'Humidity (%)',
data: [],
borderColor: '#3498db',
backgroundColor: 'rgba(52, 152, 219, 0.2)',
tension: 0.3,
fill: true,
pointRadius: 2
}]
}
});
}
function updateLiveData() {
fetch('/data')
.then(res => res.json())
.then(data => {
document.getElementById('liveTemp').textContent = data.temp.toFixed(1);
document.getElementById('liveHumidity').textContent = data.humidity.toFixed(1);
});
}
function updateCharts() {
fetch('/history')
.then(res => res.json())
.then(data => {
const labels = data.map((_, i) => {
const t = new Date(Date.now() - (data.length - 1 - i) * 10000);
return t.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
});
const temps = data.map(e => e.t);
const hums = data.map(e => e.h);
tempChart.data.labels = labels;
tempChart.data.datasets[0].data = temps;
tempChart.update();
humChart.data.labels = labels;
humChart.data.datasets[0].data = hums;
humChart.update();
});
}
initCharts();
updateCharts();
updateLiveData();
setInterval(updateCharts, 10000); // alle 10s Verlaufsdaten
setInterval(updateLiveData, 2000); // alle 2s Livewerte
</script>
</body>
</html>
)rawliteral";
typedef struct HTTP_SERVER_T_ {
struct tcp_pcb *server_pcb;
struct tcp_pcb *client_pcb;
} HTTP_SERVER_T;
static HTTP_SERVER_T *http_server_init(void) {
HTTP_SERVER_T *state = (HTTP_SERVER_T *)calloc(1, sizeof(HTTP_SERVER_T));
if (!state) {
__tcp_errors++;
DEBUG_printf("Failed to allocate HTTP server state\n");
return NULL;
}
return state;
}
static err_t http_server_close(void *arg) {
HTTP_SERVER_T *state = (HTTP_SERVER_T *)arg;
err_t err = ERR_OK;
if (state->client_pcb != NULL) {
tcp_arg(state->client_pcb, NULL);
tcp_poll(state->client_pcb, NULL, 0);
tcp_sent(state->client_pcb, NULL);
tcp_recv(state->client_pcb, NULL);
tcp_err(state->client_pcb, NULL);
err = tcp_close(state->client_pcb);
if (err != ERR_OK) {
__tcp_errors++;
DEBUG_printf("Close failed %d, calling abort\n", err);
tcp_abort(state->client_pcb);
err = ERR_ABRT;
}
state->client_pcb = NULL;
}
// Keep this off to keep the server alive
// if (state->server_pcb) {
// tcp_arg(state->server_pcb, NULL);
// tcp_close(state->server_pcb);
// state->server_pcb = NULL;
//}
return err;
}
static err_t http_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) {
DEBUG_printf("HTTP data sent, length: %u\n", len);
return http_server_close(arg); // Verbindung nach dem Senden schließen
}
static err_t http_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p,
err_t err) {
HTTP_SERVER_T *state = (HTTP_SERVER_T *)arg;
if (!p) {
// Client hat Verbindung geschlossen
return http_server_close(arg);
}
if (err != ERR_OK) {
__tcp_errors++;
DEBUG_printf("Error in TCP receive: %d\n", err);
pbuf_free(p);
return http_server_close(arg);
}
cyw43_arch_lwip_check();
// Eingehende Anfrage verarbeiten
if (p->tot_len > 0) {
char *req = (char *)malloc(p->tot_len + 1);
if (req == NULL) {
__tcp_errors++;
DEBUG_printf("Failed to allocate memory for request\n");
pbuf_free(p);
return http_server_close(arg);
}
pbuf_copy_partial(p, req, p->tot_len, 0);
req[p->tot_len] = '\0'; // Request-String nullterminieren
// DEBUG_printf("Received HTTP request:\n%s\n", req);
// Einfaches Routing basierend auf der URL
const char *http_header_ok_html =
"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: "
"%d\r\nConnection: close\r\n\r\n";
const char *http_header_ok_json =
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: "
"%d\r\nConnection: close\r\n\r\n";
const char *http_header_not_found =
"HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: "
"13\r\nConnection: close\r\n\r\n";
const char *not_found_body = "404 Not Found";
char response_header[256];
const char *response_body;
size_t response_body_len;
char dynamic_json_body[256]; // Puffer für dynamische JSON-Daten
char *history_body = 0;
if (strstr(req, "GET / HTTP/1.1") ||
strstr(req, "GET /index.html HTTP/1.1")) {
response_body = html_page;
response_body_len = strlen(html_page);
sprintf(response_header, http_header_ok_html, response_body_len);
} else if (strstr(req, "GET /data HTTP/1.1")) {
// Sensordaten auslesen
float temp = 0.0;
float humidity = 0.0;
if (ctx != NULL) { // Zugriff auf die globale ctx Variable
ctx->update(ctx); // Sensorwerte aktualisieren
temp = ctx->read_temp(ctx);
humidity = ctx->read_humidity(ctx);
} else {
DEBUG_printf("BME280 Kontext ist NULL, sende Standarddaten.\n");
}
sprintf(dynamic_json_body, "{\"temp\": %.2f, \"humidity\": %.2f}", temp,
humidity);
response_body = dynamic_json_body;
response_body_len = strlen(dynamic_json_body);
sprintf(response_header, http_header_ok_json, response_body_len);
} else if (strstr(req, "GET /history HTTP/1.1")) {
history_body =
(char *)malloc(4096); // or larger, depending on expected size
if (!history_body) {
__tcp_errors++;
DEBUG_printf("Memory alloc failed for history\n");
free(req);
pbuf_free(p);
return http_server_close(arg);
}
char *ptr = history_body;
ptr += sprintf(ptr, "[");
for (int i = 0; i < list_count; i++) {
int index = (list_index + i) % list_count;
ptr += sprintf(ptr, "{\"t\":%.2f,\"h\":%.2f}%s", _list[index].t,
_list[index].h, (i < list_count - 1) ? "," : "");
}
ptr += sprintf(ptr, "]");
response_body = history_body;
response_body_len = ptr - history_body;
sprintf(response_header, http_header_ok_json, response_body_len);
} else {
response_body = not_found_body;
response_body_len = strlen(not_found_body);
sprintf(response_header, http_header_not_found, response_body_len);
}
// Header senden
err_t wr_err = tcp_write(tpcb, response_header, strlen(response_header),
TCP_WRITE_FLAG_MORE);
if (wr_err != ERR_OK) {
__tcp_errors++;
DEBUG_printf("Failed to write header %d\n", wr_err);
free(req);
pbuf_free(p);
return http_server_close(arg);
}
// Body senden
wr_err =
tcp_write(tpcb, response_body, response_body_len, TCP_WRITE_FLAG_COPY);
if (wr_err != ERR_OK) {
__tcp_errors++;
DEBUG_printf("Failed to write body %d\n", wr_err);
free(req);
pbuf_free(p);
return http_server_close(arg);
}
tcp_output(tpcb); // Sicherstellen, dass Daten gesendet werden
if (history_body) {
free(history_body);
}
free(req);
}
pbuf_free(p);
tcp_recved(tpcb, p->tot_len); // Empfang der Daten bestätigen
return ERR_OK;
}
static err_t http_server_poll(void *arg, struct tcp_pcb *tpcb) {
// DEBUG_printf("HTTP server poll function called\n");
return ERR_OK;
}
static void http_server_err(void *arg, err_t err) {
if (err != ERR_ABRT) {
__tcp_errors++;
DEBUG_printf("HTTP server error: %d\n", err);
}
}
static err_t http_server_accept(void *arg, struct tcp_pcb *client_pcb,
err_t err) {
HTTP_SERVER_T *state = (HTTP_SERVER_T *)arg;
if (err != ERR_OK || client_pcb == NULL) {
__tcp_errors++;
DEBUG_printf("Failure in accept: %d\n", err);
return ERR_VAL;
}
DEBUG_printf("Client connected\n");
state->client_pcb = client_pcb;
tcp_arg(client_pcb, state);
tcp_sent(client_pcb, http_server_sent);
tcp_recv(client_pcb, http_server_recv);
tcp_poll(client_pcb, http_server_poll, POLL_TIME_S * 2);
tcp_err(client_pcb, http_server_err);
return ERR_OK;
}
bool http_server_open(void *arg) {
HTTP_SERVER_T *state = (HTTP_SERVER_T *)arg;
DEBUG_printf("Starting HTTP server at %s on port %u\n",
ip4addr_ntoa(netif_ip4_addr(netif_list)), TCP_PORT);
struct tcp_pcb *pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
if (!pcb) {
__tcp_errors++;
DEBUG_printf("Failed to create pcb\n");
return false;
}
err_t err = tcp_bind(pcb, NULL, TCP_PORT);
if (err) {
__tcp_errors++;
DEBUG_printf("Failed to bind to port %u\n", TCP_PORT);
return false;
}
state->server_pcb = tcp_listen_with_backlog(pcb, 1);
if (!state->server_pcb) {
__tcp_errors++;
DEBUG_printf("Failed to listen\n");
if (pcb) {
tcp_close(pcb);
}
return false;
}
tcp_arg(state->server_pcb, state);
tcp_accept(state->server_pcb, http_server_accept);
return true;
}
// Funktion zum Initialisieren und Ausführen des HTTP-Servers in der
// Hauptschleife
void run_http_server(void) {
static HTTP_SERVER_T *state = NULL;
if (!state) {
state = http_server_init();
if (!state) {
return;
}
if (!http_server_open(state)) {
http_server_close(state);
free(state);
state = NULL;
return;
}
}
#if PICO_CYW43_ARCH_POLL
cyw43_arch_poll();
cyw43_arch_wait_for_work_until(make_timeout_time_ms(1));
#else
sleep_ms(1);
#endif
}

216
include/tft.hpp Normal file
View File

@ -0,0 +1,216 @@
#pragma once
extern "C" {
#include <hardware/spi.h>
#include <pico/stdlib.h>
}
class TFT {
public:
TFT(uint cs, uint dc, uint rst, uint sck, uint sda)
: PinCs(cs), PinDc(dc), PinRst(rst), PinSck(sck), PinSda(sda) {}
~TFT() = default;
enum class CMD : uint8_t {
NOP = 0x00,
SWRESET = 0x01,
SLPIN = 0x10,
SLPOUT = 0x11,
INVOFF = 0x20,
INVON = 0x21,
DISPON = 0x29,
CASET = 0x2A,
RASET = 0x2B,
RAMWR = 0x2C,
MADCTL = 0x36,
COLMOD = 0x3A,
FRMCTR1 = 0xB1,
FRMCTR2 = 0xB2,
FRMCTR3 = 0xB3,
INVCTR = 0xB4,
PWCTR1 = 0xC0,
PWCTR2 = 0xC1,
PWCTR3 = 0xC2,
PWCTR4 = 0xC3,
PWCTR5 = 0xC4,
VMCTR1 = 0xC5,
GMCTRP1 = 0xE0,
GMCTRN1 = 0xE1,
NORON = 0x13,
};
void Init() {
spi_init(spi0, 20 * 1000 * 1000);
gpio_set_function(PinSck, GPIO_FUNC_SPI);
gpio_set_function(PinSda, GPIO_FUNC_SPI);
gpio_init(PinCs);
gpio_init(PinDc);
gpio_init(PinRst);
gpio_set_dir(PinCs, GPIO_OUT);
gpio_set_dir(PinDc, GPIO_OUT);
gpio_set_dir(PinRst, GPIO_OUT);
gpio_put(PinCs, 1);
gpio_put(PinDc, 1);
gpio_put(PinRst, 1);
Reset();
// Init sequence Oder so
WriteCmd(CMD::SWRESET);
sleep_ms(150);
WriteCmd(CMD::SLPOUT);
sleep_ms(150);
WriteCmd(CMD::FRMCTR1);
WriteData(0x01);
WriteData(0x2C);
WriteData(0x2D);
WriteCmd(CMD::FRMCTR2);
WriteData(0x01);
WriteData(0x2C);
WriteData(0x2D);
WriteCmd(CMD::FRMCTR3);
WriteData(0x01);
WriteData(0x2C);
WriteData(0x2D);
WriteData(0x01);
WriteData(0x2C);
WriteData(0x2D);
WriteCmd(CMD::INVCTR);
WriteData(0x07);
WriteCmd(CMD::PWCTR1);
WriteData(0xA2);
WriteData(0x02);
WriteData(0x84);
WriteCmd(CMD::PWCTR2);
WriteData(0xC5);
WriteCmd(CMD::PWCTR3);
WriteData(0x0A);
WriteData(0x00);
WriteCmd(CMD::PWCTR4);
WriteData(0x8A);
WriteData(0x2A);
WriteCmd(CMD::PWCTR5);
WriteData(0x8A);
WriteData(0xEE);
WriteCmd(CMD::VMCTR1);
WriteData(0x0E);
WriteCmd(CMD::INVOFF);
WriteCmd(CMD::MADCTL);
WriteData(0xC8);
WriteCmd(CMD::COLMOD);
WriteData(0x05); // 16-bit color
WriteCmd(CMD::CASET);
WriteData(0);
WriteData(0);
WriteData(0);
WriteData(127);
WriteCmd(CMD::RASET);
WriteData(0);
WriteData(0);
WriteData(0);
WriteData(159);
WriteCmd(CMD::GMCTRP1);
WriteData(0x02);
WriteData(0x1c);
WriteData(0x07);
WriteData(0x12);
WriteData(0x37);
WriteData(0x32);
WriteData(0x29);
WriteData(0x2d);
WriteData(0x29);
WriteData(0x25);
WriteData(0x2B);
WriteData(0x39);
WriteData(0x00);
WriteData(0x01);
WriteData(0x03);
WriteData(0x10);
WriteCmd(CMD::GMCTRN1);
WriteData(0x03);
WriteData(0x1d);
WriteData(0x07);
WriteData(0x06);
WriteData(0x2E);
WriteData(0x2C);
WriteData(0x29);
WriteData(0x2D);
WriteData(0x2E);
WriteData(0x2E);
WriteData(0x37);
WriteData(0x3F);
WriteData(0x00);
WriteData(0x00);
WriteData(0x02);
WriteData(0x10);
WriteCmd(CMD::NORON);
sleep_ms(10);
WriteCmd(CMD::DISPON);
sleep_ms(100);
}
void SetWindow(uint8_t x, uint8_t y, uint8_t x1, uint8_t y1) {
WriteCmd(CMD::CASET);
WriteData(0x00);
WriteData(x);
WriteData(0x00);
WriteData(x1);
WriteCmd(CMD::RASET);
WriteData(0x00);
WriteData(y);
WriteData(0x00);
WriteData(y1);
WriteCmd(CMD::RAMWR);
}
void DrawPixel(uint8_t x, uint8_t y, uint16_t color) {
SetWindow(x, y, x, y);
WriteData16(color);
}
void DrawRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t color) {
SetWindow(x, y, w, h);
for (int i = 0; i < w * h; i++) {
WriteData16(color);
}
}
void Reset() {
gpio_put(PinRst, 0);
sleep_ms(50);
gpio_put(PinRst, 1);
sleep_ms(50);
}
void WriteCmd(CMD cmd) { WriteCmd((uint8_t)cmd); }
void WriteCmd(uint8_t cmd) {
gpio_put(PinDc, 0); // Command Mode
gpio_put(PinCs, 0);
spi_write_blocking(spi0, &cmd, 1);
gpio_put(PinCs, 1);
}
void WriteData(uint8_t data) {
gpio_put(PinDc, 1); // Data Mode
gpio_put(PinCs, 0);
spi_write_blocking(spi0, &data, 1);
gpio_put(PinCs, 1);
}
void WriteData16(uint16_t data) {
uint8_t d8[2] = {uint8_t(data >> 8), uint8_t(data & 0xff)};
gpio_put(PinDc, 1); // Data Mode
gpio_put(PinCs, 0);
spi_write_blocking(spi0, d8, 2);
gpio_put(PinCs, 1);
}
uint PinCs = 0;
uint PinDc = 0;
uint PinRst = 0;
uint PinSck = 0;
uint PinSda = 0;
};

47
source/hw_config.c Executable file
View File

@ -0,0 +1,47 @@
#include "hw_config.h"
/* SDIO Interface */
static sd_sdio_if_t sdio_if = {
/*
Pins CLK_gpio, D1_gpio, D2_gpio, and D3_gpio are at offsets from pin
D0_gpio. The offsets are determined by sd_driver\SDIO\rp2040_sdio.pio.
CLK_gpio = (D0_gpio + SDIO_CLK_PIN_D0_OFFSET) % 32;
As of this writing, SDIO_CLK_PIN_D0_OFFSET is 30,
which is -2 in mod32 arithmetic, so:
CLK_gpio = D0_gpio -2.
D1_gpio = D0_gpio + 1;
D2_gpio = D0_gpio + 2;
D3_gpio = D0_gpio + 3;
*/
.CMD_gpio = 3,
.D0_gpio = 4,
.baud_rate = 125 * 1000 * 1000 / 6 // 20833333 Hz
};
/* Hardware Configuration of the SD Card socket "object" */
static sd_card_t sd_card = {.type = SD_IF_SDIO, .sdio_if_p = &sdio_if};
/**
* @brief Get the number of SD cards.
*
* @return The number of SD cards, which is 1 in this case.
*/
size_t sd_get_num() { return 1; }
/**
* @brief Get a pointer to an SD card object by its number.
*
* @param[in] num The number of the SD card to get.
*
* @return A pointer to the SD card object, or @c NULL if the number is invalid.
*/
sd_card_t* sd_get_by_num(size_t num) {
if (0 == num) {
// The number 0 is a valid SD card number.
// Return a pointer to the sd_card object.
return &sd_card;
} else {
// The number is invalid. Return @c NULL.
return NULL;
}
}

310
source/main.cpp Executable file
View File

@ -0,0 +1,310 @@
#include <stdio.h>
#include <string.h>
#include "hardware/i2c.h"
extern "C" {
#include "hardware/watchdog.h"
#include "pico/cyw43_arch.h"
#include "pico/stdlib.h"
}
#include <bme280.h>
#include <server.h>
#include <font.hpp>
#include <format>
#include <string>
#include <tft.hpp>
// #define MOBILE_WIFI
#include "boot.h"
#include "wifi.hpp"
// FatFS
extern "C" {
#include "f_util.h"
#include "ff.h"
#include "hw_config.h"
}
////////
void BSOD(const char *);
void msg(const char *msg) { printf("[INFO] %s\n", msg); }
void err(const char *msg) {
printf("[ERROR] %s\n", msg);
BSOD(msg);
}
////////// CONFIG //////////
#define I2C_PORT i2c0
#define I2C_SDA 4
#define I2C_SCL 5
constexpr int PinReboot = 13;
constexpr int PinNoWifi = 14;
constexpr int WifiError = 15;
constexpr uint PinCs = 22;
constexpr uint PinDc = 21;
constexpr uint PinRst = 20;
constexpr uint PinSck = 18;
constexpr uint PinSda = 19;
////////////////////////////
TFT tft(PinCs, PinDc, PinRst, PinSck, PinSda);
#define ClearScreen(c) tft.DrawRect(0, 0, 127, 159, c)
void DrawChar(uint8_t x, uint8_t y, char c, uint16_t fg, uint16_t bg) {
if (c < 0 || c > 255) return;
const uint8_t *chr = &font[c * FONT_HEIGHT];
for (uint8_t row = 0; row < FONT_HEIGHT; ++row) {
uint8_t bits = chr[row];
for (uint8_t col = 0; col < FONT_WIDTH; ++col) {
uint16_t color = (bits & (1 << (7 - col))) ? fg : bg;
tft.DrawPixel(x + col, y + row, color);
}
}
}
void DrawText(uint8_t x, uint8_t y, const char *text, uint16_t fg,
uint16_t bg) {
while (*text) {
if (*text == '\n') {
y += FONT_HEIGHT;
x = 1;
*text++;
continue;
} else if (*text == '\0') {
break;
}
if (x + FONT_WIDTH > 127) {
y += FONT_HEIGHT;
x = 1;
}
DrawChar(x, y, *text++, fg, bg);
x += FONT_WIDTH;
}
}
// Blue Screen of Death
void BSOD(const char *what) {
ClearScreen(0xF800);
DrawText(1, 5, "ERROR", 0xffff, 0xf800);
DrawText(1, 7 + FONT_HEIGHT, what, 0xffff, 0xf800);
for (int i = 0; i < 10; i++) {
DrawText(1, 140, "Rebooting in\n10 seconds...", 0xffff, 0xf800);
sleep_ms(1000);
}
watchdog_reboot(0, 0, 0);
}
void ScreenMsg(const char *what, uint16_t fg_col, uint16_t bg_col) {
ClearScreen(bg_col);
DrawText(1, 5 + FONT_HEIGHT, what, fg_col, bg_col);
}
static size_t get_mac_ascii(int idx, size_t chr_off, size_t chr_len,
char *dest_in) {
static const char *hexchr = "0123456789ABCDEF";
uint8_t mac[6];
char *dest = dest_in;
assert(chr_off + chr_len <= (2 * sizeof(mac)));
cyw43_hal_get_mac(idx, mac);
for (; chr_len && (chr_off >> 1) < sizeof(mac); ++chr_off, --chr_len) {
*dest++ = hexchr[mac[chr_off >> 1] >> (4 * (1 - (chr_off & 1))) & 0xf];
}
return dest - dest_in;
}
int init_wifi() {
msg("Init Wifi");
// Initialise the Wi-Fi chip
if (cyw43_arch_init()) {
err("Wi-Fi init failed");
return -1;
}
msg("Enable STA");
cyw43_arch_enable_sta_mode();
msg("Get Hostname / Mac Address");
char hostname[sizeof(CYW43_HOST_NAME) + 4];
memcpy(&hostname[0], CYW43_HOST_NAME, sizeof(CYW43_HOST_NAME) - 1);
get_mac_ascii(CYW43_HAL_MAC_WLAN0, 8, 4,
&hostname[sizeof(CYW43_HOST_NAME) - 1]);
hostname[sizeof(hostname) - 1] = '\0';
netif_set_hostname(&cyw43_state.netif[CYW43_ITF_STA], hostname);
msg("Connect Wifi");
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD,
CYW43_AUTH_WPA2_AES_PSK, 30000)) {
err("Wi-Fi connect failed");
return -1;
}
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
msg("Connected to Wi-Fi!");
return 0;
}
// #define I2C_PORT i2c0
data _list[1000];
int list_index = 0;
int list_count = 0; // Total stored, max 1000
void list_update(float temp, float humidity) {
_list[list_index].t = temp;
_list[list_index].h = humidity;
list_index = (list_index + 1) % 1000;
if (list_count < 1000) {
list_count++;
}
}
void list_average(float *avg_temp, float *avg_humidity) {
if (list_count == 0) {
*avg_temp = 0.0f;
*avg_humidity = 0.0f;
return;
}
float sum_t = 0.0f;
float sum_h = 0.0f;
for (int i = 0; i < list_count; i++) {
sum_t += _list[i].t;
sum_h += _list[i].h;
}
*avg_temp = sum_t / list_count;
*avg_humidity = sum_h / list_count;
}
bme280_ctx *ctx;
int init_fs() {
printf("Init FS\n");
FATFS fs;
FRESULT fr = f_mount(&fs, "", 1);
if (fr != FR_OK) {
printf("f_mount error: %s\n", FRESULT_str(fr));
return 1;
}
FIL fil;
const char *fn = "test.txt";
fr = f_open(&fil, fn, FA_OPEN_APPEND | FA_WRITE);
if (fr != FR_OK) {
printf("f_open error: %s\n", FRESULT_str(fr));
return 1;
}
if (f_printf(&fil, "Hello World!\n") < 0) {
printf("Failed to write!");
return 1;
}
fr = f_close(&fil);
if (fr != FR_OK) {
printf("f_close error: %s\n", FRESULT_str(fr));
return 1;
}
f_unmount("");
return 0;
}
float __a_te = 0.0f;
float __a_hu = 0.0f;
float __temp = 0.f;
float __humidity = 0.f;
int main() {
stdio_init_all();
tft.Init();
ClearScreen(0xffff);
tft.SetWindow(0, 16, 127, 127);
for (int i = 0; i < 16384; i++) {
tft.WriteData16(boot_image[i]);
}
// if (init_fs() != 0) {
// return 1;
// }
/// NO WIFI CHECK ///
gpio_init(PinNoWifi);
gpio_pull_down(PinNoWifi);
gpio_set_dir(PinNoWifi, GPIO_IN);
gpio_init(PinReboot);
gpio_pull_down(PinReboot);
gpio_set_dir(PinReboot, GPIO_IN);
bool use_wifi = !gpio_get(PinNoWifi);
/////////////////////
if (use_wifi) {
gpio_init(WifiError);
gpio_set_dir(WifiError, GPIO_OUT);
gpio_put(WifiError, 0);
if (init_wifi() != 0) {
gpio_put(WifiError, 1);
return -1;
}
} else {
DrawText(1, 1, "WIFI Disabled...", 0x00ff, 0xffff);
sleep_ms(2000);
}
ClearScreen(0xffff);
ctx = bme280_init(I2C_PORT, I2C_SDA, I2C_SCL);
if (use_wifi) {
DrawText(1, 150, ip4addr_ntoa(netif_ip4_addr(netif_list)), 0x0000, 0xffff);
} else {
DrawText(1, 150, "WIFI disabled...", 0x00ff, 0xffff);
}
int __i = 0;
while (true) {
__temp = ctx->read_temp(ctx);
__humidity = ctx->read_humidity(ctx);
if (gpio_get(PinReboot)) {
ScreenMsg(
"D7-System:\nReboot initiated!\n\nYou have 3\nseconds to remove\nthe "
"wire!",
0xffff, 0x00df);
sleep_ms(3000);
watchdog_reboot(0, 0, 0);
}
if (use_wifi) {
DrawText(1, 120,
std::format("TCP Errors:\n - {:016X}", __tcp_errors).c_str(),
0x0000, 0xffff);
if (cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA) ==
CYW43_LINK_UP) {
// Space to keep the string the same len
DrawText(1, 140, "Conected: true ", 0x0000, 0xffff);
} else {
DrawText(1, 140, "Conected: false", 0x0000, 0xffff);
}
}
ctx->update(ctx);
list_average(&__a_te, &__a_hu);
std::string text = std::format(
"Temp: {:.1f} C\nHumidity: {:.2f}%\nAVG Temp: {:.1f} C\nAVG Hum: "
"{:.2f}%",
__temp, __humidity, __a_te, __a_hu);
DrawText(1, 1, text.c_str(), 0x0000, 0xffff);
if (__i >= 10) {
list_update(__temp, __humidity);
__i = 0;
}
__i++;
printf("Temperatur=%.2f °C, Luftfeuchtigkeit=%.2f %\n", __temp, __humidity);
if (use_wifi) {
run_http_server();
}
sleep_ms(1000);
}
if (ctx) {
bme280_deinit(ctx);
}
}

View File

@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.22)
project(img2c LANGUAGES CXX)
add_executable(img2c source/main.cpp)
target_include_directories(img2c PRIVATE include)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include <cstdio>
#include <iostream>
#include <vector>
/**
* Usage:
* img2c <image> > out.c
*/
int main(int argc, char* argv[]) {
int w, h, c;
unsigned char* buf = stbi_load(argv[1], &w, &h, &c, 3);
std::vector<uint16_t> rgb565;
for (int i = 0; i < w * h * 3; i += 3) {
unsigned char r = buf[i];
unsigned char g = buf[i + 1];
unsigned char b = buf[i + 2];
uint16_t color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
rgb565.push_back(color);
}
std::cout << "const uint16_t image[" << w * h << "] = {\n";
for (size_t i = 0; i < rgb565.size(); ++i) {
printf("0x%04X", rgb565[i]);
if (i != rgb565.size() - 1) std::cout << ", ";
if ((i + 1) % 8 == 0) std::cout << "\n";
}
std::cout << "\n};\n";
stbi_image_free(buf);
return 0;
}

1
vendor/bme280 vendored Submodule

@ -0,0 +1 @@
Subproject commit 3397950723f5bd572624ba4d72f75cf1af6875c7

1
vendor/pico-fatfs vendored Submodule

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