Mini proiect (53) - Trimiterea semnalului de la un senzor hall conectat la ESP32 către RaspberryPi 4 pe SPI

Trimiterea semnalului de la un senzor hall conectat la ESP32 către RaspberryPi 4 pe SPI

În acest mic proiect urmăresc transmiterea semnalului de la un senzor Hall către un Raspberry Pi 4, utilizând o conexiune SPI cu un microcontroler ESP32. Descoperiți tehnologia din spatele senzorului Hall și modul în care acesta poate detecta câmpurile magnetice, apoi învățați cum să implementați o conexiune Serial Peripheral Interface (SPI) între ESP32 și Raspberry Pi 4 pentru a transfera eficient datele măsurate. Acest ghid practic vă oferă informații esențiale și pași detaliați pentru a realiza o integrare robustă și precisă între dispozitivele dumneavoastră, deschizând astfel poarta către aplicații diverse, de la monitorizarea mediului înconjurător la proiecte IoT inovatoare.

Comunicația SPI - Serial Peripheral Interface

Comunicarea prin SPI (Serial Peripheral Interface) între un ESP32 și un Raspberry Pi 4 implică utilizarea a trei linii principale: MISO (Master In Slave Out), MOSI (Master Out Slave In), și SCK (Serial Clock). În plus, este posibil să fie nevoie de o linie suplimentară numită SS (Slave Select) sau CS (Chip Select), care indică la dispozitivul slave că trebuie să asculte datele transmise de master.

Despre comunicația SPI am mai discutat și în următoarele articole:

Conectarea Hardware între RaspberryPi4 și ESP32

 Iată pașii generali pentru a realiza comunicarea SPI între un ESP32 și un Raspberry Pi 4:

  • Asigurați-vă că ambele dispozitive au SPI activat. Pe Raspberry Pi, acest lucru se poate face din raspi-config.

  • Conectați MISO la MISO, MOSI la MOSI, SCK la SCK, și, dacă este necesar, SS/CS la linia corespunzătoare pe ambele dispozitive.
  • Asigurați-vă că ambele dispozitive au aceeași referință de tensiune (de exemplu în acest caz avem  3.3V pentru fiecare dispozitiv, pentru că ambele dispozitive operează la această tensiune).
  • Placa ESP32 am conectat-o pe unul din USB-urile de la RaspberryPi4 care asigura aceeasi tensiune de referinta si același GND

 Senzorul Hall

Un senzor Hall este un dispozitiv electronic care detectează câmpurile magnetice. Principiul de funcționare se bazează pe efectul Hall, numit după fizicianul Edwin Hall, care a descoperit acest fenomen în 1879. Iată cum funcționează un senzor Hall în linii mari:

  • Placă Hall: Senzorul Hall are o mică placă de semiconductori (de obicei arseniu de galiu) prin care curge un curent electric.

     

  • Câmp Magnetic: Atunci când senzorul Hall este expus la un câmp magnetic extern, acesta afectează mișcarea purtătorilor de sarcină (electroni sau găuri) în semiconductori.

  • Efectul Hall: Din cauza efectului Hall, care este o deviație laterală a purtătorilor de sarcină într-un câmp magnetic, se creează o diferență de potențial laterală (tensiune) între laturile laterale ale plăcii Hall.

  • Generare Semnal: Această tensiune laterală este măsurată și convertită într-un semnal electric, care poate fi apoi interpretat pentru a determina intensitatea și direcția câmpului magnetic.

  • Interpretarea Semnalului: Spre exemplu, într-un dispozitiv de măsurare a curentului electric, un senzor Hall ar putea fi utilizat pentru a detecta câmpul magnetic generat de curentul electric. În aplicații de tipul senzorilor Hall rotativi (rotary encoders), schimbările în câmpul magnetic datorate rotației sunt detectate pentru a măsura poziția sau viteza.

Avantajele senzorilor Hall includ durabilitatea, sensibilitatea la câmpuri magnetice mici, consum redus de energie și durată lungă de viață. Aceste caracteristici îi fac potriviți pentru o gamă variată de aplicații, de la sisteme de control industrial la dispozitive electronice de consum și automobile.

Alt proiecțel similar mai vechi: https://blog.automatic-house.ro/2019/03/01/mini-proiect-11-modul-senzor-magnetic-hall/

Componente

Configurarea și compilarea pentru RaspberryPi

Pentru instalarea librăriei ncurse, care se utilizează în aplicație se utilizează următoarea comandă:

sudo apt-get install libncurses5-dev libncursesw5-dev

Fisierul make care ne ajută să compilăm mai ușor conține următoarele configurări:
#
# Cross Platform Makefile
# Compatible with MSYS2/MINGW, Ubuntu 14.04.1 and Mac OS X
#
# You will need GLFW (http://www.glfw.org):
# Linux:
#   apt-get install libglfw-dev
# Mac OS X:
#   brew install glfw
# MSYS2:
#   pacman -S --noconfirm --needed mingw-w64-x86_64-toolchain mingw-w64-x86_64-glfw
#

#CXX = g++
#CXX = clang++

EXE = spi_test
APP_DIR = ../
SOURCES = main.cpp
SOURCES += $(APP_DIR)/WiringPi/wiringPi.c $(APP_DIR)/WiringPi/wiringPiSPI.c  $(APP_DIR)/WiringPi/piThread.c $(APP_DIR)/WiringPi/softTone.c $(APP_DIR)/WiringPi/softPwm.c $(APP_DIR)/WiringPi/piHiPri.c 
SOURCES += $(APP_DIR)/spidevlib/spidev_lib.c 


OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)

CXXFLAGS = -std=c++11  -I$(APP_DIR)/WiringPi -I$(APP_DIR)/spidevlib
CXXFLAGS += -g -Wall -Wformat
LIBS =  -lpthread -lm -lcrypt -lrt -lncurses

##--------------------------------------------------------------------- 
## BUILD FLAGS PER PLATFORM
##---------------------------------------------------------------------

ifeq ($(UNAME_S), Linux) #LINUX
	ECHO_MESSAGE = "Linux"
	LIBS += -lGL `pkg-config --static --libs glfw3`

	CXXFLAGS += `pkg-config --cflags glfw3`
	CFLAGS = $(CXXFLAGS)
endif


##---------------------------------------------------------------------
## BUILD RULES
##---------------------------------------------------------------------

%.o:%.cpp
	$(CXX) $(CXXFLAGS) -c -o $@ $<

%.o:$(IMGUI_DIR)/WiringPi/%.c
	$(CXX) $(CXXFLAGS) -c -o $@ $<
	
%.o:$(IMGUI_DIR)/spidevlib/%.c
	$(CXX) $(CXXFLAGS) -c -o $@ $<

all: $(EXE)
	@echo Build complete for $(ECHO_MESSAGE)

$(EXE): $(OBJS)
	$(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS)

clean:
	rm -f $(EXE) $(OBJS)
După lansarea compilării se vor genera fișierele obiect "*.o", iar apoi se vor link edita și va rezulta un executabil spi_test.
florins@raspberrypi:~/imgui_demo_gl2/src2 $ make
g++ -std=c++11  -I..//WiringPi -I..//spidevlib -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o main.o main.cpp
g++ -std=c++11  -I..//WiringPi -I..//spidevlib -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o wiringPi.o ..//WiringPi/wiringPi.c
g++ -std=c++11  -I..//WiringPi -I..//spidevlib -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o wiringPiSPI.o ..//WiringPi/wiringPiSPI.c
g++ -std=c++11  -I..//WiringPi -I..//spidevlib -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o piThread.o ..//WiringPi/piThread.c
g++ -std=c++11  -I..//WiringPi -I..//spidevlib -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o softTone.o ..//WiringPi/softTone.c
g++ -std=c++11  -I..//WiringPi -I..//spidevlib -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o softPwm.o ..//WiringPi/softPwm.c
g++ -std=c++11  -I..//WiringPi -I..//spidevlib -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o piHiPri.o ..//WiringPi/piHiPri.c
g++ -std=c++11  -I..//WiringPi -I..//spidevlib -g -Wall -Wformat `pkg-config --cflags glfw3` -c -o spidev_lib.o ..//spidevlib/spidev_lib.c
g++ -o spi_test main.o wiringPi.o wiringPiSPI.o piThread.o softTone.o softPwm.o piHiPri.o spidev_lib.o -std=c++11  -I..//WiringPi -I..//spidevlib -g -Wall -Wformat `pkg-config --cflags glfw3` -lpthread -lm -lcrypt -lrt -lncurses -lGL `pkg-config --static --libs glfw3`
Build complete for Linux


 Pentru rularea aplicației se execută comanda:

florins@raspberrypi:~/imgui_demo_gl2/src2 $ ./spi_test
 
Aplicația rulează într-o buclă infinită, și se oprește doar dacă se apasă tasta 'q'.

Configurarea și compilarea pentru ESP32

Configurarea și compilarea pentru ESP23 am realizat-o folosind tot VisualStudioCode, dar pe Windows, iar apoi am conectat ESP-ul la unul din USB-urile RaspberryPi4.

Cod de test pentru RaspberryPi4

 
/*
Florin Simedru
Complete project details at https://blog.automatic-house.ro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
#include <wiringPiSPI.h>
#include <wiringPi.h>
#include <iostream>
#include <ncurses.h>
#include <cstdlib>
// Funcție pentru tratarea semnalului de întrerupere
void handleInterrupt(int signal) {
endwin(); // Termină modul curses înainte de închiderea programului
std::cout << "Program întrerupt de la semnalul " << signal << ". Închidere..." << std::endl;
exit(0);
}
int main() {
// Deschide conexiunea SPI
int channel = 0; // Poate fi 0 sau 1, în funcție de canalul SPI folosit
int speed = 1000000; // Viteza de transfer în Hz
int spi = wiringPiSPISetup(channel, speed);
if (spi == -1) {
std::cerr << "Eroare la deschiderea conexiunii SPI. Verificați conexiunile hardware." << std::endl;
return 1;
}
// Buffer pentru date
unsigned char data[2];
// Inițializare mod curses
initscr();
timeout(0); // Timpul maxim de așteptare pentru citirea unei taste
// Configurare pentru tratarea semnalelor de întrerupere
//signal(SIGINT, handleInterrupt);
while (true) {
// Citeste datele de pe SPI
wiringPiSPIDataRW(channel, data, 2);
// Procesează datele aici
// data[0] conține primul byte, data[1] conține al doilea byte
// Modificați această parte în funcție de formatul datelor primite
// Exemplu de afișare a datelor citite
if((data[0] != 0) && (data[0]!=0))
{
//std::cout << "Date citite: " << static_cast<int>(data[0]) << " " << static_cast<int>(data[1]) << std::endl;
// Exemplu de afișare a datelor citite
printw("Date citite: %d %d\n", static_cast<int>(data[0]), static_cast<int>(data[1]));
refresh(); // Actualizează ecranul
}
// Citește o tastă de la tastatură
int ch = getch();
//std::cout << "Tasta citita: " << static_cast<int>(ch) << " " << std::endl;
// Verifică dacă tasta 'q' a fost apăsată
if (ch == 'q') {
//std::cout << "Tasta citita: " << static_cast<int>(ch) << "Întrerupere program. " << std::endl;
printw("Tasta 'q' apăsată. Întrerupere program.\n");
refresh();
break;
}
delay(100);
}
// Termină modul curses înainte de închiderea programului
endwin();
return 0;
}

Codul de test pentru ESP32

/*; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:esp32doit-devkit-v1]
platform = espressif32
board = esp32doit-devkit-v1
framework = arduino
upload_port = COM9
monitor_port = COM9
monitor_speed = 115200
lib_deps = hideakitai/ESP32DMASPI@^0.3.0
*/
#include <Arduino.h>
#include <ESP32DMASPISlave.h>
ESP32DMASPI::Slave slave;
// HallSensor Analog value is connected to GPIO 35 (Analog ADC1_CH7)
const int hallSensorPin = 35;
const int hallSensorDPin = 13;
int i = 0;
static const uint32_t BUFFER_SIZE = 8;
uint8_t *spi_slave_tx_buf;
uint8_t *spi_slave_rx_buf;
void set_buffer()
{
for (uint32_t i = 0; i < BUFFER_SIZE; i++)
{
spi_slave_tx_buf[i] = i+ 0x31;
}
//memset(spi_slave_rx_buf, 0, BUFFER_SIZE);
}
void setup()
{
Serial.begin(115200);
// to use DMA buffer, use these methods to allocate buffer
spi_slave_tx_buf = slave.allocDMABuffer(BUFFER_SIZE);
spi_slave_rx_buf = slave.allocDMABuffer(BUFFER_SIZE);
set_buffer();
delay(5000);
// slave device configuration
slave.setDataMode(SPI_MODE0);
slave.setMaxTransferSize(BUFFER_SIZE);
// begin() after setting
slave.begin(VSPI); // HSPI = CS: 15, CLK: 14, MOSI: 13, MISO: 12 -> default
// VSPI (CS: 5, CLK: 18, MOSI: 23, MISO: 19)
pinMode(hallSensorDPin, INPUT);
Serial.println("Boot finalized!");
}
void loop()
{
i=i+4;
uint8_t hallSensorDValue = digitalRead(hallSensorDPin);
uint16_t HallSensorValue = analogRead(hallSensorPin);
Serial.print("Analog Data: ");
Serial.println(HallSensorValue);
uint8_t val_hall = map(HallSensorValue, 0,4095, 0, 255);
if(i==7)
i = 0;
spi_slave_tx_buf[0] = val_hall;
spi_slave_tx_buf[1] = 0xff;
// if there is no transaction in queue, add transaction
if (slave.remained() == 0)
{
slave.queue(spi_slave_rx_buf, spi_slave_tx_buf, BUFFER_SIZE);
}
// if transaction has completed from master,
// available() returns size of results of transaction,
// and buffer is automatically updated
while (slave.available())
{
//Serial.printf("Slave received: %s\n\r", spi_slave_rx_buf);
//Serial.printf("Slave Transmitted: %s\n\r", spi_slave_tx_buf);
slave.pop();
}
delay(50);
}

Documentație proiect

Afiliere eMag

 Linkurile de la secțiunea "Componente" conțin adresa mea de afiliere la eMag.ro, iar dacă cumperi folosind aceste linkuri vei susține blogul meu. Mulțumesc! 

eMag Genius:
Hai și tu în Genius! Abonează-te la Genius 12 luni și primești beneficii premium și 20 lei card cadou eMAG. Profită acum! eMag Genius

Mulțumesc pentru atenție!

Pentru întrebări și/sau consultanță tehnică vă stau la dispoziție pe blog mai jos în secțiunea de comentarii sau pe email simedruflorin@automatic-house.ro. O zi plăcută tuturor !

  Back to top of page

Etichete

Afișați mai multe

Arhiva

Afișați mai multe