feat: initial version
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
use panic_halt as _;
|
||||
use rp2040_hal::{
|
||||
Timer,
|
||||
clocks::ClocksManager,
|
||||
gpio::Pins,
|
||||
pac::{self, I2C0, RESETS},
|
||||
};
|
||||
|
||||
#[unsafe(link_section = ".boot2")]
|
||||
#[used]
|
||||
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GENERIC_03H;
|
||||
const XTAL_FREQ_HZ: u32 = 12_000_000u32;
|
||||
|
||||
pub struct PicoParts {
|
||||
pub timer: Timer,
|
||||
pub pins: Pins,
|
||||
pub i2c0: I2C0,
|
||||
pub resets: RESETS,
|
||||
pub clocks: ClocksManager,
|
||||
}
|
||||
|
||||
pub fn setup() -> PicoParts {
|
||||
let mut pac = pac::Peripherals::take().unwrap();
|
||||
let mut watchdog = rp2040_hal::Watchdog::new(pac.WATCHDOG);
|
||||
let clocks = rp2040_hal::clocks::init_clocks_and_plls(
|
||||
XTAL_FREQ_HZ,
|
||||
pac.XOSC,
|
||||
pac.CLOCKS,
|
||||
pac.PLL_SYS,
|
||||
pac.PLL_USB,
|
||||
&mut pac.RESETS,
|
||||
&mut watchdog,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let timer = rp2040_hal::Timer::new(pac.TIMER, &mut pac.RESETS, &clocks);
|
||||
let sio = rp2040_hal::Sio::new(pac.SIO);
|
||||
|
||||
let pins = rp2040_hal::gpio::Pins::new(
|
||||
pac.IO_BANK0,
|
||||
pac.PADS_BANK0,
|
||||
sio.gpio_bank0,
|
||||
&mut pac.RESETS,
|
||||
);
|
||||
|
||||
PicoParts {
|
||||
timer,
|
||||
pins,
|
||||
i2c0: pac.I2C0,
|
||||
resets: pac.RESETS,
|
||||
clocks,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
use embedded_hal::digital::InputPin;
|
||||
use rp2040_hal::{
|
||||
Timer,
|
||||
gpio::{FunctionNull, FunctionSio, Pin, PullDown, PullUp, SioInput, bank0::*},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
lights::{PedestrianLight, TrafficLight},
|
||||
phases::{PHASES, Phase},
|
||||
};
|
||||
|
||||
pub struct TrafficController {
|
||||
pub phase_index: usize,
|
||||
pub phase_start: u64,
|
||||
pub main_traffic_light: TrafficLight<Gpio0, Gpio1, Gpio2>,
|
||||
pub north_traffic_light: TrafficLight<Gpio3, Gpio4, Gpio5>,
|
||||
pub south_traffic_light: TrafficLight<Gpio6, Gpio7, Gpio8>,
|
||||
pub pedestrian_light: PedestrianLight<Gpio9, Gpio10>,
|
||||
pub button: Pin<Gpio11, FunctionSio<SioInput>, PullUp>,
|
||||
pub button_state: bool,
|
||||
}
|
||||
|
||||
impl TrafficController {
|
||||
pub fn new(
|
||||
gpio0: Pin<Gpio0, FunctionNull, PullDown>,
|
||||
gpio1: Pin<Gpio1, FunctionNull, PullDown>,
|
||||
gpio2: Pin<Gpio2, FunctionNull, PullDown>,
|
||||
gpio3: Pin<Gpio3, FunctionNull, PullDown>,
|
||||
gpio4: Pin<Gpio4, FunctionNull, PullDown>,
|
||||
gpio5: Pin<Gpio5, FunctionNull, PullDown>,
|
||||
gpio6: Pin<Gpio6, FunctionNull, PullDown>,
|
||||
gpio7: Pin<Gpio7, FunctionNull, PullDown>,
|
||||
gpio8: Pin<Gpio8, FunctionNull, PullDown>,
|
||||
gpio9: Pin<Gpio9, FunctionNull, PullDown>,
|
||||
gpio10: Pin<Gpio10, FunctionNull, PullDown>,
|
||||
gpio11: Pin<Gpio11, FunctionNull, PullDown>,
|
||||
) -> Self {
|
||||
Self {
|
||||
phase_index: 0,
|
||||
phase_start: 0,
|
||||
|
||||
main_traffic_light: TrafficLight::new(
|
||||
gpio0.into_push_pull_output(),
|
||||
gpio1.into_push_pull_output(),
|
||||
gpio2.into_push_pull_output(),
|
||||
),
|
||||
|
||||
north_traffic_light: TrafficLight::new(
|
||||
gpio3.into_push_pull_output(),
|
||||
gpio4.into_push_pull_output(),
|
||||
gpio5.into_push_pull_output(),
|
||||
),
|
||||
|
||||
south_traffic_light: TrafficLight::new(
|
||||
gpio6.into_push_pull_output(),
|
||||
gpio7.into_push_pull_output(),
|
||||
gpio8.into_push_pull_output(),
|
||||
),
|
||||
|
||||
pedestrian_light: PedestrianLight::new(
|
||||
gpio9.into_push_pull_output(),
|
||||
gpio10.into_push_pull_output(),
|
||||
),
|
||||
|
||||
button: gpio11.into_pull_up_input(),
|
||||
button_state: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_inputs(&mut self) {
|
||||
if !PHASES[self.phase_index].accepts_button_request {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.button.is_low().unwrap_or(false) {
|
||||
self.button_state = true;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_phase(&mut self, now: u64) {
|
||||
self.phase_index = (self.phase_index + 1) % PHASES.len();
|
||||
self.phase_start = now;
|
||||
}
|
||||
|
||||
pub fn apply_phase(&mut self, phase: &Phase) {
|
||||
self.main_traffic_light.set(&phase.main);
|
||||
self.north_traffic_light.set(&phase.north);
|
||||
self.south_traffic_light.set(&phase.south);
|
||||
self.pedestrian_light.set(&phase.pedestrian);
|
||||
}
|
||||
|
||||
pub fn execute_cycle(&mut self, timer: &Timer) {
|
||||
let now = timer.get_counter().ticks();
|
||||
let elapsed = now.wrapping_sub(self.phase_start);
|
||||
if elapsed < PHASES[self.phase_index].duration {
|
||||
return;
|
||||
}
|
||||
|
||||
let previous_was_button_phase = PHASES[self.phase_index].requires_button_request;
|
||||
self.next_phase(now);
|
||||
if !self.button_state {
|
||||
while PHASES[self.phase_index].requires_button_request {
|
||||
self.next_phase(now);
|
||||
}
|
||||
}
|
||||
let next_is_button_phase = PHASES[self.phase_index].requires_button_request;
|
||||
|
||||
if !previous_was_button_phase && next_is_button_phase {
|
||||
self.button_state = false;
|
||||
}
|
||||
self.apply_phase(&PHASES[self.phase_index]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
use embedded_graphics::{
|
||||
Drawable,
|
||||
geometry::Point,
|
||||
mono_font::{MonoTextStyle, ascii::FONT_6X10},
|
||||
pixelcolor::BinaryColor,
|
||||
text::Text,
|
||||
};
|
||||
use rp2040_hal::{
|
||||
I2C,
|
||||
fugit::{Rate, RateExtU32},
|
||||
gpio::{
|
||||
FunctionI2C, Pin, PullUp,
|
||||
bank0::{Gpio16, Gpio17},
|
||||
},
|
||||
pac::{I2C0, RESETS},
|
||||
};
|
||||
use ssd1306::{
|
||||
I2CDisplayInterface, Ssd1306, mode::{BufferedGraphicsMode, DisplayConfig}, prelude::I2CInterface,
|
||||
rotation::DisplayRotation, size::DisplaySize128x64,
|
||||
};
|
||||
|
||||
type DisplayI2c = I2C<
|
||||
I2C0,
|
||||
(
|
||||
Pin<Gpio16, FunctionI2C, PullUp>,
|
||||
Pin<Gpio17, FunctionI2C, PullUp>,
|
||||
),
|
||||
>;
|
||||
|
||||
type OledDisplay =
|
||||
Ssd1306<I2CInterface<DisplayI2c>, DisplaySize128x64, BufferedGraphicsMode<DisplaySize128x64>>;
|
||||
|
||||
pub struct DisplayModule {
|
||||
display: OledDisplay,
|
||||
}
|
||||
|
||||
impl DisplayModule {
|
||||
pub fn new(
|
||||
sda: Pin<Gpio16, FunctionI2C, PullUp>,
|
||||
scl: Pin<Gpio17, FunctionI2C, PullUp>,
|
||||
i2c0: I2C0,
|
||||
resets: &mut RESETS,
|
||||
freq: Rate<u32, 1, 1>,
|
||||
) -> Self {
|
||||
let i2c = I2C::i2c0(i2c0, sda, scl, 400.kHz(), resets, freq);
|
||||
let interface = I2CDisplayInterface::new(i2c);
|
||||
let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
|
||||
.into_buffered_graphics_mode();
|
||||
|
||||
display.init().unwrap();
|
||||
|
||||
Self { display }
|
||||
}
|
||||
|
||||
pub fn print(&mut self, text: &str) {
|
||||
let style = MonoTextStyle::new(&FONT_6X10, BinaryColor::On);
|
||||
|
||||
Text::new(text, Point::new(0, 16), style)
|
||||
.draw(&mut self.display)
|
||||
.unwrap();
|
||||
|
||||
self.display.flush().unwrap();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
use embedded_hal::digital::OutputPin;
|
||||
use rp2040_hal::gpio::{FunctionSio, Pin, PinId, PullDown, SioOutput};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TrafficLightColor {
|
||||
Red,
|
||||
Yellow,
|
||||
Green,
|
||||
RedYellow,
|
||||
}
|
||||
|
||||
pub struct TrafficLight<P1: PinId, P2: PinId, P3: PinId> {
|
||||
red_light: Pin<P1, FunctionSio<SioOutput>, PullDown>,
|
||||
yellow_light: Pin<P2, FunctionSio<SioOutput>, PullDown>,
|
||||
green_light: Pin<P3, FunctionSio<SioOutput>, PullDown>,
|
||||
}
|
||||
|
||||
impl<P1: PinId, P2: PinId, P3: PinId> TrafficLight<P1, P2, P3> {
|
||||
pub fn new(
|
||||
red_light: Pin<P1, FunctionSio<SioOutput>, PullDown>,
|
||||
yellow_light: Pin<P2, FunctionSio<SioOutput>, PullDown>,
|
||||
green_light: Pin<P3, FunctionSio<SioOutput>, PullDown>,
|
||||
) -> Self {
|
||||
Self {
|
||||
red_light,
|
||||
yellow_light,
|
||||
green_light,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, color: &TrafficLightColor) {
|
||||
self.red_light.set_low().ok();
|
||||
self.yellow_light.set_low().ok();
|
||||
self.green_light.set_low().ok();
|
||||
|
||||
match color {
|
||||
TrafficLightColor::Red => {
|
||||
self.red_light.set_high().ok();
|
||||
}
|
||||
TrafficLightColor::Yellow => {
|
||||
self.yellow_light.set_high().ok();
|
||||
}
|
||||
TrafficLightColor::Green => {
|
||||
self.green_light.set_high().ok();
|
||||
}
|
||||
TrafficLightColor::RedYellow => {
|
||||
self.red_light.set_high().ok();
|
||||
self.yellow_light.set_high().ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PedestrianLightColor {
|
||||
Red,
|
||||
Green,
|
||||
}
|
||||
|
||||
pub struct PedestrianLight<P1: PinId, P2: PinId> {
|
||||
red_light: Pin<P1, FunctionSio<SioOutput>, PullDown>,
|
||||
green_light: Pin<P2, FunctionSio<SioOutput>, PullDown>,
|
||||
}
|
||||
|
||||
impl<P1: PinId, P2: PinId> PedestrianLight<P1, P2> {
|
||||
pub fn new(
|
||||
red_light: Pin<P1, FunctionSio<SioOutput>, PullDown>,
|
||||
green_light: Pin<P2, FunctionSio<SioOutput>, PullDown>,
|
||||
) -> Self {
|
||||
Self {
|
||||
red_light,
|
||||
green_light,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, color: &PedestrianLightColor) {
|
||||
self.red_light.set_low().ok();
|
||||
self.green_light.set_low().ok();
|
||||
|
||||
match color {
|
||||
PedestrianLightColor::Red => {
|
||||
self.red_light.set_high().ok();
|
||||
}
|
||||
PedestrianLightColor::Green => {
|
||||
self.green_light.set_high().ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
mod boilerplate;
|
||||
mod controller;
|
||||
mod display;
|
||||
mod lights;
|
||||
mod phases;
|
||||
|
||||
use boilerplate::*;
|
||||
use controller::*;
|
||||
use phases::*;
|
||||
use rp2040_hal::Clock;
|
||||
|
||||
use crate::display::DisplayModule;
|
||||
|
||||
#[rp2040_hal::entry]
|
||||
fn main() -> ! {
|
||||
let PicoParts {
|
||||
timer,
|
||||
pins,
|
||||
i2c0,
|
||||
mut resets,
|
||||
clocks,
|
||||
} = setup();
|
||||
|
||||
let mut display = {
|
||||
let sda = pins.gpio16.reconfigure();
|
||||
let scl = pins.gpio17.reconfigure();
|
||||
let freq = clocks.system_clock.freq();
|
||||
|
||||
DisplayModule::new(sda, scl, i2c0, &mut resets, freq)
|
||||
};
|
||||
display.print("Hello Pico");
|
||||
|
||||
let mut traffic_controller = TrafficController::new(
|
||||
pins.gpio0,
|
||||
pins.gpio1,
|
||||
pins.gpio2,
|
||||
pins.gpio3,
|
||||
pins.gpio4,
|
||||
pins.gpio5,
|
||||
pins.gpio6,
|
||||
pins.gpio7,
|
||||
pins.gpio8,
|
||||
pins.gpio9,
|
||||
pins.gpio10,
|
||||
pins.gpio11,
|
||||
);
|
||||
traffic_controller.phase_start = timer.get_counter().ticks();
|
||||
traffic_controller.apply_phase(&PHASES[0]);
|
||||
|
||||
loop {
|
||||
traffic_controller.read_inputs();
|
||||
traffic_controller.execute_cycle(&timer);
|
||||
}
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
use crate::lights::{PedestrianLightColor, TrafficLightColor};
|
||||
|
||||
pub struct Phase {
|
||||
pub duration: u64,
|
||||
pub main: TrafficLightColor,
|
||||
pub north: TrafficLightColor,
|
||||
pub south: TrafficLightColor,
|
||||
pub pedestrian: PedestrianLightColor,
|
||||
pub requires_button_request: bool,
|
||||
pub accepts_button_request: bool,
|
||||
}
|
||||
|
||||
pub const PHASES: [Phase; 14] = [
|
||||
Phase {
|
||||
duration: 500_000,
|
||||
main: TrafficLightColor::RedYellow,
|
||||
north: TrafficLightColor::Red,
|
||||
south: TrafficLightColor::Red,
|
||||
pedestrian: PedestrianLightColor::Red,
|
||||
requires_button_request: false,
|
||||
accepts_button_request: true,
|
||||
},
|
||||
Phase {
|
||||
duration: 500_000,
|
||||
main: TrafficLightColor::Green,
|
||||
north: TrafficLightColor::Red,
|
||||
south: TrafficLightColor::Red,
|
||||
pedestrian: PedestrianLightColor::Red,
|
||||
requires_button_request: false,
|
||||
accepts_button_request: true,
|
||||
},
|
||||
Phase {
|
||||
duration: 500_000,
|
||||
main: TrafficLightColor::Yellow,
|
||||
north: TrafficLightColor::Red,
|
||||
south: TrafficLightColor::Red,
|
||||
pedestrian: PedestrianLightColor::Red,
|
||||
requires_button_request: false,
|
||||
accepts_button_request: true,
|
||||
},
|
||||
Phase {
|
||||
duration: 500_000,
|
||||
main: TrafficLightColor::Red,
|
||||
north: TrafficLightColor::Red,
|
||||
south: TrafficLightColor::Red,
|
||||
pedestrian: PedestrianLightColor::Red,
|
||||
requires_button_request: false,
|
||||
accepts_button_request: true,
|
||||
},
|
||||
Phase {
|
||||
duration: 500_000,
|
||||
main: TrafficLightColor::Red,
|
||||
north: TrafficLightColor::RedYellow,
|
||||
south: TrafficLightColor::Red,
|
||||
pedestrian: PedestrianLightColor::Red,
|
||||
requires_button_request: false,
|
||||
accepts_button_request: true,
|
||||
},
|
||||
Phase {
|
||||
duration: 500_000,
|
||||
main: TrafficLightColor::Red,
|
||||
north: TrafficLightColor::Green,
|
||||
south: TrafficLightColor::Red,
|
||||
pedestrian: PedestrianLightColor::Red,
|
||||
requires_button_request: false,
|
||||
accepts_button_request: true,
|
||||
},
|
||||
Phase {
|
||||
duration: 500_000,
|
||||
main: TrafficLightColor::Red,
|
||||
north: TrafficLightColor::Yellow,
|
||||
south: TrafficLightColor::Red,
|
||||
pedestrian: PedestrianLightColor::Red,
|
||||
requires_button_request: false,
|
||||
accepts_button_request: true,
|
||||
},
|
||||
Phase {
|
||||
duration: 500_000,
|
||||
main: TrafficLightColor::Red,
|
||||
north: TrafficLightColor::Red,
|
||||
south: TrafficLightColor::Red,
|
||||
pedestrian: PedestrianLightColor::Red,
|
||||
requires_button_request: false,
|
||||
accepts_button_request: true,
|
||||
},
|
||||
Phase {
|
||||
duration: 500_000,
|
||||
main: TrafficLightColor::Red,
|
||||
north: TrafficLightColor::Red,
|
||||
south: TrafficLightColor::RedYellow,
|
||||
pedestrian: PedestrianLightColor::Red,
|
||||
requires_button_request: false,
|
||||
accepts_button_request: true,
|
||||
},
|
||||
Phase {
|
||||
duration: 500_000,
|
||||
main: TrafficLightColor::Red,
|
||||
north: TrafficLightColor::Red,
|
||||
south: TrafficLightColor::Green,
|
||||
pedestrian: PedestrianLightColor::Red,
|
||||
requires_button_request: false,
|
||||
accepts_button_request: true,
|
||||
},
|
||||
Phase {
|
||||
duration: 500_000,
|
||||
main: TrafficLightColor::Red,
|
||||
north: TrafficLightColor::Red,
|
||||
south: TrafficLightColor::Yellow,
|
||||
pedestrian: PedestrianLightColor::Red,
|
||||
requires_button_request: false,
|
||||
accepts_button_request: true,
|
||||
},
|
||||
Phase {
|
||||
duration: 500_000,
|
||||
main: TrafficLightColor::Red,
|
||||
north: TrafficLightColor::Red,
|
||||
south: TrafficLightColor::Red,
|
||||
pedestrian: PedestrianLightColor::Red,
|
||||
requires_button_request: false,
|
||||
accepts_button_request: true,
|
||||
},
|
||||
Phase {
|
||||
duration: 500_000,
|
||||
main: TrafficLightColor::Red,
|
||||
north: TrafficLightColor::Red,
|
||||
south: TrafficLightColor::Red,
|
||||
pedestrian: PedestrianLightColor::Green,
|
||||
requires_button_request: true,
|
||||
accepts_button_request: false,
|
||||
},
|
||||
Phase {
|
||||
duration: 500_000,
|
||||
main: TrafficLightColor::Red,
|
||||
north: TrafficLightColor::Red,
|
||||
south: TrafficLightColor::Red,
|
||||
pedestrian: PedestrianLightColor::Red,
|
||||
requires_button_request: true,
|
||||
accepts_button_request: false,
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user