Joystick se skládá ze dvou potenciometrů, které jsou umístěny kolmo na sebe a mechanicky spřaženy. Pokud chceme zjistit, v jaké poloze se joystick nachází, stačí nám ADC převodníkem změřit napětí na středním kontaktu každého z potenciometrů.

Tlačítko na joysticku zůstane nevyužito.
Pokud by ho chtěl někdo používat, stačí kontakt SW na joysticku připojit na nějaký GPIO pin a programově lze zjišťovat funkcí gpio_get( cislo_pinu ) jeho stav.
Tlačítko jde stisknout jenom pokud je joystick ve střední poloze.

Jednoduchý příklad se nachází přímo v příkladech Pico-SDK (adresář pico-examples)
CMakeLists.txt
cmake_minimum_required(VERSION 3.12)
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
project(joystick_display)
pico_sdk_init()
add_executable(joystick_display
joystick_display.c
)
target_link_libraries(joystick_display pico_stdlib hardware_adc)
# create map/bin/hex file etc.
pico_add_extra_outputs(joystick_display)
pico_enable_stdio_usb(joystick_display 1)
pico_enable_stdio_uart(joystick_display 1)
Ve smyčce (trvá přibližně 50ms) čteme nejprve polohu x z ADC0 a potom polohu y z ADC1.
V programu nás nezajímá přesná hodnota napětí.
V proměnných adc_x_raw a adc_y_raw budeme mít po každém čtení adc_read() nějaké číslo z rozsahu 0 až 4096.
(Možná bude rozsah menší, protože se joystick nedá vytočit až do krajních poloh potenciometrů).
Pokud je joystick v neutrální poloze, tak naměříme přibližně polovinu (2048).
joystick_display.c
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
int main() {
stdio_init_all();
adc_init();
// Make sure GPIO is high-impedance, no pullups etc
adc_gpio_init(26);
adc_gpio_init(27);
while (1) {
adc_select_input(0);
uint adc_x_raw = adc_read();
adc_select_input(1);
uint adc_y_raw = adc_read();
// Display the joystick position something like this:
// X: [ o ] Y: [ o ]
const uint bar_width = 60;
const uint adc_max = (1 << 12) - 1;
uint bar_x_pos = adc_x_raw * bar_width / adc_max;
uint bar_y_pos = adc_y_raw * bar_width / adc_max;
printf("\rX: [");
for (uint i = 0; i < bar_width; ++i)
putchar( i == bar_x_pos ? 'o' : ' ');
printf("] Y: [");
for (uint i = 0; i < bar_width; ++i)
putchar( i == bar_y_pos ? 'o' : ' ');
printf("]");
sleep_ms(50);
}
}
Nepříjemnou vlastností je to, že i když s nebudeme s joystickem hýbat, tak budou naměřené hodnoty poskakovat. Je to způsobeno jednak nepřesností samotného ADC převodníku a dále nestabilitou referenčního napětí 3.3V.
Nestabilitu referenčního napětí můžeme zmenšit přepnutím PWM měniče to neúsporného režimu. Dělá se to takto:
// nastavení měniče na malý šum
gpio_set_function(23, GPIO_FUNC_SIO);
gpio_set_dir( 23, true );
gpio_put( 23, 1 );
Další zlepšení může být třeba tak, že hodnoty adc_x_raw a adc_y_raw převedeme na reálné číslo float, vydělíme 10 a zaokrouhlíme.
Nebo lze snížit citlivost ADC bitovým posunem přečtené hodnoty na 8 bitů (256 hodnot). (Spodní bity dělají ono poskakování.)
Tím se sníží přesnost i citlivost a zároveň se potlačí šum (ono poskakování).
V dalším příkladu je to vyřešeno.