prettyprint

2022年11月15日 星期二

Raspberry Pi Pico PIO(Programmable IO) Episode 5: IR-Receiver(VS1838B)

 本篇文章介紹使用Raspberry Pi Pico PIO功能,製作一個IR 遙控器接收器,並用來控制伺服馬達。


一、使用材料:

  1. Raspberry Pi Pico
  2. VS1838B IR 接收器
  3. SG90 MicroServo
二、紅外線協定使用Samsung IR protocol:
Start bits: 4.5ms burst pulse + 4.5ms space
32 bits data(Address + command): logical "0": 590us burst pulse + 590us space; 
                                                        logical "1": 590us burst pulse + 1690us space
stop bits: 590us burst pulse + 590us space

三、VS1838B Datasheet:

burst pulse: output level LOW
space : output leve HIGH

四、Raspberry Pi Pico PIO說明:
1.設定StateMachine clock cycle週期為10us。

2. StateMachine程式碼:
  • 確定start bits: 4.5ms burst pulse + 4.5ms space
  • 每個bit 取樣點:650us > 560us 
  • IR發送器發送data bits為LSB first,所以設定shift right,且autopush=false

五、成果影片:


六、程式碼
  • PIO
; IR protocol:
; start bits: 4.5ms burst pulse + 4.5 ms space
; 32 bits data: logical "0": 590us burst pulse+590us space, logical "1": 590us burst pulse+1690us space
; stop bits: 590us burst pulse + 590us space
; StateMachine clock cycle period=10us 
.program samsung_ir_receiver
.wrap_target
start:
set x, 31                   ; 32*14=4480(us)   
start_burst:
jmp pin start
jmp x--, start_burst [12]

wait 1 pin 0                ; 10us
set x, 31                   ; 32*14=4480us
start_space:
in pins, 1
mov y, isr
jmp !y  start
jmp pin start_space [10]

mov isr, NULL

set x, 31
bit_loop:
wait 1 pin 0
nop [31]
nop [31] 
in pins, 1 
wait 0 pin 0
jmp x--, bit_loop
push
irq 0

wait 1 pin 0
wait_stop:
jmp pin, wait_stop

.wrap
  • ir-receiver.c
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "IR-receiver.h"
#include "hardware/clocks.h"
#include "hardware/pwm.h"

#define IR_PIN  15
#define PWM_PIN 16

int angle=0;
int slice, pwm_ch;

void setServoAngle(int ang) {
    uint16_t top_count = (uint16_t)(ang/0.09 + 1500);  // angle 0: 1.5 ms duty
    pwm_set_chan_level(slice, pwm_ch, top_count);

}
void ir_irq_handle() {
    if (pio_interrupt_get(pio0, 0)) {
        pio_interrupt_clear(pio0, 0);
        uint32_t code = pio_sm_get(pio0, 0);
        
        switch (code) {
            case 0xf8070707:    
                angle += 2;
                if (angle > 90) angle = 90;
                break;
            case 0xf40b0707:
                angle -= 2;
                if (angle < -90) angle = -90;
                break;
            case 0xed120707:
                angle = 90;
                break;
            case 0xef100707:
                angle = 0;
                break;
        }
        setServoAngle(angle);
    }

}

void ir_receiver_pio_init(PIO pio, uint sm, uint pin, uint32_t freq) {
    uint offset = pio_add_program(pio, &samsung_ir_receiver_program);
    pio_sm_config c = samsung_ir_receiver_program_get_default_config(offset);
    pio_gpio_init(pio, pin);
    pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
    float div = clock_get_hz(clk_sys)/freq;
    sm_config_set_clkdiv(&c, div);
    sm_config_set_in_pins(&c, pin);
    sm_config_set_in_shift(&c, true, false,32);
    sm_config_set_jmp_pin(&c, pin);
    // set interrupt 
    pio_set_irq0_source_enabled(pio, pis_interrupt0, true);
    irq_add_shared_handler(PIO0_IRQ_0, ir_irq_handle, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
    irq_set_enabled(PIO0_IRQ_0, true);
    
    pio_sm_init(pio, sm, offset, &c);
    pio_sm_set_enabled(pio, sm, true);

}

int main()
{
    stdio_init_all();
    gpio_init(IR_PIN);
    gpio_set_dir(IR_PIN, false);
    gpio_disable_pulls(IR_PIN);
    ir_receiver_pio_init(pio0, 0, IR_PIN, 100000);  // set StateMachine clock sycle period=10us

    // set Servo pwm
    gpio_set_function(PWM_PIN, GPIO_FUNC_PWM);
    slice = pwm_gpio_to_slice_num(PWM_PIN);
    pwm_ch = pwm_gpio_to_channel(PWM_PIN);
    pwm_config c = pwm_get_default_config();
    pwm_config_set_clkdiv(&c, 125);  // 20ms period, steps 20000, clkdiv = 125 
    pwm_config_set_wrap(&c, 20000);
    pwm_config_set_phase_correct(&c, false);
    pwm_init(slice, &c, true);    
    
    setServoAngle(0);
    
    while(true) {
        tight_loop_contents();
    }
    return 0;
}

沒有留言:

張貼留言