📄 oximeter_ext_probe_1.c
字号:
//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 + -