Contador de Giros com Sensor Efeito Hall e Raspberry Pi Pico Deixe um comentário

Foto do projeto montado: Contador de Giros com Sensor Efeito Hall e Raspberry Pi Pico
Contador de Giros com Sensor Efeito Hall e Raspberry Pi Pico

Neste post vamos ver como construir um medidor de rotações por minuto, composto por três elementos principais:

Um sensor para detectar a rotação – vamos usar um sensor de efeito Hall.
Um display para apresentar o resultado – vamos usar um display de 7 segmentos com quatro dígitos.
Um microcontrolador para receber o sinal do sensor, calcular as rotações por minuto e apresentar no display – vamos usar a Raspberry Pi Pico.

Com esse projeto você vai conhecer esses três elementos e ver algumas técnicas interessantes de programação da Pi Pico usando o SDK C/C++.

Raspberry Pi Pico

A “Pi Pico” é uma placa com o poderoso microcontrolador RP2040, que possui respeitáveis capacidades de processamento, memória e entrada e saída. Você vai encontrar detalhes sobre ela em vários artigos aqui no blog.

Foto Raspberry Pi Pico
Raspberry Pi Pico

No exemplo deste post vamos usar as saídas digitais para acionar o display, uma entrada digital para ler o sensor e o recurso de timer para medir tempo e atualizar periodicamente o display.

Sensor Efeito Hall

O Efeito Hall consiste na produção de uma diferença de voltagem em um condutor quando este é submetido a um campo magnético. Este efeito é usado para detectar a presença de um campo magnético, por exemplo produzido por um imã.

Existem vários modelos de sensores efeito Hall. Alguns fornecem uma saída analógica indicando a intensidade do campo, outros tem uma saída digital que indica a presença de um campo magnético e tem até modelos que detectam uma mudança de polaridade do campo magnético.

No nosso projeto vamos usar o módulo KY-003 com o sensor A3144 da Allegro. Esse sensor possui internamente um elemento Hall e o circuito necessário para controlar uma saída digital:

Foto do módulo módulo KY-003
Módulo KY-003

O sensor precisa ser alimentado com 5V. A saída digital está normalmente desconectada, ao detectar um campo magnético a saída é conectada à terra, forçando um nível lógico baixo. Vamos usar o pull-up interno da Pi Pico para garantir um nível lógico alto quando não for detectado campo magnético.

Display de LED 7 Segmentos com Quatro Dígitos

O display LED de 7 segmentos utiliza sete LEDs (os segmentos) para apresentar números (e, com um pouco de imaginação, algumas letras). Estes segmentos são normalmente referenciados por letras de ‘A’ a ‘G’:

Esquemático do Display de LED 7 Segmentos
Display de LED 7 Segmentos

Como cada segmento é um LED, se fossemos conectar cada um separadamente, teríamos 14 terminais. Para simplificar o uso, uma das pontas (catodo ou anodo) de todos LEDs são ligadas em conjunto. Com isso temos displays do tipo catodo comum e anodo comum.

Quando temos vários dígitos, não é prático conectarmos uma saída digital a cada segmento de cada dígito. O que é feito é conectar os segmentos iguais dos dígitos. A figura abaixo mostra as conexões do display que vamos usar (que é do tipo anodo comum):

Conexões do diaplay utilizadas no projeto
Conexões do diaplay utilizadas no projeto

Para acender um segmento do display é preciso colocar uma tensão entre o anodo comum e o catodo do segmento. Para apresentar um dígito, o selecionamos através do anodo e colocamos nos segmentos as tensões para acender ou apagá-los conforme o desenho desejado.

Para apresentarmos “simultaneamente” os quatro dígitos fazemos uma multiplexação, acendendo um dígito de cada vez por uma fração de segundo. A nossa vista não perceberá que cada dígito está aceso apenas um quarto do tempo.

Uma última coisa a considerar é a corrente que fluirá. Vamos colocar um resistor de 1K em série com cada segmento para limitar a corrente em cada um em menos de 2mA. Se todos os segmentos estiverem ligados, no anodo comum fluirá uma corrente total de, no máximo, 14mA. Uma característica das saídas digitais do Pi Pico é que elas podem ser configuradas para trabalharem com diferentes níveis de corrente. Configurando os pinos ligados aos anodos para a corrente máxima podemos ligar diretamente o display.

Se você achar que a intensidade do display é pouca, você pode alterar os resistores de 1K para valores menores (por exemplo 470 ohms), aumentando a corrente em cada segmento. Porém aí não será possível ligar diretamente os anodos ao Pi Pico, será necessário utilizar um transistor PNP de uso geral (como o 2N5401):

Esquemático do 2N5401
Esquemático do 2N5401

Material Necessário para o Contador de Giros

Para a parte prática você precisará:

Montagem

A figura abaixo mostra a montagem do circuito:

Esquemático do circuito Contador de Giros com Sensor Efeito Hall e Raspberry Pi Pico
Esquemático do Contador de Giros com Sensor Efeito Hall e Raspberry Pi Pico

O imã deve ser fixado na borda da superfície giratória e o sensor posicionado em uma posição onde seja acionado na passagem do ímã (veja adiante como acertar a posição).

Software

O nosso programa vai ser escrito em C. A programação da Raspberry Pi Pico em C é descrita no manual do SDK (que você baixa aqui); a preparação do ambiente é descrita neste artigo da Rosana Guse (e na documentação oficial).

O programa (contagiro.c) é o seguinte:

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/sync.h"

// Conexões aos GPIOs
// Segmentos:  A:6 B:4 C:1 D:2 E:3 F:5 G:0
// Dígitos:    1:7 2:8 3:9 4:10
// Sensor:     16
#define SEGTOS_MASK     0x0007F
#define DIGITOS_MASK    0x00780
#define SENSOR_MASK     0x10000
#define DIGITO_1        7
#define DIGITO_2        8
#define DIGITO_3        9
#define DIGITO_4        10
#define SENSOR          16

// GPIOs de seleção dos dígitos
int digito[] = { DIGITO_1, DIGITO_2, DIGITO_3, DIGITO_4 };

// Quais segmentos ativar para cada dígito
int segtos[] = { // AFB EDCG   0 = aceso, 1 = apagado
    0x01,        // 000 0001     --A--
    0x6D,        // 110 1101     F   B
    0x22,        // 010 0010     --G--
    0x28,        // 010 1000     E   C
    0x4C,        // 100 1100     --D--
    0x18,        // 001 1000
    0x10,        // 001 0000
    0x2D,        // 010 1101
    0x00,        // 000 0000
    0x08         // 000 1000
 };

// Timer para disparar a atualização do display
struct repeating_timer timer;

// Valor a apresentar
volatile int valor[4];

// Rotinas locais
void init(void);
bool atlDisplay(struct repeating_timer *t);

// Programa principal
int main() {
    init();
    uint64_t anterior = 0;
    while (1) {
	  // espera detectar o sensor
        while (gpio_get(SENSOR))
            ;
        uint64_t atual = time_us_64 ();
	  // espera ímã se afastar do sensor
        while (!gpio_get(SENSOR))
            ;
        if (anterior != 0) {
		// Calcular o rpm a partir do tempo de uma volta
            uint64_t tempo = atual - anterior;
            int rpm = 0;
            if (tempo <= 6000) {
                rpm = 9999;
            } else if (tempo < 90000000L) {
                rpm = (int) (600000000L/tempo);
                rpm = (rpm + 5) / 10;	// arredonda
            }
		// atualizar o valor com interrupções inibidas
		// para não piscar valor incorreto
            uint32_t flags = save_and_disable_interrupts();
            valor[0] = rpm / 1000;
            valor[1] = (rpm/100) % 10;
            valor[2] = (rpm/10) % 10;
            valor[3] = rpm % 10;
            restore_interrupts(flags);
        }
        anterior = atual;
    }
    return 0;
}

// Iniciação
void init() {
    int i;

    // Inicia os GPIOs
    gpio_init_mask (SEGTOS_MASK | DIGITOS_MASK | SENSOR_MASK);
    gpio_set_dir_masked (SEGTOS_MASK | DIGITOS_MASK | SENSOR_MASK,
 SEGTOS_MASK | DIGITOS_MASK);
    for (i = 0; i < 4; i++) {
        gpio_set_drive_strength (digito[i], GPIO_DRIVE_STRENGTH_12MA);
    }
    gpio_pull_up (SENSOR);
    
    // Dispara atualização do display
    add_repeating_timer_ms(5, atlDisplay, NULL, &timer);
}

// Atualização do display
bool atlDisplay(struct repeating_timer *t) {
    static int nDig = 3;

    gpio_put (digito[nDig], false); // desliga o dígito anterior
    nDig = (nDig + 1) & 3;  // passa para o próximo dígito
    
    // acerta os segmentos
    gpio_put_masked (SEGTOS_MASK, segtos[valor[nDig]]); 
    
    gpio_put (digito[nDig], true); // liga o dígito atual

    return true;	// continuar chamando
}


Alguns comentários sobre as funções do SDK usadas no programa:

  • gpio_init_mask() seleciona os pinos que serão usados para GPIO
  • gpio_set_dir_masked() seleciona a direção dos pinos
  • gpio_set_drive_strength() controla a corrente fornecida ou absorvida pelo pino
  • add_repeating_timer_ms() programa um timer para chamar periodicamente uma rotina (no nosso caso vai chamar atlDisplay() a cada 5 milissegundos)
  • gpio_put() controla um GPIO de saída
  • gpio_put_masked() controla vários GPIOs de saída ao mesmo tempo
  • gpio_get() informa o estado de um GPIO de entrada
  • time_us_64() retorna um contador de microsegundos (com 64 bits)
  • save_and_disable_interrupts() desativa as interrupções, retornado quais estavam habilitadas
  • restore_interrupts() re-habilita as interrupções

As “máscaras” usadas nas funções de controle do GPIO são valores onde cada bit corresponde a um pino. Detalhes sobre estas funções podem ser vistas na documentação do SDK.

As informações para compilar este programa serão colocadas em um arquivo CMakeLists.txt:

cmake_minimum_required(VERSION 3.13)

include(pico_sdk_import.cmake)

project(contagiro_project)

pico_sdk_init()

add_executable(contagiro
    contagiro.c
)

target_link_libraries(contagiro PRIVATE
    pico_stdlib
)

pico_add_extra_outputs(contagiro)

As instruções abaixo para gerar o executável usando a linha de comando são para Linux (veja mais detalhes nas referências acima) e supõem que você instalou o SDK dentro do seu ‘home’, num diretório chamado pico. Crie debaixo deste diretório pico o diretório contagiro e coloque dentro dele os arquivos contagiro.c e CMakeLists.txt listados acima e execute os seguintes comandos:

cd ~/pico/contafiro
cp ~/pico/pico-sdk/external/pico_sdk_import.cmake .
mkdir build
cd build
export PICO_SDK_PATH=../../pico-sdk
cmake ..
make


Ao final terá sido criado no diretório build, entre outros, o arquivo contagiro.uf2. Aperte o botão BOOT da Pi Pico, conecte ao micro e solte o botão. O micro vai reconhecer a placa como um pendrive. Copie o arquivo contagiro.uf2 para este drive, a placa irá reiniciar e executar o programa.

Uso do Contador de Giros

O primeiro passo para o uso é acertar a posição do ímã e do sensor. Para facilitar isso, o módulo possui um LED que é aceso quando o sensor detecta o imã. Atenção que o sensor A3144 é acionado por apenas um dos pólos do ímã. Qual pólo depende do ímã estar acima ou abaixo do sensor.

Alimente o circuito e movimente com a mão (se possível) o objeto cuja rotação você deseja medir. Ignore por enquanto o valor apresentado no display, o importante é o LED estar aceso quando o ímã passa pelo sensor e apagado quando o ímã está afastado:

Funcionamento do contador de giros
Funcionamento do contador de giros

Se o LED não estiver acendendo, provavelmente você está com o polo errado na direção do sensor. Experimente girar o ímã.

Feito este acerto, ponha o objeto para rodar e veja a medida de rotações por minuto ser apresentada no display:

YouTube video

Conclusão

Este projeto mostrou como conectar um display LED de 7 segmentos com quatro dígitos e um sensor magnético por efeito Hall ao Raspberry Pi Pico.

Um desafio para você exercitar a sua habilidade de programação: aproveitar melhor o display usando um ponto decimal para valores menores que 1000 rpm. Para isso você vai precisar:

  • Ligar o “segmento” DP à Pi Pico
  • Fazer o cálculo da rotação com maior precisão
  • Determinar a posição do ponto conforme o valor
  • Atualizar o ponto junto com os demais segmentos

Então, gostou do artigo? Pretende montar o projeto ou fazer algo derivado dele? Dúvidas? Use os comentários abaixo para contar para nós!

E não esqueça de nos seguir no Instagram para ser avisado das novidades do nosso blog!

Faça seu comentário

Acesse sua conta e participe