Closed47

ラズパイ入門記録(入力編)

(love cat)(love cat)

まずはなんの変哲もないボタンをやっていく。
ボタンを押すと何かが起こるというのは絶対に楽しい。
https://docs.sunfounder.com/projects/davinci-kit/ja/latest/2.1.1_button.html

(love cat)(love cat)

10kΩの抵抗が登場。ピンにインプットとして入れるにはこれぐらいの抵抗を噛ませる必要があるということだろうか。
回路図の意味がよくわからなかったが、通常時(ボタン内の回路が繋がっている)はGNDの方に電流が流れボタンを押すとGPIO18の方に電流が流れるってことかな。

(love cat)(love cat)

まあ他に解釈のしようもないんだけど、GNDに流れる道があるならそっちに全部流れるというイメージがついていない。

(love cat)(love cat)

ボタンを押したときに一瞬オフになってすぐオンになる(またはその逆)ということがある。
ボタンの不良というよりかは回路の組み方に問題がある?

(love cat)(love cat)

ボタンを押している間だけLEDが消える。理想とはちょっと違うな。

pub fn button() -> Result<(), Box<dyn Error>> {
    let input = Gpio::new()?.get(GPIO18)?.into_input();
    let mut output = Gpio::new()?.get(GPIO17)?.into_output();
    loop {
        if input.is_high() {
            output.set_low();
        } else {
            output.set_high();
        }
    }
}
(love cat)(love cat)

もっといい方法がありそうだがまずは力技。

pub fn button() -> Result<(), Box<dyn Error>> {
    let input = Gpio::new()?.get(GPIO18)?.into_input();
    let mut output = Gpio::new()?.get(GPIO17)?.into_output();
    let mut pressed = 0;

    output.set_high();
    loop {
        if pressed == 1 && output.is_set_high() {
            output.set_low();
            while input.is_low() {}
            pressed = 0;
        } else if pressed == 1 && output.is_set_low() {
            output.set_high();
            while input.is_low() {}
            pressed = 0;
        } else if pressed == 0 && input.is_low() {
            pressed = 1;
        }
    }
}
(love cat)(love cat)

set_interruptの第一引数はTrigger列挙体(Disabled,RisingEdge,FallingEdge,Both)。
RisingEdgeとFallingEdgeはイメージつくが他の2つはあんまり使わないんじゃないかと思って確認もしていない。
セットしたらpoll_interruptでブロックする。第一引数はresetで、trueかfalseかでキャッシュされたイベントをクリアするかどうか(何が変わるのかわかってない)。
第2引数はタイムアウト時間。ブロックする時間を指定できる。

pub fn button() -> Result<(), Box<dyn Error>> {
    let mut input = Gpio::new()?.get(GPIO18)?.into_input();
    let mut output = Gpio::new()?.get(GPIO17)?.into_output();

    output.set_high();
    input
        .set_interrupt(rppal::gpio::Trigger::FallingEdge)
        .expect("failed to set_interrupt.");
    loop {
        match input.poll_interrupt(true, None) {
            Ok(_) => output.toggle(),
            Err(e) => println!("{}", e),
        }
    }
}
(love cat)(love cat)

下記のようにしてボタンをポチポチすると最初に押してから2秒後にLEDがついたり消えたりする。
キャッシュしたイベントをクリアするようにしておけば勿論そんな挙動はしない。
ボタン使ってる分には基本trueかな。

match input.poll_interrupt(false, None) {
    Ok(_) => {
        thread::sleep(Duration::from_secs(2));
        output.toggle();
    },
    Err(e) => println!("{}", e),
}
(love cat)(love cat)

次はスライドスイッチ。どんな仕組みなのか考えたこともなかった。別にこれに限った話ではないが。
https://docs.sunfounder.com/projects/davinci-kit/ja/latest/2.1.2_slide Switch.html

(love cat)(love cat)

スイッチを切り替えてから3秒くらい待たないでもう一度切り替えるとラズパイ落ちるっぽい?
落とすとマズそうな間はラズパイ本体の赤LEDも消えてる。いつもどうだったか、あまり覚えてないからこれがどういうことなのかはやっぱりわからない。

(love cat)(love cat)

低電圧状態になると消灯するらしい。
https://raspberrypi.mongonta.com/underpower/
上記のブログを参考に"vcgencmd get_throttled"を試したところ、"throttled=0x50000"との答え。
スイッチ切り替え直後に試すと"throttled=0x50005"と返ってきた。

じゃあ電源あれば満足なのかと電源モジュールを繋いだら何も気にせずスイッチを切り替えられるようになった。

(love cat)(love cat)

落ち着いて回路図を見る。ここで逆起電力とやらが発生しているのでは?

ダイオードを追加したところ解決。電源モジュールなんてなくともスイッチ切り替え放題になった。

(love cat)(love cat)

面白いところはないが。

pub fn slide_button() -> Result<(), Box<dyn Error>> {
    let mut led_1 = Gpio::new()?.get(GPIO22)?.into_output();
    let mut led_2 = Gpio::new()?.get(GPIO27)?.into_output();
    let input_pin = Gpio::new()?.get(GPIO17)?.into_input();

    loop {
        if input_pin.is_high() {
            led_1.set_low();
            led_2.set_high();
            println!("LED1 on");
            thread::sleep(Duration::from_secs(1));
        } else {
            led_2.set_low();
            led_1.set_high();
            println!("LED2 on");
            thread::sleep(Duration::from_secs(1));
        }
    }
}
(love cat)(love cat)

Trigger::Bothを使うとしたらここだなと思い使ってみた。
スライドしまくっているといつの間にかスライド位置と点灯するLEDの組み合わせが変わっていたりする。

    // 省略
    input_pin
        .set_interrupt(rppal::gpio::Trigger::Both)
        .expect("failed to set_interrupt.");

    loop {
        match input_pin.poll_interrupt(true, None) {
            Ok(_) => {
                led_1.toggle();
                led_2.toggle();
            }
            Err(e) => println!("{}", e),
        }
    }
(love cat)(love cat)

チルトスイッチ。傾きの検出に使われるらしい。
https://docs.sunfounder.com/projects/davinci-kit/ja/latest/2.1.3_tilt_switch.html

(love cat)(love cat)

これだとちょっとブレッドボードを小突いただけでLEDが切り替わる。

pub fn tilt() -> Result<(), Box<dyn Error>> {
    let mut led_1 = Gpio::new()?.get(GPIO22)?.into_output();
    let mut led_2 = Gpio::new()?.get(GPIO27)?.into_output();
    let mut input_pin = Gpio::new()?.get(GPIO17)?.into_input();

    led_1.set_high();
    led_2.set_low();
    input_pin
        .set_interrupt(rppal::gpio::Trigger::Both)
        .expect("failed to set_interrupt.");

    let running = Arc::new(AtomicBool::new(true));
    let r = running.clone();
    ctrlc::set_handler(move || {
        r.store(false, Ordering::SeqCst);
    })
    .expect("Error setting Ctrl-C handler");

    while running.load(Ordering::SeqCst) {
        match input_pin.poll_interrupt(true, None) {
            Ok(_) => {
                led_1.toggle();
                led_2.toggle();
                thread::sleep(Duration::from_millis(500));
            }
            Err(e) => println!("{}", e),
        }
    }
    led_1.set_low();
    led_2.set_low();
    Ok(())
}
(love cat)(love cat)

サンプルコードをちゃんと見てsleepを挟むようにした。
Trigger::Bothで待ち受けても、HighかLowかで処理を振り分けられるよう。

pub fn tilt() -> Result<(), Box<dyn Error>> {
    let mut led_1 = Gpio::new()?.get(GPIO22)?.into_output();
    let mut led_2 = Gpio::new()?.get(GPIO27)?.into_output();
    let mut input_pin = Gpio::new()?.get(GPIO17)?.into_input();

    input_pin
        .set_interrupt(rppal::gpio::Trigger::Both)
        .expect("failed to set_interrupt.");

    let running = Arc::new(AtomicBool::new(true));
    let r = running.clone();
    ctrlc::set_handler(move || {
        r.store(false, Ordering::SeqCst);
    })
    .expect("Error setting Ctrl-C handler");
    while running.load(Ordering::SeqCst) {
        match input_pin.poll_interrupt(true, None) {
            Ok(trigger) => {
                thread::sleep(Duration::from_millis(10));
                match trigger {
                    Some(rppal::gpio::Level::High) => {
                        led_1.set_high();
                        led_2.set_low();
                    }
                    Some(rppal::gpio::Level::Low) => {
                        println!("Tilt!");
                        led_2.set_high();
                        led_1.set_low();
                    }
                    None => break,
                }
                thread::sleep(Duration::from_millis(500));
            }
            Err(_) => println!("\nEnd"),
        }
    }
    led_1.set_low();
    led_2.set_low();
    Ok(())
}
(love cat)(love cat)

ポテンショメータ。つまみで抵抗値を変化させられるものらしい。
そんな名前だったのか。
ADC0834というADコンバータによって、アナログ信号をデジタル信号に変換することでつまみの回し具合でLEDの明るさを調整する。
https://docs.sunfounder.com/projects/davinci-kit/ja/latest/2.1.4_potentiometer.html

(love cat)(love cat)

C言語での例をもとにどう操作してるのか整理する。
get_ADC_Result関数で明るさを操作する値を取得していて、呼び出し時に渡す値は常に0(channel)。
get_ADC_Result側でselとoddという変数があるがこれはchannelをもとに決まるので引数の値が0のときはselが0、oddが1。
スタートビットを送り、SGLをhigh、ODDをhigh、Select Bitをlowで送ることでチャンネルを1に設定。
次にhighを2回送っているがこれがわからない。マニュアルでも無視しろって書いてあるが気になりすぎる。教えてくれよ。

(love cat)(love cat)

最初のクロックをスカすのは、MSB-First Dataの前が1つ空いてるからか。
get_ADC_Resultの2つ目のループでCLK操作の前にdat2の値の計算に入っているのはLSBがMSB-First DataとLSB First Dataの最下位ビットだから。

(love cat)(love cat)

サンプルコード、どうしてDIとDOを1つのピンでまかなっているんだろう。節約?
気に食わなかったのでDOにGPIO23を割り当てたが動いた。
どうも変換をしくってそう。Cのサンプルコードでの変換後の値と比べると1bit足りない感じの値、明るさ。

fn snd_bit(clk_pin: &mut OutputPin, input_pin: &mut OutputPin, value: u8) {
    clk_pin.set_low();
    thread::sleep(Duration::from_micros(2));
    if value == 0 {
        input_pin.set_low();
    } else {
        input_pin.set_high();
    }
    clk_pin.set_high();
    thread::sleep(Duration::from_micros(2));
}

fn rcv_bit(clk_pin: &mut OutputPin, output_pin: &mut InputPin) -> u8 {
    let result;
    clk_pin.set_low();
    thread::sleep(Duration::from_micros(2));
    if output_pin.is_high() {
        result = 1;
    } else {
        result = 0;
    }
    clk_pin.set_high();
    thread::sleep(Duration::from_micros(2));
    return result;
}

pub fn potentiometer() -> Result<(), Box<dyn Error>> {
    let mut msb = 0;
    let mut lsb = 0;

    let mut adc_cs = Gpio::new()?.get(GPIO17)?.into_output();
    let mut adc_do = Gpio::new()?.get(GPIO23)?.into_input();
    let mut adc_di = Gpio::new()?.get(GPIO27)?.into_output();
    let mut adc_clk = Gpio::new()?.get(GPIO18)?.into_output();
    let mut led = Gpio::new()?.get(GPIO22)?.into_output();

    loop {
        // 変換の開始
        adc_cs.set_low();
        // スタートビット
        snd_bit(&mut adc_clk, &mut adc_di, 1);
        // SGL
        snd_bit(&mut adc_clk, &mut adc_di, 1);
        // ODD
        snd_bit(&mut adc_clk, &mut adc_di, 1);
        // Select
        snd_bit(&mut adc_clk, &mut adc_di, 0);

        // スカされるbit。送信する値に意味なし。
        snd_bit(&mut adc_clk, &mut adc_di, 0);

        // MSB-First Data
        for _ in 0..7 {
            msb = msb << 1 | rcv_bit(&mut adc_clk, &mut adc_do);
        }
        // MSB-First DataとLSB-First Dataの最下位bit
        adc_clk.set_low();
        thread::sleep(Duration::from_micros(2));
        msb = msb << 1 | if adc_do.is_high() { 1 } else { 0 };
        lsb = if adc_do.is_high() { 1 } else { 0 };
        adc_clk.set_high();
        // LSB-First Data
        for i in 1..8 {
            lsb = rcv_bit(&mut adc_clk, &mut adc_do) << i | lsb;
        }
        // 変換の終了
        adc_cs.set_high();
        // LED点灯
        if msb == lsb {
            led.set_pwm_frequency(2000.0, (msb as f64) / 255.0)?;
        }
    }
}
(love cat)(love cat)
(love cat)(love cat)

まだまだ汚く見えるけど、とりあえず動く。
サンプルコードとの違いは、同時押しの判定がシビアになっていることと、連続で同じキーを押しても印字してくれること。

pub fn keypad() -> Result<(), Box<dyn Error>> {
    const KEYS: [char; 16] = [
        '1', '2', '3', 'A', '4', '5', '6', 'B', '7', '8', '9', 'C', '*', '0', '#', 'D',
    ];
    let row = [GPIO18, GPIO23, GPIO24, GPIO25];
    let col = [SPIMOSI, GPIO22, GPIO27, GPIO17];
    let mut row_pins = row
        .map(|pin| -> Result<OutputPin, Box<dyn Error>> {
            Ok(Gpio::new()?.get(pin)?.into_output())
        })
        .map(|result: Result<OutputPin, Box<dyn Error>>| result.unwrap());
    let col_pins = col
        .map(|pin| -> Result<InputPin, Box<dyn Error>> { Ok(Gpio::new()?.get(pin)?.into_input()) })
        .map(|result: Result<InputPin, Box<dyn Error>>| result.unwrap());

    let mut pressed: HashSet<char> = vec![].into_iter().collect();
    let mut last_pressed: HashSet<char> = vec![].into_iter().collect();
    loop {
        for (i, output) in &mut row_pins.iter_mut().enumerate() {
            output.set_high();
            for (j, input) in col_pins.iter().enumerate() {
                if input.is_high() {
                    pressed.insert(KEYS[i * 4 + j]);
                }
            }
            thread::sleep(Duration::from_millis(1));
            output.set_low();
        }
        if pressed.difference(&last_pressed).collect::<Vec<_>>().len() != 0 {
            println!("{:?}", pressed.difference(&last_pressed));
        }
        last_pressed.clone_from(&pressed);
        pressed.clear();
        thread::sleep(Duration::from_millis(100));
    }
}
(love cat)(love cat)
(love cat)(love cat)

大体ポテンショメーターと一緒のコードになるのか。
今度はCH0とCH1に繋いでいるので、ポテンショメーターのときみたいに0決め打ちでは行けない。
あんまりやる気が出ないが先を見るとADC関数はちょくちょく登場するので今度こそちゃんと動作するものを書いておきたい…。

(love cat)(love cat)

ADC0834を構造体に切り出すか〜としてみたらAD変換はメソッドであるべきだなと思った。色々とこれでいいのかわからない。ラズパイで遊んでないでなんか設計の本を読んだほうがいい気がする。
ちょいと呼び出してみたところサンプルコードと同じような値を返してきてくれる。
ポテンショメータのときの変換関数との違いは毎回ピンを作り直しているかどうかぐらいのつもりなんだけども…。

impl Adc0834 {
    fn new(adc_cs: u8, adc_do: u8, adc_di: u8, adc_clk: u8) -> Self {
        Self {
            adc_cs,
            adc_do,
            adc_di,
            adc_clk,
        }
    }
    fn get_adc_result(&self, ch_pin: u8) -> Result<u8, Box<dyn Error>> {
        let mut adc_cs = Gpio::new()?.get(self.adc_cs)?.into_output();
        let mut adc_do = Gpio::new()?.get(self.adc_do)?.into_input();
        let mut adc_di = Gpio::new()?.get(self.adc_di)?.into_output();
        let mut adc_clk = Gpio::new()?.get(self.adc_clk)?.into_output();

        // 変換の開始
        adc_cs.set_low();
        // スタートビット
        snd_bit(&mut adc_clk, &mut adc_di, 1);
        // SGL
        snd_bit(&mut adc_clk, &mut adc_di, 1);
        // ODD
        snd_bit(&mut adc_clk, &mut adc_di, ch_pin & 1 as u8);
        // Select
        snd_bit(&mut adc_clk, &mut adc_di, if ch_pin > 1 { 1 } else { 0 });

        // スカされるクロック。送信する値に意味なし。
        snd_bit(&mut adc_clk, &mut adc_di, 1);

        let mut msb = 0;
        let mut lsb;
        // MSB-First Data
        for _ in 0..7 {
            msb = msb << 1 | rcv_bit(&mut adc_clk, &mut adc_do);
        }
        // MSB-First DataとLSB-First Dataの最下位bit
        adc_clk.set_low();
        thread::sleep(Duration::from_micros(2));
        msb = msb << 1 | if adc_do.is_high() { 1 as u8 } else { 0 as u8 };
        lsb = if adc_do.is_high() { 1 } else { 0 };
        adc_clk.set_high();
        // LSB-First Data
        for i in 1..8 {
            lsb = rcv_bit(&mut adc_clk, &mut adc_do) << i | lsb;
        }
        // 変換の終了
        adc_cs.set_high();
        if lsb == msb {
            Ok(lsb)
        } else {
            println!("something is wrong!!!");
            Ok(0)
        }
    }
}
(love cat)(love cat)

ピンには内蔵のプルアップ(あとプルダウン)抵抗があるらしく、それを最初に有効にしてInputpinを作れるよう。

pub fn joystick() -> Result<(), Box<dyn Error>> {
    let button = Gpio::new()?.get(GPIO22)?.into_input_pullup();

    let mut x_val;
    let mut y_val;
    let adc = Adc0834::new(GPIO17, GPIO23, GPIO27, GPIO18);

    loop {
        x_val = adc.get_adc_result(0)?;
        y_val = adc.get_adc_result(1)?;
        println!(
            "x: {}, y: {}, button: {}",
            x_val,
            y_val,
            if button.is_low() {
                "pressed"
            } else {
                "not pressed"
            }
        );
        thread::sleep(Duration::from_millis(100));
    }
}
(love cat)(love cat)

次からはセンサー系。まずはフォトレジスタ。明るさによって変化する可変抵抗。
https://docs.sunfounder.com/projects/davinci-kit/ja/latest/2.2.1_photoresistor.html

(love cat)(love cat)

サンプルコードはポテンショメータと同じ。
1つ前で作った構造体を使って動作することを確認。
部屋を真っ暗にするとLEDがつく。

pub fn photoregister() -> Result<(), Box<dyn Error>> {
    let mut val;

    let adc = Adc0834::new(GPIO17, GPIO23, GPIO27, GPIO18);
    let mut led = Gpio::new()?.get(GPIO22)?.into_output();

    loop {
        val = adc.get_adc_result(0)?;
        led.set_pwm_frequency(2000.0, (val as f64) / 255.0)?;
        println!("val: {}", val);
        thread::sleep(Duration::from_millis(100));
    }
}
(love cat)(love cat)

部屋を真っ暗にしてボタンを押下した状態でテレビリモコンを近づけるとちゃんと検知してLEDが消えたりする。
…10cm以内ぐらいまで近づけるとなので、実用性はちょっと思いつかない。
とはいえ自分の目には見えない何かにちゃんと反応してくれるものが作れるのは楽しい。

(love cat)(love cat)

次はサーミスタ。こちらは熱によって抵抗値が変化するものらしい。
その特性を利用して温度を測ったりするのに使われると。
寒くなってきたしちょうどいいな(?)。
https://docs.sunfounder.com/projects/davinci-kit/ja/latest/2.2.2_thermistor.html

(love cat)(love cat)

とりあえずpythonのサンプルコード動かしてみたら196.63℃と表示された。
体感的にはそんなはずないので回路かコードが間違っている。

(love cat)(love cat)

数値計算にはnumクレイトを。
計算の意味はさっぱりわからないです。

pub fn thermistor() -> Result<(), Box<dyn Error>> {
    use num::Float;

    let mut analog_val: u8;
    let mut vr: f64;
    let mut rt: f64;
    let mut temp: f64;
    let mut cel: f64;
    let mut fah: f64;

    let adc = Adc0834::new(GPIO17, GPIO23, GPIO27, GPIO18);

    loop {
        analog_val = adc.get_adc_result(0).expect("adc failed");
        vr = 5.0 * analog_val as f64 / 255.0;
        rt = 10000.0 * vr / (5.0 - vr);
        temp = 1.0 / ((Float::ln(rt / 10000.0) / 3950.0) + (1.0 / (273.15 + 25.0)));
        cel = temp - 273.15;
        fah = cel * 1.8 + 32.0;
        println!("cel: {}, fah: {}", cel, fah);
        thread::sleep(Duration::from_millis(100));
    }
}
(love cat)(love cat)

区切りいい感じにしてると更新しなくてはという気持ちがなくなる。
次はDHT-11をやる。温湿度計。良いコーディングライフには適切な温度・湿度が必要だ。
https://docs.sunfounder.com/projects/davinci-kit/ja/latest/2.2.3_dht-11.html

(love cat)(love cat)

うまく取れないな…。

コード
struct Dht11 {
    pin: u8,
    max_tim: u8,
}

impl Dht11 {
    pub fn new(pin: u8) -> Self {
        Dht11 { pin, max_tim: 85 }
    }

    pub fn read(&self) -> Result<((i8, i8), (i8, i8)), Box<dyn Error>> {
        let mut pin = Gpio::new()?.get(self.pin)?.into_output();
        pin.set_high();
        thread::sleep(Duration::from_micros(1));
        pin.set_low();
        thread::sleep(Duration::from_millis(18));
        pin.set_high();
        thread::sleep(Duration::from_micros(40));
        drop(pin);

        let pin = Gpio::new()?.get(self.pin)?.into_input();

        let mut last_state: Level = Level::High;
        let mut data: [i8; 5] = [0; 5];
        let mut times_collect_bit = 0;

        'main_loop: for i in 0..self.max_tim {
            let mut counter = 0;
            while pin.read() == last_state {
                counter += 1;
                thread::sleep(Duration::from_micros(1));
                if counter == 255 {
                    break 'main_loop;
                }
            }
            last_state = pin.read();
            // ignore first 3 transitions
            if i >= 4 && i % 2 == 0 {
                data[times_collect_bit / 8] <<= 1;
                if counter > 50 {
                    data[times_collect_bit / 8] |= 1;
                }
                times_collect_bit += 1;
            }
        }
        if times_collect_bit >= 40 && data[4] == (data[0] + data[1] + data[2] + data[3]) {
            Ok(((data[0], data[1]), (data[2], data[3])))
        } else {
            Err("Data not good, skip!".into())
        }
    }
}
(love cat)(love cat)

人のコード読むの勉強になるから習慣づけたいですね。
それはそれとして値は取れなかったです。きっとしょうもないミスだと思うけど諦め。

(love cat)(love cat)

まあ温湿度なんて測りたかったら温湿度計買いましょうね。
次はPIR。こいつを使って猫が水を飲んでいるか監視しようと思う。
https://docs.sunfounder.com/projects/davinci-kit/ja/latest/2.2.4_pir.html

(love cat)(love cat)

とりあえずサンプルコード写経。pwmのことは何もわからない。
pir自体はonかoffかしかないのでシンプルなもんである。

pub fn pir() -> Result<(), Box<dyn Error>> {
    let pir = Gpio::new()?.get(GPIO17)?.into_input();
    let mut red = Gpio::new()?.get(GPIO18)?.into_output();
    let mut blue = Gpio::new()?.get(GPIO22)?.into_output();
    let mut green = Gpio::new()?.get(GPIO27)?.into_output();

    let running = Arc::new(AtomicBool::new(true));
    let r = running.clone();
    ctrlc::set_handler(move || {
        r.store(false, Ordering::SeqCst);
    })
    .expect("Error setting Ctrl-C handler");
    while running.load(Ordering::SeqCst) {
        if pir.is_high() {
            red.set_pwm_frequency(100.0, 100.0)?;
            green.set_pwm_frequency(100.0, 100.0)?;
            blue.set_pwm_frequency(0.0, 100.0)?;
        } else {
            red.set_pwm_frequency(0.0, 100.0)?;
            green.set_pwm_frequency(0.0, 100.0)?;
            blue.set_pwm_frequency(100.0, 100.0)?;
        }
    }
    Ok(())
}
(love cat)(love cat)

トリガーで。

pub fn pir() -> Result<(), Box<dyn Error>> {
    let mut pir = Gpio::new()?.get(GPIO17)?.into_input();
    let mut red = Gpio::new()?.get(GPIO18)?.into_output();
    let mut blue = Gpio::new()?.get(GPIO22)?.into_output();
    let mut green = Gpio::new()?.get(GPIO27)?.into_output();

    pir.set_interrupt(rppal::gpio::Trigger::Both)?;

    let running = Arc::new(AtomicBool::new(true));
    let r = running.clone();
    ctrlc::set_handler(move || {
        r.store(false, Ordering::SeqCst);
    })
    .expect("Error setting Ctrl-C handler");
    while running.load(Ordering::SeqCst) {
        match pir.poll_interrupt(true, None) {
            Ok(trigger) => match trigger {
                Some(rppal::gpio::Level::High) => {
                    red.set_pwm_frequency(100.0, 100.0)?;
                    green.set_pwm_frequency(100.0, 100.0)?;
                    blue.set_pwm_frequency(0.0, 100.0)?;
                }
                Some(rppal::gpio::Level::Low) => {
                    red.set_pwm_frequency(0.0, 100.0)?;
                    green.set_pwm_frequency(0.0, 100.0)?;
                    blue.set_pwm_frequency(100.0, 100.0)?;
                }
                None => (),
            },
            _ => break,
        }
    }
    Ok(())
}
(love cat)(love cat)

色々怪しいししばらくいじってなかったらだいぶ忘れたけど多分ラズパイ完全に理解したのであとは実践をしていく。

このスクラップは2022/11/12にクローズされました