Я бы хотел, чтобы мой датчик 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