1. Introduktion
Dagsordenen handlede om at udvikle en kommunikationsprotokol mellem mikrokontrolleren nrf52832 og to halvbro-kinesiske belastningssensorer.
Opgaven viste sig at være vanskelig, da jeg stødte på manglen på tydelig information. Sandsynligvis er "roden til problemet" i selve SDK'et fra Nordic Semiconductor — dets konstante versionsopdateringer, noget overflødighed og forvirring omkring funktionaliteten. Jeg måtte skrive alt fra bunden.
Jeg tror, at dette emne er ret aktuelt, da denne chip har en BLE-stak og en masse "lækre" energibesparende funktioner. Men jeg vil ikke dykke dybt ned i den tekniske del, da der er skrevet en hel del artikler om dette emne.
2. Projektbeskrivelse

Hardware:
- Adafruit Feather nRF52 Bluefruit LE (det, der var tilgængeligt)
- ADC HX711
- Kinesiske belastningssensorer 2 stk. (50x2 kg)
- Programmer ST-LINK V2
Software:
- IDE VSCODE
- NRF SDK 16
- OpenOCD
- Programmer ST-LINK V2
Alt er samlet i ét projekt, det bliver nødvendigt kun at justere Makefile (angive placeringen af dit SDK).
3. Kodebeskrivelse
Vi vil bruge GPIOTE-modulet til at arbejde med periferien baseret på opgave- og hændelsesbinding, samt PPI-modulet til at overføre data fra én periferienhed til en anden uden involvering af processoren.
ret_code_t err_code;
err_code = nrf_drv_gpiote_out_init(PD_SCK, &config); // konfigurerer til output
nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false); // vil skifte pin for et signal
err_code = nrf_drv_gpiote_out_init(PD_SCK, &config); // konfigurerer til output
Vi konfigurerer synkroniseringslinjen PD_SCL til output for at generere impulser med en varighed på 10 µs.
nrf_drv_gpiote_in_config_t gpiote_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(false); // niveauovergang fra høj til lav
nrf_gpio_cfg_input(DOUT, NRF_GPIO_PIN_NOPULL); // til input uden pull-up
err_code = nrf_drv_gpiote_in_init(DOUT, &gpiote_config, gpiote_evt_handler); static void gpiote_evt_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
nrf_drv_gpiote_in_event_disable(DOUT); // deaktiverer afbrydelsen
nrf_drv_timer_enable(&m_timer0); // aktiverer timeren
}
Vi konfigurerer datalinjen DOUT til at læse tilstanden af HX711's klarhed. Ved tilstedeværelse af lavt niveau aktiveres en behandler, hvor vi deaktiverer afbrydelsen og starter timeren til at generere synkroniseringsimpulser på output PD_SCL.
err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel1);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_assign(m_ppi_channel1, nrf_drv_timer_event_address_get(&m_timer0, NRF_TIMER_EVENT_COMPARE0), nrf_drv_gpiote_out_task_addr_get(PD_SCK)); // tilslut timeren til udgangen
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_enable(m_ppi_channel1); // aktiver kanal
APP_ERROR_CHECK(err_code);
nrf_drv_gpiote_out_task_enable(PD_SCK); // включаем gpiote
Derefter initialiserer vi PPI-modulet og forbinder vores timer til udgangen PD_SCL for at generere impulser af 10µs varighed ved sammenligningsbegivenheden, og aktiverer GPIOTE-modulet.
nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG; // som standard
timer_cfg.frequency = NRF_TIMER_FREQ_1MHz; // takt med 1MHz
ret_code_t err_code = nrf_drv_timer_init(&m_timer0, &timer_cfg, timer0_event_handler);
APP_ERROR_CHECK(err_code);
nrf_drv_timer_extended_compare(&m_timer0,
NRF_TIMER_CC_CHANNEL0,
nrf_drv_timer_us_to_ticks(&m_timer0,
10),
NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
true); // aktiveres ved sammenligningVi initialiserer timeren 0 og dens handler.
if(m_counter%2 != 0 && m_counter<=48){
buffer <<= 1; // variabel for de læste data
c_counter++; // tæller positive impulser
if(nrf_gpio_pin_read(DOUT))buffer++; // læser indgangsstatus
}
Det mest interessante sker i timerhandleren. Impulsperioden er 20µs. Vi er interesserede i ulige impulser (ved den stigende kant) og under forudsætning af, at deres antal ikke overstiger 24, og begivenhederne er 48. Ved hver ulige begivenhed sker der en læsning fra DOUT.
Fra databladet fremgår det, at antallet af impulser skal være mindst 25, hvilket svarer til en forstærkning på 128 (i koden anvendte jeg 25 impulser), hvilket svarer til 50 timerhændelser, der indikerer slutningen af datarammen.
++m_counter; // tæller begivenheder
if(m_counter==50){
nrf_drv_timer_disable(&m_timer0); // deaktiver timer
m_simple_timer_state = SIMPLE_TIMER_STATE_STOPPED; //
buffer = buffer ^ 0x800000;
hx711_stop(); // deaktiver hx711
}
Derefter deaktiverer vi timeren og behandler dataene (ifølge databladet) og sætter HX711 i lavere strømtilstand.
static void repeated_timer_handler(void * p_context)
{
nrf_drv_gpiote_out_toggle(LED_2);
if(m_simple_timer_state == SIMPLE_TIMER_STATE_STOPPED){
hx711_start(); // tænder hx711
nrf_drv_gpiote_out_toggle(LED_1);
m_simple_timer_state = SIMPLE_TIMER_STATE_STARTED;
}
}
/**@brief Opret timer.
*\/
static void create_timers()
{
ret_code_t err_code;
// Opret timer
err_code = app_timer_create(&m_repeated_timer_id,
APP_TIMER_MODE_REPEATED,
repeated_timer_handler);
APP_ERROR_CHECK(err_code);
}
Vi venter på begivenhed fra RTC timeren med et interval på 10 s (dette er op til dig) i håndtereren, aktiverer vi HX711 ved at kalde et afbrydelse på DOUT-linjen.
Der er en anden ting, loggene udskrives via UART (baud rate 115200, TX — pin 6, RX — pin 8), alle indstillinger findes i sdk_config.h

Konklusioner
Tak for opmærksomheden, jeg håber, at denne artikel vil være nyttig og spare værdifuld tid for udviklerne på jagt efter en løsning. Jeg vil sige, at den tekniske tilgang, som Nordic bruger i deres platforme, er ret interessant med hensyn til energieffektivitet.
P.S.
Projektet er stadig i udvikling, så hvis emnet er interessant, vil jeg i næste artikel forsøge at beskrive algoritmen til kalibrering af vægtdatere samt tilslutning af BLE-stakken.
Materialer
Kilde: habr.com
