1. Bevezetés
A feladat az nrf52832 mikrovezérlő kommunikációs protokolljának kidolgozása volt két kínai feszültségérzékelőn keresztül.
A feladat nem volt egyszerű, mivel szembe kellett nézni azzal, hogy nem volt egyértelmű információ. Valószínűleg a 'gonosz gyökere' magában a Nordic Semiconductor SDK-jában rejlik - a folyamatos verziófrissítések, a némi redundancia és a funkciók összezavarodottsága miatt. Mindennek nulláról kellett nekifutnom.
Azt hiszem, ez a téma elég aktuális, mivel ez a chip BLE stack-kel és számos 'finomsággal' rendelkezik az energiatakarékos üzemmódban. De a technikai részbe nem akarok túl mélyen belemerülni, mivel erről a témáról sok cikket írtak.
2. A projekt leírása

Hardver:
- Adafruit Feather nRF52 Bluefruit LE (ami éppen kéznél volt)
- HX711 ADC
- 2 db kínai feszültségérzékelő (50x2 kg)
- ST-LINK V2 programozó
Szoftver:
- IDE VSCODE
- NRF SDK 16
- OpenOCD
- ST-LINK V2 programozó
Minden egy projektben található, csak a Makefile-t kell kicsit módosítani (megadni a SDK elérési útját).
3. A kód leírása
A perifériával való munka során a GPIOTE modult fogjuk használni a feladatok és események kötése alapján, valamint a PPI modult az adatok egy perifériáról a másikra való átviteléhez a processzor közreműködése nélkül.
ret_code_t err_code;
err_code = nrf_drv_gpiote_out_init(PD_SCK, &config); // kimenetre állítjuk
nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false); // a lábat fogjuk késleltetni az impulzusokhoz
err_code = nrf_drv_gpiote_out_init(PD_SCK, &config); // kimenetre állítjuk
A PD_SCL szinkronizáló vonalat kimenetre állítjuk, hogy 10 μs hosszúságú impulzusokat generáljon.
nrf_drv_gpiote_in_config_t gpiote_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(false); // a magas szintről alacsony szintre való váltás
nrf_gpio_cfg_input(DOUT, NRF_GPIO_PIN_NOPULL); // bemeneti állapot, felhúzás nélkül
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); // az megszakítást letiltjuk
nrf_drv_timer_enable(&m_timer0); // a timert bekapcsoljuk
}
A DOUT adatvonalat állítjuk be az HX711 készenlét állapotának ellenőrzésére, alacsony szintű jel esetén aktiválódik az eseménykezelő, amely letiltja az megszakítást és elindítja a timert a PD_SCL kimeneti szinkronizáló impulzusok generálásához.
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));// kapcsoljuk a timert a kimenetre
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_enable(m_ppi_channel1);// engedélyezzük a csatornát
APP_ERROR_CHECK(err_code);
nrf_drv_gpiote_out_task_enable(PD_SCK); // включаем gpiote
Ezután inicializáljuk a PPI modult, és összekapcsoljuk a timerünket a PD_SCL kimenettel, hogy 10 µs hosszúságú impulzusokat generáljunk, amikor a hasonlítási esemény bekövetkezik, valamint engedélyezzük a GPIOTE modult.
nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;// alapértelmezett
timer_cfg.frequency = NRF_TIMER_FREQ_1MHz;// 1 MHz-en működik
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);// a hasonlítás alapján aktiválódikInicializáljuk a nulla timert és annak kezelőjét.
if(m_counter%2 != 0 && m_counter<=48){
buffer <<= 1;// a beolvasott adatok változója
c_counter++;// pozitív impulzusok számlálója
if(nrf_gpio_pin_read(DOUT))buffer++;// beolvassuk a bemenet állapotát
}
A legérdekesebb dolog a timer kezelőben történik. Az impulzusok periódusa 20 µs. Azokat az páratlan impulzusokat keressük (felfelé átlépő élen), és annak a feltételnek megfelelően, hogy ezek száma nem haladja meg a 24, valamint az események száma 48. Minden páratlan eseménynél beolvassuk a DOUT-ot.
A datasheetből következik, hogy az impulzusok száma legalább 25 kell legyen, ami 128-as erősítési aránynak felel meg (a kódban 25 impulzust használtam), ez 50 timer eseménynek felel meg, ami a dátumkeret végét jelzi.
++m_counter;// az események számlálója
if(m_counter==50){
nrf_drv_timer_disable(&m_timer0);// letiltjuk a timert
m_simple_timer_state = SIMPLE_TIMER_STATE_STOPPED;//
buffer = buffer ^ 0x800000;
hx711_stop();// kikapcsoljuk az hx711-et
}
Ezután leállítjuk a timert és feldolgozzuk az adatokat (a datasheet szerint), majd átkapcsoljuk az HX711-et alacsony energiafogyasztású módba.
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();// elindítjuk az hx711-et
nrf_drv_gpiote_out_toggle(LED_1);
m_simple_timer_state = SIMPLE_TIMER_STATE_STARTED;
}
}
/**@brief Időzítők létrehozása.
*//
static void create_timers()
{
ret_code_t err_code;
// Időzítők létrehozása
err_code = app_timer_create(&m_repeated_timer_id,
APP_TIMER_MODE_REPEATED,
repeated_timer_handler);
APP_ERROR_CHECK(err_code);
}
Várjuk az eseményeket az RTC időzítőtől 10 másodperces időközönként (ez már az Ön választása), az eseménykezelőben elindítjuk az HX711-et, megszakítást hívva a DOUT vonalon.
Van még egy dolog, a naplókat UART-on keresztül küldjük (baud rate 115200, TX — 6 pin, RX — 8 pin), minden beállítás a sdk_config.h fájlban található.

Következtetések
Köszönöm mindenkinek a figyelmet, remélem, hogy ez a cikk hasznos lesz, és értékes időt takarít meg a fejlesztők számára a megoldáskeresés során. Szeretném megemlíteni, hogy a Nordic által használt technikai megközelítés a platformjaikon nagyon érdekes az energiahatékonyság szempontjából.
P.S.
A projekt még fejlesztés alatt áll, így ha érdekli ez a téma, a következő cikkben megpróbálom leírni a súlymérők kalibrálásának algoritmusát, valamint a BLE verem csatlakozását.
Anyagok
Forrás: habr.com
