ESP32 и датчик Myoware - PullRequest
       13

ESP32 и датчик Myoware

0 голосов
/ 23 марта 2020

Я бы хотел, чтобы мой датчик Myoware и ESP32 работали вместе. У меня есть набор мышц myoware от Sparkfun, и у меня есть несколько кодов в программах Arduino и MATLAB, которые вы можете увидеть ниже.

Может кто-нибудь сказать мне, как я могу заставить ESP32 и датчик мышц myoware работать вместе, чтобы я мог измерять необработанные поверхностные EMG-сигналы, пожалуйста? Может быть, кто-нибудь мог бы объяснить мне, как настроить мои инструменты на скудной доске с изображением?

Это для MATLAB:

 clc
clear 
close all

comport = '/dev/cu.SLAB_USBtoUART'; % port to arduino
serial_port = serial(comport, 'TimeOut', 20, 'BaudRate', 115200, 'InputBufferSize', 4096);

Fs = 1500;       % Arduino data frequency
recording_time = 2;    
num_of_channels = 1;    
byte_per_channel = 2;   %  bytes per channel (int16 = 2 bytes)
samples_per_channel = 100; 

%data_length = (Fs * recording_time) + 100;
data_length = 30000;
data = NaN*ones(data_length,num_of_channels);  

try 
    fopen(serial_port)         
    port_open = 1;
    pause(1)
catch err
    disp(err.message)           
    disp(sprintf('\n See your device manager to find your own com-port\n'))
    port_open = 0;
end

if port_open                     
    H = figure(1);                  
    set(H,'windowstyle','modal')    
    key = '';                       
    disp('Data visualisation is started')  
    %t0 = clock;
    %t1 = t0;
    while (~(strcmp(key,'q') || strcmp(key,'s'))) %&& (etime(t1,t0) < recording_time)          
        data_stream = fread(serial_port,samples_per_channel*num_of_channels,'int16');   
        for i = 1:num_of_channels   
            data(:,i) = [data(samples_per_channel+1:end,i) ; data_stream(i:num_of_channels:end)];
        end
        plot(data)
        %plot(data(:,1))                             
        %hold on
        %plot(data(:,3))
        %hold off
        v = axis;
        axis([0 data_length 0 1050])
        drawnow                                 
        key = lower(get(H,'CurrentCharacter')); 
        %t1 = clock;
    end
    pause(1)
    fclose(serial_port)                 
    close(H)                            
    disp('Data visualisation is stopped')  

    if ~strcmp(key,'q') || strcmp(key,'s') 
        disp('Saving data ...')
        [file,path] = uiputfile('*.mat','Save data to location','tendon_reflex.mat');
        if file ~= 0
            full_path = strcat(path, file);
            save(full_path, 'data', 'Fs', 'num_of_channels')
            disp(['Saved to: ', full_path])
        end
    end
end

И эти 3 для Arduino. Окно номер 1 для Arduino здесь:

    #include "TimerOne.h"

#define number_of_channels 1 // Antal ADC kanaler

boolean runADC = false;
const uint8_t channels[number_of_channels] = {A0};//,A1,A2,A3,A4,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15};
uint16_t sensorValue[number_of_channels];

void TimerIsr() {
    runADC = true;
}

void setup() {
  Serial.begin(115200); // Start serial output
  Timer1.initialize(500); //Tid mellem måledata i microseconds - 1/tid = Hz 
  Timer1.attachInterrupt(TimerIsr); // initialize serial communication at 115200 bits per second:
}

void loop() {
  if (runADC) {
    runADC = false;  
    for (int i = 0; i < number_of_channels; i++) {
      sensorValue[i] = analogRead(channels[i]);   
    }
    for (int i = 0; i < number_of_channels; i++) {
        Serial.write(sensorValue[i]);
        Serial.write(sensorValue[i]>>8);
    }   
  }
}

И номер 2 для Arduino:

 #ifndef TIMERONE_cpp
#define TIMERONE_cpp

#include "TimerOne.h"

TimerOne Timer1;              // preinstatiate

ISR(TIMER1_OVF_vect)          // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  Timer1.isrCallback();
}


void TimerOne::initialize(long microseconds)
{
  TCCR1A = 0;                 // clear control register A 
  TCCR1B = _BV(WGM13);        // set mode 8: phase and frequency correct pwm, stop the timer
  setPeriod(microseconds);
}


void TimerOne::setPeriod(long microseconds)     // AR modified for atomic access
{

  long cycles = (F_CPU / 2000000) * microseconds;                                // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
  if(cycles < RESOLUTION)              clockSelectBits = _BV(CS10);              // no prescale, full xtal
  else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11);              // prescale by /8
  else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10);  // prescale by /64
  else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12);              // prescale by /256
  else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10);  // prescale by /1024
  else        cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10);  // request was out of bounds, set as maximum

  oldSREG = SREG;               
  cli();                            // Disable interrupts for 16 bit register access
  ICR1 = pwmPeriod = cycles;                                          // ICR1 is TOP in p & f correct pwm mode
  SREG = oldSREG;

  TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
  TCCR1B |= clockSelectBits;                                          // reset clock select register, and starts the clock
}

void TimerOne::setPwmDuty(char pin, int duty)
{
  unsigned long dutyCycle = pwmPeriod;

  dutyCycle *= duty;
  dutyCycle >>= 10;

  oldSREG = SREG;
  cli();
  if(pin == 1 || pin == 9)       OCR1A = dutyCycle;
  else if(pin == 2 || pin == 10) OCR1B = dutyCycle;
  SREG = oldSREG;
}

void TimerOne::pwm(char pin, int duty, long microseconds)  // expects duty cycle to be 10 bit (1024)
{
  if(microseconds > 0) setPeriod(microseconds);
  if(pin == 1 || pin == 9) {
    DDRB |= _BV(PORTB1);                                   // sets data direction register for pwm output pin
    TCCR1A |= _BV(COM1A1);                                 // activates the output pin
  }
  else if(pin == 2 || pin == 10) {
    DDRB |= _BV(PORTB2);
    TCCR1A |= _BV(COM1B1);
  }
  setPwmDuty(pin, duty);
  resume();         // Lex - make sure the clock is running.  We don't want to restart the count, in case we are starting the second WGM
                    // and the first one is in the middle of a cycle
}

void TimerOne::disablePwm(char pin)
{
  if(pin == 1 || pin == 9)       TCCR1A &= ~_BV(COM1A1);   // clear the bit that enables pwm on PB1
  else if(pin == 2 || pin == 10) TCCR1A &= ~_BV(COM1B1);   // clear the bit that enables pwm on PB2
}

void TimerOne::attachInterrupt(void (*isr)(), long microseconds)
{
  if(microseconds > 0) setPeriod(microseconds);
  isrCallback = isr;                                       // register the user's callback with the real ISR
  TIMSK1 = _BV(TOIE1);                                     // sets the timer overflow interrupt enable bit
    // might be running with interrupts disabled (eg inside an ISR), so don't touch the global state
//  sei();
  resume();                                             
}

void TimerOne::detachInterrupt()
{
  TIMSK1 &= ~_BV(TOIE1);                                   // clears the timer overflow interrupt enable bit 
                                                            // timer continues to count without calling the isr
}

void TimerOne::resume()             // AR suggested
{ 
  TCCR1B |= clockSelectBits;
}

void TimerOne::restart()        // Depricated - Public interface to start at zero - Lex 10/9/2011
{
    start();                
}

void TimerOne::start()  // AR addition, renamed by Lex to reflect it's actual role
{
  unsigned int tcnt1;

  TIMSK1 &= ~_BV(TOIE1);        // AR added 
  GTCCR |= _BV(PSRSYNC);        // AR added - reset prescaler (NB: shared with all 16 bit timers);

  oldSREG = SREG;               // AR - save status register
  cli();                        // AR - Disable interrupts
  TCNT1 = 0;                    
  SREG = oldSREG;               // AR - Restore status register
    resume();
  do {  // Nothing -- wait until timer moved on from zero - otherwise get a phantom interrupt
    oldSREG = SREG;
    cli();
    tcnt1 = TCNT1;
    SREG = oldSREG;
  } while (tcnt1==0); 

//  TIFR1 = 0xff;                   // AR - Clear interrupt flags
//  TIMSK1 = _BV(TOIE1);              // sets the timer overflow interrupt enable bit
}

void TimerOne::stop()
{
  TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));          // clears all clock selects bits
}

unsigned long TimerOne::read()      //returns the value of the timer in microseconds
{                                   //rember! phase and freq correct mode counts up to then down again
    unsigned long tmp;              // AR amended to hold more than 65536 (could be nearly double this)
    unsigned int tcnt1;             // AR added

    oldSREG= SREG;
    cli();                          
    tmp=TCNT1;                      
    SREG = oldSREG;

    char scale=0;
    switch (clockSelectBits)
    {
    case 1:// no prescalse
        scale=0;
        break;
    case 2:// x8 prescale
        scale=3;
        break;
    case 3:// x64
        scale=6;
        break;
    case 4:// x256
        scale=8;
        break;
    case 5:// x1024
        scale=10;
        break;
    }

    do {    // Nothing -- max delay here is ~1023 cycles.  AR modified
        oldSREG = SREG;
        cli();
        tcnt1 = TCNT1;
        SREG = oldSREG;
    } while (tcnt1==tmp); //if the timer has not ticked yet

    //if we are counting down add the top value to how far we have counted down
    tmp = (  (tcnt1>tmp) ? (tmp) : (long)(ICR1-tcnt1)+(long)ICR1  );        // AR amended to add casts and reuse previous TCNT1
    return ((tmp*1000L)/(F_CPU /1000L))<<scale;
}

#endif


**And number 3 for Arduino:**
    #ifndef TIMERONE_h
#define TIMERONE_h

#include <avr/io.h>
#include <avr/interrupt.h>

#define RESOLUTION 65536    // Timer1 is 16 bit

class TimerOne
{
  public:

    // properties
    unsigned int pwmPeriod;
    unsigned char clockSelectBits;
    char oldSREG;                   // To hold Status Register while ints disabled

    // methods
    void initialize(long microseconds=1000000);
    void start();
    void stop();
    void restart();
    void resume();
    unsigned long read();
    void pwm(char pin, int duty, long microseconds=-1);
    void disablePwm(char pin);
    void attachInterrupt(void (*isr)(), long microseconds=-1);
    void detachInterrupt();
    void setPeriod(long microseconds);
    void setPwmDuty(char pin, int duty);
    void (*isrCallback)();
};

extern TimerOne Timer1;
#endif
...