prettyprint

2023年8月16日 星期三

[Raspberry Pi Pico W] BTstack: Ep 6. HID device, Mouse and ADC Joystick

 這篇文章介紹Raspberry Pi Pico W使用BTstack bluetooth HID功能,製作一組HID Bluetooth Mouse。使用模擬設備為HW-504 joystick 模組。

HW-504為一個x-y方向2D的電位計,因此在Pi Pico W使用GPIO pin 26(ADC NUM 0)接VRx腳位,GPIO pin 27(ADC NUM 1)接VRy腳位,SW開關壓下時為接地,本實驗使用的模組未接上拉電位,因此要先接一個上拉電阻。

BTstack example 有一個hid_mouse_demo.c程式碼,本次實驗直接使用,因為在檔案中很多宣告為static,所以在主程式中#include "hid_mouse_demo.c"當作程式的一部分。

根據 HID Descriptor, input report含有三個bytes,第一個byte 最小三個位元分別為代表滑鼠按鈕,值為0與1,第2個byte為x軸移動速度,值為-127~127,第個byte為y軸移動速度,值為-127~127。


Pico W的ADC 為12 bits,因此取樣值為0~4095,而HW-504模組輸出需對應到-127~127之間。因為HW-504模組輸出靈敏度較差,因此本實驗將x軸與y軸輸出定在-8~8之間。
主程式如下說明:
理論上ADC取樣值0~2047應對應到dx or dy:-8~0。將ADC取樣值設每256為一個階級。

起始時當HW-504模組靜止x與y軸個取樣100次平均當作中間的參考值。

取樣結束判斷是否有按下按鍵或是移動座標。送出send report要求事件。
hid_device_request_can_send_now(hid_cid);

展示影片:


程式碼如下:
hid_mouse_demo.c需作下列三項修正。


btstack_config.h檔案內容可參閱前篇文章內容。

  • picow_bt_mouse_joystick.c
 #include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
#include "hardware/gpio.h"
#include "stdlib.h"
#include "pico/cyw43_arch.h"
#include "hid_mouse_demo.c"

#define ADC_X_PIN   26
#define ADC_X_NUM   0
#define ADC_Y_PIN   27
#define ADC_Y_NUM   1
#define ADC_VREF    3.3
#define ADC_RANGE (1<<12)    // pi pico 12 bits ADC


#define BUTTON_PIN  16
#define STEP        256   // min 16, 2048/256=8, mouse moving speed 0~8

uint32_t adc_x_center=0;
uint32_t adc_y_center=0;

int main()
{
    stdio_init_all();
    if (cyw43_arch_init()) {
        printf("cyw43 arch init error\n");
        return 0;
    }

    btstack_main(0, NULL);
    
    gpio_init(BUTTON_PIN);
    gpio_set_dir(BUTTON_PIN, false);
    adc_init();                     // init and assign ADC pin
    adc_gpio_init(ADC_X_PIN);
    adc_gpio_init(ADC_Y_PIN);

    for (int i=0; i < 100; i++) {     // average 100 samples as mouse static position
        adc_select_input(ADC_X_NUM);
        adc_x_center += adc_read();
        adc_select_input(ADC_Y_NUM);
        adc_y_center += adc_read();
    }
    adc_x_center /=100;
    adc_y_center /=100;
    printf("x:%d, y:%d\n", adc_x_center, adc_y_center);
    

    uint adc_raw=ADC_RANGE/2;
    uint adc_x=ADC_RANGE/2;
    uint adc_y=ADC_RANGE/2;
    bool button_pressed=false;
    bool mouse_moving=false;
    while(1) {
        
        if (abs(adc_x-adc_x_center) < 10 &&  abs(adc_y-adc_y_center) < 10)
        {
            mouse_moving=false;
            dx=dy=0;
        }
        
        if (!gpio_get(BUTTON_PIN)) {
            if(!button_pressed) {
                button_pressed = true;
                printf("button pressed\n");
                buttons |= 1;
                dx=dy=0;
                mouse_moving = false;
            } 
        } else {
            button_pressed = false;
            buttons = 0;
            adc_select_input(ADC_X_NUM);
            adc_raw = adc_read();
            if(abs(adc_raw-adc_x_center) > 10) {   
                adc_x=adc_raw;
                dx = (adc_raw - ADC_RANGE/2)/STEP;
                mouse_moving=true;
            }
                
            adc_select_input(ADC_Y_NUM);
            adc_raw = adc_read();
            if(abs(adc_raw-adc_y_center) > 10) {
                adc_y=adc_raw;
                dy = (adc_raw - ADC_RANGE/2)/STEP;
                mouse_moving=true;
            }
        }
        if (dx || dy || buttons) {
            hid_device_request_can_send_now_event(hid_cid);
        }
        sleep_ms(10);
    }

    return 0;
}

  • CMakeLists.txt
 # Generated Cmake Pico project file

cmake_minimum_required(VERSION 3.13)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

# Initialise pico_sdk from installed location
# (note this can come from environment, CMake cache etc)
set(PICO_SDK_PATH "/home/duser/pico/pico-sdk")

set(PICO_BOARD pico_w CACHE STRING "Board type")

# Pull in Raspberry Pi Pico SDK (must be before project)
include(pico_sdk_import.cmake)

if (PICO_SDK_VERSION_STRING VERSION_LESS "1.4.0")
  message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()

project(picow_bt_mouse_joystick C CXX ASM)

# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()

# Add executable. Default name is the project name, version 0.1

add_executable(picow_bt_mouse_joystick picow_bt_mouse_joystick.c )

pico_set_program_name(picow_bt_mouse_joystick "picow_bt_mouse_joystick")
pico_set_program_version(picow_bt_mouse_joystick "0.1")

pico_enable_stdio_uart(picow_bt_mouse_joystick 1)
pico_enable_stdio_usb(picow_bt_mouse_joystick 0)

# Add the standard library to the build
target_link_libraries(picow_bt_mouse_joystick
        pico_stdlib
        hardware_adc
        pico_util
        pico_cyw43_arch_none
        pico_btstack_cyw43
        pico_btstack_classic)

# Add the standard include files to the build
target_include_directories(picow_bt_mouse_joystick PRIVATE
  ${CMAKE_CURRENT_LIST_DIR}
  ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required
)

pico_add_extra_outputs(picow_bt_mouse_joystick)

沒有留言:

張貼留言