1. Представљање
На дневном реду је био задатак развоја комуникационог протокола за микроконтролер нрф52832 са два кинеска полумостна мерача напрезања.
Испоставило се да задатак није био лак, јер сам се суочио са недостатком било каквих разумљивих информација. Вероватније је да је „корен зла“ у СДК-у самог Нордиц Семицондуцтор-а – константна ажурирања верзија, мало редундантности и збуњујућа функционалност. Морао сам да напишем све од нуле.
Мислим да је ова тема прилично релевантна на основу чињенице да овај чип има БЛЕ стек и читав сет „доброћа“ за режим уштеде енергије. Али нећу улазити превише у технички део, пошто је на ову тему написано много чланака.
2. Опис пројекта

Гвожђе:
- Адафруит Феатхер нРФ52 Блуефруит ЛЕ (оно што се догодило при руци)
- АДЦ ХКС711
- Кинески тензометар 2 ком. (50к2 кг)
- Програматор СТ-ЛИНК В2
мекано:
- ИДЕ ВСЦОДЕ
- НРФ СДК 16
- ОпенОЦД
- Програматор СТ-ЛИНК В2
Све је у једном пројекту, само морате да подесите Макефиле (наведите локацију вашег СДК-а).
3. Опис кода
Користићемо ГПИОТЕ модул за рад са периферијама на основу везивања задатака и догађаја, као и ППИ модул за пренос података са једне периферије на другу без учешћа процесора.
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);//настраеваем на выход
Конфигуришемо линију за синхронизацију ПД_СЦЛ на излаз да генерише импулсе у трајању од 10 μс.
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);//включаем таймер
}
Конфигуришемо линију података ДОУТ да чита стање спремности ХКС711, ако постоји низак ниво, покреће се руковалац у коме деактивирамо прекид и покрећемо тајмер да генерише импулсе такта на излазу ПД_СЦЛ.
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); // омогући гпиоте
Након тога, иницијализујемо ППИ модул и повезујемо наш тајмер са ПД_СЦЛ излазом да генеришемо импулсе у трајању од 10 μс када дође до догађаја поређења, а такође укључујемо ГПИОТЕ модул.
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);// срабатывает по сравнениюИницијализујемо нулти тајмер и његов руковалац.
if(m_counter%2 != 0 && m_counter<=48){
buffer <<= 1;// переменная считанных даных
c_counter++;// счетчик положительных импульсов
if(nrf_gpio_pin_read(DOUT))buffer++;//считываем состояние входа
}
Најзанимљивија ствар се дешава у управљачу тајмера. Период импулса је 20 μс. Заинтересовани смо за непарне импулсе (по растућој ивици) и под условом да њихов број није већи од 24, а за сваки непарни догађај се очитава ДОУТ
Из датасхеет-а произилази да број импулса мора бити најмање 25, што одговара појачању од 128 (у коду сам користио 25 импулса), што је еквивалентно 50 догађаја тајмера, што указује на крај оквира података.
++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
}
Након тога, искључимо тајмер и обрадимо податке (према подацима) и пребацимо ХКС711 у режим ниске потрошње енергије.
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);
}
Очекујемо догађаје од РТЦ тајмера са интервалом од 10 с (ово је по вашем нахођењу) и покрећемо ХКС711 у руковаоцу, изазивајући прекид на ДОУТ линији.
Постоји још једна ствар, дневници се излазе преко УАРТ-а (брзина преноса 115200, ТКС - 6 пинова, РКС - 8 пинова) сва подешавања су у сдк_цонфиг.х

Налази
Хвала свима на пажњи, надам се да ће овај чланак бити користан и да ће програмерима смањити драгоцено време да пронађу решење. Желим да кажем да је технички приступ који Нордиц користи у својим платформама прилично занимљив са становишта енергетске ефикасности.
ПС
Пројекат је још у развоју, па ако је ова тема интересантна, у следећем чланку ћу покушати да опишем алгоритам за калибрацију сензора тежине, као и повезивање БЛЕ стека.
Материјали
Извор: ввв.хабр.цом
