1. Sissejuhatus
Päevakorral oli ülesanne välja töötada suhtlusprotokoll mikroprotsessori nrf52832 ja kahe hiina pool-autoantud pingemõõturi vahel.
Ülesanne osutus keeruliseks, kuna kokku puutusin teabe puudumisega. Tõenäoliselt on „kuri juur“ Nordic Semiconductori enda SDK-s — pidevad versioonide uuendused, teatud liialdus ja funktsionaalsuse segadus. Tänaseks tuli kõik nullist kirjutada.
Ma arvan, et see teema on üsna aktuaalne, arvestades, et see kiip omab BLE steki ja terve kogumi energiatõhususe funktsioone. Kuid tehnilisse ossa ma liiga sügavale ei lasku, kuna sellel teemal on kirjutatud palju artikleid.
2. Projekti kirjeldus

Riistvara:
- Adafruit Feather nRF52 Bluefruit LE (see, mis käepärast oli)
- ADC HX711
- 2 hiina pingemõõturit (50x2 kg)
- Programmeerija ST-LINK V2
Tarkvara:
- IDE VSCODE
- NRF SDK 16
- OpenOCD
- Programmeerija ST-LINK V2
Kõik asub ühes projektis, tuleb vaid Makefile'i pisut kohandada (näidata teie SDK asukohta).
3. Koodi kirjeldus
Kasutame GPIOTE moodulit perifeeria haldamiseks, tuginedes ülesannete ja sündmuste seotusele, samuti PPI moodulit andmete edastamiseks ühelt perifeeriast teisele ilma protsessori osaluseta.
ret_code_t err_code;
err_code = nrf_drv_gpiote_out_init(PD_SCK, &config); // seadistame väljundiks
nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false); // lülitame pini impulsi jaoks
err_code = nrf_drv_gpiote_out_init(PD_SCK, &config); // seadistame väljundiks
Seadistame sünkroonimisliini PD_SCL väljundiks, et genereerida 10 μs impulsi.
nrf_drv_gpiote_in_config_t gpiote_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(false); // taseme üleminek ülalt allapoole
nrf_gpio_cfg_input(DOUT, NRF_GPIO_PIN_NOPULL); // sisend ilma tõmbejõuta
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); // keelame katkestuse
nrf_drv_timer_enable(&m_timer0); // lülitame taimeri sisse
}
Seadistame andmeliini DOUT HX711 valmisoleku oleku lugemiseks, madala taseme kohal aktiveerub käitleja, kus keelame katkestuse ja käivitame taimeri, et genereerida sünkroonimisimpulsse väljundil 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)); // соединяем таймер с выходом
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_enable(m_ppi_channel1); // включаем канал
APP_ERROR_CHECK(err_code);
nrf_drv_gpiote_out_task_enable(PD_SCK); // включаем gpiote
Seejärel initsialiseerime PPI mooduli ja ühendame meie taimeri väljundiga PD_SCL, et genereerida 10μs impulsi, kui toimub võrdlemise sündmus, ning lülitame sisse GPIOTE mooduli.
nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG; // vaikimisi
timer_cfg.frequency = NRF_TIMER_FREQ_1MHz; // sünkroniseerime sagedusel 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); // aktiveeritakse võrreldesAlustame nulliga taimerit ja selle töötlejat.
if(m_counter % 2 != 0 && m_counter <= 48){
buffer <<= 1; // loetud andmete muutuja
c_counter++; // positiivsete impulsside loenduri
if(nrf_gpio_pin_read(DOUT)) buffer++; // loeme sisenemise seisundit
}
Kõige huvitavam juhtub taimeri töötlejas. Impulsside periood on 20μs. Meid huvitavad paarilised impulssid (kasvava ääre järgi) ja tingimusel, et nende arv on mitte enam kui 24, ning sündmusi 48. Iga paarilise sündmuse puhul loeme DOUT-i。
Andmelehe kohaselt peab impulsside arv olema vähemalt 25, mis vastab võimendussuhtele 128 (koodis kasutasin 25 impulssi), see on ekvivalentne 50 taimeri sündmusele, mis märgib andmepakendi lõppu.
++m_counter; // sündmuste loendur
if(m_counter == 50){
nrf_drv_timer_disable(&m_timer0); // lülitame taimeri välja
m_simple_timer_state = SIMPLE_TIMER_STATE_STOPPED; //
buffer = buffer ^ 0x800000;
hx711_stop(); // lülitame hx711 välja
}
Seejärel lülitame taimeri välja ja töötleme andmed (vastavalt andmelehele) ning viime HX711 madala energiatarbimise režiimi.
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();// запускаем hx711
nrf_drv_gpiote_out_toggle(LED_1);
m_simple_timer_state = SIMPLE_TIMER_STATE_STARTED;
}
}
/**@brief Создать таймеры.
*//*
static void create_timers()
{
ret_code_t err_code;
// Создание таймеров
err_code = app_timer_create(&m_repeated_timer_id,
APP_TIMER_MODE_REPEATED,
repeated_timer_handler);
APP_ERROR_CHECK(err_code);
}
Ootame sündmust RTC taimerilt 10-sekundilise intervalliga (see sõltub juba teie soovist), käivitatakse HX711, вызвав прерывание по линии DOUT.
On veel üks asi, logid kuvatakse läbi UART (baud rate 115200, TX — 6 pin, RX — 8 pin) kõik seaded asuvad sdk_config.h

Järeldused
Aitäh kõigile tähelepanu eest, loodan, et see artikkel on kasulik ja aitab arendajatel lahenduste leidmist kiirendada. Tahaksin öelda, et tehniline lähenemine, mida Nordic oma platvormidel kasutab, on energiaefektiivsuse seisukohalt üsna huvitav.
P.S.
Projekt on veel arendamisjärgus, seega kui see teema huvi pakub, siis järgmises artiklis üritan kirjeldada kaalumisandurite kalibreerimise algoritmi ja BLE stacki ühendamist.
Materjalid
Allikas: habr.com
