Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[General] The Design of a Heart Rate Monitor Design software problem (CCS)

Status
Not open for further replies.

Jordan M Buhagiar

Newbie level 3
Joined
Apr 25, 2015
Messages
3
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
69
Hi i am designing a heart rate monitor via photoplethysmography, the signal is derived in to port A0 of the PIC as illustrated. I am looking to display results via a 2 thresholds that was set with respect to the voltage reference towards a 10 bit ADC. This is my code, could someone identify any thing wrong with it??


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#include <16F877.h>
#device ADC=10
#use delay(crystal=8000000)
 
/* Main.c file generated by New Project wizard
*
* Created: Thu Apr 16 2015
* Processor: PIC16F877
* Compiler: CCS for PIC
*/
 
#include "LCD.c"
#include <float.h>
#include <stdlib.h>
#include <string.h>
#use RS232(baud=9600, xmit=PIN_C7, rcv=PIN_C6)
#use delay(clock = 8000000)
 
#fuses HS, NOWDT, NOPROTECT, PUT, NOBROWNOUT, NOLVP, NOWRT, NODEBUG
//A/D Control Register
#BYTE ADCON0 = 0x1F
 
#define LCD_ENABLE_PIN PIN_B3
#define LCD_RS_PIN PIN_B1
#define LCD_RW_PIN PIN_B2
#define LCD_DATA4 PIN_D4
#define LCD_DATA5 PIN_D5
#define LCD_DATA6 PIN_D6
#define LCD_DATA7 PIN_D7
 
#define Analog_In PIN_A0
#define bool int
#define BUFFER_SIZE 10
 
// define globals
const int TIMER_STOP_TIME = 15000; // pulses stop time in milliseconds
const int MOVING_AVG_SIZE = 10;
char message[BUFFER_SIZE];
int ring_buffer[BUFFER_SIZE];
int rb_start = 0;
int rb_end = 0;
const int16 PULSE_UPPER_THRESHOLD = 460;
const int16 PULSE_LOWER_THRESHOLD = 376;
int pulse_display;
int pulse_count = 0;
int ready = 0;
int heart_pulse = 0;
int timer_count = 0;
int16 timer_ms = 0;
int16 volt = 0;
 
// function prototypes
void LCD_DISP();
void read_ADC_Data();
void initialize();
int is_below_upper_threshold(int q);
int is_above_lower_threshold(int q);
void write_rb(int val);
int get_time_duration();
void reset_timer();
 
// 262 milliseconds timer interval
#int_TIMER1
void TIMER1_isr()
{ 
timer_count++;
}
 
#int_AD
void AD_isr()
{ 
delay_ms(500);
setup_adc(ADC_CLOCK_DIV_32);
setup_adc_ports(AN0_AN1_VSS_VREF);
set_adc_channel(0); 
}
 
void main()
{
initialize();
read_ADC_Data();
} 
 
// resets the timer counter for a new time duration
void reset_timer()
{
timer_count = 0;
}
 
// returns the time elapsed from last timer reset (reset_timer)
int get_time_duration()
{
return 262 * timer_count; // 262: see TIMER1_isr
} 
 
void LCD_DISP()
{
lcd_init();
Delay_ms(50);
putc(254); putc(1); delay_ms(10); //Clear Display
Delay_ms(100);
printf("Heart Rate:"); putc(heart_pulse);
}
 
void read_ADC_Data()
{ 
// pulse definition: hits first upper threshold from above it then hits
// lower threshold and then hits upper threshold again -> that is one full pulse
// hit_upperthreshold is only true if the upperthreshold is hit from above it
int hit_upperthreshold = false;
// hit_lowerthreshold can only be true if the upper threshold has first been
// hit (hit_upperthreshold = true)
int hit_lowerthreshold = false; 
int prev_value_above_upper_threshold = false;
int i;
int1 timer_started = false;
int16 adc_value;
for (i=0; i<5; i++)
{
output_high(PIN_B4); // Green LED on while no input
delay_ms(250);
output_low(PIN_B4);
}
// start reading adc values as long they are coming
while (input(Analog_In))
{
AD_isr();
adc_value = read_adc(); // Read ADC values - in built function
output_high(PIN_B5); // Yellow LED on 'Buffer'
delay_ms(2000);
 
if (is_below_upper_threshold(adc_value) == true)
{
if(prev_value_above_upper_threshold == true)
{
// we hit the upper threshold from above the upperthreshold
// so we have (start of) a new pulse
hit_upperthreshold = true;
if (pulse_count == 0)
{
reset_timer(); // saves the current time so the duration can be calculated
timer_started = true;
}
// only those adc values which are between lower_threshold and
// upper_threshold will be added to the ring buffer:
if(is_above_lower_threshold(adc_value) == true)
write_rb(adc_value); // Ring buffer receives adc value
}
prev_value_above_upper_threshold = false;
}
else // we are above the upper threshold
{
prev_value_above_upper_threshold = true;
}
if((hit_upperthreshold == true) && (is_above_lower_threshold(adc_value) == false))
{
// hit upper threshold and now lower threshold
hit_lowerthreshold = true;
}
else if((hit_lowerthreshold == true) && (is_below_upper_threshold(adc_value) == false))
{
// hit upper threshold then lower threshold and now uppert hreshold again
// so one pulse is now finished
pulse_count++;
// zero threshold-hit flags
hit_upperthreshold = false;
hit_lowerthreshold = false;
}
// Condition if timer reaches 15 seconds
if (timer_started && (get_time_duration() >= TIMER_STOP_TIME)) 
{
// Stop timer and perform heart pulse calculations
heart_pulse = pulse_count * 4; // Such calculations provides BPM
LCD_DISP();
delay_ms(1000);
output_low(PIN_B4); // Green LED off
output_low(PIN_B5); // Yellow LED off while no input
// initialize the while-loop for the next heart rate calculations:
pulse_count = 0;
timer_started = false; // wait for the next pulse to start using timer again
prev_value_above_upper_threshold = false;
// zero the threshold-hit flags
hit_upperthreshold = false;
hit_lowerthreshold = false;
}
}
}
 
/*
initialize:
Function to initialize the globals and the in built functions accrodingly
*/
void initialize()
{
// the circular buffer
int q;
for (q = 0; q < BUFFER_SIZE; q++)
{
ring_buffer[q] = 0;
}
//I/O PORTS
output_D(255); //PortD as OUTPUT 
 
// Interrupts
enable_interrupts(int_timer1);
enable_interrupts(INT_AD);
enable_interrupts(GLOBAL);
 
//Timer1
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); //262 ms overflow
 
// init display start
lcd_init();
}
 
/*
is_above_lower_threshold:
Function for threshold setup. Checks if a value is above the lower threshold.
*/
int is_above_lower_threshold(int q)
{
return ((q > PULSE_LOWER_THRESHOLD) ? true : false);
}
 
/*
is_below_upper_threshold:
Function for threshold setup. Checks if a value is below the upper threshold.
*/
int is_below_upper_threshold(int q)
{
return ((q < PULSE_UPPER_THRESHOLD) ? true : false);
}
 
/*
write_rb:
Writes val to ring buffer ring_buffer[].
*/
void write_rb(int val)
{
ring_buffer[rb_end++] = val; // Ring buffer designed to shift, therefore end value increments(shifts)
if (rb_end == BUFFER_SIZE) // If rb_end on the last location
rb_end = 0; // loop round
if (rb_end == rb_start) // if they overlap, increment the start value as well
rb_start++;
if (rb_start == BUFFER_SIZE) // If rb_start on the last location
rb_start = 0; // loop round
} Capture.PNG Capture.PNG

 
Last edited by a moderator:

It doesn't look like your code is running in an infinite loop. Shouldn't it be

while(1){
read_ADC_data();
}

inside the main function?
 

I am using some inbuilt functions from CCS such as;

Code C - [expand]
1
2
3
4
5
6
7
8
#int_AD
void AD_isr()
{ 
delay_ms(500);
setup_adc(ADC_CLOCK_DIV_32);
setup_adc_ports(AN0_AN1_VSS_VREF);
set_adc_channel(0); 
}



So i was wondering if anyone familiar with ccs built in funtions knew if there was anything missing regarding setups.

The code has been designes to be self explanatory with the variables and functions chosen for others to understand.

That code heart rate monitor does seem very interesting. Although i have time constraints and cant afford to change the logic at this point in time.

Thanks for your reply

- - - Updated - - -

Hi thanks for your reply,

It does make sense however, i dont know if that will make a difference completely.

will keep you updated soon.

kind regards
 
Last edited by a moderator:

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top