📄 oximeter_ext_probe_1.c
字号:
//*****************************************************************************
// THIS PROGRAM IS PROVIDED "AS IS". TI MAKES NO WARRANTIES OR
// REPRESENTATIONS, EITHER EXPRESS, IMPLIED OR STATUTORY,
// INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR
// COMPLETENESS OF RESPONSES, RESULTS AND LACK OF NEGLIGENCE.
// TI DISCLAIMS ANY WARRANTY OF TITLE, QUIET ENJOYMENT, QUIET
// POSSESSION, AND NON-INFRINGEMENT OF ANY THIRD PARTY
// INTELLECTUAL PROPERTY RIGHTS WITH REGARD TO THE PROGRAM OR
// YOUR USE OF THE PROGRAM.
//
// IN NO EVENT SHALL TI BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
// CONSEQUENTIAL OR INDIRECT DAMAGES, HOWEVER CAUSED, ON ANY
// THEORY OF LIABILITY AND WHETHER OR NOT TI HAS BEEN ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGES, ARISING IN ANY WAY OUT
// OF THIS AGREEMENT, THE PROGRAM, OR YOUR USE OF THE PROGRAM.
// EXCLUDED DAMAGES INCLUDE, BUT ARE NOT LIMITED TO, COST OF
// REMOVAL OR REINSTALLATION, COMPUTER TIME, LABOR COSTS, LOSS
// OF GOODWILL, LOSS OF PROFITS, LOSS OF SAVINGS, OR LOSS OF
// USE OR INTERRUPTION OF BUSINESS. IN NO EVENT WILL TI'S
// AGGREGATE LIABILITY UNDER THIS AGREEMENT OR ARISING OUT OF
// YOUR USE OF THE PROGRAM EXCEED FIVE HUNDRED DOLLARS
// (U.S.$500).
//
// Unless otherwise stated, the Program written and copyrighted
// by Texas Instruments is distributed as "freeware". You may,
// only under TI's copyright in the Program, use and modify the
// Program without any charge or restriction. You may
// distribute to third parties, provided that you transfer a
// copy of this license to the third party and the third party
// agrees to these terms by its first use of the Program. You
// must reproduce the copyright notice and any other legend of
// ownership on each copy or partial copy, of the Program.
//
// You acknowledge and agree that the Program contains
// copyrighted material, trade secrets and other TI proprietary
// information and is protected by copyright laws,
// international copyright treaties, and trade secret laws, as
// well as other intellectual property laws. To protect TI's
// rights in the Program, you agree not to decompile, reverse
// engineer, disassemble or otherwise translate any object code
// versions of the Program to a human-readable form. You agree
// that in no event will you alter, remove or destroy any
// copyright notice included in the Program. TI reserves all
// rights not specifically granted under this license. Except
// as specifically provided herein, nothing in this agreement
// shall be construed as conferring by implication, estoppel,
// or otherwise, upon you, any license or other right under any
// TI patents, copyrights or trade secrets.
//
// You may not use the Program in non-TI devices.
//*****************************************************************************
//*****************************************************************************
// MSP430FG437 based pulse oximeter demonstration
// V. Chan and S. Underwood
// Texas Instruments Hong Kong Ltd.
// May 2005
//*****************************************************************************
#include <msp430xG43x.h>
#include "stdint.h"
#define seg_a 0x01
#define seg_b 0x02
#define seg_c 0x10
#define seg_d 0x04
#define seg_e 0x80
#define seg_f 0x20
#define seg_g 0x08
#define seg_h 0x40
#define NUM_0 (seg_a | seg_b | seg_c | seg_d | seg_e | seg_f)
#define NUM_1 (seg_b | seg_c)
#define NUM_2 (seg_a | seg_b | seg_d | seg_e | seg_g)
#define NUM_3 (seg_a | seg_b | seg_c | seg_d | seg_g)
#define NUM_4 (seg_b | seg_c | seg_f | seg_g)
#define NUM_5 (seg_a | seg_c | seg_d | seg_f | seg_g)
#define NUM_6 (seg_a | seg_c | seg_d | seg_e | seg_f | seg_g)
#define NUM_7 (seg_a | seg_b | seg_c)
#define NUM_8 (seg_a | seg_b | seg_c | seg_d | seg_e | seg_f | seg_g)
#define NUM_9 (seg_a | seg_b | seg_c | seg_d | seg_f | seg_g)
#define NUM_A (seg_a | seg_b | seg_c | seg_e | seg_f | seg_g)
#define NUM_B (seg_c | seg_d | seg_e | seg_f | seg_g)
#define NUM_C (seg_a | seg_d | seg_e | seg_f)
#define NUM_D (seg_b | seg_c | seg_d | seg_e | seg_g)
#define NUM_E (seg_a | seg_d | seg_e | seg_f | seg_g)
#define NUM_F (seg_a | seg_e | seg_f | seg_g)
const unsigned char hex_table[] =
{
NUM_0,NUM_1,NUM_2,NUM_3,NUM_4,NUM_5,NUM_6,NUM_7,
NUM_8,NUM_9,NUM_A,NUM_B,NUM_C,NUM_D,NUM_E,NUM_F
};
int32_t mul16(register int16_t x, register int16_t y);
//FIR filter coefficient for
//removing 50/60Hz and 100/120Hz
//from the signals
#if 0
static const int16_t coeffs[9] =
{
5225,
5175,
7255,
9453,
11595,
13507,
15016,
15983,
16315
};
#else
static const int16_t coeffs[12] =
{
688,
1283,
2316,
3709,
5439,
7431,
9561,
11666,
13563,
15074,
16047,
16384
};
#endif
//#define FIRST_STAGE_TARGET_HIGH 3900
//#define FIRST_STAGE_TARGET_LOW 3600
//#define FIRST_STAGE_TARGET_HIGH_FINE 4096
//#define FIRST_STAGE_TARGET_LOW_FINE 3500
#define FIRST_STAGE_TARGET_HIGH 3500
#define FIRST_STAGE_TARGET_LOW 3000
#define FIRST_STAGE_TARGET_HIGH_FINE 4096
#define FIRST_STAGE_TARGET_LOW_FINE 2500
#define FIRST_STAGE_STEP 5
#define FIRST_STAGE_FINE_STEP 1
enum scope_type_e
{
SCOPE_TYPE_OFF = 0,
SCOPE_TYPE_HEART_SIGNALS,
SCOPE_TYPE_RAW_SIGNALS,
SCOPE_TYPE_LED_DRIVE,
};
int scope_type = SCOPE_TYPE_HEART_SIGNALS;
int ir_dc_offset = 2000;
int vs_dc_offset = 2000;
int ir_LED_level;
int vs_LED_level;
int ir_heart_signal;
int vs_heart_signal;
int ir_heart_ac_signal;
int vs_heart_ac_signal;
int ir_sample;
int vs_sample;
unsigned int rms_ir_heart_ac_signal;
unsigned int rms_vs_heart_ac_signal;
unsigned int sample_count_ir = 0;
unsigned int sample_count_vs = 0;
int32_t ir_dc_register = 0;
int32_t vs_dc_register = 0;
int32_t ir_2nd_dc_register = 0;
int32_t vs_2nd_dc_register = 0;
unsigned long log_sq_ir_heart_ac_signal;
unsigned long log_sq_vs_heart_ac_signal;
unsigned long sq_ir_heart_ac_signal;
unsigned long sq_vs_heart_ac_signal;
unsigned int pos_edge = 0;
unsigned int edge_debounce;
unsigned int heart_beat_counter;
unsigned int log_heart_signal_sample_counter;
unsigned int heart_signal_sample_counter;
unsigned int led_on_always;
int32_t ir_pi_last_y = 0;
int32_t ir_pi_last_x = 0;
int32_t vs_pi_last_y = 0;
int32_t vs_pi_last_x = 0;
/* The results */
unsigned int heart_rate;
unsigned int SaO2;
/* Function prototypes */
unsigned long isqrt32(register unsigned long h);
int16_t dc_estimator(register int32_t *p, register int16_t x);
int16_t ir_filter(int16_t sample);
int16_t vs_filter(int16_t sample);
void set_LCD(void);
void display_word(unsigned int);
void display_number(int value, int start, int width);
void display_pulse(int on);
void display_correcting(int x, int on);
void main(void)
{
double f1;
unsigned int i;
int32_t x;
int32_t y;
WDTCTL = WDTPW | WDTHOLD;
//Allow a little time for things
//like the 32kHz oscillator to
//settle
for (i = 0; i < 0xFFFF; i++)
//dummy loop */;
#if 0
SVSCTL |= (SVSON | 0x40);
//Wait for adequate voltage to
//run at full speed
while ((SVSCTL & SVSOP));
//Dummy loop */;
//The voltage should now be OK to
//run the CPU at full speed. Now
//it should be OK to use the SVS
//as a reset source.
SVSCTL |= PORON;
#endif
SCFI0 |= FN_4; // x2 DCO frequency, 8MHz nominal
// DCO
SCFQCTL = 91; // 32768 x 2 x (91 + 1) = 6.03 MHz
FLL_CTL0 = DCOPLUS + XCAP14PF; // DCO+ set so freq = xtal x D x
//(N + 1)
P1OUT = 0;
P1DIR = BIT0;
P2SEL = (BIT4 | BIT5);
P2DIR = (BIT2 | BIT3);
P2OUT = 0;
P3OUT = 0;
P3OUT |= (BIT2 | BIT3); //P3.2, P3.3 drives the LED
//PNP transistor
P3DIR |= (BIT2 | BIT3);
P4OUT = 0;
P5OUT = 0;
P6OUT = 0;
set_LCD();
/* First amplifier stage - transconductance configuration */
P6SEL |= (BIT0 | BIT1 | BIT2); //Select OA0O
//-ve=OA0I0, +ve=OA0I1
OA0CTL0 = OAN_0 | OAP_1 | OAPM_3 | OAADC1;
OA0CTL1 = 0x00;
/* Second amplifier stage */
P6SEL |= (BIT3 | BIT4); // Select 0A1O 0A1I
// -ve=OA1I0, +ve=DAC1
//OA1CTL0 = OAN_0 | OAP_3 | OAPM_3 | OAADC1;
//OA1CTL1 = 0x00;
//Inverted input internally
//connected to OA0 output
OA1CTL0 = OAN_2 | OAP_3 | OAPM_3 | OAADC1;
OA1CTL1 = OAFBR_7 | OAFC_6; //OA as inv feedback amp, internal
//gain = 16;
//Configure DAC 1 to provide
//bias for the amplifier */
P6SEL |= BIT7;
DAC12_1CTL = DAC12CALON | DAC12IR | DAC12AMP_7 | DAC12ENC;
DAC12_1DAT = 0;
//Configure DAC 0 to provide
//variable drive to the LEDs */
DAC12_0CTL = DAC12CALON | DAC12IR | DAC12AMP_7 | DAC12ENC;
P2OUT |= BIT3; //turn off source for D2
P2OUT &= ~BIT2; //turn on source for D3
DAC12_0DAT = 3340;
//Set initial values for the LED brightnesses */
ir_LED_level = 1300;
vs_LED_level = 1450;
ir_pi_last_y = ir_LED_level*32768;
vs_pi_last_y = vs_LED_level*32768;
ir_dc_register = 0;
vs_dc_register = 0;
ir_2nd_dc_register = 0;
vs_2nd_dc_register = 0;
ADC12CTL0 &= ~ENC; // Enable conversions
// Turn on the ADC12, and
// set the sampling time
ADC12CTL0 = ADC12ON | MSC | SHT0_4 | REFON | REF2_5V;
ADC12CTL1 = SHP | SHS_1 | CONSEQ_1; // Use sampling timer, single
//sequence, TA1 trigger
ADC12MCTL0 = INCH_1 | SREF_1; // ref+=Vref, channel = A1 = OA0
ADC12MCTL1 = INCH_3 | SREF_1 | EOS; // ref+=Vref, channel = A3 = OA1
ADC12IE = BIT1;
ADC12CTL0 |= ENC; // Enable the ADC
ADC12CTL0 |= ADC12SC; // Start conversion
TACTL = TASSEL0 | MC_1 | TACLR; // ACLK, clear TAR, up mode
CCTL1 = OUTMOD_2; // Set/Reset enable interrupt
CCTL0 = CCIE;
//This gives a sampling rate of
//512sps
CCR0 = 31; //Do two channels, at
//512sps each.
CCR1 = 20; //Allow plenty of time for the
//signal to become stable before
//sampling
//Configure the USART, so we
//can report readings to a PC */
P2DIR |= BIT4;
P2SEL |= BIT4;
UCTL0 &= ~SWRST;
ME1 |= UTXE0; // Enable USART1 TXD
UCTL0 |= CHAR; // 8-bit char, SWRST=1
UTCTL0 |= SSEL1; // UCLK = SMCLK
UBR00 = 52; // 115200 from 6.02MHz = 52.33
UBR10 = 0x00;
UMCTL0 = 0x45; // Modulation = 0.375
UCTL0 &= ~SWRST; // Initialise USART
led_on_always=1;
_EINT();
//We now go round this small
//loop forever, with most of
//the work happening in the
//interrupt routines */
for (;;)
{
_BIS_SR(LPM0_bits);
f1 = 60.0*500.0*3.0/(float) log_heart_signal_sample_counter;
heart_rate = f1;
//log_heart_signal_sample_counter /= 10;
//heart_rate = (6*500*3)/log_heart_signal_sample_counter;
display_number(heart_rate, 3, 3);
//rms_ir_heart_ac_signal = (unsigned int) (isqrt32(log_sq_ir_heart_ac_signal/log_heart_signal_sample_counter) >> 16);
//rms_vs_heart_ac_signal = (unsigned int) (isqrt32(log_sq_vs_heart_ac_signal/log_heart_signal_sample_counter) >> 16);
x = isqrt32(log_sq_ir_heart_ac_signal);
y = isqrt32(log_sq_vs_heart_ac_signal);
SaO2 = (unsigned int) (100.0*x/y);
display_number(SaO2, 7, 3);
}
}
// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A0(void)
{
int i;
if ((DAC12_0CTL & DAC12OPS)) //D2 enabled in demo board
{
//Immediately enable the visible
//LED, to allow time for the
//transimpedance amp to settle
DAC12_0CTL &= ~DAC12ENC;
P2OUT |= BIT3; //turn off source for D2
DAC12_0CTL &= ~DAC12OPS; // Disable IR LED, enable visible LED
DAC12_0CTL |= DAC12ENC;
DAC12_0DAT = vs_LED_level;
DAC12_1DAT = vs_dc_offset; // Load op-amp offset value for visible
P2OUT &= ~BIT2; //turn on source for D3
//Read the IR LED results */
ir_sample = ADC12MEM0;
i = ADC12MEM1;
//Enable the next conversion
//sequence. The sequence is
//started by TA1 */
ADC12CTL0 &= ~ENC;
ADC12CTL0 |= ENC;
//Filter away 50/60Hz electrical
//pickup, and 100/120Hz room
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -