Como conectar o ADC HX711 ao NRF52832

1. Introdução

O objetivo era desenvolver um protocolo de comunicação entre o microcontrolador nrf52832 e dois sensores de pressão semi-pontes chineses.

A tarefa não foi simples, pois me deparei com a ausência de informações claras. É provável que a "raiz do problema" esteja no próprio SDK da Nordic Semiconductor — as constantes atualizações de versões, certa redundância e confusão na funcionalidade. Tive que escrever tudo do zero.

Acredito que este tema seja bastante relevante, considerando que este chip possui uma pilha BLE e um conjunto inteiro de "vantagens" em modo de economia de energia. Mas não vou me aprofundar muito na parte técnica, pois já foram escritas várias matérias sobre isso.

2. Descrição do projeto

Como conectar o ADC HX711 ao NRF52832

Hardware:

  • Adafruit Feather nRF52 Bluefruit LE (o que estava à mão)
  • ADC HX711
  • Sensores de pressão chineses 2 un. (50x2 kg)
  • Programador ST-LINK V2

Software:

  • IDE VSCODE
  • NRF SDK 16
  • OpenOCD
  • Programador ST-LINK V2

Tudo está em um único projeto, só será necessário ajustar o Makefile (especificar a localização do seu SDK).

3. Descrição do código

Usaremos o módulo GPIOTE para trabalhar com a periferia, com base na vinculação de tarefas e eventos, assim como o módulo PPI para transferir dados de uma periferia para outra sem a participação do processador.

ret_code_t err_code;
   err_code = nrf_drv_gpiote_out_init(PD_SCK, &config); // configuramos para saída
   nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false); // iremos alternar o pino para um pulso
   err_code = nrf_drv_gpiote_out_init(PD_SCK, &config); // configuramos para saída

Configuramos a linha de sincronização PD_SCL como saída para gerar pulsos com duração de 10 microssegundos.

   nrf_drv_gpiote_in_config_t gpiote_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(false); // transição de nível de alto para baixo
   nrf_gpio_cfg_input(DOUT, NRF_GPIO_PIN_NOPULL); // como entrada sem pull-up
   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); // desativamos a interrupção
    nrf_drv_timer_enable(&m_timer0); // ativamos o timer
}
 

Configuramos a linha de dados DOUT para ler o estado de disponibilidade do HX711; quando um nível baixo é detectado, o manipulador desativa a interrupção e ativa o timer para gerar pulsos de sincronização na saída 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)); // conectamos o timer à saída
   APP_ERROR_CHECK(err_code);
   err_code = nrf_drv_ppi_channel_enable(m_ppi_channel1); // ativamos o canal
   APP_ERROR_CHECK(err_code);
   nrf_drv_gpiote_out_task_enable(PD_SCK); 

// включаем gpiote

Em seguida, inicializamos o módulo PPI e conectamos nosso timer à saída PD_SCL, para gerar pulsos de 10 µs quando ocorrer o evento de comparação, além de ativar o módulo GPIOTE.


nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG; // padrão
   timer_cfg.frequency = NRF_TIMER_FREQ_1MHz; // configuramos para uma frequência de 1 MHz
   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); // ativa na comparação

Inicializamos o timer zero e seu manipulador.

  if(m_counter % 2 != 0 && m_counter <= 48){
       buffer <<= 1; // variável de dados lidos
        c_counter++; // contador de pulsos positivos
           if(nrf_gpio_pin_read(DOUT)) buffer++; // lemos o estado da entrada
   }

O mais interessante acontece no manipulador do timer. O período dos pulsos é de 20 µs. Estamos interessados em pulsos ímpares (na borda ascendente) e sob a condição de que sua quantidade não exceda 24, e eventos — 48. A cada evento ímpar, ocorre a leitura de DOUT.

Do datasheet, é indicado que o número de pulsos deve ser de pelo menos 25, o que corresponde a um ganho de 128 (no código, utilizei 25 pulsos), isso equivale a 50 eventos do timer, indicando o fim do quadro de dados.

 ++m_counter; // contador de eventos
if(m_counter == 50){
      nrf_drv_timer_disable(&m_timer0); // desativamos o timer
       m_simple_timer_state = SIMPLE_TIMER_STATE_STOPPED; //
       buffer = buffer ^ 0x800000;
       hx711_stop(); // desligamos o hx711
       }
   

Após isso, desligamos o timer e processamos os dados (conforme o datasheet) e colocamos o HX711 em modo de baixo consumo de energia.


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();\/\/ ativar hx711
       nrf_drv_gpiote_out_toggle(LED_1);
       m_simple_timer_state = SIMPLE_TIMER_STATE_STARTED;
   }
  
}
\/\**@brief Criar temporizadores.
*\/\nstatic void create_timers()\n{\n   ret_code_t err_code;\n \n   \/\/ Criar temporizadores\n   err_code = app_timer_create(&m_repeated_timer_id,\n                               APP_TIMER_MODE_REPEATED,\n                               repeated_timer_handler);\n   APP_ERROR_CHECK(err_code);\n}

Aguardando evento do temporizador RTC com intervalo de 10s (isso já fica a seu critério) no manipulador, ativamos o HX711, chamando a interrupção na linha DOUT.

Há mais um ponto, os logs são gerados via UART (taxa de transmissão 115200, TX — pino 6, RX — pino 8) todas as configurações estão em sdk_config.h

Como conectar o ADC HX711 ao NRF52832

Como resultado, obtemos um serviço de "monitoramento como serviço", automatizado na linha de produção de integração contínua. O desenvolvedor ou testador precisa apenas definir a lista de métricas em um arquivo JSON, e tudo o mais acontece automaticamente. Obtemos um controle de qualidade transparente dos lançamentos: todas as notificações sobre desempenho, consumo de recursos ou regressões arquitetônicas.

Agradeço a todos pela atenção, espero que este artigo seja útil e economize o precioso tempo dos desenvolvedores na busca por soluções. Gostaria de dizer que a abordagem técnica utilizada pela Nordic em suas plataformas é bastante interessante do ponto de vista da eficiência energética.

P.S.

O projeto ainda está em desenvolvimento, portanto, se este tema for de interesse, no próximo artigo tentarei descrever o algoritmo de calibração dos sensores de peso, bem como a conexão da pilha BLE.

Materiais

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster