找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1974|回复: 3
打印 上一主题 下一主题
收起左侧

最近在做STC15W4K32S4采集心率的实验,调试了三天没调试出来,希望有高手指点指点

[复制链接]
跳转到指定楼层
楼主
ID:689493 发表于 2020-4-2 17:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
   采用的是STC15W4K32S4单片机作为处理器,心率模块用的是Pulse sensor,只需要得出心跳次数BPM就行,其中AD转换我用了P1.3口,通信用的是串口2(P1.0/RxD2    P1.1/TxD2), 另外,心率数据处理部分我参照了那个宝卖家给的Pulse sensor资料,不知道问题出在哪里了,一直没调试出来(不需要上位机显示,只需要得到心率值就行),希望有高手帮忙指点一下,谢谢了。下面代码中我简单注释了一下。    再次谢谢大家了

    //系统频率为11.0592MHz
#include<stc15.h>
#define u8 unsigned char
#define u16 unsigned int
#define false 0
#define true 1       
       
char bdata bit_S2CON;         //定义它主要是为了进行位操作,我用的串口2
sbit TI_2 = bit_S2CON^1;               
sbit RI_2 = bit_S2CON^0;

u8 aa[3];            //定义它是为了存得出的心跳BPM(当成3位数来处理,主要是方便串口通信传输它)

//下面这些定义是用在T0中断中心率的处理,资料上是这样的
volatile unsigned int BPM;                  //每分钟的心跳
volatile unsigned int Signal;                //脉冲
volatile unsigned int IBI = 600;             //IBI是相邻两次心跳的时间间隔,600的意思应该是0.6ms,我不太清楚
volatile bit Pulse = false;                  // 脉冲的标志
volatile bit QS = false;                   // 这个是得出计算出了心跳次数BPM时候的一个标志
volatile int rate[10];                    //定义成10位数组,主要是为了存10次心跳的间隔时间,然后为了求个平均值
volatile unsigned long sampleCounter = 0;         //上一次心跳的时间
volatile unsigned long lastBeatTime = 0;          //紧接着的下次心跳的时间,这两个时间相减就是紧挨着的两次心跳之间的时间
volatile int Peak =512;                    //脉冲峰值,这里资料上是512,我不清楚,是个脉冲中间值吧
volatile int Trough = 512;                 //脉冲的波谷
volatile int thresh = 512;               //波谷上升到波峰的那段的一个中间值,资料上意思是计算相邻这样的中间值来计算心跳准确点
volatile int amp = 100;                   //用在波谷到波峰中间值的一个量,初值为什么是100,资料是这样写的
volatile bit firstBeat = true;           
volatile bit secondBeat = false;      //跟上面那个一样是个标志

void delay_ms(u16 z)                 //大概延时1ms的时间
{
        u8 x;
        for(; z > 0; z--)
                for(x = 110; x > 0; x--);
}

void Delay_6us()                //大概延时6us
{
        u8 i;
        i = 14;
        while (--i);
}

void ad_init()                            //ADC初始化 (STC15W4K32S4单片机)
{
        ADC_CONTR |= 0x80;       //开启ADC的电源
        delay_ms(1);                  //第一次开电源需要延时1ms,书上这样写的
        P1ASF |= 0x08;                  //将P1.3口作为AD功能
        ADC_CONTR |= 0x40;      //ADC转换速度,我选择额的是180个时钟周期转换一次,可以达10位精度
        Delay_6us();                 //每次执行ADC_CONTR寄存器赋值时,要延时一下,书上这样介绍的
        CLK_DIV |= 0x20;      //这里我设置成转换结果的高两位存在ADC_RSE[1:0],转换结果的低八位存在ADC_RESL[7:0]
}

u16 ad_work()                    //进行AD转换函数,有返回值,需要对返回的结果进行计算处理,得出心跳次数BPM
{
        u16 result;                    //定义它来存结果
        ADC_CONTR |= 0x03;        //选择P1.3作为A/D输入来用
        Delay_6us();
        ADC_CONTR |= 0x08;       //将开始转换位ADC_START置1,开始进行A/D转换
        Delay_6us();
        while(!(ADC_CONTR & 0x10));    //判断标志位ADC_FLAG是否为1了,也就是是否A/D转换完了
        ADC_CONTR &= 0xE7;           //转换结束后将标志ADC_FLAG和开始转换位ADC_START置0;
        Delay_6us();
        result = ADC_RES;            
        result = result << 8;
        result = result + ADC_RESL;  //上面这几行就是将结果存在result中
        return result;                 //返回值
}

void uart_init()              //串口2的初始化
{
        AUXR |= 0x04;                //采用定时器2,不分频,它是固定为16位自动重装
        T2L = 0xFD;               
        T2H = 0x1F;                //装初值设置波特率为9600
        AUXR |= 0x10;             //将TR2置1
        S2CON = 0x50;        //串口工作在方式2 , 8位数据
        EA = 1;

}

void uart_sendchar(u8 dat)            //发送单个字符
{
        S2BUF = dat;
        while(!(S2CON & 0x02));       //因为S2CON不能被位寻址,所以这里用了前面定义的可以被位寻址的bit_S2CON
        bit_S2CON = S2CON;
        TI_2 = 0;
        S2CON = bit_S2CON;
}

void uart_sendstring(u8 *astring, u16 stringlength)        //发送数组,发送前面定义的aa[3],
{
        u8 i;
        for ( i = 0; i < stringlength; i++ )
        {
                uart_sendchar( astring[i] );
        }
}

void T0_init()                //定时器T0的初始化
{
        TMOD = 0x01;    //工作方式1,16位定时器
        TH0 = 0xF8;
        TL0 = 0xFC;       //定时2ms
        TR0 = 1;
        ET0 = 1;
        EA = 1;
}

void main()
{
        ad_init();
        uart_init();
        T0_init();
        while(1)                        //主函数里就只做将得到的心跳值BPM存在aa数组里,然后发送,,这两件事情
        {
                if(QS == true)
                {
                        QS = false;
                        aa[0] = BPM/100;
                        aa[1] = BPM%100/10;
                        aa[2] = BPM%100%10;
                        uart_sendstring(aa,3);
                }
        }
}

void Timer0_rountine(void) interrupt 1            //这个T0中断里下面就是对AD转换后的值做处理和运算了,得到想要的心跳数BPM,那个宝老板给的资料
{                                                                //这资料里的就是这样处理的,,不知道它程序逻辑有没有问题,反正意思清楚,基本上没怎么改动它
       int N;
        unsigned char i;
       unsigned int runningTotal = 0;                     

        EA=0;                                      
        TH0 = 0xF8;
        TL0 = 0xFC;
  Signal = ad_work();                      //这个地方换成我自己的AD转换后的结果,然后付给了初始信号Signal
  sampleCounter += 2;                        
  N = sampleCounter - lastBeatTime;      

  if(Signal < thresh && N > (IBI/5)*3){      
    if (Signal < Trough){                        
      Trough = Signal;                       
    }
  }

  if(Signal > thresh && Signal > Peak){         
    Peak = Signal;                           
  }                                      

  if (N > 250){                                 
    if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) ){        
      Pulse = true;                              
      IBI = sampleCounter - lastBeatTime;        
      lastBeatTime = sampleCounter;            

      if(secondBeat){                     
        secondBeat = false;               
        for(i=0; i<=9; i++){            
          rate[i] = IBI;                     
        }
      }

      if(firstBeat){                        
        firstBeat = false;                  
        secondBeat = true;               
        EA=1;                             
        return;                          
      }   

      for(i=0; i<=8; i++){               
        rate[i] = rate[i+1];                 
        runningTotal += rate[i];           
      }

      rate[9] = IBI;                        
      runningTotal += rate[9];               
      runningTotal /= 10;                  
      BPM = 60000/runningTotal;            
                        if(BPM>200)BPM=200;                       
                        if(BPM<30)BPM=30;                               
      QS = true;                                                //这里这个QS就是得出心跳次数BPM后的标志
    }                       
  }

  if (Signal < thresh && Pulse == true){   
    Pulse = false;                     
    amp = Peak - Trough;                        
    thresh = amp/2 + Trough;                 
    Peak = thresh;                          
    Trough = thresh;
  }

  if (N > 2500){                           
    thresh = 512;                        
    Peak = 512;                             
    Trough = 512;                           
    lastBeatTime = sampleCounter;               
    firstBeat = true;                     
    secondBeat = false;                    
  }

  EA=1;                                 
}


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:721191 发表于 2020-4-2 19:04 | 只看该作者
程序代码看看有没有报错,如果没报错,在protues上你试试运行一下
回复

使用道具 举报

板凳
ID:689493 发表于 2020-4-3 08:46 | 只看该作者
岸鞍 发表于 2020-4-2 19:04
程序代码看看有没有报错,如果没报错,在protues上你试试运行一下

没有报错的,代码中我已经简化了,只需要得到计算出来的BPM,通过串口把他发送出去就行,通过上位机Processing显示波形我都省去了
回复

使用道具 举报

地板
ID:689493 发表于 2020-4-3 08:52 | 只看该作者
岸鞍 发表于 2020-4-2 19:04
程序代码看看有没有报错,如果没报错,在protues上你试试运行一下

没有报错的,其他什么传送上位机processing显示波形我都省去了,只需要通过串口传输计算出的心跳次数BPM就行,还是没有结果,我单独测试了AD功能,串口一直会收到'00 00 00 00 00'数据(是按照我预先设定时间运行的)
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表