1. Hyrje
ĂĂ«shtja ishte tĂ« zhvillohej njĂ« protokoll komunikimi pĂ«r mikrocontrollerin nrf52832 me dy senzora tĂ« tensionit polumĂ«s pĂ«r nga Kina.
Detyra doli tĂ« ishte e vĂ«shtirĂ«, pasi u ndesha me mungesĂ«n e informacionit tĂ« qartĂ«. MĂ« shumĂ« se kaq, duket se "rrĂ«nja e sĂ« keqes" ndodhet nĂ« vetĂ« SDK-nĂ« e Nordic Semiconductor â kĂ«to pĂ«rditĂ«sime tĂ« vazhdueshme tĂ« versioneve, njĂ«farĂ« tepricĂ«s dhe ndĂ«rlikimi tĂ« funksionaliteteve. Duhej ta shkruaja gjithçka nga e para.
Mendoj se ky temë është mjaft aktuale meqenëse ky çip ka një stil BLE dhe një gamë të tërë "saldosh" për modalitetin e kursimit të energjisë. Por nuk do të thellohem shumë në pjesën teknike, pasi për këtë temë janë shkruar shumë artikuj.
2. Përshkrimi i projektit

Hardueri:
- Adafruit Feather nRF52 Bluefruit LE (ajo që kishte dorë)
- ADC HX711
- Dy senzora tensioni nga Kina (50x2 kg)
- Programatori ST-LINK V2
Software:
- IDE VSCODE
- NRF SDK 16
- OpenOCD
- Programatori ST-LINK V2
Të gjitha ndodhen në një projekt, do të duhet vetëm të modifikoni Makefile (të specifikoni vendndodhjen e SDK tuaj).
3. Përshkrimi i kodit
Do t'i përdorim modulin GPIOTE për të punuar me periferinë bazuar në lidhjen e detyrave dhe ngjarjeve, si dhe modulin PPI për të transferuar të dhëna nga një periferik në tjetrin pa angazhimin e procesorit.
ret_code_t err_code;
err_code = nrf_drv_gpiote_out_init(PD_SCK, &config); //setup output
nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false); // do të tërheqim pinin për impuls
err_code = nrf_drv_gpiote_out_init(PD_SCK, &config); //setup output
Konfigurojmë linjën e sinkronizimit PD_SCL për të gjeneruar impulse me gjatësi 10 ”s.
nrf_drv_gpiote_in_config_t gpiote_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(false); // kalimi i nivelit nga i lartë në të ulët
nrf_gpio_cfg_input(DOUT, NRF_GPIO_PIN_NOPULL); // në input pa tërheqje
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); //ndalojmë ndërprerjen
nrf_drv_timer_enable(&m_timer0); //aktivizojmë timerin
}
Konfigurojmë linjën e të dhënave DOUT për të lexuar gjendjen e gatishmërisë së HX711, kur ka një nivel të ulët aktivizohet procesori në të cilin ndalim ndërprerjen dhe aktivizojmë timerin për të gjeneruar impulse sinkronizuese në daljen 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));// lidhim timerin me dalje
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_enable(m_ppi_channel1);// aktivizojmë kanal
APP_ERROR_CHECK(err_code);
nrf_drv_gpiote_out_task_enable(PD_SCK); // ĐČĐșĐ»ŃŃĐ°Đ”ĐŒ gpiote
Pasi bëjmë kështu, ne inicializojmë modulin PPI dhe lidhi timerin tonë me daljen PD_SCL, për të gjeneruar impulse me gjatësi 10”s kur ndodh një ngjarje krahasimi, si dhe aktivizojmë modul GPIOTE.
nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;// në mënyrë default
timer_cfg.frequency = NRF_TIMER_FREQ_1MHz;// ritmi në frekuencë 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);// aktivizohet me krahasimInizializojmë timin zero dhe trajtuesin e tij.
nëse(m_counter%2 != 0 && m_counter<=48){
buffer <<= 1; // variabla e të dhënave të lexuara
c_counter++; // numëruesi i impulsave pozitive
nëse(nrf_gpio_pin_read(DOUT))buffer++; // lexojmë gjendjen e hyrjes
}
Gjithçka interesante ndodh nĂ« trajtuesin e timer-ave. Periudha e impulsave Ă«shtĂ« 20 ÎŒs. Na interesojnĂ« impulsat çiftĂ« (nĂ« rritjen e frontit) dhe me kusht qĂ« numri i tyre tĂ« mos jetĂ« mĂ« shumĂ« se 24, ndĂ«rsa ngjarjet 48. NĂ« çdo ngjarje çift ndodh leximi i DOUT
Sipas fletës së të dhënave, numri i impulsave duhet të jetë të paktën 25, që korrespondon me një faktor amplifikimi prej 128 (në kod kam përdorur 25 impulse), kjo është ekuivalente me 50 ngjarje të timer-it, që tregon përfundimin e kornizës së të dhënave.
++m_counter; // numëruesi i ngjarjeve
nëse(m_counter==50){
nrf_drv_timer_disable(&m_timer0); // fikim timer-in
m_simple_timer_state = SIMPLE_TIMER_STATE_STOPPED; //
buffer = buffer ^ 0x800000;
hx711_stop(); // fikim hx711
}
Pas kësaj, fikim timer-in dhe përpunojmë të dhënat (sipas fletës së të dhënave) dhe transferojmë HX711 në modalitetin e konsumit të ulët të energjisë.
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();// aktivizoni hx711
nrf_drv_gpiote_out_toggle(LED_1);
m_simple_timer_state = SIMPLE_TIMER_STATE_STARTED;
}
}
/**@brief Krijo timer-ët.
*/
static void create_timers()
{
ret_code_t err_code;
// Krijo timer-ët
err_code = app_timer_create(&m_repeated_timer_id,
APP_TIMER_MODE_REPEATED,
repeated_timer_handler);
APP_ERROR_CHECK(err_code);
}
Presim ngjarjen nga RTC timer me një interval prej 10 sekondash (këtë tashmë sipas dëshirës tuaj) në trajtuesin e aktivizimit të HX711, duke thirrur një ndërprerje në linjën DOUT.
Ka edhe njĂ« çështje tjetĂ«r, logĂ«t dalin pĂ«rmes UART (baud rate 115200, TX â pin 6, RX â pin 8) tĂ« gjitha konfigurimet ndodhen nĂ« sdk_config.h

Përfundimet
Faleminderit të gjithëve për vëmendjen, shpresoj se ky artikull do të jetë i dobishëm dhe do të kursejë kohë të çmuar në kërkimin e zgjidhjeve për zhvilluesit. Dëshiroj të theksoj se qasja teknike që përdor Nordic në platformat e tij është mjaft interesante për nga pikëpamja e efikasitetit të energjisë.
P.S.
Projekti është ende në proces zhvillimi, prandaj nëse kjo temë ju intereson, në artikullin e ardhshëm do të përpiqem të përshkruaj algoritmin për kalibrimin e sensorëve të peshës, si dhe lidhjen e BLE stack.
Materialet
Burimi: habr.com
