Compare commits
26 Commits
interface-
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
a69e0dbdd8 | ||
|
a84f90c925 | ||
|
bce19a3093 | ||
|
084f17b63e | ||
|
98fb8846fd | ||
|
385ef87eb0 | ||
|
0e0f9e053c | ||
|
ee55d4483f | ||
|
a96344f6b9 | ||
|
7d83e354fa | ||
|
bb84205531 | ||
|
48bfbb98ef | ||
|
cd0ebd8891 | ||
|
1be9545cd1 | ||
|
1fa1149170 | ||
|
6bd766ee41 | ||
|
4abdc2f565 | ||
|
335490b185 | ||
|
f63e4e2ba1 | ||
|
820e4af1a9 | ||
|
e845555063 | ||
|
4d1418cd43 | ||
|
4bbf8453b5 | ||
|
853c0010e7 | ||
|
0603d4557c | ||
|
f05e15c2ed |
12
.gitignore
vendored
@ -1,6 +1,5 @@
|
||||
#temporary
|
||||
datasheets/
|
||||
pi-interface-board_v1.0/export/
|
||||
export/
|
||||
pcb2gcode/
|
||||
cad/import
|
||||
@ -10,10 +9,12 @@ cad/import
|
||||
\#auto_saved_files\#
|
||||
*.lck
|
||||
_autosave-*
|
||||
fp-info-cache
|
||||
|
||||
*.kicad_sch-back
|
||||
*.bak
|
||||
*.kicad_sch-bak
|
||||
*.kicad_prl
|
||||
|
||||
#drawio
|
||||
*.bkp
|
||||
@ -21,4 +22,11 @@ _autosave-*
|
||||
|
||||
#freecad
|
||||
*.FCBak
|
||||
*.stl
|
||||
*.stl
|
||||
|
||||
|
||||
#vim
|
||||
*.swp
|
||||
|
||||
#python
|
||||
__pycache__
|
||||
|
483
README.md
@ -1,128 +1,393 @@
|
||||
A Raspberry Pi-compatible PCB that extends the GPIO header with protected I/O, relays, and various features for versatile use in prototyping and project development.
|
||||
# Raspberry Pi Extension Board
|
||||
|
||||
A custom PLC-like system based on the Raspberry Pi.
|
||||
With a custom interface board, a Raspberry Pi is extended with protected I/O, bus systems, analog inputs, and Relay or PWM outputs. All components, including a display, are housed in a custom-designed enclosure.
|
||||
|
||||
The project is intended for versatile use in prototyping and project development.
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Notes:**
|
||||
|
||||
# RPI Specs (Zero, 3+)
|
||||
- Available (old) Pi: Raspberry Pi 2 Model B v1.1
|
||||
- GPIO
|
||||
- Low: 0.9V
|
||||
- High: 1.6V
|
||||
- Input current: 5uA
|
||||
- Input capacitance: 5pF
|
||||
- Output Current +-17mA
|
||||
- Pullup / Pulldown 50-65k
|
||||
- EEPROM GPIO0 GPIO1, leave unused
|
||||
# TOC
|
||||
- [Photos](#photos)
|
||||
- [Repository Content](#repository-content)
|
||||
- [Features Overview](#features-overview)
|
||||
- [Designed PCBs](#designed-pcbs)
|
||||
* [1. Raspberry Pi Interface Board](#1-raspberry-pi-interface-board)
|
||||
* [2. Power Supply Board](#2---power-supply-board--)
|
||||
* [3. LED Boards](#3---led-boards--)
|
||||
- [Raspberry Pi Usage](#raspberry-pi-usage)
|
||||
* [Connectivity](#connectivity)
|
||||
+ [LAN Connection (Ethernet)](#lan-connection--ethernet-)
|
||||
+ [WiFi Connection](#wifi-connection)
|
||||
+ [SSH Access](#ssh-access)
|
||||
+ [Remote Desktop (RDP)](#remote-desktop--rdp-)
|
||||
+ [Mount Raspberry Pi Filesystem in Windows (SAMBA)](#mount-raspberry-pi-filesystem-in-windows--samba-)
|
||||
- [Python Scripting](#python-scripting)
|
||||
* [Running Python Examples](#running-python-examples)
|
||||
* [Starting a New Python Project with I/O Access](#starting-a-new-python-project-with-i-o-access)
|
||||
* [GUI Interface](#gui-interface)
|
||||
- [Housing](#housing)
|
||||
- [Dropped Features](#dropped-features)
|
||||
|
||||
|
||||
|
||||
# Feature Ideas
|
||||
- [x] Temperature control
|
||||
- fan
|
||||
- auto turn on
|
||||
- temp sensor
|
||||
- ~~turn on via gpio~~
|
||||
# Photos
|
||||
#### Photo of all Hardware Components
|
||||
### All components:
|
||||
<img src="doc/photos/all-components.jpg" alt="All Components (Disassembled)" width="65%"/>
|
||||
|
||||
### Assembly:
|
||||
<img src="doc\photos\all-connected.jpg" alt="" width="65%"/>
|
||||
|
||||
### Finished Project:
|
||||
<img src="doc\photos\final_diagonal-view.jpg" alt="" width="65%"/>
|
||||
<img src="doc\photos\final_back-view.jpg" alt="" width="65%"/>
|
||||
<img src="doc\photos\final_right-view.jpg" alt="" width="55%"/>
|
||||
|
||||
### Detail views with annotations:
|
||||
<img src="doc\photos\interface-board_top_annotated.jpg" alt="" width="65%"/>
|
||||
<img src="doc\photos\supply-raspberry_annotated.jpg" alt="" width="65%"/>
|
||||
|
||||
|
||||
## Supply
|
||||
- Input protection
|
||||
- [x] TVS
|
||||
- [x] reverse polarity (polyfuse will trigger)
|
||||
- [x] Fuse (5A polyfuse)
|
||||
- [x] buffer
|
||||
- [x] Pass through power supply
|
||||
- [x] 3.3V, 5V, 12V, 24V Regulator
|
||||
|
||||
- [x] power by barrel connector (24V 5A)
|
||||
- ~~power by usb~~ [not allowed]
|
||||
- ~~Switch between power by USB or power supply?~~
|
||||
- ~~power by battery~~ [dropped]
|
||||
- liion cell connector
|
||||
- BMS / charge controller
|
||||
- measure battery voltage
|
||||
- USB charging port
|
||||
---
|
||||
|
||||
|
||||
## IO
|
||||
- Input
|
||||
- GPIO
|
||||
- [x] wide voltage range (-1.7 to 120V)
|
||||
- [x] TVS
|
||||
- [x] reverse polarity (-1.73V max)
|
||||
- [x] Low pass filter
|
||||
- [x] Optocoupler input
|
||||
- [x] ADC
|
||||
- external IC
|
||||
- ~~multiplexer?~~
|
||||
- protection
|
||||
- scale input voltage
|
||||
- fixed inputs: 24V 12V 5V 3.3V
|
||||
- 20mA input
|
||||
- ~~trim potentiometer?~~
|
||||
- Output
|
||||
- [x] Relay
|
||||
- [x] Mosfet
|
||||
- [x] Optocoupler output
|
||||
- [ ] GPIO with over current protection
|
||||
- [ ] GPIO level shift (24V output)
|
||||
- [x] PWM pins
|
||||
- [x] shift register
|
||||
- [ ] DAC
|
||||
|
||||
- [x] LEDS indicate I/O state
|
||||
- [ ] Testpoints
|
||||
- [x] ESD protection (tvs diodes uart, i2c...)
|
||||
# Repository Content
|
||||
- **KiCad Projects**: 3 KiCad projects with schematics and PCB layouts for the custom PCBs created.
|
||||
- **Housing**: Custom enclosure design for PCBs and Raspberry Pi created in FreeCAD.
|
||||
- **Software/Firmware**: Python scripts run on the Raspberry Pi for operating and testing the PCB features and providing examples as base for future projects.
|
||||
|
||||
|
||||
## Bus
|
||||
- [x] UART/RS485
|
||||
- [ ] RS232 Connector
|
||||
- [x] I2C Pullup
|
||||
- [x] SPI
|
||||
- [ ] CAN
|
||||
- ~~Serial to usb (if Arduino)~~
|
||||
- ~~OWB default GPIO4~~
|
||||
---
|
||||
|
||||
|
||||
## UI
|
||||
- Input [dropped]
|
||||
- Buttons
|
||||
- DIP switches?
|
||||
- Temperature sensor
|
||||
- Encoder
|
||||
- Potentiometer
|
||||
- Output
|
||||
- [ ] Display [RPI display pending]
|
||||
- [x] Buzzer
|
||||
- [x] LEDS
|
||||
# Features Overview
|
||||
This project provides:
|
||||
- Protected GPIO I/O for Raspberry Pi.
|
||||
- Various analog inputs.
|
||||
- Flexible power supply options (3.3 V, 5 V, -5 V, 12 V, 24 V outputs).
|
||||
- Relay and MOSFET control.
|
||||
- Integrated LEDs for status indication.
|
||||
- RS485, I2C, SPI, and UART bus communication.
|
||||
|
||||
Detailed features of each PCB are described in the respective sections below.
|
||||
|
||||
---
|
||||
|
||||
# Designed PCBs
|
||||
|
||||
## 1. Raspberry Pi Interface Board
|
||||
This board connects to the Raspberry Pi via a 40-pin ribbon cable and provides protected GPIO extensions and versatile input/output features.
|
||||
|
||||
### Photo
|
||||
<img src="doc/photos/rpi-interface-board.jpg" alt="Raspberry Pi Interface Board" width="80%"/>
|
||||
|
||||
### Features
|
||||
**Inputs**:
|
||||
- **8x Digital Inputs**:
|
||||
- Wide voltage range (-1.7 V to 120 V) → compatible with 3 V and 24 V devices.
|
||||
- TVS diodes for ESD and spike protection.
|
||||
- Reverse polarity protection.
|
||||
- Isolated with optocouplers.
|
||||
- Optional low-pass filters (toggle via DIP switches).
|
||||
|
||||
- **8x Analog Inputs**:
|
||||
- Different fixed range inputs:
|
||||
- 2x 0 - 3.3 V.
|
||||
- 2x 0 - 5 V.
|
||||
- 1x 0 - 12 V.
|
||||
- 1x 0 - 24 V.
|
||||
- 2x 0 - 20 mA.
|
||||
- Overvoltage protection with clamping diodes.
|
||||
- Optional low-pass filters (toggle via DIP switches).
|
||||
|
||||
**Outputs**:
|
||||
- 1x onboard buzzer.
|
||||
- 2x 16 A relays.
|
||||
- 2x high-power MOSFETs (N-channel, max 55 V, 33 A continuous, 160 A pulsed).
|
||||
- 8x digital outputs (via shift register):
|
||||
- Low-power (30 mA push-pull) and high-power (500 mA open-drain) outputs.
|
||||
- Buzzer and relays connected to channels 6-8, with enable/disable switches.
|
||||
- **Note**: Outputs are **not short-circuit proof**.
|
||||
|
||||
**General**:
|
||||
- WAGO spring-loaded terminals for easy wiring.
|
||||
- JST connectors for external LEDs for all inputs and outputs to indicate the current pin state.
|
||||
|
||||
**Bus Communication**:
|
||||
- RS485 (TVS protection, idle pull-up/pull-down, 120 Ω terminator).
|
||||
- UART (unprotected).
|
||||
- I2C (TVS diodes, 2.2 kΩ pull-ups).
|
||||
- SPI (unprotected).
|
||||
- **Note**: RS485 and UART cannot be used simultaneously (select via jumpers).
|
||||
|
||||
### Schematic and Layout
|
||||
<p align="center">
|
||||
<a href="pi-interface-board_v1.0/export/schematic_interface-board.pdf">
|
||||
<img src="pi-interface-board_v1.0/export/schematic_interface-board.svg" width="49%" alt="Schematic"/>
|
||||
</a>
|
||||
<img src="pi-interface-board_v1.0/export/layout_interface-board.png" width="49%" alt="PCB Layout"/>
|
||||
</p>
|
||||
|
||||
|
||||
## Mechanical
|
||||
- [x] Barrel plug (24V 3A supply)
|
||||
- ~~Screw terminals~~
|
||||
- [x] spring loaded?
|
||||
- ~~pass through all pins?~~
|
||||
|
||||
## Housing
|
||||
- RPI ports
|
||||
- banana sockets for power out
|
||||
- screw terminal exposed
|
||||
- buttons, leds: need to open up?
|
||||
- BNC? []
|
||||
---
|
||||
|
||||
|
||||
## Other
|
||||
- Extension board with multiplexer
|
||||
- Breadboard compatible?
|
||||
- SD Card
|
||||
- ~~Onboard MCU for standalone use?~~
|
||||
- ~~separate bought MCU via i2c for additional GPIO, DAC, ADC in one~~
|
||||
## 2. Power Supply Board
|
||||
Creates different voltages from supplied 24 V. Supply for the Raspberry Pi interface board as well as several terminals for variable use (connect sensors, devices, etc., to the housing).
|
||||
|
||||
### Photo
|
||||
<img src="doc/photos/power-supply-board.jpg" alt="Power Supply Board" width="60%"/>
|
||||
|
||||
### Features
|
||||
**Input**:
|
||||
- 24 V 5 A barrel plug.
|
||||
- 5 A self-resetting polyfuse.
|
||||
- Reverse polarity protection.
|
||||
|
||||
**Output**:
|
||||
- 3.3 V, 3 A (buck converter).
|
||||
- 5 V, 5 A (buck converter).
|
||||
- -5 V, 20 mA (charge pump).
|
||||
- 12 V, 3 A (buck converter).
|
||||
- 24 V (supply voltage filtered).
|
||||
|
||||
**Fan Control**:
|
||||
- 2x connector for 10 kΩ NTC.
|
||||
- Threshold adjustable (trimmer potentiometer).
|
||||
- Hysteresis adjustable (trimmer potentiometer).
|
||||
- Select between 5 V or 12 V fan.
|
||||
|
||||
**General**:
|
||||
- Spring-loaded terminals for each voltage.
|
||||
- Combined internal terminals for all voltages.
|
||||
|
||||
### Schematic and Layout
|
||||
<p align="center">
|
||||
<a href="power-supply-board_v1.0/export/schematic_power-supply.pdf">
|
||||
<img src="power-supply-board_v1.0/export/schematic_power-supply.svg" width="55%" alt="Schematic"/>
|
||||
</a>
|
||||
<img src="power-supply-board_v1.0/export/layout_power-supply.png" width="44%" alt="PCB Layout"/>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## 3. LED Boards
|
||||
Small PCBs with LEDs, resistors, and mounting holes for housing indicators.
|
||||
|
||||
### Photo
|
||||
<img src="doc/photos/led-boards.jpg" alt="LED Boards" width="60%"/>
|
||||
|
||||
### Boards
|
||||
1. 2x 5 mm LEDs for relays.
|
||||
2. 2x 5 mm LEDs for PWM outputs.
|
||||
3. 8x 3 mm yellow LEDs for analog inputs.
|
||||
4. 8x 3 mm orange LEDs for digital inputs.
|
||||
5. 8x 3 mm red LEDs for digital outputs.
|
||||
|
||||
### Schematic and Layout
|
||||
<p align="center">
|
||||
<a href="led-boards_v0.1/export/schematic_led-boards.pdf">
|
||||
<img src="led-boards_v0.1/export/schematic_led-boards.svg" width="48%" alt="Schematic"/>
|
||||
</a>
|
||||
<img src="led-boards_v0.1/export/layout_led-boards.png" width="51%" alt="PCB Layout"/>
|
||||
</p>
|
||||
|
||||
|
||||
## Questions
|
||||
- what analog input ranges (Voltage, Count)
|
||||
- RS232 RS485 SPI, IIC actually necessary? examples
|
||||
- CAN to second SPI?
|
||||
- 8x shift register outputs, 0.5A open drain or 7mA tristate
|
||||
- 2x PWM 30A enough?
|
||||
- max used PWM freq? (drop opto if >80khz)
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
<br>
|
||||
|
||||
# Raspberry Pi Usage
|
||||
|
||||
## Connectivity
|
||||
The Raspberry Pi can operate **standalone** with a connected keyboard, mouse, and HDMI monitor, or by using the integrated display in the housing.
|
||||
|
||||
However, for **development**, it is recommended to connect it to a network via **WiFi or LAN**, allowing easy remote access from a laptop. A direct **Ethernet connection** between the Raspberry Pi and a laptop is often the simplest method.
|
||||
|
||||
### LAN Connection (Ethernet)
|
||||
- **Connection**: Connect cable directly between raspberry and PC
|
||||
- **Configure the PC interface**: Set a static ip address e.g. `192.168.1.1/24`
|
||||
Note: Optionally also enable network sharing to enable the RPI to use the internet connection the PC currently has.
|
||||
- **Configure the Raspberry Interface**: Set a static ip address e.g. `192.168.1.100/24`
|
||||
The Raspberry Pi can be configured for **Ethernet access** using different methods:
|
||||
- **Boot Partition Configuration:** Modify `cmdline.txt` on the SD card.
|
||||
- **GUI Setup:** Use the built-in network manager if a monitor is connected.
|
||||
- **Command Line (`nmcli`)**: Configure networking via the terminal.
|
||||
|
||||
To check the assigned IP run:
|
||||
```bash
|
||||
ip a
|
||||
```
|
||||
|
||||
### WiFi Connection
|
||||
Probably the **fastest and easiest** way to set up communication between the Raspberry Pi and a PC - while even maintaining internet access - is to **use a mobile phone as a WiFi hotspot**.
|
||||
Simply **connect both the Raspberry Pi and the laptop** to the same hotspot.
|
||||
|
||||
To connect to a WiFi network, use:
|
||||
```bash
|
||||
nmcli device wifi connect <SSID> password <password>
|
||||
```
|
||||
Replace `<SSID>` and `<password>` with the actual credentials.
|
||||
The Raspberry Pi will **automatically reconnect** after a reboot.
|
||||
|
||||
Once connected, you can check the assigned IP on the Raspberry Pi using:
|
||||
```
|
||||
ip a
|
||||
```
|
||||
|
||||
### SSH Access
|
||||
For remote terminal access, connect via SSH from a laptop:
|
||||
```bash
|
||||
ssh pi@192.168.1.100
|
||||
```
|
||||
Replace the IP with the actual address of the Raspberry Pi.
|
||||
|
||||
### Remote Desktop (RDP)
|
||||
To control the Raspberry Pi’s **GUI remotely**, RDP is pre-configured.
|
||||
|
||||
#### Connect via Windows Remote Desktop:
|
||||
- Open **Remote Desktop Connection (mstsc)**.
|
||||
- Enter the Raspberry Pi’s IP address.
|
||||
- **Login:**
|
||||
- **User:** `root`
|
||||
- **Password:** (configured during setup)
|
||||
- **Note:** Logging in as `pi` may result in a black screen.
|
||||
|
||||
#### Alternatively, use PowerShell:
|
||||
```powershell
|
||||
mstsc /v:192.168.1.100:3389
|
||||
```
|
||||
|
||||
### Mount Raspberry Pi Filesystem in Windows (SAMBA)
|
||||
For convenient file access and editing (e.g., with **VS Code**), the Raspberry Pi’s `/home/pi` directory can be **mounted as a network drive** using Samba.
|
||||
|
||||
#### Steps:
|
||||
1. Determine the Raspberry Pi’s IP address:
|
||||
```bash
|
||||
ip a
|
||||
```
|
||||
2. Mount the `/home/pi` directory in Windows:
|
||||
```powershell
|
||||
net use X: \\192.168.1.100\pi /user:pi
|
||||
```
|
||||
Replace `192.168.1.100` with the actual IP address.
|
||||
|
||||
**Note:**
|
||||
Currently, only `/home/pi` is available for mounting. To share additional directories, edit the Samba configuration file:
|
||||
```bash
|
||||
# add a new `[share]` section with the desired folder path and permissions.
|
||||
sudo nano /etc/samba/smb.conf
|
||||
# then restart samba
|
||||
sudo systemctl restart smbd
|
||||
```
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
# Python Scripting
|
||||
All **terminal-to-pin assignments** are mapped in [`interface_board_pins.py`](rpi-scripts/interface_board_pins.py), allowing easy reference to terminal numbers labeled on the housing.
|
||||
|
||||
Example scripts demonstrating I/O control can be found in [`rpi-scripts/examples`](rpi-scripts/examples).
|
||||
|
||||
---
|
||||
|
||||
## Running Python Examples
|
||||
Pre-written **Python scripts** to control I/O terminals are located in:
|
||||
```
|
||||
rpi-scripts/examples
|
||||
```
|
||||
To run an example, execute:
|
||||
```bash
|
||||
cd /home/pi/git/rpi-interface-board/rpi-scripts/examples/
|
||||
python read_digital_inputs.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Starting a New Python Project with I/O Access
|
||||
To create a custom Python project using the **interface board**, follow these steps:
|
||||
|
||||
1. **Copy the entire `rpi-scripts/` folder** to your new project directory.
|
||||
2. **Remove unnecessary files**, keeping at least:
|
||||
- `rpi-scripts/interface_board_libs/` → contains custom drivers.
|
||||
- `rpi-scripts/interface_board_pins.py` → maps terminal numbers to GPIO/ADC channels.
|
||||
3. **Start coding** by modifying an existing example in `examples/`.
|
||||
|
||||
---
|
||||
|
||||
## GUI Interface
|
||||
A **Python GUI** is available for **real-time monitoring** and **control** of all I/O terminals for quick testing.
|
||||
Currently it auto starts after boot and shows on the integrated display in fullscreen mode.
|
||||
|
||||
### Run the GUI
|
||||
```bash
|
||||
cd rpi-scripts/gui
|
||||
python main.py
|
||||
```
|
||||
|
||||
### Enable GUI Autostart on Boot
|
||||
The GUI is configured to start automatically on boot in **fullscreen mode**. To modify this behavior:
|
||||
|
||||
#### Enable autostart:
|
||||
```bash
|
||||
sudo cp rpi-scripts/gui/gui-start.service /etc/systemd/system/
|
||||
sudo systemctl enable gui-start.service
|
||||
```
|
||||
|
||||
#### Disable autostart:
|
||||
```bash
|
||||
sudo systemctl disable gui-start.service
|
||||
```
|
||||
|
||||
### GUI Screenshots
|
||||
<p align="center">
|
||||
<img src="doc\graphics\GUI_tab-control.png" width="70%" />
|
||||
<img src="doc\graphics\GUI_tab-adc-plot.png" width="70%" />
|
||||
<img src="doc\graphics\GUI_tab-digital-plot.png" width="70%" />
|
||||
</p>
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
# Housing
|
||||
Custom-designed enclosure includes:
|
||||
- Cutouts for all Ports for Raspberry Pi.
|
||||
- Mounting screws for all pcbs and Raspberry
|
||||
- Fan mount + venting slots
|
||||
- Cutouts for all external pcb terminals
|
||||
- Cutout + mounting arms (M2.5) for Display
|
||||
<img src="doc/graphics/3d-model_housing.png" width="80%" alt="3D Model"/>
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
# Dropped Features
|
||||
The following ideas were considered but not implemented:
|
||||
- UI Input Elements:
|
||||
- Buttons, DIP switches, temperature sensors, encoders, or potentiometers.
|
||||
- USB or battery-powered operation:
|
||||
- Battery packs with BMS and voltage measurement.
|
||||
- Li-ion cell holders.
|
||||
- Analog output (DAC)
|
||||
- More bus systems
|
||||
- RS232 Interface
|
||||
- CAN Interface
|
||||
|
177
doc/annotate-photos.drawio
Normal file
BIN
doc/graphics/3d-model_housing.png
Normal file
After Width: | Height: | Size: 469 KiB |
BIN
doc/graphics/GUI_tab-adc-plot.png
Normal file
After Width: | Height: | Size: 154 KiB |
BIN
doc/graphics/GUI_tab-control.png
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
doc/graphics/GUI_tab-digital-plot.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
doc/photos/all-components.jpg
Normal file
After Width: | Height: | Size: 965 KiB |
BIN
doc/photos/all-connected.jpg
Normal file
After Width: | Height: | Size: 634 KiB |
BIN
doc/photos/final_back-view.jpg
Normal file
After Width: | Height: | Size: 518 KiB |
BIN
doc/photos/final_diagonal-view.jpg
Normal file
After Width: | Height: | Size: 547 KiB |
BIN
doc/photos/final_right-view.jpg
Normal file
After Width: | Height: | Size: 335 KiB |
BIN
doc/photos/interface-board_top.jpg
Normal file
After Width: | Height: | Size: 1.0 MiB |
BIN
doc/photos/interface-board_top_annotated.jpg
Normal file
After Width: | Height: | Size: 798 KiB |
BIN
doc/photos/led-boards.jpg
Normal file
After Width: | Height: | Size: 216 KiB |
BIN
doc/photos/power-supply-board.jpg
Normal file
After Width: | Height: | Size: 213 KiB |
BIN
doc/photos/rpi-interface-board.jpg
Normal file
After Width: | Height: | Size: 411 KiB |
BIN
doc/photos/supply-raspberry.jpg
Normal file
After Width: | Height: | Size: 925 KiB |
BIN
doc/photos/supply-raspberry_annotated.jpg
Normal file
After Width: | Height: | Size: 704 KiB |
BIN
led-boards_v0.1/export/layout_led-boards.pdf
Normal file
BIN
led-boards_v0.1/export/layout_led-boards.png
Normal file
After Width: | Height: | Size: 300 KiB |
BIN
led-boards_v0.1/export/schematic_led-boards.pdf
Normal file
38608
led-boards_v0.1/export/schematic_led-boards.svg
Normal file
After Width: | Height: | Size: 674 KiB |
@ -13403,7 +13403,7 @@
|
||||
(justify left bottom)
|
||||
)
|
||||
)
|
||||
(gr_text "Note milling: mount holes om 8x led-boards cant be used with 2.2mm torx (too close to outline)"
|
||||
(gr_text "Note milling: mount holes on 8x led-boards cant be used with 2.2mm torx (too close to outline)"
|
||||
(at 131.4704 95.0976 0)
|
||||
(layer "Cmts.User")
|
||||
(uuid "63943838-40a0-44c5-a443-8f6982aa89df")
|
||||
@ -13427,7 +13427,7 @@
|
||||
(justify left bottom)
|
||||
)
|
||||
)
|
||||
(gr_text "2x PWM\n - 5mm blue\n - 20 Ohm\n - common anode"
|
||||
(gr_text "2x PWM\n - 5mm blue\n - 15 Ohm\n - common anode"
|
||||
(at 205.0288 48.8696 90)
|
||||
(layer "User.4")
|
||||
(uuid "33d1b519-e13f-4c02-9e89-5896e7524b33")
|
||||
@ -13439,7 +13439,7 @@
|
||||
(justify left bottom)
|
||||
)
|
||||
)
|
||||
(gr_text "8x analog in\n - 3mm yellow\n - 470 Ohm\n - common Cathode"
|
||||
(gr_text "8x analog in\n - 3mm yellow\n - 47 Ohm\n - common Cathode"
|
||||
(at 114.9096 71.6026 0)
|
||||
(layer "User.4")
|
||||
(uuid "4eaa8315-7c92-440c-a17c-7b34641e5a7d")
|
||||
@ -13463,7 +13463,7 @@
|
||||
(justify left bottom)
|
||||
)
|
||||
)
|
||||
(gr_text "8x digital out\n - 3mm red\n - 470 Ohm\n - common Anode"
|
||||
(gr_text "8x digital out\n - 3mm red\n - 47 Ohm\n - common Anode"
|
||||
(at 115.5446 58.5216 0)
|
||||
(layer "User.4")
|
||||
(uuid "ec0bb2f4-36e5-4095-bc0c-1aa615f8bbb7")
|
||||
|
@ -1,82 +0,0 @@
|
||||
{
|
||||
"board": {
|
||||
"active_layer": 44,
|
||||
"active_layer_preset": "",
|
||||
"auto_track_width": false,
|
||||
"hidden_netclasses": [],
|
||||
"hidden_nets": [],
|
||||
"high_contrast_mode": 0,
|
||||
"net_color_mode": 1,
|
||||
"opacity": {
|
||||
"images": 0.6,
|
||||
"pads": 1.0,
|
||||
"tracks": 1.0,
|
||||
"vias": 1.0,
|
||||
"zones": 0.6000000238418579
|
||||
},
|
||||
"selection_filter": {
|
||||
"dimensions": false,
|
||||
"footprints": false,
|
||||
"graphics": false,
|
||||
"keepouts": false,
|
||||
"lockedItems": false,
|
||||
"otherItems": false,
|
||||
"pads": false,
|
||||
"text": true,
|
||||
"tracks": false,
|
||||
"vias": false,
|
||||
"zones": false
|
||||
},
|
||||
"visible_items": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
13,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
32,
|
||||
33,
|
||||
34,
|
||||
35,
|
||||
36,
|
||||
39,
|
||||
40
|
||||
],
|
||||
"visible_layers": "ffeffff_ffffffff",
|
||||
"zone_display_mode": 0
|
||||
},
|
||||
"git": {
|
||||
"repo_password": "",
|
||||
"repo_type": "",
|
||||
"repo_username": "",
|
||||
"ssh_key": ""
|
||||
},
|
||||
"meta": {
|
||||
"filename": "led-boards_v0.1.kicad_prl",
|
||||
"version": 3
|
||||
},
|
||||
"project": {
|
||||
"files": []
|
||||
}
|
||||
}
|
@ -313,7 +313,7 @@
|
||||
)
|
||||
(wire
|
||||
(pts
|
||||
(xy 118.11 119.38) (xy 137.16 119.38)
|
||||
(xy 123.19 119.38) (xy 142.24 119.38)
|
||||
)
|
||||
(stroke
|
||||
(width 0)
|
||||
@ -413,7 +413,7 @@
|
||||
)
|
||||
(wire
|
||||
(pts
|
||||
(xy 118.11 127) (xy 137.16 127)
|
||||
(xy 123.19 127) (xy 142.24 127)
|
||||
)
|
||||
(stroke
|
||||
(width 0)
|
||||
@ -433,7 +433,7 @@
|
||||
)
|
||||
(polyline
|
||||
(pts
|
||||
(xy 172.085 95.25) (xy 172.085 146.05)
|
||||
(xy 106.68 95.25) (xy 106.68 146.05)
|
||||
)
|
||||
(stroke
|
||||
(width 0)
|
||||
@ -473,7 +473,7 @@
|
||||
)
|
||||
(wire
|
||||
(pts
|
||||
(xy 128.27 111.76) (xy 128.27 113.03)
|
||||
(xy 133.35 111.76) (xy 133.35 113.03)
|
||||
)
|
||||
(stroke
|
||||
(width 0)
|
||||
@ -483,7 +483,7 @@
|
||||
)
|
||||
(wire
|
||||
(pts
|
||||
(xy 128.27 113.03) (xy 137.16 113.03)
|
||||
(xy 133.35 113.03) (xy 142.24 113.03)
|
||||
)
|
||||
(stroke
|
||||
(width 0)
|
||||
@ -523,7 +523,7 @@
|
||||
)
|
||||
(wire
|
||||
(pts
|
||||
(xy 118.11 129.54) (xy 137.16 129.54)
|
||||
(xy 123.19 129.54) (xy 142.24 129.54)
|
||||
)
|
||||
(stroke
|
||||
(width 0)
|
||||
@ -543,7 +543,7 @@
|
||||
)
|
||||
(wire
|
||||
(pts
|
||||
(xy 118.11 121.92) (xy 137.16 121.92)
|
||||
(xy 123.19 121.92) (xy 142.24 121.92)
|
||||
)
|
||||
(stroke
|
||||
(width 0)
|
||||
@ -553,7 +553,7 @@
|
||||
)
|
||||
(wire
|
||||
(pts
|
||||
(xy 118.11 116.84) (xy 137.16 116.84)
|
||||
(xy 123.19 116.84) (xy 142.24 116.84)
|
||||
)
|
||||
(stroke
|
||||
(width 0)
|
||||
@ -643,7 +643,7 @@
|
||||
)
|
||||
(wire
|
||||
(pts
|
||||
(xy 118.11 124.46) (xy 137.16 124.46)
|
||||
(xy 123.19 124.46) (xy 142.24 124.46)
|
||||
)
|
||||
(stroke
|
||||
(width 0)
|
||||
@ -653,7 +653,7 @@
|
||||
)
|
||||
(wire
|
||||
(pts
|
||||
(xy 118.11 134.62) (xy 137.16 134.62)
|
||||
(xy 123.19 134.62) (xy 142.24 134.62)
|
||||
)
|
||||
(stroke
|
||||
(width 0)
|
||||
@ -663,7 +663,7 @@
|
||||
)
|
||||
(wire
|
||||
(pts
|
||||
(xy 118.11 132.08) (xy 137.16 132.08)
|
||||
(xy 123.19 132.08) (xy 142.24 132.08)
|
||||
)
|
||||
(stroke
|
||||
(width 0)
|
||||
@ -751,7 +751,7 @@
|
||||
)
|
||||
(uuid "0b1b0300-2259-4950-a74f-fd7767ec8854")
|
||||
)
|
||||
(text "5mm blue\n3V 20mA\n=> 20 Ohm"
|
||||
(text "5mm blue\n3V 20mA\n=> 15 Ohm"
|
||||
(exclude_from_sim no)
|
||||
(at 178.308 53.594 0)
|
||||
(effects
|
||||
@ -761,7 +761,7 @@
|
||||
)
|
||||
(uuid "100b8fd8-72b9-469a-be3b-fa49a5b022ae")
|
||||
)
|
||||
(text "3mm yellow\n2.3V 20mA\n-> 50Ohm -> 47Ohm"
|
||||
(text "3mm yellow\n2.3V 20mA\n-> 50 Ohm -> 47 Ohm"
|
||||
(exclude_from_sim no)
|
||||
(at 85.852 121.412 0)
|
||||
(effects
|
||||
@ -782,7 +782,7 @@
|
||||
)
|
||||
(uuid "2d4508d1-3ee0-4c2f-8a75-7442b6f42231")
|
||||
)
|
||||
(text "3mm red\n2.3V 20mA\n-> 50Ohm -> 47Ohm"
|
||||
(text "3mm red\n2.3V 20mA\n-> 50 Ohm -> 47 Ohm"
|
||||
(exclude_from_sim no)
|
||||
(at 241.808 122.682 0)
|
||||
(effects
|
||||
@ -794,7 +794,7 @@
|
||||
)
|
||||
(text "8x Digital Input (0-120V)"
|
||||
(exclude_from_sim no)
|
||||
(at 131.572 101.346 0)
|
||||
(at 136.652 101.346 0)
|
||||
(effects
|
||||
(font
|
||||
(size 2.2 2.2)
|
||||
@ -806,7 +806,7 @@
|
||||
)
|
||||
(text "3mm orange\n2.4V 30mA\n=> 27 Ohm"
|
||||
(exclude_from_sim no)
|
||||
(at 143.002 106.426 0)
|
||||
(at 148.082 106.426 0)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@ -837,7 +837,7 @@
|
||||
(uuid "f29599db-8ead-43ef-83ed-0987f5b28d85")
|
||||
)
|
||||
(label "LED_digital-out_6"
|
||||
(at 118.11 129.54 0)
|
||||
(at 123.19 129.54 0)
|
||||
(fields_autoplaced yes)
|
||||
(effects
|
||||
(font
|
||||
@ -848,7 +848,7 @@
|
||||
(uuid "072aff27-aaf2-4be4-afbf-274347824c00")
|
||||
)
|
||||
(label "LED_digital-out_3"
|
||||
(at 118.11 121.92 0)
|
||||
(at 123.19 121.92 0)
|
||||
(fields_autoplaced yes)
|
||||
(effects
|
||||
(font
|
||||
@ -859,7 +859,7 @@
|
||||
(uuid "0d7815ad-5557-40cf-8b30-0a142e5ea8a5")
|
||||
)
|
||||
(label "LED_digital-out_2"
|
||||
(at 118.11 119.38 0)
|
||||
(at 123.19 119.38 0)
|
||||
(fields_autoplaced yes)
|
||||
(effects
|
||||
(font
|
||||
@ -881,7 +881,7 @@
|
||||
(uuid "4b9f7c68-4da1-4f54-825b-8a53798277d6")
|
||||
)
|
||||
(label "LED_digital-out_4"
|
||||
(at 118.11 124.46 0)
|
||||
(at 123.19 124.46 0)
|
||||
(fields_autoplaced yes)
|
||||
(effects
|
||||
(font
|
||||
@ -903,7 +903,7 @@
|
||||
(uuid "a1c798e9-8ad2-4c32-99ba-2de06794f909")
|
||||
)
|
||||
(label "LED_digital-out_1"
|
||||
(at 118.11 116.84 0)
|
||||
(at 123.19 116.84 0)
|
||||
(fields_autoplaced yes)
|
||||
(effects
|
||||
(font
|
||||
@ -914,7 +914,7 @@
|
||||
(uuid "a7d8e74e-73bd-4897-8f46-7fbcfb513213")
|
||||
)
|
||||
(label "LED_digital-out_8"
|
||||
(at 118.11 134.62 0)
|
||||
(at 123.19 134.62 0)
|
||||
(fields_autoplaced yes)
|
||||
(effects
|
||||
(font
|
||||
@ -969,7 +969,7 @@
|
||||
(uuid "ba0bf30e-9aa8-48b7-827e-6edf8b31978d")
|
||||
)
|
||||
(label "LED_digital-out_7"
|
||||
(at 118.11 132.08 0)
|
||||
(at 123.19 132.08 0)
|
||||
(fields_autoplaced yes)
|
||||
(effects
|
||||
(font
|
||||
@ -1002,7 +1002,7 @@
|
||||
(uuid "c6de0414-3677-4ea9-b488-3930297bb16a")
|
||||
)
|
||||
(label "LED_digital-out_5"
|
||||
(at 118.11 127 0)
|
||||
(at 123.19 127 0)
|
||||
(fields_autoplaced yes)
|
||||
(effects
|
||||
(font
|
||||
@ -1234,7 +1234,7 @@
|
||||
)
|
||||
(symbol
|
||||
(lib_id "power:+3V3")
|
||||
(at 128.27 111.76 0)
|
||||
(at 133.35 111.76 0)
|
||||
(unit 1)
|
||||
(exclude_from_sim no)
|
||||
(in_bom yes)
|
||||
@ -1242,7 +1242,7 @@
|
||||
(dnp no)
|
||||
(uuid "3164481f-11e6-40e9-b0cd-a1da03401eb5")
|
||||
(property "Reference" "#PWR053"
|
||||
(at 128.27 115.57 0)
|
||||
(at 133.35 115.57 0)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@ -1251,7 +1251,7 @@
|
||||
)
|
||||
)
|
||||
(property "Value" "+3V3"
|
||||
(at 128.27 107.95 0)
|
||||
(at 133.35 107.95 0)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@ -1259,7 +1259,7 @@
|
||||
)
|
||||
)
|
||||
(property "Footprint" ""
|
||||
(at 128.27 111.76 0)
|
||||
(at 133.35 111.76 0)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@ -1268,7 +1268,7 @@
|
||||
)
|
||||
)
|
||||
(property "Datasheet" ""
|
||||
(at 128.27 111.76 0)
|
||||
(at 133.35 111.76 0)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@ -1277,7 +1277,7 @@
|
||||
)
|
||||
)
|
||||
(property "Description" "Power symbol creates a global label with name \"+3V3\""
|
||||
(at 128.27 111.76 0)
|
||||
(at 133.35 111.76 0)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@ -2138,7 +2138,7 @@
|
||||
)
|
||||
)
|
||||
(sheet
|
||||
(at 137.16 110.49)
|
||||
(at 142.24 110.49)
|
||||
(size 12.7 26.67)
|
||||
(stroke
|
||||
(width 0.1524)
|
||||
@ -2149,7 +2149,7 @@
|
||||
)
|
||||
(uuid "fa531529-e8ec-4675-8588-b82f9739f0d2")
|
||||
(property "Sheetname" "8x-LED-common-anode_external1"
|
||||
(at 120.904 139.7 0)
|
||||
(at 125.984 139.7 0)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@ -2158,7 +2158,7 @@
|
||||
)
|
||||
)
|
||||
(property "Sheetfile" "8x-LED-common-anode_external.kicad_sch"
|
||||
(at 122.936 140.716 0)
|
||||
(at 128.016 140.716 0)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@ -2167,7 +2167,7 @@
|
||||
)
|
||||
)
|
||||
(pin "LED1" input
|
||||
(at 137.16 116.84 180)
|
||||
(at 142.24 116.84 180)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@ -2177,7 +2177,7 @@
|
||||
(uuid "6da8b6a2-b024-4247-a890-5bf51440f28c")
|
||||
)
|
||||
(pin "LED2" input
|
||||
(at 137.16 119.38 180)
|
||||
(at 142.24 119.38 180)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@ -2187,7 +2187,7 @@
|
||||
(uuid "2370100f-ad7c-4528-88fa-8bcc40fbaa2d")
|
||||
)
|
||||
(pin "LED3" input
|
||||
(at 137.16 121.92 180)
|
||||
(at 142.24 121.92 180)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@ -2197,7 +2197,7 @@
|
||||
(uuid "8d3abcd6-30b8-4aeb-b4cb-795661ef8610")
|
||||
)
|
||||
(pin "LED4" input
|
||||
(at 137.16 124.46 180)
|
||||
(at 142.24 124.46 180)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@ -2207,7 +2207,7 @@
|
||||
(uuid "ea3a86ef-fab8-419a-9e21-421f525afbb0")
|
||||
)
|
||||
(pin "LED5" input
|
||||
(at 137.16 127 180)
|
||||
(at 142.24 127 180)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@ -2217,7 +2217,7 @@
|
||||
(uuid "62da66b4-50cb-44c4-b2b0-e398ac79dfbc")
|
||||
)
|
||||
(pin "LED7" input
|
||||
(at 137.16 132.08 180)
|
||||
(at 142.24 132.08 180)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@ -2227,7 +2227,7 @@
|
||||
(uuid "c6c67edf-76ba-4fea-b2fe-9b50ed6ea7bd")
|
||||
)
|
||||
(pin "LED8" input
|
||||
(at 137.16 134.62 180)
|
||||
(at 142.24 134.62 180)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@ -2237,7 +2237,7 @@
|
||||
(uuid "ebaacf63-30fb-4b4a-847c-fb3a8175f1e2")
|
||||
)
|
||||
(pin "LED6" input
|
||||
(at 137.16 129.54 180)
|
||||
(at 142.24 129.54 180)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@ -2247,7 +2247,7 @@
|
||||
(uuid "b204f650-9a0c-4653-a989-79dd1f2f4420")
|
||||
)
|
||||
(pin "Anode" input
|
||||
(at 137.16 113.03 180)
|
||||
(at 142.24 113.03 180)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
|
@ -224,6 +224,17 @@
|
||||
)
|
||||
(uuid "ff8e5d9b-ee46-4657-a2a4-813fdfa4d6f5")
|
||||
)
|
||||
(text "Note: Legacy hierachial sheet\nThis was outsourced to separate pcb project \n\"led-boards_v0.1\""
|
||||
(exclude_from_sim no)
|
||||
(at 40.132 46.228 0)
|
||||
(effects
|
||||
(font
|
||||
(size 2 2)
|
||||
)
|
||||
(justify left)
|
||||
)
|
||||
(uuid "d216fd8a-355b-44d9-82c9-ccddba031600")
|
||||
)
|
||||
(hierarchical_label "LED1"
|
||||
(shape input)
|
||||
(at 48.26 66.04 180)
|
||||
|
@ -438,6 +438,17 @@
|
||||
)
|
||||
(uuid "f0f511aa-d379-4ed6-b9f1-8d300b8f7a64")
|
||||
)
|
||||
(text "Note: Legacy hierachial sheet\nThis was outsourced to separate pcb project \n\"led-boards_v0.1\""
|
||||
(exclude_from_sim no)
|
||||
(at 70.612 38.862 0)
|
||||
(effects
|
||||
(font
|
||||
(size 2 2)
|
||||
)
|
||||
(justify left)
|
||||
)
|
||||
(uuid "0f424e6d-836c-4e21-bd19-f1b997455939")
|
||||
)
|
||||
(text "Connector for external LED board"
|
||||
(exclude_from_sim no)
|
||||
(at 75.692 48.768 0)
|
||||
|
@ -449,6 +449,17 @@
|
||||
)
|
||||
(uuid "3bb6e485-1926-4a9c-a057-6e133e2e6a90")
|
||||
)
|
||||
(text "Note: Legacy hierachial sheet\nThis was outsourced to separate pcb project \n\"led-boards_v0.1\""
|
||||
(exclude_from_sim no)
|
||||
(at 72.136 39.624 0)
|
||||
(effects
|
||||
(font
|
||||
(size 2 2)
|
||||
)
|
||||
(justify left)
|
||||
)
|
||||
(uuid "e0c12a11-96f5-42ef-8716-5299f12502f0")
|
||||
)
|
||||
(hierarchical_label "LED8"
|
||||
(shape input)
|
||||
(at 83.82 76.2 180)
|
||||
|
BIN
pi-interface-board_v1.0/export/layout_interface-board.pdf
Normal file
BIN
pi-interface-board_v1.0/export/layout_interface-board.png
Normal file
After Width: | Height: | Size: 847 KiB |
BIN
pi-interface-board_v1.0/export/schematic_interface-board.pdf
Normal file
295322
pi-interface-board_v1.0/export/schematic_interface-board.svg
Normal file
After Width: | Height: | Size: 5.2 MiB |
@ -1,82 +0,0 @@
|
||||
{
|
||||
"board": {
|
||||
"active_layer": 49,
|
||||
"active_layer_preset": "",
|
||||
"auto_track_width": false,
|
||||
"hidden_netclasses": [],
|
||||
"hidden_nets": [],
|
||||
"high_contrast_mode": 0,
|
||||
"net_color_mode": 1,
|
||||
"opacity": {
|
||||
"images": 0.6,
|
||||
"pads": 1.0,
|
||||
"tracks": 1.0,
|
||||
"vias": 1.0,
|
||||
"zones": 0.1599999964237213
|
||||
},
|
||||
"selection_filter": {
|
||||
"dimensions": false,
|
||||
"footprints": false,
|
||||
"graphics": false,
|
||||
"keepouts": false,
|
||||
"lockedItems": false,
|
||||
"otherItems": false,
|
||||
"pads": false,
|
||||
"text": true,
|
||||
"tracks": false,
|
||||
"vias": false,
|
||||
"zones": false
|
||||
},
|
||||
"visible_items": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
13,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
32,
|
||||
33,
|
||||
34,
|
||||
35,
|
||||
36,
|
||||
39,
|
||||
40
|
||||
],
|
||||
"visible_layers": "fffffff_fffffff9",
|
||||
"zone_display_mode": 0
|
||||
},
|
||||
"git": {
|
||||
"repo_password": "",
|
||||
"repo_type": "",
|
||||
"repo_username": "",
|
||||
"ssh_key": ""
|
||||
},
|
||||
"meta": {
|
||||
"filename": "pi-interface-board_v1.0.kicad_prl",
|
||||
"version": 3
|
||||
},
|
||||
"project": {
|
||||
"files": []
|
||||
}
|
||||
}
|
@ -37,9 +37,9 @@
|
||||
"other_text_thickness": 0.15,
|
||||
"other_text_upright": false,
|
||||
"pads": {
|
||||
"drill": 3.2,
|
||||
"height": 3.2,
|
||||
"width": 3.2
|
||||
"drill": 1.8,
|
||||
"height": 4.0,
|
||||
"width": 4.0
|
||||
},
|
||||
"silk_line_width": 0.1,
|
||||
"silk_text_italic": false,
|
||||
|
BIN
power-supply-board_v1.0/export/layout_power-supply.pdf
Normal file
BIN
power-supply-board_v1.0/export/layout_power-supply.png
Normal file
After Width: | Height: | Size: 419 KiB |
BIN
power-supply-board_v1.0/export/schematic_power-supply.pdf
Normal file
95813
power-supply-board_v1.0/export/schematic_power-supply.svg
Normal file
After Width: | Height: | Size: 1.9 MiB |
@ -4915,7 +4915,7 @@
|
||||
)
|
||||
)
|
||||
(property "Value" "Fan"
|
||||
(at 1.009962 6.24 180)
|
||||
(at 0.889962 7.9 -90)
|
||||
(layer "F.Fab")
|
||||
(uuid "4d4df2c7-768a-440f-b24d-257e61a23141")
|
||||
(effects
|
||||
@ -5362,7 +5362,7 @@
|
||||
)
|
||||
)
|
||||
(property "Value" "TP 5V"
|
||||
(at -4.4196 0.1016 0)
|
||||
(at -5.374 0.205 0)
|
||||
(layer "F.Fab")
|
||||
(uuid "a0c561cd-f07b-449b-bdd1-95638dd33795")
|
||||
(effects
|
||||
@ -6504,7 +6504,7 @@
|
||||
)
|
||||
)
|
||||
(property "Value" "TP GND"
|
||||
(at 0 2.33 0)
|
||||
(at -5.674 -0.009 0)
|
||||
(layer "F.Fab")
|
||||
(uuid "f731c7b1-c8fe-4e90-ac69-cb625c88948a")
|
||||
(effects
|
||||
@ -7243,7 +7243,7 @@
|
||||
)
|
||||
)
|
||||
(property "Value" "TP TEMP"
|
||||
(at 9.652 0.254 0)
|
||||
(at 9.528 -0.432 0)
|
||||
(layer "F.Fab")
|
||||
(uuid "ed3680c0-c9ba-4169-a084-10cfa6173f52")
|
||||
(effects
|
||||
@ -10050,7 +10050,7 @@
|
||||
)
|
||||
)
|
||||
(property "Value" "TP BATT"
|
||||
(at -5.2324 0.254 0)
|
||||
(at -6.84 0.174 0)
|
||||
(layer "F.Fab")
|
||||
(uuid "5f62316e-74b6-43ed-bb58-25015d3a0537")
|
||||
(effects
|
||||
@ -10306,7 +10306,7 @@
|
||||
)
|
||||
)
|
||||
(property "Value" "2200uf"
|
||||
(at -0.6096 2.579362 0)
|
||||
(at -0.952 2.579362 0)
|
||||
(layer "F.Fab")
|
||||
(uuid "1f7d7bb5-f802-471e-8ae7-4e1a80563b95")
|
||||
(effects
|
||||
@ -15778,7 +15778,7 @@
|
||||
)
|
||||
)
|
||||
(property "Value" "low power supply"
|
||||
(at 5 4.6 90)
|
||||
(at 5.304 -17.46 -90)
|
||||
(layer "F.Fab")
|
||||
(uuid "1d2b2d9a-85f8-4869-9ad4-78ea70baaaa5")
|
||||
(effects
|
||||
@ -16269,7 +16269,7 @@
|
||||
)
|
||||
)
|
||||
(property "Value" "24V 6A Supply"
|
||||
(at -19.9136 1.2954 0)
|
||||
(at -15.187 0.642 90)
|
||||
(layer "F.Fab")
|
||||
(uuid "b5278e3f-7951-4c56-8683-37a8cd2cebf3")
|
||||
(effects
|
||||
@ -20435,7 +20435,7 @@
|
||||
)
|
||||
)
|
||||
(property "Value" "high power supply"
|
||||
(at 5.1206 -3.456 0)
|
||||
(at 5.165 -6.037 0)
|
||||
(layer "F.Fab")
|
||||
(uuid "d9ee3520-6870-4f5a-8c4c-ed027f9844b0")
|
||||
(effects
|
||||
@ -20835,7 +20835,7 @@
|
||||
)
|
||||
)
|
||||
(property "Value" "high power supply"
|
||||
(at 5.5778 -3.5068 0)
|
||||
(at 5.115 -21.832 0)
|
||||
(layer "F.Fab")
|
||||
(uuid "7e1d6e39-ec62-4779-b99d-5474369325c0")
|
||||
(effects
|
||||
@ -24017,7 +24017,7 @@
|
||||
)
|
||||
)
|
||||
(property "Value" "TS-NTC-103 10k"
|
||||
(at 2.1444 -11.9634 0)
|
||||
(at 1.215 -11.968 0)
|
||||
(layer "F.Fab")
|
||||
(uuid "b5f74fe3-90ad-4c5b-8181-6c82cc7709ee")
|
||||
(effects
|
||||
@ -24808,7 +24808,7 @@
|
||||
)
|
||||
)
|
||||
(property "Value" "TP fan"
|
||||
(at 8.636 0 0)
|
||||
(at 8.907 -0.499 0)
|
||||
(layer "F.Fab")
|
||||
(uuid "66939a73-4b2f-47c9-b473-948dee2ca964")
|
||||
(effects
|
||||
@ -31280,7 +31280,7 @@
|
||||
)
|
||||
)
|
||||
(property "Value" "supply nopop"
|
||||
(at 1.761438 15.3135 0)
|
||||
(at 1.571038 11.0415 90)
|
||||
(unlocked yes)
|
||||
(layer "F.Fab")
|
||||
(uuid "e46b6e15-9716-430d-b064-c043b6a581e4")
|
||||
@ -33614,7 +33614,7 @@
|
||||
)
|
||||
)
|
||||
(property "Value" "TS-NTC-103 10k"
|
||||
(at 2.6162 -11.9126 180)
|
||||
(at 1.234 -12.068 180)
|
||||
(layer "F.Fab")
|
||||
(uuid "e646e6c0-b3cf-4c3c-86ed-e6c7826a5762")
|
||||
(effects
|
||||
@ -38546,7 +38546,7 @@
|
||||
)
|
||||
)
|
||||
(property "Value" "5A polyfuse"
|
||||
(at 5.6896 -0.5588 0)
|
||||
(at 6.3952 -0.3016 0)
|
||||
(layer "F.Fab")
|
||||
(uuid "3d2a814d-7d8a-4c99-959b-f1990d4d82c3")
|
||||
(effects
|
||||
@ -43261,6 +43261,32 @@
|
||||
(justify left bottom)
|
||||
)
|
||||
)
|
||||
(gr_text "5V/12V Drain\n"
|
||||
(at 183.9 109.025 90)
|
||||
(layer "B.Cu")
|
||||
(uuid "822cfa54-4e7d-4926-a61c-a59f69039109")
|
||||
(effects
|
||||
(font
|
||||
(size 1 1)
|
||||
(thickness 0.25)
|
||||
(bold yes)
|
||||
)
|
||||
(justify left bottom)
|
||||
)
|
||||
)
|
||||
(gr_text "12V, 5V, 3V3, GND"
|
||||
(at 126.625 29.55 0)
|
||||
(layer "Cmts.User")
|
||||
(uuid "0768b060-fa5a-44d8-8fb6-510f71d7a46c")
|
||||
(effects
|
||||
(font
|
||||
(size 1 1)
|
||||
(thickness 0.25)
|
||||
(bold yes)
|
||||
)
|
||||
(justify left bottom)
|
||||
)
|
||||
)
|
||||
(gr_text "Via"
|
||||
(at 195.707 48.006 0)
|
||||
(layer "Cmts.User")
|
||||
@ -43273,6 +43299,32 @@
|
||||
(justify left bottom)
|
||||
)
|
||||
)
|
||||
(gr_text "GND, 3V3, -5V, 5V, GND"
|
||||
(at 184.2 53.2 90)
|
||||
(layer "Cmts.User")
|
||||
(uuid "ac167a33-155f-491c-855c-7a657d21e44e")
|
||||
(effects
|
||||
(font
|
||||
(size 1 1)
|
||||
(thickness 0.25)
|
||||
(bold yes)
|
||||
)
|
||||
(justify left bottom)
|
||||
)
|
||||
)
|
||||
(gr_text "FIXME: Power supply barrel connector wrong polarity -> reroute"
|
||||
(at 94.91 137.52 0)
|
||||
(layer "Cmts.User")
|
||||
(uuid "d06dcb3d-61f7-46b5-ab9d-a35c29a9f224")
|
||||
(effects
|
||||
(font
|
||||
(size 1.5 1.5)
|
||||
(thickness 0.3)
|
||||
(bold yes)
|
||||
)
|
||||
(justify left bottom)
|
||||
)
|
||||
)
|
||||
(gr_text "Solder on Top side as well"
|
||||
(at 195.4022 53.1368 0)
|
||||
(layer "Cmts.User")
|
||||
|
@ -1,82 +0,0 @@
|
||||
{
|
||||
"board": {
|
||||
"active_layer": 31,
|
||||
"active_layer_preset": "",
|
||||
"auto_track_width": false,
|
||||
"hidden_netclasses": [],
|
||||
"hidden_nets": [],
|
||||
"high_contrast_mode": 0,
|
||||
"net_color_mode": 1,
|
||||
"opacity": {
|
||||
"images": 0.5,
|
||||
"pads": 1.0,
|
||||
"tracks": 1.0,
|
||||
"vias": 1.0,
|
||||
"zones": 0.4000000059604645
|
||||
},
|
||||
"selection_filter": {
|
||||
"dimensions": false,
|
||||
"footprints": true,
|
||||
"graphics": true,
|
||||
"keepouts": false,
|
||||
"lockedItems": false,
|
||||
"otherItems": false,
|
||||
"pads": false,
|
||||
"text": true,
|
||||
"tracks": true,
|
||||
"vias": false,
|
||||
"zones": false
|
||||
},
|
||||
"visible_items": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
13,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
32,
|
||||
33,
|
||||
34,
|
||||
35,
|
||||
36,
|
||||
39,
|
||||
40
|
||||
],
|
||||
"visible_layers": "48352a0_80000001",
|
||||
"zone_display_mode": 0
|
||||
},
|
||||
"git": {
|
||||
"repo_password": "",
|
||||
"repo_type": "",
|
||||
"repo_username": "",
|
||||
"ssh_key": ""
|
||||
},
|
||||
"meta": {
|
||||
"filename": "power-supply-board_v1.0.kicad_prl",
|
||||
"version": 3
|
||||
},
|
||||
"project": {
|
||||
"files": []
|
||||
}
|
||||
}
|
@ -4,6 +4,13 @@
|
||||
(generator_version "8.0")
|
||||
(uuid "af4d11a6-73e1-4c39-a25e-5fe7dfa07237")
|
||||
(paper "A3")
|
||||
(title_block
|
||||
(title "power-supply-board")
|
||||
(date "2024-12-20")
|
||||
(rev "V1.0")
|
||||
(comment 2 "Supplies 3V3, 5V -5V, 12V, Filtered 24V")
|
||||
(comment 3 "Supply board for rpi-interface board")
|
||||
)
|
||||
(lib_symbols
|
||||
(symbol "Amplifier_Operational:MCP6002-xP"
|
||||
(pin_names
|
||||
@ -14504,7 +14511,7 @@
|
||||
)
|
||||
(uuid "c5813cfa-ba8c-4a80-a9d4-664143707d07")
|
||||
)
|
||||
(text "2 NTC sensors spread in housing"
|
||||
(text "2 NTC sensors spread in housing\ne.g. RPI Cpu and 5V Regulator"
|
||||
(exclude_from_sim no)
|
||||
(at 208.534 59.436 0)
|
||||
(effects
|
||||
@ -14675,7 +14682,7 @@
|
||||
)
|
||||
(uuid "f9ba8cda-125a-469c-9294-dbb980b4df9f")
|
||||
)
|
||||
(text "TODO next version:\n - add LED for each voltage in housing (external using connector)?\n\nFixed since V1.0:\n - TVS polarity\n - Fuse, Diode footprint\n - add GND Testpoint\n - led gnd via\n - 5x low power connector\n\n"
|
||||
(text "TODO next version:\n - add LED for each voltage in housing (external using connector)?\n - FIXME: Verify power supply barrel connector polarity (wrong in V1.0)\n\nChangelog / Fixed since V1.0:\n - TVS polarity\n - Fuse, Diode footprint\n - add GND Testpoint\n - led gnd via\n - 5x low power connector\n\n"
|
||||
(exclude_from_sim no)
|
||||
(at 114.3 34.544 0)
|
||||
(effects
|
||||
|
64
rpi-scripts/examples/pass_through_inputs_to_outputs.py
Normal file
@ -0,0 +1,64 @@
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import RPi.GPIO as GPIO
|
||||
|
||||
|
||||
|
||||
# Import pin assignments and custom libraries
|
||||
# Add the parent directory to the module search path
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
from interface_board_pins import GPIO_DIGITAL_INPUTS # Input GPIO mapping
|
||||
from interface_board_pins import ( # Shift register pin assignment
|
||||
GPIO_SHIFT_REG_DATA,
|
||||
GPIO_SHIFT_REG_LATCH,
|
||||
GPIO_SHIFT_REG_CLOCK,
|
||||
)
|
||||
from interface_board_libs.shift_register import ShiftRegister # Custom shift register class
|
||||
|
||||
|
||||
|
||||
# Initialize GPIO for digital inputs
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
for pin in GPIO_DIGITAL_INPUTS.values():
|
||||
print(f"Configuring GPIO pin {pin} as input")
|
||||
GPIO.setup(pin, GPIO.IN)
|
||||
|
||||
|
||||
|
||||
# Initialize shift register
|
||||
sr = ShiftRegister(GPIO_SHIFT_REG_DATA, GPIO_SHIFT_REG_LATCH, GPIO_SHIFT_REG_CLOCK)
|
||||
|
||||
|
||||
|
||||
# Main loop: Read inputs and write to shift register
|
||||
print("\nStarting passthrough mode: Digital inputs → Shift register outputs")
|
||||
try:
|
||||
while True:
|
||||
shift_register_value = 0 # Byte to be written to the shift register
|
||||
print("\nReading inputs and updating shift register...")
|
||||
|
||||
for i, (label, pin) in enumerate(GPIO_DIGITAL_INPUTS.items()):
|
||||
state = GPIO.input(pin) # Read GPIO state
|
||||
print(f"Input {label} (GPIO {pin}): {'HIGH' if state else 'LOW'}")
|
||||
|
||||
# Set corresponding bit in shift register byte
|
||||
if state:
|
||||
shift_register_value |= (1 << i) # Set bit at position `i`
|
||||
else:
|
||||
shift_register_value &= ~(1 << i) # Clear bit at position `i`
|
||||
|
||||
# Write the final byte to the shift register
|
||||
sr.write_byte(shift_register_value)
|
||||
print(f"Shift Register Output: {format(shift_register_value, '08b')[::-1]}") # Print binary representation (mirrored, lsb first = terminal order)
|
||||
|
||||
time.sleep(0.3) # Small delay to prevent excessive polling
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\nExiting...")
|
||||
|
||||
finally:
|
||||
sr.clear() # Clear shift register before exiting
|
||||
print("Shift register cleared.")
|
||||
GPIO.cleanup() # Cleanup GPIO settings
|
||||
|
79
rpi-scripts/examples/read_analog_inputs.py
Normal file
@ -0,0 +1,79 @@
|
||||
# Include external libraries
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
# Include custom files
|
||||
# Add the parent directory to the module search path
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
from interface_board_libs.adc_mcp3208 import MCP3208 # custom driver for ADC-IC
|
||||
from interface_board_pins import (
|
||||
# mapping of ADC channels to terminals + max value:
|
||||
ADC_TERMINALS,
|
||||
# mapping of ADC channels to terminals:
|
||||
ADC_CHANNEL_T0__0_TO_3V3,
|
||||
ADC_CHANNEL_T1__0_TO_3V3,
|
||||
ADC_CHANNEL_T2__0_TO_5V,
|
||||
ADC_CHANNEL_T3__0_TO_5V,
|
||||
ADC_CHANNEL_T4__0_TO_12V,
|
||||
ADC_CHANNEL_T5__0_TO_24V,
|
||||
ADC_CHANNEL_T6__0_TO_20MA,
|
||||
ADC_CHANNEL_T7__0_TO_20MA,
|
||||
) # mapping of ADC channels to terminals
|
||||
|
||||
|
||||
# create ADC instance
|
||||
adc = MCP3208()
|
||||
|
||||
|
||||
|
||||
# local helper function to scale the adc value to an actual voltage
|
||||
def adc2value(adc_value, max_value):
|
||||
max_adc = 4095
|
||||
return adc_value * max_value / max_adc
|
||||
|
||||
|
||||
|
||||
|
||||
while True:
|
||||
print("-" * 40)
|
||||
|
||||
# Read all available channels in a loop according to terminal order / map
|
||||
values = []
|
||||
for terminal, config in ADC_TERMINALS.items():
|
||||
adc_channel = config["adc_channel"]
|
||||
max_value = config["max_value"]
|
||||
value = adc.read(adc_channel)
|
||||
print(f"T{terminal}: ADC={value:04d} => U_ADC = {adc2value(value, max_value):5.3f}V")
|
||||
|
||||
|
||||
# Read channels one by one using defined constants (more intuitive)
|
||||
print("-" * 40)
|
||||
value = adc.read(ADC_CHANNEL_T0__0_TO_3V3)
|
||||
print(f"Terminal 0 (0 to 3.3V): ADC={value:04d} => Terminal={adc2value(value, 3.3):4.2f}V")
|
||||
|
||||
value = adc.read(ADC_CHANNEL_T1__0_TO_3V3)
|
||||
print(f"Terminal 1 (0 to 3.3V): ADC={value:04d} => Terminal={adc2value(value, 3.3):4.2f}V")
|
||||
|
||||
value = adc.read(ADC_CHANNEL_T2__0_TO_5V)
|
||||
print(f"Terminal 2 (0 to 5V): ADC={value:04d} => Terminal={adc2value(value, 5):4.2f}V")
|
||||
|
||||
value = adc.read(ADC_CHANNEL_T3__0_TO_5V)
|
||||
print(f"Terminal 3 (0 to 5V): ADC={value:04d} => Terminal={adc2value(value, 5):4.2f}V")
|
||||
|
||||
value = adc.read(ADC_CHANNEL_T4__0_TO_12V)
|
||||
print(f"Terminal 4 (0 to 12V): ADC={value:04d} => Terminal={adc2value(value, 12):05.2f}V")
|
||||
|
||||
value = adc.read(ADC_CHANNEL_T5__0_TO_24V)
|
||||
print(f"Terminal 5 (0 to 24V): ADC={value:04d} => Terminal={adc2value(value, 24):05.2f}V")
|
||||
|
||||
value = adc.read(ADC_CHANNEL_T6__0_TO_20MA)
|
||||
print(f"Terminal 6 (0 to 20mA): ADC={value:04d} => Terminal={adc2value(value, 20):05.2f}mA")
|
||||
|
||||
value = adc.read(ADC_CHANNEL_T7__0_TO_20MA)
|
||||
print(f"Terminal 7 (0 to 20mA): ADC={value:04d} => Terminal={adc2value(value, 20):05.2f}mA")
|
||||
|
||||
print("-" * 40)
|
||||
time.sleep(1) # Delay before next read cycle
|
||||
|
37
rpi-scripts/examples/read_digital_inputs.py
Normal file
@ -0,0 +1,37 @@
|
||||
import os
|
||||
import sys
|
||||
# Add the parent directory to the module search path
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
# Include the common pin assignment (from parent folder)
|
||||
from interface_board_pins import GPIO_DIGITAL_INPUTS # map of which GPIO pins are associated with which input terminal (1-8)
|
||||
|
||||
import RPi.GPIO as GPIO
|
||||
import time
|
||||
|
||||
|
||||
|
||||
# Initialize GPIO
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
for pin in GPIO_DIGITAL_INPUTS.values():
|
||||
print(f"configuring pin {pin} as input")
|
||||
GPIO.setup(pin, GPIO.IN)
|
||||
|
||||
|
||||
|
||||
# Repeatedly read GPIOs
|
||||
print("Reading digital inputs:")
|
||||
try:
|
||||
while True:
|
||||
print("reading all gpio pins...")
|
||||
for label, pin in GPIO_DIGITAL_INPUTS.items():
|
||||
print(f"reading pin {pin}")
|
||||
state = GPIO.input(pin)
|
||||
print(f"Input {label} (GPIO {pin}): {'HIGH' if state else 'LOW'}")
|
||||
print("-" * 40)
|
||||
time.sleep(0.5)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("Exiting...")
|
||||
|
||||
finally:
|
||||
GPIO.cleanup()
|
82
rpi-scripts/examples/write_digital_outputs_shift_reg.py
Normal file
@ -0,0 +1,82 @@
|
||||
# Include external libraries
|
||||
import os
|
||||
import sys
|
||||
import RPi.GPIO as GPIO
|
||||
from time import sleep
|
||||
|
||||
|
||||
# Include custom files
|
||||
# Add the parent directory to the module search path
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
from interface_board_libs.shift_register import ShiftRegister # custom shift register class
|
||||
from interface_board_pins import ( # pin / channel assignment
|
||||
GPIO_SHIFT_REG_DATA,
|
||||
GPIO_SHIFT_REG_LATCH,
|
||||
GPIO_SHIFT_REG_CLOCK,
|
||||
SHIFT_REG_CHANNEL_BUZZER,
|
||||
SHIFT_REG_CHANNEL_RELAY1,
|
||||
SHIFT_REG_CHANNEL_RELAY2,
|
||||
)
|
||||
|
||||
|
||||
|
||||
# Config
|
||||
COUNT_UP_TEST_ENABLED = False
|
||||
DELAY_COUNT_UP = 0.008
|
||||
DELAY_TOGGLE = 0.3
|
||||
|
||||
|
||||
# Initialize the shift register
|
||||
sr = ShiftRegister(GPIO_SHIFT_REG_DATA, GPIO_SHIFT_REG_LATCH, GPIO_SHIFT_REG_CLOCK)
|
||||
|
||||
try:
|
||||
print("Writing to shift register...")
|
||||
|
||||
|
||||
# repeatedly write to shift register
|
||||
while True:
|
||||
# Cycle through all combinations of pin states (write entire byte)
|
||||
if COUNT_UP_TEST_ENABLED:
|
||||
print("Writing all byte values (0-255)...")
|
||||
for value in range(256):
|
||||
sr.write_byte(value) # Write the current value
|
||||
print(f"Output: {'{0:08b}'.format(value)}") # Print binary representation
|
||||
sleep(DELAY_COUNT_UP) # Delay between each byte
|
||||
|
||||
sleep(0.5)
|
||||
sr.clear() # Clear the shift register
|
||||
|
||||
|
||||
# Turn each pin on and off one by one
|
||||
print("\nToggling each pin one by one...")
|
||||
# channels 0-2 are connected to buzzer and relays:
|
||||
print(f"Num {SHIFT_REG_CHANNEL_BUZZER}: Toggling buzzer...") # channel 0
|
||||
sr.set_pin(SHIFT_REG_CHANNEL_BUZZER, True) # Turn buzzer ON
|
||||
sleep(DELAY_TOGGLE)
|
||||
sr.set_pin(SHIFT_REG_CHANNEL_BUZZER, False) # Turn buzzer OFF
|
||||
|
||||
print(f"Num {SHIFT_REG_CHANNEL_RELAY1}: Toggling Relay 1...") # channel 1
|
||||
sr.toggle_pin(SHIFT_REG_CHANNEL_RELAY1)
|
||||
sleep(DELAY_TOGGLE)
|
||||
sr.toggle_pin(SHIFT_REG_CHANNEL_RELAY1)
|
||||
|
||||
print(f"Num {SHIFT_REG_CHANNEL_RELAY2}: Toggling Relay 2...") # channel 2
|
||||
sr.set_pin(SHIFT_REG_CHANNEL_RELAY2, True) # Turn relay ON
|
||||
sleep(DELAY_TOGGLE)
|
||||
sr.set_pin(SHIFT_REG_CHANNEL_RELAY2, False) # Turn relay OFF
|
||||
|
||||
|
||||
# channels 3-7 are connected to terminals only (no dedicated device on pcb):
|
||||
for pin in range(3,8): # 3-7 are connected to terminal only
|
||||
print(f"Num: {pin}: Toggling Terminal")
|
||||
sr.set_pin(pin, True) # Set the pin HIGH
|
||||
sleep(DELAY_TOGGLE)
|
||||
#print(f"Setting pin {pin} LOW.")
|
||||
sr.set_pin(pin, False) # Set the pin LOW
|
||||
#sleep(0.5)
|
||||
|
||||
|
||||
finally:
|
||||
sr.clear() # Clear the shift register
|
||||
print("Shift register cleared.")
|
||||
GPIO.cleanup() # Clean up GPIO settings
|
76
rpi-scripts/examples/write_pwm_outputs.py
Normal file
@ -0,0 +1,76 @@
|
||||
# Include external libraries
|
||||
import os
|
||||
import sys
|
||||
import RPi.GPIO as GPIO
|
||||
from time import sleep
|
||||
|
||||
|
||||
# Include custom files
|
||||
# Add the parent directory to the module search path
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
from interface_board_pins import ( # pin / channel assignment
|
||||
GPIO_PWM1, # RPI_PWM0
|
||||
GPIO_PWM2 # RPI_PWM0 too
|
||||
)
|
||||
|
||||
|
||||
|
||||
# Config
|
||||
BLINK_ONLY = False
|
||||
|
||||
|
||||
|
||||
# PWM Settings
|
||||
FREQ = 1000 # PWM frequency in Hz
|
||||
STEP = 2 # Step size for fading
|
||||
DELAY = 0.03 # Delay between steps
|
||||
|
||||
try:
|
||||
print("Configuring PWM pins...")
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setup(GPIO_PWM1, GPIO.OUT)
|
||||
GPIO.setup(GPIO_PWM2, GPIO.OUT)
|
||||
|
||||
|
||||
if BLINK_ONLY:
|
||||
while True:
|
||||
print(f"PWM1 ON (GPIO {GPIO_PWM1})")
|
||||
GPIO.output(GPIO_PWM1, 1)
|
||||
sleep(2)
|
||||
print("PWM1 OFF")
|
||||
GPIO.output(GPIO_PWM1, 0)
|
||||
print(f"PWM2 ON (GPIO {GPIO_PWM2})")
|
||||
GPIO.output(GPIO_PWM2, 1)
|
||||
sleep(2)
|
||||
print("PWM2 OFF")
|
||||
GPIO.output(GPIO_PWM2, 0)
|
||||
|
||||
|
||||
# Initialize PWM on both pins
|
||||
pwm1 = GPIO.PWM(GPIO_PWM1, FREQ)
|
||||
pwm2 = GPIO.PWM(GPIO_PWM2, FREQ)
|
||||
|
||||
pwm1.start(0) # Start with 0% duty cycle
|
||||
pwm2.start(100) # Start with 100% duty cycle
|
||||
|
||||
print("Starting PWM fade effect...")
|
||||
while True:
|
||||
# Fade up PWM1 and fade down PWM2
|
||||
for duty in range(0, 101, STEP): # Duty cycle from 0% to 100%
|
||||
pwm1.ChangeDutyCycle(duty)
|
||||
pwm2.ChangeDutyCycle(100 - duty) # Opposite fade
|
||||
print(f"PWM1: {duty}% | PWM2: {100 - duty}%")
|
||||
sleep(DELAY)
|
||||
|
||||
# Fade down PWM1 and fade up PWM2
|
||||
for duty in range(100, -1, -STEP): # Duty cycle from 100% to 0%
|
||||
pwm1.ChangeDutyCycle(duty)
|
||||
pwm2.ChangeDutyCycle(100 - duty) # Opposite fade
|
||||
print(f"PWM1: {duty}% | PWM2: {100 - duty}%")
|
||||
sleep(DELAY)
|
||||
|
||||
finally:
|
||||
print("Exiting, stopping PWM and cleaning up...")
|
||||
pwm1.stop()
|
||||
pwm2.stop()
|
||||
GPIO.cleanup() # Clean up GPIO settings
|
27
rpi-scripts/gui/gui-start.service
Normal file
@ -0,0 +1,27 @@
|
||||
# systemd service file for auto starting the python gui
|
||||
# at the correct time after startup (when window manager finished starting)
|
||||
|
||||
|
||||
# Usage:
|
||||
# - Install: `sudo cp rpi-scripts/gui/gui-start.service /etc/systemd/system/`
|
||||
# - Enable autostart: `sudo systemctl enable gui-start.service`
|
||||
# - Disable autostart: `sudo systemctl disable gui-start.service`
|
||||
|
||||
[Unit]
|
||||
Description=Start Python GUI for IO-control and monitoring after startup
|
||||
# note: when using After=graphical.target: it only starts after successful network connection...
|
||||
After=display-manager.service
|
||||
Wants=display-manager.service
|
||||
|
||||
[Service]
|
||||
Environment=DISPLAY=:0
|
||||
|
||||
# note: some delay is needed for DISPLAY :0 to be available
|
||||
ExecStart=/bin/bash -c "/bin/sleep 6 && /usr/bin/python3 /home/pi/git/rpi-interface-board/rpi-scripts/gui/main.py"
|
||||
WorkingDirectory=/home/pi/git/rpi-interface-board/rpi-scripts/gui
|
||||
User=pi
|
||||
Group=pi
|
||||
Restart=no
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
90
rpi-scripts/gui/main.py
Normal file
@ -0,0 +1,90 @@
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from tkinter import messagebox
|
||||
import RPi.GPIO as GPIO
|
||||
|
||||
# Add the parent directory to the module search path
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
from interface_board_libs.adc_mcp3208 import MCP3208
|
||||
from interface_board_libs.shift_register import ShiftRegister
|
||||
from interface_board_pins import * # Import pin assignments
|
||||
from tab_control import create_control_tab
|
||||
from tab_control import set_updating_enabled as tab_control__set_updating_enabled
|
||||
from tab_adc_plot import create_adc_plot_tab
|
||||
from tab_adc_plot import set_updating_enabled as tab_analog_plot__set_updating_enabled
|
||||
from tab_digital_plot import create_digital_plot_tab
|
||||
from tab_digital_plot import set_updating_enabled as tab_digital_plot__set_updating_enabled
|
||||
from tab_exit import create_exit_tab
|
||||
|
||||
|
||||
# Initialize ADC & Shift Register
|
||||
adc = MCP3208()
|
||||
shift_reg = ShiftRegister(GPIO_SHIFT_REG_DATA, GPIO_SHIFT_REG_LATCH, GPIO_SHIFT_REG_CLOCK)
|
||||
|
||||
|
||||
# GPIO Setup
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
for pin in GPIO_DIGITAL_INPUTS.values():
|
||||
GPIO.setup(pin, GPIO.IN)
|
||||
GPIO.setup(GPIO_PWM1, GPIO.OUT)
|
||||
GPIO.setup(GPIO_PWM2, GPIO.OUT)
|
||||
pwm1 = GPIO.PWM(GPIO_PWM1, 1000)
|
||||
pwm2 = GPIO.PWM(GPIO_PWM2, 1000)
|
||||
pwm1.start(0)
|
||||
pwm2.start(0)
|
||||
|
||||
|
||||
# Tkinter GUI
|
||||
root = tk.Tk()
|
||||
root.title("Raspberry Pi Interface Board")
|
||||
root.attributes('-fullscreen', True)
|
||||
root.configure(bg="black")
|
||||
|
||||
|
||||
# Tabbed Interface
|
||||
notebook = ttk.Notebook(root)
|
||||
notebook.pack(expand=True, fill="both")
|
||||
|
||||
|
||||
# Track active tab
|
||||
def on_tab_change(event):
|
||||
active_tab = event.widget.tab(event.widget.index("current"), "text")
|
||||
print (f"INFO: switched to tab {active_tab}")
|
||||
match active_tab:
|
||||
case "ADC Plot":
|
||||
tab_control__set_updating_enabled(False)
|
||||
tab_analog_plot__set_updating_enabled(True)
|
||||
tab_digital_plot__set_updating_enabled(False)
|
||||
case "Digital Inputs":
|
||||
tab_control__set_updating_enabled(False)
|
||||
tab_analog_plot__set_updating_enabled(False)
|
||||
tab_digital_plot__set_updating_enabled(True)
|
||||
case "Controls":
|
||||
tab_control__set_updating_enabled(True)
|
||||
tab_analog_plot__set_updating_enabled(False)
|
||||
tab_digital_plot__set_updating_enabled(False)
|
||||
case "EXIT":
|
||||
pass
|
||||
case _:
|
||||
print(f"unhandled change to tab {active_tab}")
|
||||
|
||||
notebook.bind("<<NotebookTabChanged>>", on_tab_change)
|
||||
|
||||
|
||||
# Add tabs
|
||||
create_control_tab(notebook, adc, shift_reg, pwm1, pwm2)
|
||||
create_adc_plot_tab(notebook, adc)
|
||||
create_digital_plot_tab(notebook)
|
||||
create_exit_tab(notebook, root, pwm1, pwm2)
|
||||
|
||||
|
||||
# Run GUI
|
||||
try:
|
||||
root.mainloop()
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print('Keyboard interrupt -> exiting')
|
||||
exit()
|
86
rpi-scripts/gui/tab_adc_plot.py
Normal file
@ -0,0 +1,86 @@
|
||||
import sys
|
||||
import os
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from matplotlib.figure import Figure
|
||||
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
||||
import time
|
||||
|
||||
# Add the parent directory to the module search path
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
from interface_board_pins import ADC_TERMINALS # Import pin assignments
|
||||
|
||||
|
||||
# CONFIG
|
||||
ADC_PLOT_UPDATE_DELAY_MS = 50 # note: delay is additional to time it takes to update the chart
|
||||
TAB_NOT_ACTIVE_CHECK_INTERVAL_MS = 2000
|
||||
MAX_X_HISTORY_VALUES = 150
|
||||
AUTO_SCALE_ENABLED = True
|
||||
DEBUG = False
|
||||
|
||||
|
||||
# Variables
|
||||
updating_enabled = False
|
||||
adc_channels = list(range(8))
|
||||
data = {ch: [0] * MAX_X_HISTORY_VALUES for ch in adc_channels} # Preallocate lists
|
||||
time_data = list(range(-MAX_X_HISTORY_VALUES, 0)) # Simulated time axis
|
||||
|
||||
|
||||
def create_adc_plot_tab(notebook, adc):
|
||||
frame = ttk.Frame(notebook)
|
||||
notebook.add(frame, text="ADC Plot")
|
||||
|
||||
figure = Figure(figsize=(8, 5), dpi=100)
|
||||
ax = figure.add_subplot(1, 1, 1)
|
||||
|
||||
ax.set_title("ADC Inputs") # Set title
|
||||
ax.set_xlabel("Time (s)") # X-axis label
|
||||
ax.set_ylabel("Voltage / Current (V / mA)") # Y-axis label
|
||||
|
||||
ax.set_xlim(-MAX_X_HISTORY_VALUES, 0) # Keep time axis fixed
|
||||
canvas = FigureCanvasTkAgg(figure, master=frame)
|
||||
canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# Initialize lines for fast updates
|
||||
lines = {}
|
||||
for terminal, config in ADC_TERMINALS.items():
|
||||
label = f"T{terminal} ({config['max_value']} {config['unit']})" # Format: T1 (3.3V)
|
||||
lines[terminal] = ax.plot(time_data, data[terminal], label=label)[0]
|
||||
|
||||
ax.legend() # Show legend
|
||||
|
||||
def update_plot():
|
||||
if not updating_enabled:
|
||||
frame.after(TAB_NOT_ACTIVE_CHECK_INTERVAL_MS, update_plot)
|
||||
return
|
||||
|
||||
for terminal, config in ADC_TERMINALS.items():
|
||||
adc_channel = config["adc_channel"]
|
||||
max_value = config["max_value"]
|
||||
# Shift existing data left and
|
||||
# read new data + scale based on the correct max voltage
|
||||
data[terminal].pop(0)
|
||||
data[terminal].append(round(adc.read(adc_channel) * max_value / 4095, 2))
|
||||
|
||||
# Recalculate limits (autoscale)
|
||||
if AUTO_SCALE_ENABLED:
|
||||
ax.set_ylim(bottom=0) # Lower limit always 0
|
||||
ax.autoscale(enable=True, axis='y', tight=False) # Enable autoscale for upper limit
|
||||
ax.relim() # Recalculate limits
|
||||
ax.autoscale_view(scalex=False, scaley=True) # Autoscale only y-axis
|
||||
else:
|
||||
ax.set_ylim(0, 24) # Fixed range if autoscale is disabled
|
||||
|
||||
for terminal in ADC_TERMINALS:
|
||||
lines[terminal].set_ydata(data[terminal])
|
||||
|
||||
canvas.draw_idle() # Efficient redraw
|
||||
frame.after(ADC_PLOT_UPDATE_DELAY_MS, update_plot)
|
||||
|
||||
update_plot()
|
||||
|
||||
|
||||
def set_updating_enabled(is_active):
|
||||
global updating_enabled
|
||||
updating_enabled = is_active
|
||||
if DEBUG: print(f"adc_plot tab: set updating_enabled to {updating_enabled}")
|
141
rpi-scripts/gui/tab_control.py
Normal file
@ -0,0 +1,141 @@
|
||||
import sys
|
||||
import os
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
import RPi.GPIO as GPIO
|
||||
|
||||
# Add the parent directory to the module search path
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
from interface_board_pins import * # Import pin assignments
|
||||
|
||||
|
||||
# CONFIG
|
||||
ADC_VALUES_UPDATE_INTERVAL_MS = 500
|
||||
DIGITAL_INPUTS_UPDATE_INTERVAL_MS = 200
|
||||
TAB_NOT_ACTIVE_CHECK_INTERVAL_MS = 2000
|
||||
DEBUG = False
|
||||
|
||||
|
||||
# Variables
|
||||
updating_enabled = False
|
||||
|
||||
|
||||
def create_control_tab(notebook, adc, shift_reg, pwm1, pwm2):
|
||||
frame = ttk.Frame(notebook)
|
||||
notebook.add(frame, text="Controls")
|
||||
|
||||
digital_input_states = [tk.StringVar(value="LOW") for _ in range(8)]
|
||||
digital_output_states = [tk.BooleanVar(value=False) for _ in range(8)]
|
||||
adc_values = [tk.StringVar(value=" --- ") for _ in range(8)]
|
||||
pwm_values = [tk.IntVar(value=0), tk.IntVar(value=0)]
|
||||
output_buttons = {} # Store button references to change colors
|
||||
|
||||
|
||||
def update_inputs():
|
||||
if not updating_enabled:
|
||||
frame.after(TAB_NOT_ACTIVE_CHECK_INTERVAL_MS, update_inputs)
|
||||
return
|
||||
for i, pin in enumerate(GPIO_DIGITAL_INPUTS.values()):
|
||||
digital_input_states[i].set("HIGH" if GPIO.input(pin) else "LOW")
|
||||
frame.after(DIGITAL_INPUTS_UPDATE_INTERVAL_MS, update_inputs)
|
||||
|
||||
|
||||
def update_adc():
|
||||
if not updating_enabled:
|
||||
frame.after(TAB_NOT_ACTIVE_CHECK_INTERVAL_MS, update_adc)
|
||||
return
|
||||
|
||||
for terminal, config in ADC_TERMINALS.items():
|
||||
adc_channel = config["adc_channel"]
|
||||
max_value = config["max_value"]
|
||||
unit = config["unit"]
|
||||
|
||||
# Read ADC value and scale to the correct voltage
|
||||
value = adc.read(adc_channel)
|
||||
adc_values[terminal].set(f"{value * max_value / 4095:4.2f} {unit}")
|
||||
|
||||
frame.after(ADC_VALUES_UPDATE_INTERVAL_MS, update_adc)
|
||||
|
||||
|
||||
def toggle_output(index):
|
||||
""" Toggle shift register output and update button color. """
|
||||
new_state = not digital_output_states[index].get()
|
||||
digital_output_states[index].set(new_state)
|
||||
shift_reg.set_pin(index, new_state)
|
||||
|
||||
if index in output_buttons:
|
||||
for btn in output_buttons[index]:
|
||||
btn.configure(bg="green" if new_state else "red", activebackground="green" if new_state else "red")
|
||||
|
||||
|
||||
style = ttk.Style()
|
||||
style.configure("TScale", thickness=60)
|
||||
style.configure("TButton", font=("Arial", 18), padding=5)
|
||||
|
||||
control_frame = ttk.Frame(frame, padding=40)
|
||||
control_frame.grid(row=0, column=0, sticky="nsew")
|
||||
|
||||
frame.grid_rowconfigure(0, weight=1)
|
||||
frame.grid_rowconfigure(1, weight=0)
|
||||
frame.grid_columnconfigure(0, weight=1)
|
||||
|
||||
for i in range(8):
|
||||
ttk.Label(control_frame, text=f"ADC-{i}: ", font=("Arial", 18)).grid(row=i, column=0, sticky="e")
|
||||
ttk.Label(control_frame, textvariable=adc_values[i], width=10, font=("Arial", 18)).grid(row=i, column=1, sticky="w")
|
||||
ttk.Label(control_frame, text=f"IN-{i}:", font=("Arial", 18)).grid(row=i, column=2, sticky="e", padx=20)
|
||||
ttk.Label(control_frame, textvariable=digital_input_states[i], width=6, font=("Arial", 18)).grid(row=i, column=3, sticky="w")
|
||||
|
||||
btn = tk.Button(control_frame, text=f"OUT-{i}", font=("Arial", 16), width=10, bg="red", activebackground="red", command=lambda i=i: toggle_output(i))
|
||||
btn.grid(row=i, column=4, sticky="w", padx=20)
|
||||
|
||||
output_buttons.setdefault(i, []).append(btn)
|
||||
|
||||
if i == 0:
|
||||
buzzer_btn = tk.Button(control_frame, text="BUZZER", font=("Arial", 16), width=10, bg="red", activebackground="red", command=lambda: toggle_output(0))
|
||||
buzzer_btn.grid(row=i, column=5, padx=20)
|
||||
output_buttons[0].append(buzzer_btn)
|
||||
|
||||
if i == 1:
|
||||
relay2_btn = tk.Button(control_frame, text="RELAY2", font=("Arial", 16), width=10, bg="red", activebackground="red", command=lambda: toggle_output(1))
|
||||
relay2_btn.grid(row=i, column=5, padx=20)
|
||||
output_buttons[1].append(relay2_btn)
|
||||
|
||||
if i == 2:
|
||||
relay1_btn = tk.Button(control_frame, text="RELAY1", font=("Arial", 16), width=10, bg="red", activebackground="red", command=lambda: toggle_output(2))
|
||||
relay1_btn.grid(row=i, column=5, padx=20)
|
||||
output_buttons[2].append(relay1_btn)
|
||||
|
||||
pwm_frame = ttk.Frame(frame, padding=20)
|
||||
pwm_frame.grid(row=1, column=0, sticky="ew")
|
||||
|
||||
pwm_frame.columnconfigure(0, weight=0)
|
||||
pwm_frame.columnconfigure(1, weight=1)
|
||||
pwm_frame.columnconfigure(2, weight=0)
|
||||
|
||||
pwm1_label = ttk.Label(pwm_frame, text="PWM-1:", font=("Arial", 18))
|
||||
pwm1_label.grid(row=0, column=0, padx=20, sticky="e")
|
||||
|
||||
pwm1_slider = ttk.Scale(
|
||||
pwm_frame, from_=0, to=100, orient="horizontal", length=400,
|
||||
variable=pwm_values[0], command=lambda val: pwm1.ChangeDutyCycle(int(float(val)))
|
||||
)
|
||||
pwm1_slider.grid(row=0, column=1, columnspan=2, sticky="we", padx=10)
|
||||
|
||||
pwm2_label = ttk.Label(pwm_frame, text="PWM-2:", font=("Arial", 18))
|
||||
pwm2_label.grid(row=1, column=0, padx=20, sticky="e")
|
||||
|
||||
pwm2_slider = ttk.Scale(
|
||||
pwm_frame, from_=0, to=100, orient="horizontal", length=400,
|
||||
variable=pwm_values[1], command=lambda val: pwm2.ChangeDutyCycle(int(float(val)))
|
||||
)
|
||||
pwm2_slider.grid(row=1, column=1, columnspan=2, sticky="we", padx=10)
|
||||
|
||||
update_inputs()
|
||||
update_adc()
|
||||
|
||||
|
||||
|
||||
def set_updating_enabled(is_active):
|
||||
global updating_enabled
|
||||
updating_enabled = is_active
|
||||
if DEBUG: print(f"control tab: set updating_enabled to {updating_enabled}")
|
78
rpi-scripts/gui/tab_digital_plot.py
Normal file
@ -0,0 +1,78 @@
|
||||
import sys
|
||||
import os
|
||||
import threading
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
import RPi.GPIO as GPIO
|
||||
from matplotlib.figure import Figure
|
||||
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
||||
import time
|
||||
# Add the parent directory to the module search path
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
from interface_board_pins import * # Import pin assignments
|
||||
|
||||
|
||||
# CONFIG
|
||||
DIGITAL_PLOT_UPDATE_DELAY_MS = 50 # note: delay is additional to time it takes to update the chart
|
||||
TAB_NOT_ACTIVE_CHECK_INTERVAL_MS = 2000 # Check inactive tabs less frequently
|
||||
MAX_X_HISTORY_VALUES = 100 # Keep last 100 values for scrolling
|
||||
DEBUG = False
|
||||
|
||||
|
||||
# Variables
|
||||
updating_enabled = False # Track if the tab is active
|
||||
input_channels = list(range(8))
|
||||
data = {ch: [0] * MAX_X_HISTORY_VALUES for ch in input_channels} # Preallocate data
|
||||
time_data = list(range(-MAX_X_HISTORY_VALUES, 0)) # Simulated time axis
|
||||
|
||||
|
||||
def create_digital_plot_tab(notebook):
|
||||
frame = ttk.Frame(notebook)
|
||||
notebook.add(frame, text="Digital Inputs")
|
||||
|
||||
figure = Figure(figsize=(8, 5), dpi=100)
|
||||
ax = figure.add_subplot(1, 1, 1)
|
||||
|
||||
ax.set_title("Digital Inputs") # Set title
|
||||
ax.set_xlabel("Time (s)") # X-axis label
|
||||
ax.set_ylabel("State (1=HIGH / 0=LOW)") # Y-axis label
|
||||
|
||||
ax.set_ylim(-0.2, 1.2)
|
||||
ax.set_xlim(-MAX_X_HISTORY_VALUES, 0) # Keep time axis fixed
|
||||
canvas = FigureCanvasTkAgg(figure, master=frame)
|
||||
canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# Initialize lines for fast updates
|
||||
lines = {}
|
||||
for ch in input_channels:
|
||||
label = f"Digital In {ch}"
|
||||
lines[ch] = ax.step(time_data, data[ch], where="post", label=label)[0]
|
||||
|
||||
ax.legend() # Show legend
|
||||
|
||||
def update_plot():
|
||||
if not updating_enabled:
|
||||
frame.after(TAB_NOT_ACTIVE_CHECK_INTERVAL_MS, update_plot)
|
||||
return
|
||||
|
||||
# Shift existing data left
|
||||
for ch in input_channels:
|
||||
data[ch].pop(0)
|
||||
data[ch].append(GPIO.input(GPIO_DIGITAL_INPUTS[ch]))
|
||||
|
||||
# Update only the y-data for efficiency
|
||||
for ch in input_channels:
|
||||
lines[ch].set_ydata(data[ch])
|
||||
|
||||
canvas.draw_idle() # More efficient than draw()
|
||||
frame.after(DIGITAL_PLOT_UPDATE_DELAY_MS, update_plot)
|
||||
|
||||
update_plot()
|
||||
|
||||
|
||||
|
||||
def set_updating_enabled(is_active):
|
||||
global updating_enabled
|
||||
updating_enabled = is_active
|
||||
if DEBUG: print(f"digital_plot tab: set updating_enabled to {updating_enabled}")
|
||||
|
21
rpi-scripts/gui/tab_exit.py
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
|
||||
def create_exit_tab(notebook, root, pwm1, pwm2):
|
||||
frame = ttk.Frame(notebook)
|
||||
notebook.add(frame, text="EXIT")
|
||||
|
||||
ttk.Label(frame, text="Exit the GUI", font=("Arial", 20)).pack(pady=20)
|
||||
|
||||
def exit_program():
|
||||
pwm1.stop()
|
||||
pwm2.stop()
|
||||
root.quit()
|
||||
root.destroy()
|
||||
|
||||
exit_button = ttk.Button(frame, text="Exit Application", command=exit_program, style="TButton")
|
||||
exit_button.pack(pady=20)
|
||||
|
||||
style = ttk.Style()
|
||||
style.configure("TButton", font=("Arial", 18), padding=10)
|
74
rpi-scripts/interface_board_libs/adc_mcp3208.py
Normal file
@ -0,0 +1,74 @@
|
||||
import spidev
|
||||
import time
|
||||
|
||||
DEBUG = False
|
||||
|
||||
|
||||
class MCP3208:
|
||||
def __init__(self, bus=0, device=0):
|
||||
# Initialize SPI bus and device
|
||||
self.spi = spidev.SpiDev()
|
||||
self.spi.open(bus, device) # Default SPI bus 0, device 0 (you can change as needed)
|
||||
self.spi.max_speed_hz = 1000000 # Adjust based on your needs (e.g., 1MHz)
|
||||
self.spi.mode = 0b00 # Set SPI mode (Mode 0 for MCP3208)
|
||||
|
||||
|
||||
def read(self, channel):
|
||||
"""
|
||||
Read the ADC value from the specified channel (0-7).
|
||||
"""
|
||||
|
||||
# MCP3208 is a 12-bit SPI ADC. Communication requires sending a 3-byte command and receiving a 3-byte response.
|
||||
# The bits in the command sequence are structured as follows:
|
||||
|
||||
# Command Byte (8 bits):
|
||||
# | Start (1) | Mode (1) | Channel (3) | Padding (3) |
|
||||
|
||||
# The MCP3208 responds with 3 bytes:
|
||||
# - Byte 1: Contains the highest bit (bit 11) of the 12-bit ADC result.
|
||||
# - Byte 2: Contains bits 10-3 of the ADC result.
|
||||
# - Byte 3: Contains bits 2-0 of the ADC result.
|
||||
|
||||
# Ensure the channel is valid (0-7)
|
||||
if channel < 0 or channel > 7:
|
||||
raise ValueError(f"Channel must be between 0 and 7. (current channel={channel})")
|
||||
|
||||
# Construct the command byte sequence:
|
||||
# - Start bit (1) -> 1000 0000 (0x80)
|
||||
# - Single-ended (1) -> 1100 0000 (0xC0)
|
||||
# - Channel (3 bits) shifted into position
|
||||
cmd = 0x80 # Start bit: 1000 0000
|
||||
cmd |= 0x40 # Single-ended mode: 1100 0000
|
||||
cmd |= (channel & 0x07) << 3 # Move channel number to bits 5-3
|
||||
|
||||
# Send the command and receive the 3-byte response
|
||||
ret = self.spi.xfer2([cmd, 0x00, 0x00]) # Send 3 bytes, receive 3 bytes
|
||||
|
||||
if DEBUG:
|
||||
print(f"result[0]: {bin(ret[0])}, result[1]: {bin(ret[1])}, result[2]: {bin(ret[2])}")
|
||||
|
||||
# Extract the 12-bit ADC result from the received bytes:
|
||||
val = (ret[0] & 0x01) << 11 # Extract bit 11 (MSB)
|
||||
val |= ret[1] << 3 # Extract bits 10-3
|
||||
val |= ret[2] >> 5 # Extract bits 2-0 (shift down)
|
||||
|
||||
return val & 0x0FFF # Mask to ensure only the lower 12 bits are used
|
||||
|
||||
|
||||
def close(self):
|
||||
"""Close SPI connection."""
|
||||
self.spi.close()
|
||||
|
||||
|
||||
|
||||
# Example usage:
|
||||
if __name__ == "__main__":
|
||||
adc = MCP3208()
|
||||
try:
|
||||
while True:
|
||||
for i in range(8):
|
||||
adc_value = adc.read(i)
|
||||
print(f'ADC[{i}]: {adc_value}')
|
||||
time.sleep(0.5)
|
||||
finally:
|
||||
adc.close()
|
51
rpi-scripts/interface_board_libs/shift_register.py
Normal file
@ -0,0 +1,51 @@
|
||||
import RPi.GPIO as GPIO
|
||||
from time import sleep
|
||||
|
||||
|
||||
class ShiftRegister:
|
||||
def __init__(self, data_pin, latch_pin, clock_pin):
|
||||
self.data_pin = data_pin
|
||||
self.latch_pin = latch_pin
|
||||
self.clock_pin = clock_pin
|
||||
self.current_byte = 0 # Tracks the current state of the shift register
|
||||
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setup(self.data_pin, GPIO.OUT)
|
||||
GPIO.setup(self.latch_pin, GPIO.OUT)
|
||||
GPIO.setup(self.clock_pin, GPIO.OUT)
|
||||
|
||||
def write_byte(self, byte):
|
||||
"""Writes an 8-bit value to the shift register."""
|
||||
GPIO.output(self.latch_pin, 0)
|
||||
for i in range(8):
|
||||
GPIO.output(self.clock_pin, 0)
|
||||
GPIO.output(self.data_pin, (byte >> (7 - i)) & 1) # MSB first
|
||||
GPIO.output(self.clock_pin, 1)
|
||||
GPIO.output(self.latch_pin, 1)
|
||||
self.current_byte = byte # Update the internal state
|
||||
|
||||
def clear(self):
|
||||
"""Clears the shift register (sets all outputs to 0)."""
|
||||
self.write_byte(0)
|
||||
|
||||
def set_pin(self, pin, state):
|
||||
"""
|
||||
Sets an individual pin to HIGH (1) or LOW (0).
|
||||
Pins are numbered 0-7, with 0 being the LSB (Q0) and 7 being the MSB (Q7).
|
||||
"""
|
||||
if not 0 <= pin <= 7:
|
||||
raise ValueError("Pin must be in range 0-7.")
|
||||
if state:
|
||||
self.current_byte |= (1 << pin) # Set the bit to 1
|
||||
else:
|
||||
self.current_byte &= ~(1 << pin) # Set the bit to 0
|
||||
self.write_byte(self.current_byte)
|
||||
|
||||
|
||||
def toggle_pin(self, pin):
|
||||
"""Toggles the state of an individual pin."""
|
||||
if not 0 <= pin <= 7:
|
||||
raise ValueError("Pin must be in range 0-7.")
|
||||
self.current_byte ^= (1 << pin) # Flip the bit
|
||||
self.write_byte(self.current_byte)
|
||||
|
113
rpi-scripts/interface_board_pins.py
Normal file
@ -0,0 +1,113 @@
|
||||
# Pin mappings for GPIOs and other components specifically for the pi-interface-board_v1.0
|
||||
|
||||
|
||||
|
||||
|
||||
# ======================
|
||||
# === Digital Inputs ===
|
||||
# ======================
|
||||
# Pin mappings for digital inputs (labeled on housing as 1-8)
|
||||
GPIO_DIGITAL_INPUTS = {
|
||||
0: 25, # Dig-IN_1 is connected to GPIO_25
|
||||
1: 16, # Dig-IN_2 is connected to GPIO_16
|
||||
2: 26, # Dig-IN_3 is connected to GPIO_26
|
||||
3: 13, # Dig-IN_4 is connected to GPIO_13
|
||||
4: 6, # Dig-IN_5 is connected to GPIO_6
|
||||
5: 5, # Dig-IN_6 is connected to GPIO_5
|
||||
6: 22, # Dig-IN_7 is connected to GPIO_22
|
||||
7: 24, # Dig-IN_8 is connected to GPIO_24
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
# ======================
|
||||
# === Shift Register ===
|
||||
# ======================
|
||||
GPIO_SHIFT_REG_DATA = 27
|
||||
GPIO_SHIFT_REG_LATCH = 17
|
||||
GPIO_SHIFT_REG_CLOCK = 4
|
||||
|
||||
# FIXME: numbering in schematic is wrong (inverse) layout / terminal order matches the shift register though (left to right -> 0-7)
|
||||
# Shift Register Channel Assignments
|
||||
SHIFT_REG_CHANNEL_BUZZER = 0 # Buzzer connected to shift register channel 0
|
||||
SHIFT_REG_CHANNEL_RELAY1 = 2 # Relay 1 connected to shift register channel 2
|
||||
SHIFT_REG_CHANNEL_RELAY2 = 1 # Relay 2 connected to shift register channel 1
|
||||
|
||||
|
||||
|
||||
|
||||
# ===============
|
||||
# ===== ADC =====
|
||||
# ===============
|
||||
# ADC IC is connected to RPI SPI interface 0 (pins below)
|
||||
ADC_SPI_BUS_NUM = 0
|
||||
ADC_SPI_DEVICE_NUM = 0
|
||||
ADC_SPI_CS_PIN = 8 # SPI Chip Select for MCP3208
|
||||
# MISO_0: GPIO_9
|
||||
# MOSI_0: GPIO_10
|
||||
# SCLK_0: GPIO_11
|
||||
# CE_0: GPIO# MCP3208 (ADC)
|
||||
|
||||
# Pin mappings for Terminal number to actual ADC channels, including max voltage range
|
||||
ADC_TERMINALS = {
|
||||
0: {"adc_channel": 1, "max_value": 3.3, "unit": "V"}, # Terminal 0 -> ADC channel 1, max 3.3V
|
||||
1: {"adc_channel": 0, "max_value": 3.3, "unit": "V"}, # Terminal 1 -> ADC channel 0, max 3.3V
|
||||
2: {"adc_channel": 3, "max_value": 5, "unit": "V"}, # Terminal 2 -> ADC channel 3, max 5V
|
||||
3: {"adc_channel": 2, "max_value": 5, "unit": "V"},
|
||||
4: {"adc_channel": 5, "max_value": 12, "unit": "V"},
|
||||
5: {"adc_channel": 4, "max_value": 24, "unit": "V"},
|
||||
6: {"adc_channel": 7, "max_value": 20, "unit": "mA"}, # Terminal 6 -> ADC channel 7, max 20mA
|
||||
7: {"adc_channel": 6, "max_value": 20, "unit": "mA"},
|
||||
}
|
||||
|
||||
|
||||
# Alternative to ADC_CHANNELS list have separate constants for the channels (more intuitive)
|
||||
ADC_CHANNEL_T0__0_TO_3V3 = 1
|
||||
ADC_CHANNEL_T1__0_TO_3V3 = 0
|
||||
ADC_CHANNEL_T2__0_TO_5V = 3
|
||||
ADC_CHANNEL_T3__0_TO_5V = 2
|
||||
ADC_CHANNEL_T4__0_TO_12V = 5
|
||||
ADC_CHANNEL_T5__0_TO_24V = 4
|
||||
ADC_CHANNEL_T6__0_TO_20MA = 7
|
||||
ADC_CHANNEL_T7__0_TO_20MA = 6
|
||||
|
||||
|
||||
|
||||
|
||||
# ====================
|
||||
# === SPI Terminal ===
|
||||
# ====================
|
||||
SPI_BUS_NUM = 1
|
||||
# MISO_1: GPIO_19
|
||||
# MOSI_1: GPIO_20
|
||||
# SCLK_1: GPIO_21
|
||||
# CE_1: GPIO_7
|
||||
|
||||
|
||||
|
||||
|
||||
# ====================
|
||||
# === I2C Terminal ===
|
||||
# ====================
|
||||
GPIO_I2C_SDA = 2
|
||||
GPIO_I2C_SCL = 3
|
||||
|
||||
|
||||
|
||||
|
||||
# ===================
|
||||
# === PWM outputs ===
|
||||
# ===================
|
||||
GPIO_PWM1 = 18 # RPI_PWM0
|
||||
GPIO_PWM2 = 12 # RPI_PWM0 too
|
||||
|
||||
|
||||
|
||||
|
||||
# ====================
|
||||
# === UART / RS485 ===
|
||||
# ====================
|
||||
GPIO_UART_TX = 14 # RPI TXD
|
||||
GPIO_UART_RX = 15 # RPI RXD
|
||||
GPIO_UART_DIR = 23
|