1. Úvod
Na programu byl úkol vyvinout komunikační protokol pro mikrokontrolér nrf52832 se dvěma polomůstkovými čínskými tenzometry.
Ukázalo se, že úkol není snadný, protože jsem se potýkal s nedostatkem jakýchkoli srozumitelných informací. Je pravděpodobnější, že „kořen zla“ je v samotném SDK od Nordic Semiconductor – neustálé aktualizace verzí, určitá redundance a matoucí funkce. Všechno jsem musel psát od začátku.
Myslím, že toto téma je docela relevantní na základě skutečnosti, že tento čip má zásobník BLE a celou sadu „dobrot“ pro režim úspory energie. Ale nepůjdu příliš hluboko do technické části, protože na toto téma bylo napsáno mnoho článků.
2. Popis projektu
Žehlička:
- Adafruit Feather nRF52 Bluefruit LE (co bylo náhodou po ruce)
- HX711 ADC
- Čínské tenzometry 2 ks. (50x2 kg)
- Programátor ST-LINK V2
Software:
- IDE VSCODE
- NRF SDK 16
- OpenOCD
- Programátor ST-LINK V2
Vše je v jednom projektu, stačí jen vyladit Makefile (určit umístění vašeho SDK).
3. Popis kódu
Modul GPIOTE využijeme pro práci s periferiemi na základě vazby úkolů a událostí, stejně jako modul PPI pro přenos dat z jedné periferie na druhou bez účasti procesoru.
ret_code_t err_code;
err_code = nrf_drv_gpiote_out_init(PD_SCK, &config);//настраеваем на выход
nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);//будем передергивать пин для импульса
err_code = nrf_drv_gpiote_out_init(PD_SCK, &config);//настраеваем на выход
Synchronizační linku PD_SCL na výstup nakonfigurujeme pro generování pulzů s délkou trvání 10 μs.
nrf_drv_gpiote_in_config_t gpiote_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(false);// переход уровня с высокого на низкий
nrf_gpio_cfg_input(DOUT, NRF_GPIO_PIN_NOPULL);// на вход без подтяжки
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);//отключаем прерывание
nrf_drv_timer_enable(&m_timer0);//включаем таймер
}
Nakonfigurujeme datovou linku DOUT pro čtení stavu připravenosti HX711, pokud je nízká úroveň, spustí se handler, ve kterém zakážeme přerušení a spustíme časovač pro generování hodinových impulzů na výstupu 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);
// povolit gpiote
Poté inicializujeme PPI modul a připojíme náš časovač na výstup PD_SCL pro generování pulsů s délkou trvání 10 μs při výskytu porovnávací události a také zapneme modul GPIOTE.
nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;// по умолчанию
timer_cfg.frequency = NRF_TIMER_FREQ_1MHz;// тактируем на частоте 1Мгц
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);// срабатывает по сравнению
Inicializujeme nulový časovač a jeho handler.
if(m_counter%2 != 0 && m_counter<=48){
buffer <<= 1;// переменная считанных даных
c_counter++;// счетчик положительных импульсов
if(nrf_gpio_pin_read(DOUT))buffer++;//считываем состояние входа
}
To nejzajímavější se děje v ovladači časovače. Perioda impulsu je 20 μs. Zajímají nás liché pulsy (po náběžné hraně) a za předpokladu, že jejich počet není větší než 24 a událostí je 48. Pro každou lichou událost se čte DOUT
Z datasheetu vyplývá, že počet pulzů musí být minimálně 25, což odpovídá zisku 128 (v kódu jsem použil 25 pulzů), to je ekvivalent 50 událostí časovače, což indikuje konec datového rámce.
++m_counter;// счетчик событий
if(m_counter==50){
nrf_drv_timer_disable(&m_timer0);// отключаем таймер
m_simple_timer_state = SIMPLE_TIMER_STATE_STOPPED;//
buffer = buffer ^ 0x800000;
hx711_stop();//jотключаем hx711
}
Poté vypneme časovač a zpracujeme data (podle datasheetu) a přepneme HX711 do režimu nízké spotřeby.
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 Create timers.
*/
static void create_timers()
{
ret_code_t err_code;
// Create timers
err_code = app_timer_create(&m_repeated_timer_id,
APP_TIMER_MODE_REPEATED,
repeated_timer_handler);
APP_ERROR_CHECK(err_code);
}
Očekáváme události z časovače RTC s intervalem 10 s (toto je na vašem uvážení) a spustíme HX711 v handleru, což způsobí přerušení na lince DOUT.
Je tu ještě jeden bod, logy se vydávají přes UART (přenosová rychlost 115200, TX - 6 pinů, RX - 8 pinů) všechna nastavení jsou v sdk_config.h
Závěry
Děkuji všem za pozornost, doufám, že tento článek bude užitečný a vývojářům zkrátí drahocenný čas na hledání řešení. Chci říci, že technický přístup, který Nordic používá ve svých platformách, je z hlediska energetické účinnosti docela zajímavý.
PS
Projekt je stále ve vývoji, takže pokud je toto téma zajímavé, v příštím článku se pokusím popsat algoritmus pro kalibraci snímačů hmotnosti a také připojení BLE stacku.
materiály
Zdroj: www.habr.com