本篇文章介紹使用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;
}
沒有留言:
張貼留言