⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 oximeter_ext_probe_1.c

📁 MSP430FG437 SPO2 Source code
💻 C
📖 第 1 页 / 共 2 页
字号:
//*****************************************************************************
// 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 + -