# Need help on Coding for storing 2 values at different intervals from counter timer.

Status
Not open for further replies.

#### Brien Cheow

##### Newbie level 6
n= First peak time taken
a=Second peak time taken
v= Difference in time between the two peaks
b=Difference in time converted to seconds
f=Calculation for beats per minute
s=Counter for every 10ms overflow from timer0.

Code:
{

for(l=0; l<127; l++)

{

if(p<h+5)
{
p=h;
}

else
{
n=s;
break;
}

}
for(l=0; l<127; l++)
{

if(p>h-1)
{
p=h;
}
else
{

break;

}
}
for(l=0; l<127; l++)
{
if(p-1<h)
{

p=h;
}

else
{
a=s;
break;
}
}
v=a-n;
b =v*0^01;
f = (1/b)*60;

for (l=0; l<127; l++)
{

if(p>h-1)
{
p=h;
}

else
{

break;
}

}

}
}
Somehow i cannot seem to get int a to copy value of s at second peak of my sin wave. Where as for n i can get it to copy value s when the peak of my sin wave reaches. The thing is that it constantly copies the s value when a peak reaches as compared to what i initially planned, that was to hold value for first peak and a will hold value of s on second peak.
Any help is greatly appreciated and thank you in advance

#### doraemon

##### Super Moderator
Staff member
Hello!

A good way to get help would to tell us what exactly you are trying to do.
Do you want to count peaks per minute for some signal? Is it really a sine wave?
- I don't understand what your loops from 0 to 127 do.
- I don't understand what you mean by b = v * 0^01;
- I don't know what your variable types are
- Your code starts in the middle of nowhere with a {. What was before, what is next?
- Your code is likely to use float numbers, which is also useless.

Beside this, you also complicate simple things. Example:

if(p > h-1) p = h ... Why not if(p > h) p = h? It's the same and easier to
understand, the -1 is useless: Here is a list of p, h and results with your method
18 20 -> h=1 = 19, p is unchanged
19 20 -> p is still unchanged
20 20 -> p is more than 20-1, so it is replaced by h, which is 20 -> p is unchanged -> useless assignment with the same value.
21 20 -> p is replaced by 20. The equivalence with "if(p > h) p = h" seems to be proved.

1. Use meaningful variable names. Example;
n= First peak time taken------> ???
a=Second peak time taken------> ???
v= Difference in time between the two peaks------> time_diff_ms
b=Difference in time converted to seconds--------> time_diff
f=Calculation for beats per minute-------> signal_bpm
s=Counter for every 10ms overflow from timer0.
2. Comment your code. This would help to understand for instance what your loops are for,
and what your b = v * 0^01; calculates.
3. Try to think first, program next, not the opposite.

Dora.

Brien Cheow

### Brien Cheow

Points: 2

#### Brien Cheow

##### Newbie level 6
Hi doraemon! Thank you so very much for replying to my post!!
I have written comments for my code shown below so that people can understand it now!!
As for the question on why (p>h-1), i did it so that there is a threshold to be reached before the calculations begin as opposed to putting (p>h).

Code:
{

for(l=0; l<127; l++)//For loop for sampling till peak is reached and after that break out of loop in else function.

{

{
}

else
{
n=s;//Int variable to store value from running overflow counter at first peak
break;//Break out of for loop and move on to next for loop
}

}
for(l=0; l<127; l++)//For Loop to sample till bottom of sin wave is reached.
{

{
p=h;
}
else
{

break;//Break out of for loop

}
}
for(l=0; l<127; l++)//For loop for continues sampling until peak is reached
{
if(p-1<h)//Same as previous peak detection loop.T his time i am storing the counter value in another int variable to calculate time elapsed between two peaks.
{

p=h;
}

else
{
a=s;
break;
}
}
v=a-n;//Time between two peaks of sin wave
b =v*0^01;//My counter s shows number of overflows my timer0 has, and for a single overflow it takes timer0 10ms, therefore i am converting the time to seconds as opposed to ms.
f = (1/b)*60; //1/T*60 for calculation of beats per minute.

for (l=0; l<127; l++)//This for loop is to bring Old ADC0 value back to bottom of sin wave before the whole process can be repeated.
{

if(p>h-1)
{
p=h;
}

else
{

break;
}

}

}
}

#### doraemon

##### Super Moderator
Staff member
Hello!

As for the question on why (p>h-1), i did it so that there is a threshold to be reached before the calculations begin
as opposed to putting (p>h).

I have just demonstrated above that:
Code:
if(p > h -1) {
p = h;
}
is equivalent to:
Code:
if(p > h) {
p = h;
}
Therfore thers is no opposition between f(p > h -1) p = h and if(p > h) p = h. It's the same!!! Read my example again.

Now you should consider replying to my first question: what are you trying to do?
The reply should not be "Coding for storing 2 values at different intervals from counter time" but more something like
"Try to measure the time difference between 2 peaks". Note that I'm not sure of this, it's an example.

Beside this, you have added comments, which is good, but most of them are almost useless.
Example:
Code:
if(p<h+5)//if old ADC0 value<Current ADC0 value+5

I know what "if(p<h+5)" means, so the comment is useless. The problem is: why are you doing this test? Why
ADC0 value + 5 and not ADC0 value + 69 or -45? Where does this +5 come from? That should be explained in
your comments. Comments' purpose is not to translate C into english, but to explain what you do.

It's not mandatory to have one comment per line. The best is to find an explanation that explains what you do
in plain english.

And while I'm writing this, here is another advice: Never use hard-coded constants.

Code:
if(p<h+5)

If this 5 has a well-defined meaning (for example some kind of hysteresis), then define a constant

Code:
#define   SIG_HYS  5
if(p < h + SIG_HYS) {

And to make it clear: don't use variables like p, v, n. If you read your code in 3 months from now, you will not even
understand it yourself. And don't use l as a variable because it can be confused with I (capital i) or even with 1.
And don't use capital I either.

Dora

#### Brien Cheow

##### Newbie level 6
Hello!

I have just demonstrated above that:
Code:
if(p > h -1) {
p = h;
}
is equivalent to:
Code:
if(p > h) {
p = h;
}
Therfore thers is no opposition between f(p > h -1) p = h and if(p > h) p = h. It's the same!!! Read my example again.

Now you should consider replying to my first question: what are you trying to do?
The reply should not be "Coding for storing 2 values at different intervals from counter time" but more something like
"Try to measure the time difference between 2 peaks". Note that I'm not sure of this, it's an example.

Beside this, you have added comments, which is good, but most of them are almost useless.
Example:
Code:
if(p<h+5)//if old ADC0 value<Current ADC0 value+5

I know what "if(p<h+5)" means, so the comment is useless. The problem is: why are you doing this test? Why
ADC0 value + 5 and not ADC0 value + 69 or -45? Where does this +5 come from? That should be explained in
your comments. Comments' purpose is not to translate C into english, but to explain what you do.

It's not mandatory to have one comment per line. The best is to find an explanation that explains what you do
in plain english.

And while I'm writing this, here is another advice: Never use hard-coded constants.

Code:
if(p<h+5)

If this 5 has a well-defined meaning (for example some kind of hysteresis), then define a constant

Code:
#define   SIG_HYS  5
if(p < h + SIG_HYS) {

And to make it clear: don't use variables like p, v, n. If you read your code in 3 months from now, you will not even
understand it yourself. And don't use l as a variable because it can be confused with I (capital i) or even with 1.
And don't use capital I either.

Dora
Hi Dora!
the purpose for
Code:
(p<h+5)
is basically because i do not want the sampling to jump to else and break out of the for loop when there is no signal therefore the +5 or -1. As for the Value why it is +5 or -1 is because i found it to be most effective to removing any other interference during the sampling stage such as peaks that normal pulse signals will encounter before/after hitting the true peak(e.g Dicrotic notch) in a PPG signal. Also Trying to measure the time difference between 2 peaks could be a btr header lol but i feel that its too much to ask from the community hee therefore i would rather work out most of the things myself and ask for help only when i narrow down towards the main problem in my coding

#### doraemon

##### Super Moderator
Staff member
Hello!

The problem is that if you don't give the overall picture, then nobody is going to understand the process
of your code. Detecting the interval between peaks is easy.

As for the Value why it is +5 or -1

Again, your -1 has NO EFFECT!!!

because i found it to be most effective to removing any other interference

What do you call interference? Is it noise of your input signal?
As you use the word "dicrotic", I guess you are trying to develop a heart pulse counter. In this case, why not
asking how to measure the time between two peaks of an ECG? It would be clear to everybody, and
certainly more than "storing 2 values at different intervals from counter time". By the way I still don't understand
what these 2 values are.
Then you show your code, what you have already done, and it would be easier to help.

Beside this, there are still plenty of obscure operations in your code. I don't understand the meaning of the
l loops (0 ~ 126) because all what's inside does not depend on l.

I think it should be like this: (in pseudo code)
Code:
Loop {
Get sample;
Calculate variation since last sample;
If variation was positive AND is now negative AND greater than a preset theshold {
Store current time
Calculate difference with previous time, calculate bps, display result, etc
Update previous time stamp for next time
}
}

It's possible to add some filtering, etc. By the way, for reliable peak detection and RRI measurement, you
should work at 500 or 1000 Hz. But it depends how your signal is detected (electrodes? optical?...)

Dora.

#### Brien Cheow

##### Newbie level 6
Hi Dora my full code is here.
I am using an optical sensor to detect BVP
I have implemented hardware filters to cancel out noise but interference in this case is false peak caused by a unstable amplitude of the signal which means most probably the person moved.
As for better header i mean that your suggestion to change the post title.
Thanks for all your help so far
Code:
/*
Graphic LCD 64 by 128 pixels, Monochrome
SP5-GFX1
Connection to P2 of 8051  : Silicon Lab C8051F340
#1 GND
#2 +5V
#3 SI  serial data -- P2.7
#4 SCL serial clock -- P2.6
#5 A0P  0 = select control, 1 = data port --- P2.5
#6 RESET low to reset LCD panel -- P2.4
#7 CS1    chip select, 0 = enable data transfer -- P2.3
#8 BL-  Back light - GND
#9 BL+  Back light - +5V

Page memory for display : B0 to B7, eight pages, one page 128 bytes
each byte for 8 rows x 1 column, bit 0 at row 0, bit 1 at row 1 etc.

last edited : 15 Jan 2015.
Version 1.0
*/
//#include <reg51.h>
#include <c8051f340.h>                 // SFR declarations
#include "stdio.h"

//-----------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------

#define SYSCLK      12000000           // SYSCLK frequency in Hz

sfr16 TMR2RL   = 0xca;                 // Timer2 reload value
sfr16 TMR2     = 0xcc;                 // Timer2 counter

/*
sbit LCD_SI = P2^1;
sbit LCD_SCL = P2^2;
sbit LCD_A0P = P2^3;
sbit LCD_RESET = P2^4;
sbit LCD_CS1 = P2^5;
*/

sbit LCD_SI = P2^7;
sbit LCD_SCL = P2^6;
sbit LCD_A0P = P2^5;
sbit LCD_RESET = P2^4;
sbit LCD_CS1 = P2^3;

int i,j,k,m,s,p,n,l,a,v,b,f,h,x;
char fp[6];
char sp[6];
p = 0;
s = 0;
a = 0;
v = 0;
b=0;
n=0;
f=0;
x=1;

// 5 columns by 8 rows ASCII font, starting from SPACE, 0x20
code unsigned char font[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x00,0x00,   //  !
0x00,0x03,0x00,0x03,0x00,0x14,0x7f,0x14,0x7f,0x14,   // "#
0x24,0x2a,0x7f,0x2a,0x12,0x23,0x13,0x08,0x64,0x62,   // \$%
0x36,0x49,0x55,0x22,0x50,0x00,0x05,0x03,0x00,0x00,   // &'
0x00,0x1c,0x22,0x41,0x00,0x00,0x41,0x22,0x1c,0x00,   // ()
0x14,0x08,0x3e,0x08,0x14,0x08,0x08,0x3e,0x08,0x08,   // *+
0x00,0x50,0x30,0x00,0x00,0x08,0x08,0x08,0x08,0x08,   // ,-
0x00,0x60,0x60,0x00,0x00,0x20,0x10,0x08,0x04,0x02,   // ./
0x3e,0x51,0x49,0x45,0x3e,0x00,0x42,0x7f,0x40,0x00,   // 01
0x42,0x61,0x51,0x49,0x46,0x21,0x41,0x45,0x4b,0x31,   // 23
0x18,0x14,0x12,0x7f,0x10,0x27,0x45,0x45,0x45,0x39,   // 45
0x3c,0x4a,0x49,0x49,0x30,0x01,0x71,0x09,0x05,0x03,   // 67
0x36,0x49,0x49,0x49,0x36,0x06,0x49,0x49,0x29,0x1e,   // 89
0x00,0x36,0x36,0x00,0x00,0x00,0x56,0x36,0x00,0x00,   // :;
0x08,0x14,0x22,0x41,0x00,0x14,0x14,0x14,0x14,0x14,   // <=
0x00,0x41,0x22,0x14,0x08,0x02,0x01,0x51,0x09,0x06,   // >?
0x32,0x49,0x79,0x41,0x3e,0x7e,0x11,0x11,0x11,0x7e,   // @A
0x7f,0x49,0x49,0x49,0x36,0x3e,0x41,0x41,0x41,0x22,   // BC
0x7f,0x41,0x41,0x22,0x1c,0x7f,0x49,0x49,0x49,0x41,   // DE
0x7f,0x09,0x09,0x09,0x01,0x3e,0x41,0x49,0x49,0x7a,   // FG
0x7f,0x08,0x08,0x08,0x7f,0x00,0x41,0x7f,0x41,0x00,   // HI
0x20,0x40,0x41,0x3f,0x01,0x7f,0x08,0x14,0x22,0x41,   // JK
0x7f,0x40,0x40,0x40,0x40,0x7f,0x02,0x0c,0x02,0x7f,   // LM
0x7f,0x04,0x08,0x10,0x7f,0x3e,0x41,0x41,0x41,0x3e,   // NO
0x7f,0x09,0x09,0x09,0x06,0x3e,0x41,0x51,0x21,0x5e,   // PQ
0x7f,0x09,0x19,0x29,0x46,0x46,0x49,0x49,0x49,0x31,   // RS
0x01,0x01,0x7f,0x01,0x01,0x3f,0x40,0x40,0x40,0x3f,   // TU
0x1f,0x20,0x40,0x20,0x1f,0x3f,0x40,0x38,0x40,0x3f,   // VW
0x63,0x14,0x08,0x14,0x63,0x07,0x08,0x70,0x08,0x07,   // XY
0x61,0x51,0x49,0x45,0x43,0x00,0x7f,0x41,0x41,0x00,   // Z[
0x02,0x04,0x08,0x10,0x20,0x00,0x41,0x41,0x7f,0x00,   // \]
0x04,0x02,0x01,0x02,0x04,0x40,0x40,0x40,0x40,0x40,   // ^_
0x00,0x01,0x02,0x04,0x00,0x20,0x54,0x54,0x54,0x78,   // a
0x7f,0x48,0x44,0x44,0x38,0x38,0x44,0x44,0x44,0x20,   // bc
0x38,0x44,0x44,0x48,0x7f,0x38,0x54,0x54,0x54,0x18,   // de
0x08,0x7e,0x09,0x01,0x02,0x0c,0x52,0x52,0x52,0x3e,   // fg
0x7f,0x08,0x04,0x04,0x78,0x00,0x44,0x7d,0x40,0x00,   // hi
0x20,0x40,0x44,0x3d,0x00,0x7f,0x10,0x28,0x44,0x00,   // jk
0x00,0x41,0x7f,0x40,0x00,0x7c,0x04,0x18,0x04,0x78,   // lm
0x7c,0x08,0x04,0x04,0x78,0x38,0x44,0x44,0x44,0x38,   // no
0x7c,0x14,0x14,0x14,0x08,0x08,0x14,0x14,0x18,0x7c,   // pq
0x7c,0x08,0x04,0x04,0x08,0x48,0x54,0x54,0x54,0x20,   // rs
0x04,0x3f,0x44,0x40,0x20,0x3c,0x40,0x40,0x20,0x7c,   // tu
0x1c,0x20,0x40,0x20,0x1c,0x3c,0x40,0x30,0x40,0x3c,   // vw
0x44,0x28,0x10,0x28,0x44,0x0c,0x50,0x50,0x50,0x3c,   // xy
0x44,0x64,0x54,0x4c,0x44,0x00,0x08,0x36,0x41,0x00,   // z{
0x00,0x00,0x7f,0x00,0x00,0x00,0x41,0x36,0x08,0x00,   // |}
0x10,0x08,0x08,0x10,0x08,0x00,0x00,0x02,0x05,0x02 }; // ^degree

//-----------------------------------------------------------------------------
// Function PROTOTYPES
//-----------------------------------------------------------------------------

void delay(int d);               // delay by d ms
void delaya(void);               // a short delay
void SYSCLK_Init (void);       // set CPU clock
void PORT_Init (void);           // init CPU ports
void LCD_reset(void);           // reset LCD
void LCD_command(unsigned char);        // Send command code to LCD
void LCD_data(unsigned char);        // ASCII character to be displayed on LCD
void SPI_send(unsigned char);        // shift 8 bit data to LCD interface, high bit first
void write_char(unsigned char);        // display an ASPI intSCII code at current position
void write_msg_xy(unsigned char, unsigned char, unsigned char*); // write strting at x col, y row
void set_xy(unsigned char x, unsigned char y);    // set cursor position
void plot_xy(unsigned char x, unsigned char y);

//-----------------------------------------------------------------------------

//void timer0_interrupt(void) interrupt 1 using 1   //auto reload every 50us
//{

//}

void LCD_Clear_Display()
{
for(k=0; k<8; k++)        // clear display
{
LCD_command(0xB0 + k); delay(20);
LCD_command(0x10);    //high nibble of column address
LCD_command(0x00);    // low 4 bits of column address
for(i=0; i<128; i++)
{
LCD_data(0x00);
}
}
}

void delay(int d)  // delay for d ms
{
int i, j;
for(i=0; i<d; i++)
for(j=0; j<1179; j++);
}

void delaya()      //a short delay
{
char j;
for(j=0; j<1; j++);
}
void timer0_interrupt_init()
{
TMOD = 0x01;
//  TR0 = 0;
//TL0 = 0xEF;
//TH0 = 0xD8;
TR0 = 1;
EA = 1;
ET0 = 1;

//  while(TF0==0);

//TF0 = 0;

}

void timer0 (void) interrupt 1
{

s++;
// sp = &s;
TL0 = 0xEF; //lower bit
TH0 = 0xD8; //higher bit
TF0 = 0;

}

void main (void)
{
PCA0MD &= ~0x40;                    // WDTE = 0 (clear watchdog timer
// enable)
PORT_Init();                        // Initialize Port I/O
SYSCLK_Init ();                     // Initialize Oscillator

// conversion triggered on TMR2 overflow
REF0CN = 0x03;                       //Internal voltage reference for ADC
AMX0P = 0x00;                       //   0x05=P2^6.. 0x13 ADC0 positive input = P1.1
AMX0N = 0x1F;                       // ADC0 negative input = GND
// i.e., single ended mode
ADC0CF = ((SYSCLK/3000000)-1)<<3;   // set SAR clock to 3MHz
ADC0CF |= 0x00;                     // right-justify results

// SFRPAGE = TIMER01_PAGE;             // Set SFR page

/*
TH0 = -151;    // -149;                           // Init Timer0 High register
TL0 = TH0;                          // Set the intial Timer0 value
ET0=1;                              // Timer0 interrupt enabled
TCON = 0x10;                        // Timer0 ON
// TMOD = 0x02;                        // Timer0 in 8-bit reload mode
EA = 1;       // allows interrupt
*/
//delay(200);

// initialize graphic LCD, set 8x8 fonts and graphic, OR mode for text and graphic
LCD_reset();
LCD_command(0xA2);       // LCD bias, 1/9 bias
LCD_command(0xA0);       // set normal display mode
LCD_command(0xC8);       // set output mode
LCD_command(0x23);       // set voltage regulator internal resistor
LCD_command(0x81);       // electronic voltage double - two byte instruction
LCD_command(0x1D);       // 6 bits, 0 to 0x2F, increase contrast
LCD_command(0x2B);       // set power control circuit
LCD_command(0x40);       // set start line = 0
LCD_command(0xAF);       // setdisplay on
LCD_command(0x10);     // lower 4 bits for high nibble of column address, 0 to 127
LCD_command(0x00);       // lower 4 bits for low nibble of column address
LCD_command(0xB0);     // set page address, B0 to B7 for 8 pages
LCD_Clear_Display();    //clear LCD screen

write_msg_xy(0, 0, "BVP(C)2015 NYP/BEMG 70BPM");

delay(30);

// enable timer interrupts
//    ET0=1;
//    TMOD=0x21;
//    TR0=1;
//    EA=1;

while(1)
{
timer0_interrupt_init();//initialise timer0 mode1

for(k=0; k<127; k++)
{

m= 63 - (ADC0>>4);      //take high 6 bits from the 10-bit adc
plot_xy(k, m);
plot_xy(k, m-1);    // add two more dots for thicker lines
plot_xy(k, m+1);
delay(30);

/*
if ((k & 0x1F) == 0 )          //draw straight lines
{
for(j=0; j<4; j++)
{
set_xy(k,4+j);
LCD_data(0xFF);
}
}
*/

{

//  for(l=0; l<50; l++)
while(1)

{
SPI_send;
LCD_reset;
LCD_command;
LCD_data;
write_msg_xy;
plot_xy;
set_xy;
if(p<h+4)    p=h;
else
{
n=s;
break;
}

}

//for(l=0; l<50; l++)
while(1)
{
SPI_send;
LCD_reset;
LCD_command;
LCD_data;
write_msg_xy;
plot_xy;
set_xy;
if(p+1>h)    p=h;
else    break;

}

//for(l=0; l<50; l++)
while(1)
{
SPI_send;
LCD_reset;
LCD_command;
LCD_data;
write_msg_xy;
plot_xy;
set_xy;
if(p<h+4)  p=h;
else
{
a=s;
break;
}

}
v = a-n;
b = v/100;
f = 60/b;

//for(l=0; l<50; l++)
while(1)
{
SPI_send;
LCD_reset;
LCD_command;
LCD_data;
write_msg_xy;
plot_xy;
set_xy;
if(p+1>h)
{
p=h;
}

else
{

break;
}

}

}

//delay(30);
}    LCD_Clear_Display();
//sprintf(sp,"%4D",b);
//write_msg_xy(100, 55, sp);

} // end while(1)
} // end main

// configure I/O ports
void PORT_Init (void)
{
/*
P1SKIP=0x20;
P1MDOUT = 0x0F;
P2MDOUT = 0x3F;
//  P3MDOUT = 0xFF;             // for ULN2803 drivers
//  P4MDOUT = 0xFF;
//  P0MDOUT = 0xFF;             // for LTC1298, LCD interfaces
P2MDIN &= 0x0BF;        // P2.6 as ADC0

P0MDOUT |= 0x10;        // Enable UTX as push-pull output
XBR0     = 0x01;        // Enable UART on P0.4(TX) and P0.5(RX)
XBR1     = 0x40;        //0x40; Enable crossbar and weak pull-ups
//    P2 = 0xFF;
//    P3 = 0xFF;
//    P4 = 0xFF;
*/

P1MDOUT = 0x00;            // enable P1 outputs
P2MDOUT = 0xFE;
P3MDOUT = 0xFF;             // for ULN2803 drivers
P4MDOUT = 0xFF;
P0MDOUT = 0xFF;             // for LTC1298, LCD interfaces

//    P0MDOUT |= 0x10;        // Enable UTX as push-pull output
//       XBR0     = 0x01;        // Enable UART on P0.4(TX) and P0.5(RX)
XBR1     = 0x40;        //0x40; Enable crossbar and weak pull-ups
P2 = 0xFF;
P3 = 0xFF;
P4 = 0xFF;
}

//-----------------------------------------------------------------------------
// initializes the system clock to use the internal oscillator
void SYSCLK_Init (void)
{
OSCICN |= 0x03;                     // Configure internal oscillator
RSTSRC  = 0x04;                     // Enable missing clock detector
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// LCD routnies
// send one byte to SPI interface
void SPI_send(unsigned char dd)
{
unsigned char i;
LCD_CS1=0;
for(i=0; i<8; i++)
{
LCD_SCL=0;          // set clock pulse low first
if( dd  & 0x80 )     // set data bit
LCD_SI=1;
else
LCD_SI=0;
LCD_SCL=1;        // clock high
dd = dd <<= 1;   // shifted to next bit
}
LCD_CS1=1;
delaya();
}

void LCD_reset()
{
LCD_RESET = 0;
delay(10);
LCD_RESET = 1;
delay(10);
}

void LCD_command(unsigned char ch) {    //send a command byte to LCD
LCD_A0P = 0;
SPI_send(ch);
delaya();
}

void LCD_data(unsigned char ch) {    //send a data byte to LCD data port
LCD_A0P = 1;
SPI_send(ch);
}

// print an ASCII code on LCD at current text position
void write_char(unsigned char ch)
{
unsigned char * fontptr, k;
fontptr = font + (ch-0x20) * 5;          // get the font pattern, 8 by 5
for(k=0; k<5; k++)
LCD_data( *fontptr++);
}

// display a message at column x, row y
void write_msg_xy(unsigned char x, unsigned char y, unsigned char *chptr)
{
char * ptr;
ptr = chptr;
set_xy(x, y);
while(*ptr)
write_char(*ptr++);

}

void plot_xy(unsigned char x, unsigned char y)  // draw a dot at position x, y, x: 0 to 127, y:0 to 63
{
char ypage, dd=1;
ypage = y >>3;
set_xy(x, ypage);
ypage = y & 0x7; //low 3 bits for dot position
dd = dd << ypage;
LCD_data(dd);
sprintf(fp,"%4D",n);
write_msg_xy(100, 55, sp);

sprintf (sp,"%4D",a);
write_msg_xy(100, 65,fp);

}

// set LCD display position
void set_xy(unsigned char x, unsigned char y)
{
LCD_command(0x10 | ( x>> 4) & 0x07  );    // lower 4 bits for high nibble of column address, 0 to 127
LCD_command(0x00 | x & 0x0F);    // lower 4 bits for low nibble of column address
LCD_command(0xB0 | y & 0x07);  // set page address, B0 to B7 for 8 pages
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

#### doraemon

##### Super Moderator
Staff member
Hello!

Apparently you don't want to listen (or read) what I'm telling you. I suggested some ways to make
the code easier to read and to improve it.
- You still use hardcoded constants
- You still use one-letter variables (int i,j,k,m,s,p,n,l,a,v,b,f,h,x; ) which makes your code unreadable
- I also proved that your "if(p+1>h) p=h;" is the same as if(p > h) p = h,
but you still write "if(p+1>h) p=h;", so I guess all the efforts to help you will be in vain.
I stongly encourage that you write your code yourself. At least I will not dig in it.

Now a possible cause of error:
v = a-n;
b = v/100;
f = 60/b;
All are integers.
If I suppose that f is a frequency in beats per minute, and if I also suppose the b cannot be 0 (therefore
v is necessarily greater than or equal to 100.
Possible valies for b: 1, 2, 3, etc...
Therefore possible values for f:
60, 30, 20, etc...
You will never be able to detect a pulse rate of, say, 50 bps.It will be either 60 or 30. And you will never
detect more than 60 bps.

Dora.

#### Brien Cheow

##### Newbie level 6
Hi Dora i am sorry if i angered you but i am really new to coding. Btw the bulk of the code was written by my lecturer and i was suppose to implement the peak detection algorithm and calculate the heartbeat rate from there.And btw i was the one who wrote the logic. i have a few questions. first off what is hardcoded constants. and also the part where you said that it is either 30 or 60 BPM is true.. but i dont understand what you are trying to explain.

Last edited by a moderator:

#### doraemon

##### Super Moderator
Staff member
Hello!

I'm not angry, I was just suggesting that you should make efforts to write code which is self
explanatory, and also take into account what people reply.
That said, this is a forum. Therefore I prefer not to reply by mail, but reply on the forum so that
everybody can benefit from what has been said.
As for what I was trying to explain:

1. You have these variables, all integers:
int i,j,k,m,s,p,n,l,a,v,b,f,h,x;
Now you use these variables like this:
Code:
    v = a-n;        //  The result is an integer, no surprise
b = v/100;    //  Here comes the surprise: the result is also an integer
f = 60/b;       //  Second surprise, f is also an integer`

I didn't read all the code, but from what I guess: v is a time expressed in 1/100 seconds, right?
Now you calculate this time in second, so that's why you divide by 100. You can consider that b is the period, and 1/b the
frequency.
Next, you calculate the frequency not in Hz, but in bpm, that's why you multiply the frequency (1/b) by 60.

Now let's examine what happens:
I suppose that you know that if you use only integers, dividing for example 3 by 2 gives you 1. Not 1.5 because you
are using integers.

Let's say that in the above code, v is 115.
If you divide v by 100, you will get b = 1. Not 1.15.
Now if you calculate 60 / b, you will get 60 and not the 60/1.15 = 52 that you could expect.
I suppose you agree that for any value of v in the [100, 200[ interval (the [ is not a typo, it means that 200 is not included)
you will get a b of 1, then a f of 60.
Now what happens for 200 and for any value in the [200, 300[ interval?
v/100 will be 2 and 60 / b will be 30. No intermediate value.
If you continue with the subsequent values, you will get a f of 30 for any value of v in [300, 400[, etc.

In order to solve this, you have 2 methods. One idiotic method, and one smart method.
The idiotic method consists in using float numbers. Therefore in my above example, b would become 1.15 and
f would become 60.

The smart method consists in staying in the integer domain, but thinking about what you do.

If you do: b = v/100 and f = 60 / b, then f = 60 / (v/100)
In other words, if you revert the last (v/100) and put it at the numerator, you will have 60 * 100 / v or f = 6000 / v
This time, if you get, like in the above example, a v of 115, then your final f will be 6000/115 = 52

Dora.

Status
Not open for further replies.