本篇文章介紹使用Raspberry Pi Pico PIO功能,製作一個IR 遙控器接收器,並用來控制伺服馬達。
一、使用材料:
- Raspberry Pi Pico
- VS1838B IR 接收器
- 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:
四、Raspberry Pi Pico PIO說明:
1.設定StateMachine clock cycle週期為10us。
- 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; }
沒有留言:
張貼留言