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

📄 oximeter_ext_probe_1.c

📁 MSP430FG437 SPO2 Source code
💻 C
📖 第 1 页 / 共 2 页
字号:
                                            //lighting optical pickup */
        ir_heart_signal = ir_filter(i);
                                            //Filter away the large DC
                                            //component from the sensor */
        ir_heart_ac_signal = ir_heart_signal - dc_estimator(&ir_2nd_dc_register, ir_heart_signal);

                                            //Bring the signal into range
                                            //through the second op-amp */
        if (i >= 4095)
        {
            if (ir_dc_offset > 0)
                ir_dc_offset--;
        }
        else if (i < 100)
        {
            if (ir_dc_offset < 4095)
                ir_dc_offset++;
        }
        sq_ir_heart_ac_signal += (mul16(ir_heart_ac_signal, ir_heart_ac_signal) >> 10);

                                            //Tune the LED intensity to keep
                                            //the signal produced by the first
                                            //stage within our target range.
                                            //We don't really care what the
                                            //exact values from the first
                                            //stage are. They need to be
                                            //quite high, because a weak
                                            //signal will give poor results
                                            //in later stages. However, the
                                            //exact value only has to be
                                            //within the range that can be
                                            //handled properly by the next
                                            //stage. */
        if (ir_sample > FIRST_STAGE_TARGET_HIGH
            ||
            ir_sample < FIRST_STAGE_TARGET_LOW)
        {
                                            //We are out of the target range
                                            //Starting kicking the LED
                                            //intensity in the right
                                            //direction to bring us back
                                            //into range. We use fine steps
                                            //when we are close to the target
                                            //range, and coarser steps when
                                            //we are far away.
            display_correcting(0, 1);
            if (ir_sample > FIRST_STAGE_TARGET_HIGH)
            {
                if (ir_sample >= FIRST_STAGE_TARGET_HIGH_FINE)
                    ir_LED_level -= FIRST_STAGE_STEP;
                else
                    ir_LED_level -= FIRST_STAGE_FINE_STEP;
                                            //Clamp to the range of the DAC */
                if (ir_LED_level < 0)
                    ir_LED_level = 0;
            }
            else
            {
                if (ir_sample < FIRST_STAGE_TARGET_LOW_FINE)
                    ir_LED_level += FIRST_STAGE_STEP;
                else
                    ir_LED_level += FIRST_STAGE_FINE_STEP;
                                             //Clamp to the range of the DAC */
                if (ir_LED_level > 4095)
                    ir_LED_level = 4095;
            }
        }

        switch (scope_type)
        {
        case SCOPE_TYPE_HEART_SIGNALS:
            i = (ir_heart_ac_signal >> 6) + 128;
                                            //Saturate to a byte */
            if (i > 255)
                i = 255;
            else if (i < 0)
                i = 0;
            TXBUF0 = i;
            break;
        case SCOPE_TYPE_RAW_SIGNALS:
            TXBUF0 = ir_sample >> 4;
            break;
        case SCOPE_TYPE_LED_DRIVE:
            TXBUF0 = ir_LED_level >> 4;
            break;
        }

                                          //Track the beating of the heart */
        heart_signal_sample_counter++;
        if (pos_edge)
        {
            if (edge_debounce < 120)
            {
                edge_debounce++;
            }
            else
            {
                if (ir_heart_ac_signal < -200)
                {
                    edge_debounce = 0;
                    pos_edge = 0;
                    display_pulse(0);
                }
            }
        }
        else
        {
            if (edge_debounce < 120)
            {
                edge_debounce++;
            }
            else
            {
                if (ir_heart_ac_signal > 200)
                {
                    edge_debounce = 0;
                    pos_edge = 1;
                    display_pulse(1);
                    display_correcting(0, 0);
                    display_correcting(1, 0);
                    if (++heart_beat_counter >= 3)
                    {
                        log_heart_signal_sample_counter = heart_signal_sample_counter;
                        log_sq_ir_heart_ac_signal = sq_ir_heart_ac_signal;
                        log_sq_vs_heart_ac_signal = sq_vs_heart_ac_signal;
                        heart_signal_sample_counter = 0;
                        sq_ir_heart_ac_signal = 0;
                        sq_vs_heart_ac_signal = 0;
                        heart_beat_counter = 0;
                        _BIC_SR_IRQ(LPM0_bits);
                                            // Do a dummy wake up roughly
                                            //every 2 seconds
                    }
                }
            }
        }
    }
    else                                    //D3 enabled in demoboard
    {
                                            //Immediately enable the IR LED,
                                            //to allow time for the
                                            //transimpedance amp to settle */
        DAC12_0CTL &= ~DAC12ENC;
        P2OUT |= BIT2;                      //turn off source for D2
        DAC12_0CTL |= DAC12OPS;             // Disable visible LED, enable IR
                                            //LED
        DAC12_0CTL |= DAC12ENC;
        DAC12_0DAT = ir_LED_level;
        DAC12_1DAT = ir_dc_offset;          // Load op-amp offset value for IR
        P2OUT &= ~BIT3;                     //turn on source for D3

                                            //Read the visible LED results */
        vs_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
                                            //lighting optical pickup */
        vs_heart_signal = vs_filter(i);
                                            //Filter away the large DC
                                            //component from the sensor */
        vs_heart_ac_signal = vs_heart_signal - dc_estimator(&vs_2nd_dc_register, vs_heart_signal);

                                            //Bring the signal into range
                                            //through the second op-amp */
        if (i >= 4095)
        {
            if (vs_dc_offset > 0)
                vs_dc_offset--;
        }
        else if (i < 100)
        {
            if (vs_dc_offset < 4095)
                vs_dc_offset++;
        }
        sq_vs_heart_ac_signal += (mul16(vs_heart_ac_signal, vs_heart_ac_signal) >> 10);

        if (vs_sample > FIRST_STAGE_TARGET_HIGH
            ||
            vs_sample < FIRST_STAGE_TARGET_LOW)
        {
            /* We are out of the target range */
            display_correcting(1, 1);
            if (vs_sample > FIRST_STAGE_TARGET_HIGH)
            {
                if (vs_sample >= FIRST_STAGE_TARGET_HIGH_FINE)
                    vs_LED_level -= FIRST_STAGE_STEP;
                else
                    vs_LED_level -= FIRST_STAGE_FINE_STEP;
                if (vs_LED_level < 0)
                    vs_LED_level = 0;
            }
            else
            {
                if (vs_sample < FIRST_STAGE_TARGET_LOW_FINE)
                    vs_LED_level += FIRST_STAGE_STEP;
                else
                    vs_LED_level += FIRST_STAGE_FINE_STEP;
                if (vs_LED_level > 4095)
                    vs_LED_level = 4095;
            }
        }

        switch (scope_type)
        {
        case SCOPE_TYPE_HEART_SIGNALS:
            i = (vs_heart_ac_signal >> 6) + 128;
                                            //Saturate to a byte */
            if (i > 255)
                i = 255;
            else if (i < 0)
                i = 0;
            TXBUF0 = i;
            break;
        case SCOPE_TYPE_RAW_SIGNALS:
            TXBUF0 = vs_sample >> 4;
            break;
        case SCOPE_TYPE_LED_DRIVE:
            TXBUF0 = vs_LED_level >> 4;
            break;
        }
    }
}

#pragma vector=TIMERA1_VECTOR
__interrupt void Timer_A1(void)
{
    CCTL1 &= ~CCIFG;
}

#pragma vector=ADC_VECTOR
__interrupt void ADC12ISR(void)
{
    ADC12IFG &= ~BIT1;
    //DAC12_0DAT = 0;
    //DAC12_1DAT = (ir_heart_ac_signal >> 3) + 2000;
}

int16_t vs_filter(int16_t sample)
{
    static int16_t buf[32];
    static int offset = 0;
    int32_t z;
    int i;

                                            //Filter hard above a few Hertz,
                                            //using a symmetric FIR.
                                            //This has benign phase
                                            //characteristics */
    buf[offset] = sample;
    z = mul16(coeffs[11], buf[(offset - 11) & 0x1F]);
    for (i = 0;  i < 11;  i++)
        z += mul16(coeffs[i], buf[(offset - i) & 0x1F] + buf[(offset - 22 + i) & 0x1F]);
    offset = (offset + 1) & 0x1F;
    return  z >> 15;
}

int16_t ir_filter(int16_t sample)
{
    static int16_t buf[32];
    static int offset = 0;
    int32_t z;
    int i;

                                            //Filter hard above a few Hertz,
                                            //using a symmetric FIR.
                                            //This has benign phase
                                            //characteristics */
    buf[offset] = sample;
    z = mul16(coeffs[11], buf[(offset - 11) & 0x1F]);
    for (i = 0;  i < 11;  i++)
        z += mul16(coeffs[i], buf[(offset - i) & 0x1F] + buf[(offset - 22 + i) & 0x1F]);
    offset = (offset + 1) & 0x1F;
    return  z >> 15;
}

int16_t dc_estimator(register int32_t *p, register int16_t x)
{
    /* Noise shaped DC estimator. */
    *p += ((((int32_t) x << 16) - *p) >> 9);
    return (*p >> 16);
}

unsigned long isqrt32(register unsigned long h)
{
    register unsigned long x;
    register unsigned long y;
    register int i;

                                            //Calculate a 32 bit bit square
                                            //root of a 32 bit integer,
                                            //where the top 16 bits
                                            //of the result is the integer
                                            //part of the result, and the
                                            //low 16 bits are fractional.
    x =
    y = 0;
    for (i = 0;  i < 32;  i++)
    {
        x = (x << 1) | 1;
        if (y < x)
            x -= 2;
        else
            y -= x;
        x++;
        y <<= 1;
        if ((h & 0x80000000))
            y |= 1;
        h <<= 1;
        y <<= 1;
        if ((h & 0x80000000))
            y |= 1;
        h <<= 1;
    }
    return  x;
}

void display_number(int value, int start, int width)
{
    int i;

    for (i = 0;  i < width;  i++)
    {                                       // remainder = character in table
                                            //to display
        LCDMEM[7 + i - start] = hex_table[value%10];
        value /= 10;
    }
}

void display_pulse(int on)
{
    if (on)
        LCDMEM[7] |= 0x4;
    else
        LCDMEM[7] &= ~0x4;
}

void display_correcting(int x, int on)
{
    if (on)
        LCDMEM[3] |= ((x)  ?  seg_a  :  seg_d);
    else
        LCDMEM[3] &= ~((x)  ?  seg_a  :  seg_d);
}

// For ease of construction (so that the whole LCD panel can be wired onto sockets)
//    two I/O lines are used to provide VCC and GND voltages for the LCD driver.
//    These I/O lines can be replaced by Vcc and GND in target boards.
//    In addition, 3 resistors need to be connected to R03-R33 in order to provide
//    Intemediate voltages.
// Note that COM1-COM3 and R13-R33 is mux with I/O pins.
//    To enable them for LCD function, the relevant bits in P5SEL
//    should be set.
// Also S0-S23 are MUX with I/O pins.
//    To enable them for LCD function, the LCDCTL register is used.
//    In this application, all S0-S23 have been selected for LCD function.
// Refer to the architecture guide and the data sheets for more detail

void set_LCD(void)
{
    char *lcd_pointer;

    lcd_pointer = LCDMEM;
    while (lcd_pointer != LCDMEM + 20)
        *lcd_pointer++ = 0;

    /* Turn on the COM0-COM3 and R03-R33 pins */
    P5SEL |= (BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2);

    LCDCTL = 0x7F;                          // Selected function: Analog generator on
                                            // Low impedance of AG
                                            // 4Mux active
                                            // all outputs are Seg
                                            // S0-S23 are LCD segment lines
    BTCTL = BTFRFQ0;	                    // Start Basic Timer 1s + LCD 64Hz
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -