Как ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ АЦП HX711 ΠΊ NRF52832

1. Π’Π²Π΅Π΄Π΅Π½ΠΈΠ΅

На повСсткС дня стояла Π·Π°Π΄Π°Ρ‡Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ» общСния ΠΌΠΈΠΊΡ€ΠΎΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π΅Ρ€Π° nrf52832 с двумя полумостовыми китайскими Ρ‚Π΅Π½Π·ΠΎΠ΄Π°Ρ‚Ρ‡ΠΈΠΊΠ°ΠΌΠΈ.

Π—Π°Π΄Π°Ρ‡Π° оказалась Π½Π΅ простой, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ столкнулся с отсутствиСм ΠΊΠ°ΠΊΠΎΠΉ β€” Π»ΠΈΠ±ΠΎ внятной ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ. ВСроятнСС, Ρ‡Ρ‚ΠΎ Β«ΠΊΠΎΡ€Π΅Π½ΡŒ Π·Π»Π°Β» находится Π² самом SDK ΠΎΡ‚ Nordic Semiconductor β€” это постоянноС обновлСния вСрсий, нСкоторая ΠΈΠ·Π±Ρ‹Ρ‚ΠΎΡ‡Π½ΠΎΡΡ‚ΡŒ ΠΈ Π·Π°ΠΏΡƒΡ‚Π°Π½Π½ΠΎΡΡ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»Π°. ΠŸΡ€ΠΈΡˆΠ»ΠΎΡΡŒ ΠΏΠΈΡΠ°Ρ‚ΡŒ всС с нуля.

Π― Π΄ΡƒΠΌΠ°ΡŽ эта Ρ‚Π΅ΠΌΠ° довольно Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½Π° исходя ΠΈΠ· Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ Π΄Π°Π½Π½Ρ‹ΠΉ Ρ‡ΠΈΠΏ ΠΎΠ±Π»Π°Π΄Π°Π΅Ρ‚ BLE стСком ΠΈ Ρ†Π΅Π»Ρ‹ΠΌ Π½Π°Π±ΠΎΡ€ΠΎΠΌ β€œΠ²ΠΊΡƒΡΠ½ΡΡˆΠ΅ΠΊβ€ Ρ€Π΅ΠΆΠΈΠΌΠ° энСргосбСрСТСния. Но Π² Ρ‚Π΅Ρ…Π½ΠΈΡ‡Π΅ΡΠΊΡƒΡŽ Ρ‡Π°ΡΡ‚ΡŒ я сильно ΡƒΠ³Π»ΡƒΠ±Π»ΡΡ‚ΡŒΡΡ Π½Π΅ Π±ΡƒΠ΄Ρƒ, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ Π½Π° эту Ρ‚Π΅ΠΌΡƒ написано Π½Π΅ΠΌΠ°Π»ΠΎ статСй.

2. ОписаниС ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°

Как ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ АЦП HX711 ΠΊ NRF52832

Π–Π΅Π»Π΅Π·ΠΎ:

  • Adafruit Feather nRF52 Bluefruit LE (Ρ‚ΠΎ Ρ‡Ρ‚ΠΎ оказалось ΠΏΠΎΠ΄ Ρ€ΡƒΠΊΠΎΠΉ)
  • АЦП HX711
  • ΠšΠΈΡ‚Π°ΠΉΡΠΊΠΈΠ΅ Ρ‚Π΅Π½Π·ΠΎΠ΄Π°Ρ‚Ρ‡ΠΈΠΊΠΈ 2 ΡˆΡ‚. (50Ρ…2 ΠΊΠ³)
  • ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°Ρ‚ΠΎΡ€ ST-LINK V2

Π‘ΠΎΡ„Ρ‚:

  • IDE VSCODE
  • NRF SDK 16
  • OpenOCD
  • ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°Ρ‚ΠΎΡ€ ST-LINK V2

ВсС находится Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅, придСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΠΎΠ΄ΡˆΠ°ΠΌΠ°Π½ΠΈΡ‚ΡŒ Makefile (ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ располоТСниС вашСго SDK).

3. ОписаниС кода

Π‘ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ GPIOTE ΠΌΠΎΠ΄ΡƒΠ»ΡŒ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с ΠΏΠ΅Ρ€ΠΈΡ„Π΅Ρ€ΠΈΠ΅ΠΉ исходя ΠΈΠ· привязки Π·Π°Π΄Π°Ρ‡ ΠΈ событий, Π° Ρ‚Π°ΠΊΠΆΠ΅ PPI ΠΌΠΎΠ΄ΡƒΠ»ΡŒ для ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈΠ· ΠΎΠ΄Π½ΠΎΠΉ ΠΏΠ΅Ρ€ΠΈΡ„Π΅Ρ€ΠΈΠΈ Π² Π΄Ρ€ΡƒΠ³ΡƒΡŽ Π±Π΅Π· участия процСссора.

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);//настраСваСм Π½Π° Π²Ρ‹Ρ…ΠΎΠ΄

НастраиваСм линию синхронизации PD_SCL Π½Π° Π²Ρ‹Ρ…ΠΎΠ΄ для Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ ΠΈΠΌΠΏΡƒΠ»ΡŒΡΠΎΠ² Π΄Π»ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒΡŽ 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);//Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Ρ‚Π°ΠΉΠΌΠ΅Ρ€
}
 

НастраиваСм линию Π΄Π°Π½Π½Ρ‹Ρ… DOUT для считывания состояния готовности HX711, ΠΏΡ€ΠΈ Π½Π°Π»ΠΈΡ‡ΠΈΠΈ Π½ΠΈΠ·ΠΊΠΎΠ³ΠΎ уровня срабатываСт ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΡ€Π΅Ρ€Ρ‹Π²Π°Π½ΠΈΠ΅ ΠΈ запускаСм Ρ‚Π°ΠΉΠΌΠ΅Ρ€ для Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ ΡΠΈΠ½Ρ…Ρ€ΠΎΠ½ΠΈΠ·ΠΈΡ€ΡƒΡŽΡ‰ΠΈΡ… ΠΈΠΌΠΏΡƒΠ»ΡŒΡΠΎΠ² Π½Π° Π²Ρ‹Ρ…ΠΎΠ΄Π΅ 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

ПослС Ρ‡Π΅Π³ΠΎ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ PPI ΠΌΠΎΠ΄ΡƒΠ»ΡŒ ΠΈ ΠΊΠΎΠΌΠΌΡƒΡ‚ΠΈΡ€ΡƒΠ΅ΠΌ наш Ρ‚Π°ΠΉΠΌΠ΅Ρ€ ΠΊ Π²Ρ‹Ρ…ΠΎΠ΄Ρƒ PD_SCL, для гСнСрирования ΠΈΠΌΠΏΡƒΠ»ΡŒΡΠΎΠ² Π΄Π»ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ 10мкс ΠΏΡ€ΠΈ наступлСниС события сравнСния, Π° Ρ‚Π°ΠΊΠΆΠ΅ Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ 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);// срабатываСт ΠΏΠΎ ΡΡ€Π°Π²Π½Π΅Π½ΠΈΡŽ

Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ Π½ΡƒΠ»Π΅Π²ΠΎΠΉ Ρ‚Π°ΠΉΠΌΠ΅Ρ€ ΠΈ Π΅Π³ΠΎ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ.

  if(m_counter%2 != 0 && m_counter<=48){
       buffer <<= 1;// пСрСмСнная считанных Π΄Π°Π½Ρ‹Ρ…
        c_counter++;// счСтчик ΠΏΠΎΠ»ΠΎΠΆΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ…  ΠΈΠΌΠΏΡƒΠ»ΡŒΡΠΎΠ²
           if(nrf_gpio_pin_read(DOUT))buffer++;//считываСм состояниС Π²Ρ…ΠΎΠ΄Π°
   }

Π‘Π°ΠΌΠΎΠ΅ интСрСсноС происходит Π² ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ΅ Ρ‚Π°ΠΉΠΌΠ΅Ρ€Π°. ΠŸΠ΅Ρ€ΠΈΠΎΠ΄ ΠΈΠΌΠΏΡƒΠ»ΡŒΡΠΎΠ² составляСт 20 мкс. Нас ΠΈΠ½Ρ‚Π΅Ρ€Π΅ΡΡƒΡŽΡ‚ Π½Π΅Ρ‡Π΅Ρ‚Π½Ρ‹Π΅ ΠΈΠΌΠΏΡƒΠ»ΡŒΡΡ‹ (ΠΏΠΎ восходящСму Ρ„Ρ€ΠΎΠ½Ρ‚Ρƒ) ΠΈ ΠΏΡ€ΠΈ условии, Ρ‡Ρ‚ΠΎ ΠΈΡ… количСство Π½Π΅ Π±ΠΎΠ»Π΅Π΅ 24, Π° событий β€” 48. ΠŸΡ€ΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠΌ Π½Π΅Ρ‡Π΅Ρ‚Π½ΠΎΠΌ событии происходит считываниС DOUT

Из Π΄Π°Ρ‚Π°ΡˆΠΈΡ‚Π° слСдуСт, Ρ‡Ρ‚ΠΎ количСство ΠΈΠΌΠΏΡƒΠ»ΡŒΡΠΎΠ² Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ Π½Π΅ ΠΌΠ΅Π½Π΅Π΅ 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
       }
   

ПослС этого ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Ρ‚Π°ΠΉΠΌΠ΅Ρ€ ΠΈ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅ΠΌ Π΄Π°Π½Π½Ρ‹Π΅ (ΠΏΠΎ Π΄Π°Ρ‚Π°ΡˆΠΈΡ‚Ρƒ) ΠΈ ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ΠΈΠΌ HX711 Π² Ρ€Π΅ΠΆΠΈΠΌ Π½ΠΈΠ·ΠΊΠΎΠ³ΠΎ энСргопотрСблСния.


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);
}

ОТидаСм события ΠΎΡ‚ RTC Ρ‚Π°ΠΉΠΌΠ΅Ρ€Π° с ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»ΠΎΠΌ Π² 10 с (эту ΡƒΠΆΠ΅ Π½Π° вашС усмотрСниС) Π² ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ΅ запускаСм HX711, вызывая ΠΏΡ€Π΅Ρ€Ρ‹Π²Π°Π½ΠΈΠ΅ ΠΏΠΎ Π»ΠΈΠ½ΠΈΠΈ DOUT.

Π•ΡΡ‚ΡŒ Π΅Ρ‰Π΅ ΠΎΠ΄ΠΈΠ½ ΠΌΠΎΠΌΠ΅Π½Ρ‚, Π»ΠΎΠ³ΠΈ выводятся Ρ‡Π΅Ρ€Π΅Π· UART (baud rate 115200, TX β€” 6 ΠΏΠΈΠ½, RX β€” 8 ΠΏΠΈΠ½) всС настройки находятся Π² sdk_config.h

Как ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ АЦП HX711 ΠΊ NRF52832

Π’Ρ‹Π²ΠΎΠ΄Ρ‹

Бпасибо всСм Π·Π° Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, надСюсь эта ΡΡ‚Π°Ρ‚ΡŒΡ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΠ»Π΅Π·Π½ΠΎΠΉ ΠΈ сократит Π΄Ρ€Π°Π³ΠΎΡ†Π΅Π½Π½ΠΎΠ΅ врСмя Π½Π° поиск Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ². Π₯ΠΎΡ‡Ρƒ ΡΠΊΠ°Π·Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ тСхничСский ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Nordic Π² своих ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ°Ρ… довольно интСрСсСн с Ρ‚ΠΎΡ‡ΠΊΠΈ зрСния энСргоэффСктивности.

P.S.

ΠŸΡ€ΠΎΠ΅ΠΊΡ‚ Π΅Ρ‰Π΅ Π² процСссС Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ, поэтому Ссли Π±ΡƒΠ΄Π΅Ρ‚ интСрСсна эта Ρ‚Π΅ΠΌΠ° Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ ΡΡ‚Π°Ρ‚ΡŒΠ΅ я ΠΏΠΎΡΡ‚Π°Ρ€Π°ΡŽΡΡŒ ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ ΠΊΠ°Π»ΠΈΠ±Ρ€ΠΎΠ²ΠΊΠΈ Π΄Π°Ρ‚Ρ‡ΠΈΠΊΠΎΠ² вСса, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ BLE стСка.

ΠœΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Ρ‹

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ