Hi All
I have just bought an OLimex and its ECG/EKG Shield. I'm trying to get some heart monitor readings captured using Serial.print. Ultimately, I wish to send them over BluetoothClassic, or Wifi, to a second Arduino where it will be written to an SD card.
[My platform is Linux-Fedora.]
I need help understanding the data structures in this program. Can you help?
My Questions are:
- Why is the range of the channel 1 only moving between about 235 and 255?
- What does the protocol type mean? Why does it change from 1 to 2?
- By printing the individual chars am I destroying the structure of my data? Does the Serial.print(...) print a true value in ascii?
Here's a sample of the serial monitor output:
338,1,252
339,1,252
340,1,250
341,1,250
342,1,252
343,1,251
344,2,0
345,1,250
346,2,2
347,1,252
348,2,0
349,1,253
350,1,254
351,1,248
352,1,253
353,1,250
354,1,254
355,1,249
356,1,253
357,1,251
358,2,0
359,1,252
360,2,0
361,1,251
362,1,255
363,1,245
364,1,252
365,1,244
366,1,245
367,1,249
368,1,249
369,1,252
370,1,248
371,1,254
372,1,249
373,1,254
374,1,250
375,2,0
376,1,252
377,1,255
378,1,254
Notes: Col1 to Col3 are are: continuous counter, protocol-type, channel1-value. Potocol-type 2 (see column 2) randomly appears and has low values. Above values from modification with tag: "// 3) Send Packet, MODIFIED: Serial.print selected fields."
Here is the source sketch:
/**********************************************************/
/* Demo program for: SHIELD-EKG/EMG + Olimexino328 */
/**********************************************************/
/**********************************************************
This [original] programme connects Olimexino328 to ElectricGuru(TM)
***********************************************************
For proper communication packet format given below have to be supported:
// 17-byte packets are transmitted from Olimexino328 at 256Hz,
// using 1 start bit, 8 data bits, 1 stop bit, no parity, 57600 bits per second.
// Minimial transmission speed is 256Hz * sizeof(Olimexino328_packet) * 10 = 43520 bps.
struct Olimexino328_packet
{
uint8_t sync0; // = 0xa5
uint8_t sync1; // = 0x5a
uint8_t version; // = 2 (packet version)
uint8_t count; // packet counter. Increases by 1 each packet.
uint16_t data[6]; // 10-bit sample (= 0 - 1023) in big endian (Motorola) format.
uint8_t switches; // State of PD5 to PD2, in bits 3 to 0.
};
*/
/**********************************************************/
#include <compat/deprecated.h>
#include <FlexiTimer2.h>
//http://www.arduino.cc/playground/Main/FlexiTimer2
// All definitions
// #define NUMCHANNELS 6
#define NUMCHANNELS 1 // EGB
#define HEADERLEN 4
#define PACKETLEN (NUMCHANNELS * 2 + HEADERLEN + 1)
#define SAMPFREQ 256 // Orig: ADC sampling rate 256
#define TIMER2VAL (1024/(SAMPFREQ)) // Set 256Hz sampling frequency
#define LED1 13
#define CAL_SIG 9
// Global constants and variables
volatile unsigned char TXBuf[PACKETLEN]; //The transmission packet
volatile unsigned char TXIndex; //Next byte to write in the transmission packet.
volatile unsigned char CurrentCh; //Current channel being sampled.
volatile unsigned char counter = 0; //Additional divider used to generate CAL_SIG
volatile unsigned int ADC_Value = 0; //ADC current value
unsigned int continuous_counter = 0; //Additional divider used to generate CAL_SIG
//~~~~~~~~~~
// Functions
//~~~~~~~~~~
/****************************************************/
/* Action: Switches-over LED1. */
/****************************************************/
void Toggle_LED1(void){
if((digitalRead(LED1))==HIGH){ digitalWrite(LED1,LOW); }
else{ digitalWrite(LED1,HIGH); }
}
/****************************************************/
/* Action: Switches-over GAL_SIG. */
/****************************************************/
void toggle_GAL_SIG(void){
if(digitalRead(CAL_SIG) == HIGH){ digitalWrite(CAL_SIG, LOW); }
else{ digitalWrite(CAL_SIG, HIGH); }
}
/****************************************************/
/* Action: Initializes all peripherals */
/****************************************************/
void setup() {
noInterrupts(); // Disable all interrupts before initialization
// LED1
pinMode(LED1, OUTPUT); //Setup LED1 direction
digitalWrite(LED1,LOW); //Setup LED1 state
pinMode(CAL_SIG, OUTPUT);
//Write packet header and footer
TXBuf[0] = 0xa5; //Sync 0
TXBuf[1] = 0x5a; //Sync 1
TXBuf[2] = 2; //Protocol version
TXBuf[3] = 0; //Packet counter
TXBuf[4] = 0x02; //CH1 High Byte
TXBuf[5] = 0x00; //CH1 Low Byte
TXBuf[6] = 0x02; //CH2 High Byte
TXBuf[7] = 0x00; //CH2 Low Byte
TXBuf[8] = 0x02; //CH3 High Byte
TXBuf[9] = 0x00; //CH3 Low Byte
TXBuf[10] = 0x02; //CH4 High Byte
TXBuf[11] = 0x00; //CH4 Low Byte
TXBuf[12] = 0x02; //CH5 High Byte
TXBuf[13] = 0x00; //CH5 Low Byte
TXBuf[14] = 0x02; //CH6 High Byte
TXBuf[15] = 0x00; //CH6 Low Byte
TXBuf[2 * NUMCHANNELS + HEADERLEN] = 0x01; // Switches state
// Timer2
// Timer2 is used to setup the analag channels sampling frequency and packet update.
// Whenever interrupt occures, the current read packet is sent to the PC
// In addition the CAL_SIG is generated as well, so Timer1 is not required in this case!
FlexiTimer2::set(TIMER2VAL, Timer2_Overflow_ISR);
FlexiTimer2::start();
// Serial Port
Serial.begin(57600); // Original
// MCU sleep mode = idle.
// outb(MCUCR,(inp(MCUCR) | (1<<SE)) & (~(1<<SM0) | ~(1<<SM1) | ~(1<<SM2)));
interrupts(); // Enable all interrupts after initialization has been completed
}
/****************************************************/
/* Function name: Timer2_Overflow_ISR */
/* Action: Determines ADC sampling frequency. */
/****************************************************/
void Timer2_Overflow_ISR() {
// Toggle LED1 with ADC sampling frequency /2
Toggle_LED1();
//Read the 6 ADC inputs and store current values in Packet
// for(CurrentCh=0;CurrentCh<6;CurrentCh++){ // Original
for( CurrentCh=0; CurrentCh<NUMCHANNELS ;CurrentCh++ ){ // EGB
ADC_Value = analogRead(CurrentCh);
TXBuf[((2*CurrentCh) + HEADERLEN)] = ((unsigned char)((ADC_Value & 0xFF00) >> 8)); // Write High Byte
TXBuf[((2*CurrentCh) + HEADERLEN + 1)] = ((unsigned char)(ADC_Value & 0x00FF)); // Write Low Byte
}
// 1) Send Packet: ORIGINAL
//for(TXIndex=0;TXIndex<17;TXIndex++){
// Serial.write(TXBuf[TXIndex]); // Orig
// if ( TXIndex < (17 - 1)) Serial.print(","); // EGB: added to separate the char prints
//}
// 2) Send Packet, MODIFIED: Serial.print with char separator
//for(TXIndex=0;TXIndex<17;TXIndex++){
// Serial.print(TXBuf[TXIndex]); // EGB: to convert Hex to Ascii
// if ( TXIndex < (17 - 1)) Serial.print(","); // EGB: added to separate the char prints
//}
//Serial.println(); // EGB: added for \n
// 3) Send Packet, MODIFIED: Serial.print selected fields
Serial.print(continuous_counter); // EGB:
Serial.print(","); // EGB:
Serial.print(TXBuf[4]); // EGB:
Serial.print(","); // EGB:
Serial.print(TXBuf[5]); // EGB:
Serial.println(); // EGB: added for \n
continuous_counter++; // increment
// Increment the packet counter
TXBuf[3]++;
// Generate the CAL_SIGnal
counter++; // increment the devider counter
if(counter == 12){ // 250/12/2 = 10.4Hz ->Toggle frequency
counter = 0;
toggle_GAL_SIG(); // Generate CAL signal with frequ ~10Hz
}
}
/****************************************************/
/* Action: Puts MCU into sleep mode. */
/****************************************************/
void loop() {
__asm__ __volatile__ ("sleep");
}
Notes: Modifications are marked with EGB, and for the serial printouts:
// 1) Send Packet: ORIGINAL
// 2) Send Packet, MODIFIED: Serial.print with char separator
// 3) Send Packet, MODIFIED: Serial.print selected fields
Re: the ElectricGuru stuff I cannot use it. I need data written to file.]
Well, I look forward to your help! Any instructions/ideas/recommendations will be welcome. I will reply to them all!
Thanks in advance
EGB