📄 heart rate with ekg demo_lsd048.c
字号:
//*****************************************************************************
// MSP430FG439-Heart Rate Monitor Demo
//
// Description; Uses one Instrumentation Amplifier INA321 and the three
// internal opamps of the MSP430FG439
//
// LSD ZHANGCHONG
// MAY 2006
// Built with IAR Embedded Workbench Version: 3.20A
//*****************************************************************************
//*****************************************************************************
#include <msp430xG43x.h>
#include "math.h"
//defines
#define PB_2_0 (1 << 0) // Push Button on P2.0 PB_2_0为0x01
#define PB_2_1 (1 << 1) // Push Button on P2.1 PB_2_1为0x02
#define c 0x01 // LSD 048 LCD SEGMENT DISPLAY
#define f 0x02
#define e 0x04
#define h 0x08
#define a 0x10
#define b 0x20
#define g 0x40
#define d 0x80
// variables declaration
static char beats;
int Datain, Dataout, Dataout_pulse, pulseperiod, counter, heartrate;
// Lowpass FIR filter coefficients for 17 taps to filter > 30Hz
static const int coeffslp[9] = {
5225, 5175, 7255, 9453, 11595, 13507, 15016, 15983, 16315 };
// Highpass FIR filter coefficients for 17 taps to filter < 2Hz
static const int coeffshp[9] = {
-763, -1267, -1091, -1867, -1969, -2507, -2619, -2911, 29908 };
// Character generator definition for display
const char char_gen[] = {
a+b+c+d+e+f, // 0 Displays "0"
b+c, // 1 Displays "1"
a+b+d+e+g, // 2 Displays "2"
a+b+c+d+g, // 3 Displays "3"
b+c+f+g, // 4 Displays "4"
a+c+d+f+g, // 5 Displays "5"
a+c+d+e+f+g, // 6 Displays "6"
a+b+c, // 7 Displays "7"
a+b+c+d+e+f+g, // 8 Displays "8"
a+b+c+d+f+g, // 9 Displays "9"
};
// undefines
#undef a
#undef b
#undef c
#undef d
#undef e
#undef f
#undef g
#undef h
// function prototypes
void Init(void); // Initializes device for the application
void ClearLCD(void); // Clears the LCD memory
int filterlp(int); // 17 tap lowpass FIR filter
int filterhp(int); // 17 tap highpass FIR filter
long mul16(register int x, register int y); // 16-bit signed multiplication
int itobcd(int i); // 16-bit hex to bcd conversion
// main function
void main(void)
{ Init (); // Initialize device for the application
while(1)
{LPM0; // Enter LPM0 needed for UART TX completion
Dataout = filterlp(Datain); // Lowpass FIR filter for filtering out 60Hz
Dataout_pulse = filterhp(Dataout)-128; // Highpass FIR filter to filter muscle artifacts
Dataout = Dataout >> 6; // Scale Dataout to use scope program /2^6
if(Dataout>255) // Set boundary 255 max
Dataout=255; //
if(Dataout<0) // Set boundary 0 min
Dataout=0; //
// DAC12_0DAT = Dataout; // For scope display
TXBUF0 = Dataout; // Transmit via UART0 for Scope display
counter++; // Debounce counter
pulseperiod++; // Pulse period counter
if (Dataout_pulse > 48) // Check if above threshold
{ //LCDM10 |= 0x0f; // Heart beat detected enable "^" on LCD
LCDMEM[1]=0X61; // LSD048 LCD MARK DISP 使bgc 亮
LCDMEM[2]=0X46; // LSD048 LCD MARK DISP 使feg亮
counter = 0;} // Reset debounce counter
if (counter == 128) // Allow 128 sample debounce time
{//LCDM10 = 0x00; // Disable "^" on LCD for blinking effect
LCDMEM[1]=0X00; // LSD048 LCD MARK DISP
LCDMEM[2]=0X00; // LSD048 LCD MARK DISP
beats++;
if (beats == 3)
{beats = 0;
// heartrate = itobcd(30720/pulseperiod); // Calculate beat to beat heart rate per min
heartrate = itobcd(92160/pulseperiod); // Calculate 3 beat average heart rate per min
pulseperiod = 0; // Reset pulse period for next measurement
LCDMEM[6] = char_gen[heartrate & 0x0f]; // Display current heart rate unitsn 0
LCDMEM[5] = char_gen[(heartrate & 0xf0) >> 4]; // tens 1
LCDMEM[4] = char_gen[(heartrate & 0xf00) >> 8];}} // hundreds 2
}
}//main
// Initialization function
void Init( void )
{ FLL_CTL0 |= XCAP18PF; // Set load capacitance for xtal
WDTCTL = WDTPW | WDTHOLD; // Disable the Watchdog
while ( LFOF & FLL_CTL0); // wait for watch crystal to stabilize
SCFQCTL = 63; // 32 x 32768 x 2 = 2.097152MHz MOV.B #(64–1),&SCFQTL
BTCTL = BT_fLCD_DIV128; // Set LCD frame freq = ACLK/128
// Initialize and enable LCD peripheral
ClearLCD(); // Clear LCD memory
LCDCTL = LCDSG0_3 + LCD4MUX + LCDON ; // 4mux LCD, 使用0-23段
// Initialize and enable GPIO ports
P1OUT = 0x00 + BIT3; // Clear P1OUT register, INA turned ON??
P1DIR = 0x3f; // Unused pins as outputs, Comparator p1.6ca0;p1.7ca1 pins as inputs (0设输入,1设输出)
P2OUT = 0x00; // Clear P2OUT register
P2DIR = 0xff; // Unused pins as outputs
P2DIR = ~(PB_2_0+PB_2_1); // P2.0 and P2.1 push buttons P2DIR为0x03取反所以p2.0 p2.1为输入
P2IES = 0x00; // Interrupt edge low to high transition 中断上边沿有效
P2IFG = 0x00; // Clear pending P2 interrupts 0为没有终端请求
P2IE = PB_2_0 | PB_2_1; // Enable intterupts for push buttons P2IE为0x03设p2.0 p2.1允许中断
P3OUT = 0x00; // Clear P3OUT register
P3DIR = 0xff; // Unused pins as outputs
P4OUT = 0x00; // Clear P4OUT register
P4DIR = 0xff; // Unused pins as outputs
P5OUT = 0x00; // Clear P5OUT register
P5DIR = 0xff; // Unused pins as outputs
P5SEL = 0xfc; // Set Rxx and COM pins for LCD p5.0 5.2不设为外围设备??
P6OUT = 0x00; // Clear P6OUT register
P6SEL = 0xff; // P6 = Analog p6.n都设为外围设备功能
// Initialize and enable UART
P2SEL|=BIT4; // P2.4 = TXD 0为端口功能,1为外围设备功能
UCTL0 |= SWRST; // UART SWRST = 1 将UCTLO设为0x01使usart都复位
ME1 |= UTXE0; // Enable UART0 TXD ME1,2为模块允许寄存器:UTXE0为01000000,也就是ME1.6复位USART0允许接收(UART模式)
UCTL0 |= CHAR; // 8-bit char, SWRST=1 选择字符以8位传
UTCTL0 |= SSEL1; // UCLK = SMCLK 选择UCLK时钟为SMCLK??
UBR00 = 18; // 115200 from 2.097152MHz?? 2.097152/18 用于计算波特率的分频去UBR=18.2044
UBR10 = 0;
UMCTL0 = 0x2c; // Modulation = 0.2044(3/8) 波特率余数0.2044填写波特率调整寄存器UMCTL0=00101100;18,18,19,18,19,19,18,18
UCTL0 &= ~SWRST; // UART SWRST = 0, enable UART 复位之后开始使用USART
// Initialize and enable ADC12
ADC12CTL0 = ADC12ON + SHT0_4 + REFON + REF2_5V; // ADC12 ON, Reference = 2.5V for DAC0 打开ADC内部参考电压2.5V,采样周期=TADC12CLK*64
ADC12CTL1 = SHP + SHS_1 + CONSEQ_2; // Use sampling timer, TA1 trigger SAMPCON控制位选择来自ADC的定时器采样模式,选择采样输入信号源 TIMER_A.OUT1,单通道多次转换模式??
ADC12MCTL0 = INCH_1 + SREF_1; // Vref, channel = 1 = OA0 Out 选择模拟量输入通道为A1,VR+ = VREF+; VR- = AVSS转换电压范围
ADC12IE = BIT0; // Enable interrupt for ADC12 MEM0 允许ADC MEM0存储中断标志使用
ADC12CTL0 |= ENC; // Enable conversions SAMPCON控制位启动数模转换
// Initialize and enable Timer_A
TACTL = TASSEL0 + MC_1 + TACLR; // ACLK, Clear TAR, Up Mode 选择ACLK辅助时钟模式,MC-1连续增计数到“0FFFFH”到零再计数,TAR计数器清零 TIMERA作用?
TACCTL1 = OUTMOD_2; // Set / Reset PWM翻转复位,选择输出模式
TACCR0 = 63; // 512 samples per second 在增计数器模式下,CCR0用作设置计数周期。32768/64=512
TACCR1 = 15; //设置PWM占空比 见 书167
// Initialize and enable DAC12x
DAC12_0CTL = DAC12OPS + DAC12CALON + DAC12IR + DAC12AMP_2 + DAC12ENC;// DAC0 enable OPS为MSP430FG43X专用,1时DAC12_0输出为VeREF+,DAC_1输出为P5.1,ENC使用DAC12,IR DAC12满量程输出等于ADC2.5V的电压,CALON程序初始化,DACAMP位为010时输入输出都是低速
DAC12_1CTL = DAC12CALON + DAC12IR + DAC12AMP_2 + DAC12ENC; // DAC1 enable
DAC12_1DAT = 0x099A; // Offset level = 1.5V for op amp bias 当DAC12RES为0 DAC12IR为1时,Vout =Vref*DAC12_xDAT/4096=2.5*0.6
// Initialize and enable opamps
OA0CTL0 = OAP_1 + OAPM_1 + OAADC1; // OA0 enable power mode 1, 高两位00使负向电压OA0- = P6.0, OAP_1用于选择正向电压0A0+ = P6.2, 运放输出OA0O = P6.1
OA0CTL1 = OARRIP; // General purpose mode, no Rail-to-Rail inputs
OA1CTL0 = OAP_3 + OAPM_1 + OAADC1; // OA1 enable power mode 1, 高两位00使负向电压OA1- = P6.4, OAP_3用于选择正向电压OA1+ = P6.7DAC1, 运放输出OA1O = P6.3
OA1CTL1 = OARRIP; // General purpose mode, no Rail-to-Rail inputs
OA2CTL0 = OAP_3 + OAPM_1 + OAADC1; // OA2 enable power mode 1, 高两位00使负向电压OA0- = P6.6,OAP_3用于选择正向电压OA2+ = P6.7DAC1, OA2O = P6.5, Select inputs, power mode
OA2CTL1 = OAFC_1 + OARRIP; // Unit gain Mode, no Rail-to-Rail inputs
_EINT(); // Enable global Interrupts
} //init
void ClearLCD(void)
{ int i; //
for( i = 0; i < 16; i++){ // Clear LCDMEM
LCDMEM[i] = 0; //
}
}//clear LCD
int itobcd(int i) // Convert hex word to BCD.
{ int bcd = 0; //
char j = 0; //
while (i > 9) //
{bcd |= ((i % 10) << j); //
i /= 10; //
j += 4;} //移动4位
return (bcd | (i << j)); // Return converted value
}// itobcd(i)
int filterlp(int sample) // Lowpass FIR filter for EKG
{ static int buflp[32]; // Reserve 32 loactions for circular buffering
static int offsetlp = 0;
long z;
int i;
buflp[offsetlp] = sample;
z = mul16(coeffslp[8], buflp[(offsetlp - 8) & 0x1F]);
for (i = 0; i < 8; i++)
z += mul16(coeffslp[i], buflp[(offsetlp - i) & 0x1F] + buflp[(offsetlp - 16 + i) & 0x1F]);
offsetlp = (offsetlp + 1) & 0x1F;
return z >> 15; // Return filter output
}// int filter
int filterhp(int samplehp) // Highpass FIR filter for hear rate
{ static int bufhp[32]; // Reserve 32 loactions for circular buffering
static int offsethp = 0;
long z;
int i;
bufhp[offsethp] = samplehp;
z = mul16(coeffshp[8], bufhp[(offsethp - 8) & 0x1F]);
for (i = 0; i < 8; i++)
z += mul16(coeffshp[i], bufhp[(offsethp - i) & 0x1F] + bufhp[(offsethp - 16 + i) & 0x1F]);
offsethp = (offsethp + 1) & 0x1F;
return z >> 15; // Return filter output
}// int filterhp
#pragma vector = PORT2_VECTOR
__interrupt void Port2ISR (void)
{
P2IFG = 0;
}//Push buttons unused P2口中断服务程序 P2所有中断标志位清除
#pragma vector = ADC_VECTOR // ADC12 ISR
__interrupt void ADC12ISR (void)
{
Datain = ADC12MEM0; // Store converted value in Datain
LPM0_EXIT; // Exit LPM0 on return
}// ADC12ISR
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -