找回密码
 立即注册

QQ登录

只需一步,快速开始

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

基于单片机的脉搏测量仪设计

[复制链接]
跳转到指定楼层
楼主
ID:918467 发表于 2021-5-12 19:32 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  1. #include <reg52.h>                 //调用单片机头文件
  2. #define uchar unsigned char  //无符号字符型 宏定义        变量范围0~255
  3. #define uint  unsigned int         //无符号整型 宏定义        变量范围0~65535
  4. #include <intrins.h>
  5. #include "eeprom52.h"

  6. sbit beep = P2^0;   //蜂鸣器IO口定义

  7. sbit k1 = P1^3;
  8. sbit k2 = P1^4;
  9. sbit k3 = P1^5;

  10. bit flag_300ms ;
  11. uchar flag_en;

  12. uchar code table_num[]="0123456789abcdefg";

  13. sbit rs=P1^0;         //寄存器选择信号 H:数据寄存器          L:指令寄存器
  14. sbit rw=P1^1;         //寄存器选择信号 H:数据寄存器          L:指令寄存器
  15. sbit e =P1^2;         //片选信号   下降沿触发

  16. char flag=0,bj=90;
  17. unsigned char i=0,timecount=0,displayOK=0,aa=0;
  18. float time[6]={0};
  19. uint rate;

  20. float rate1[6];


  21. /***********************1ms延时函数*****************************/
  22. void delay_1ms(uint q)
  23. {
  24.         uint i,j;
  25.         for(i=0;i<q;i++)
  26.                 for(j=0;j<110;j++);
  27. }


  28. /********************************************************************
  29. * 名称 : delay_uint()
  30. * 功能 : 小延时。
  31. * 输入 : 无
  32. * 输出 : 无
  33. ***********************************************************************/
  34. void delay_uint(uint q)
  35. {
  36.         while(q--);
  37. }

  38. /******************把数据保存到单片机内部eeprom中******************/
  39. void write_eeprom()
  40. {
  41.         SectorErase(0x2000);
  42.         byte_write(0x2000, bj % 256);
  43.         byte_write(0x2001, bj / 256);
  44.         byte_write(0x2058, a_a);       
  45. }

  46. /******************把数据从单片机内部eeprom中读出来*****************/
  47. void read_eeprom()
  48. {
  49.         bj  = byte_read(0x2001);
  50.         bj<<= 8;
  51.         bj  |= byte_read(0x2000);
  52.         a_a      = byte_read(0x2058);
  53. }

  54. /**************开机自检eeprom初始化*****************/
  55. void init_eeprom()
  56. {
  57.         read_eeprom();                //先读
  58.         if(a_a != 1)                //新的单片机初始单片机内问eeprom
  59.         {
  60.                 bj = 95;
  61.                 a_a = 1;
  62.                 write_eeprom();           //保存数据
  63.         }       
  64. }


  65. /********************************************************************
  66. * 名称 : write_com(uchar com)
  67. * 功能 : 1602命令函数
  68. * 输入 : 输入的命令值
  69. * 输出 : 无
  70. ***********************************************************************/
  71. void write_com(uchar com)
  72. {
  73.         e=0;
  74.         rs=0;
  75.         rw=0;
  76.         P0=com;
  77.         delay_uint(25);
  78.         e=1;
  79.         delay_uint(100);
  80.         e=0;
  81. }

  82. /********************************************************************
  83. * 名称 : write_data(uchar dat)
  84. * 功能 : 1602写数据函数
  85. * 输入 : 需要写入1602的数据
  86. * 输出 : 无
  87. ***********************************************************************/
  88. void write_data(uchar dat)
  89. {
  90.         e=0;
  91.         rs=1;
  92.         rw=0;
  93.         P0=dat;
  94.         delay_uint(25);
  95.         e=1;
  96.         delay_uint(100);
  97.         e=0;       
  98. }

  99. /********************************************************************
  100. * 名称 : write_string(uchar hang,uchar add,uchar *p)
  101. * 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符开始显示"ab cd ef" ,调用该函数如下
  102.                   write_string(1,5,"ab cd ef;")
  103. * 输入 : 行,列,需要输入1602的数据
  104. * 输出 : 无
  105. ***********************************************************************/
  106. void write_string(uchar hang,uchar add,uchar *p)
  107. {
  108.         if(hang==1)   
  109.                 write_com(0x80+add);
  110.         else
  111.                 write_com(0x80+0x40+add);
  112.         while(1)
  113.         {
  114.                 if(*p == '\0')  break;
  115.                 write_data(*p);
  116.                 p++;
  117.         }       
  118. }

  119. /***********************lcd1602上显示特定的字符************************/
  120. void write_zifu(uchar hang,uchar add,uchar date)
  121. {
  122.         if(hang==1)   
  123.                 write_com(0x80+add);
  124.         else
  125.                 write_com(0x80+0x40+add);
  126.         write_data(date);       
  127. }

  128. /***********************lcd1602上显示两位十进制数************************/
  129. void write_sfm3(uchar hang,uchar add,uint date)
  130. {
  131.         if(hang==1)   
  132.                 write_com(0x80+add);
  133.         else
  134.                 write_com(0x80+0x40+add);
  135.         write_data(0x30+date/100%10);
  136.         write_data(0x30+date/10%10);
  137.         write_data(0x30+date%10);       
  138. }

  139. /***********************lcd1602上显示两位十进制数************************/
  140. void write_sfm1(uchar hang,uchar add,uint date)
  141. {
  142.         if(hang==1)   
  143.                 write_com(0x80+add);
  144.         else
  145.                 write_com(0x80+0x40+add);
  146.         write_data(0x30+date%10);       
  147. }

  148. /***********************lcd1602初始化设置************************/
  149. void init_1602()
  150. {
  151.         write_com(0x38);        //设置显示模式
  152.         write_com(0x0c);  //开显示不显示光标,光标不闪烁
  153.         write_com(0x06);  //写一个数据,指针加1
  154.         delay_uint(1000);
  155.         write_string(1,0,"   Heart Rate     ");       
  156.         write_string(2,0,"     000/min       ");
  157. }

  158. /*************定时器0初始化程序***************/
  159. void time_init()          
  160. {
  161.         EA   = 1;                   //开总中断
  162.         TMOD = 0X01;          //定时器0、定时器1工作方式1
  163.         ET0  = 1;                  //开定时器0中断
  164.         TR0  = 1;                  //允许定时器0定时
  165. }


  166. /***********外部中断0初始化程序****************/
  167. void init_int0()          //外部中断0初始化程序
  168. {
  169.         EX0=1;                          //允许外部中断0中断
  170.         EA=1;                           //开总中断
  171.         IT0 = 1;                   //外部中断0负跳变中断
  172. }

  173.        
  174. /************ 排序***************/
  175. void pingjun_zhi(float *p)
  176. {
  177.         static float value;
  178.         static uchar i,j;
  179.         for(j=1;j<5;j++)                   //先对整个数组的5个值进行从小到大的排列
  180.                 for(i=0;i<5 - j;i++)
  181.                 {
  182.                         if(p[i] > p[i+1])
  183.                         {
  184.                                 value = p[i];
  185.                                 p[i] = p[i+1];
  186.                                 p[i+1] = value;               
  187.                         }       
  188.                 }
  189. }

  190. void key()
  191. {
  192.         if(k1==0)
  193.         {
  194.                 while(k1==0);
  195.                 flag++;
  196.                 if(flag==2){flag=0;write_eeprom();}
  197.                 if(flag==0)
  198.                 {
  199.                         write_string(1,0,"   Heart Rate   ");       
  200.                         write_string(2,0,"     000/min    ");               
  201.                 }
  202.                 if(flag==1)
  203.                 {
  204.                         write_string(1,0,"   set Rate     ");       
  205.                         write_string(2,0,"     000/min    ");               
  206.                 }
  207.         }
  208.         if(flag==1)
  209.         {
  210.                 if(k2==0)
  211.                 {
  212.                         while(k2==0);
  213.                         if(bj<99)bj++;
  214.                 }
  215.                 if(k3==0)
  216.                 {
  217.                         while(k3==0);
  218.                         if(bj>5) bj--;
  219.                 }
  220.         }
  221. }
  222. uchar flag_value;

  223. /****************主函数***************/
  224. void main()
  225. {       
  226.         beep = 0;                                //开机叫一声   
  227.         delay_1ms(150);
  228.         P0 = P1 = P2 = P3 = 0xff;
  229.         init_1602();                    //1602初始化
  230.         time_init();                    //初始化定时器
  231.         init_int0();          //外部中断0初始化程序
  232.         init_eeprom();
  233.         while(1)
  234.         {
  235.                 key();
  236.                 if(flag==0)
  237.                 {
  238.                         if(displayOK==0)//如果显示关
  239.                         {
  240.                                  rate = 0;
  241.                                 flag_value = 0;
  242.                         }
  243.                         else//如果显示开
  244.                         {
  245.                                 if(flag_en == 1)
  246.                                 {
  247.                                         flag_en = 0;
  248.                                         flag_value ++;
  249.                                         if(flag_value == 1)
  250.                                                 rate1[0]=60000/(time[1]/5+time[2]/5+time[3]/5+time[4]/5+time[5]/5);
  251.                                         if(flag_value == 2)
  252.                                                 rate1[1]=60000/(time[1]/5+time[2]/5+time[3]/5+time[4]/5+time[5]/5);
  253.                                         if(flag_value == 3)
  254.                                                 rate1[2]=60000/(time[1]/5+time[2]/5+time[3]/5+time[4]/5+time[5]/5);
  255.                                         if(flag_value == 4)
  256.                                                 rate1[3]=60000/(time[1]/5+time[2]/5+time[3]/5+time[4]/5+time[5]/5);
  257.                                         if(flag_value >= 5)
  258.                                         {
  259.                                                 rate1[4]=60000/(time[1]/5+time[2]/5+time[3]/5+time[4]/5+time[5]/5);
  260.                                
  261.                                                 pingjun_zhi(rate1);
  262.                                                 flag_value = 0;
  263.                                                 rate = (rate1[1] / 3 + rate1[2] / 3 + rate1[3] / 3);
  264.                                         }
  265.                                 }
  266.                         }
  267.        
  268.                         write_sfm3(2,5,rate);
  269.                        
  270.                         if(rate>bj)beep=0;
  271.                         else beep=1;       
  272.                 }                       

  273.                 if(flag==1)
  274.                 {
  275.                         write_sfm3(2,5,bj);
  276.                 }


  277. //                write_sfm3(1,13,b1);
  278. //                write_sfm3(1,14,b2);
  279. //                write_sfm3(1,15,b3);
  280.                 delay_1ms(300);
  281.         }
  282. }
  283. /************外部0中断服务程序***************/
  284. void int0() interrupt 0
  285. {
  286.         static uchar value;
  287.                 EX0=0;//暂时关外部中断
  288.                 if(timecount<8)   //当连续两次检测时间间隔小于8*50ms=400ms不处理
  289.                 {
  290.                         value ++;
  291.                         if(value >= 4)
  292.                         {
  293.                                 value = 0;
  294. //                                flag_value = 0;
  295.                         }       
  296.                         TR0=1;//开定时器
  297.                 }
  298.                 else if(timecount <= 18)
  299.                 {       
  300.                         value = 0;
  301.                         time[i]=timecount*50+TH0*0.256+TL0/1000;//算出间隔时间

  302.                         TH0 = 0x3c;
  303.                         TL0 = 0xb0;     // 50ms         12M
  304.                         timecount=0;//50ms计数清零
  305.                         i++;
  306.                         flag_en = 1;
  307.                         if(i==6)//记录到超过等于6次时间
  308.                         {
  309.                                 i=1;//计数从1开始
  310.                                 displayOK=1;    //测得5次开始显示?
  311.                         }                                                               
  312.                 } else
  313.                 {
  314.                         flag_value = 0;
  315.                         timecount = 0;
  316.                 }
  317.                 EX0=1;
  318. }
  319. /*************定时器0中断服务程序***************/
  320. void time0_int() interrupt 1
  321. {       
  322.         TH0 = 0x3c;
  323.         TL0 = 0xb0;     // 50ms         12M
  324.         timecount++;//每50ms一次计数
  325.         if(timecount>70)     //当超过25*50ms=1.5s没有检测到信号停止显示
  326.         {
  327.                         i=0;//数据个数清零
  328.                         timecount=0;//50ms计数清零
  329.                         displayOK=0;//显示关
  330.                         TR0=0;//定时器关
  331.                         TH0 = 0x3c;
  332.                         TL0 = 0xb0;     // 50ms         12M
  333.         }
  334. }
复制代码

系统总体设计由STC89C52、按键、LCD1602、光电传感器、时钟模块、运放等构成,系统设有四个按键,可以设置上下限脉搏数,当超过范围的时候单片机会驱动蜂鸣器发响,脉搏测量的时候需要人把手轻轻的按在光电传感器上面,由于人脉搏跳动的时候,血液的透光性不一样会导致接收器那边接收的信号强弱不一样,间接的把人脉搏信号传回,通过运放对其进行放大、整形后连接到单片机的IO口,单片机利用外部中断对其进行计数,最终换算成人一分钟脉搏的跳动次数,最终显示在液晶屏上。

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

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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