找回密码
 注册

QQ登录

只需一步,快速开始

搜索

基于51单片机的脉搏体温血压检测仪Proteus仿真程序

[复制链接]
coolice 发表于 2020-1-23 01:01:11 | 显示全部楼层 |阅读模式
以单片机为控制核心,设计一种电子血压计,同时具有测量体温的功能。该系统利用压力传感器采集压力信号,通过温度传感器采集温度信号,整个系统包括处理模块、测量模块、信号处理模块、显示模块以及电源处理模块;血压和体温通过按键进行切换。
基本要求:
1、用Proteus完成整体硬件设计原理图;
2、基于Keil C51编写软件,编译出所需的实际程序;
3、在Proteus硬件原理图中通过仿真验证的方式确定该电子血压计的可操作性。

基于51单片机的电子血压计设计.zip (1.01 MB, 售价: 7 E币)

2.jpg 3.jpg 1.jpg
1.gif
  1. #include <reg52.h>
  2. #include <intrins.h>
  3. #include <stdio.h>

  4. #define uint            unsigned int
  5. #define uchar           unsigned char
  6. #define ulong           unsigned long         //宏定义
  7. #define LCD_DATA        P0                                 //定义P0口为LCD_DATA
  8. unsigned char getdata; //获取ADC转换回来的值
  9. unsigned char dispbuf[4];

  10. unsigned int OverCounter = 0;
  11. unsigned char ptemp;
  12. bit OverFlg = 0;
  13. unsigned int temp,ppress = 0;
  14. float  press;        
  15. char KEY_TIMES = 0;
  16. char KEY_Set_TIMES = 0;

  17. sbit LCD_RS =P2^5;
  18. sbit LCD_RW =P2^6;
  19. sbit LCD_E  =P2^7;                                                 //定义LCD控制引脚

  20. #define R24C04ADD 0xA1
  21. #define W24C04ADD 0xA0

  22. //ADC0832的引脚
  23. sbit ADCS =P2^2;  //ADC0832 chip seclect
  24. sbit ADDI =P2^4;  //ADC0832 k in
  25. sbit ADDO =P2^4;  //ADC0832 k out
  26. sbit ADCLK =P2^3;  //ADC0832 clock signal

  27. sbit KEY  =P1^7;

  28. sbit KEY_Set = P3^0;
  29. sbit KEY_ADD = P3^1;
  30. sbit KEY_DEC = P3^2;

  31. sbit speaker =P2^0;                                                 //蜂鸣器引脚定义
  32. sbit DQ=P3^7;

  33. void delay5ms(void);   //误差 0us
  34. void LCD_WriteData(uchar LCD_1602_DATA);         /********LCD1602数据写入***********/
  35. void LCD_WriteCom(uchar LCD_1602_COM);                 /********LCD1602命令写入***********/
  36. void lcd_1602_word(uchar Adress_Com,uchar Num_Adat,uchar *Adress_Data); /*1602字符显示函数,变量依次为字符显示首地址,显示字符长度,所显示的字符*/
  37. void InitLcd();//液晶初始化函数

  38. unsigned int Adc0832(unsigned char channel);
  39. void LCD1602_Write_char( unsigned char *prointer );


  40. uchar Xintiao_H=110;        //脉搏上限
  41. uint wendu=0;



  42. /*****延时子程序*****/
  43. void Delay_DS18B20(int num)
  44. {
  45.   while(num--) ;
  46. }
  47. /*****初始化DS18B20*****/
  48. void Init_DS18B20(void)
  49. {
  50.   unsigned char x=0;
  51.   DQ = 1;         //DQ复位
  52.   Delay_DS18B20(8);    //稍做延时
  53.   DQ = 0;         //单片机将DQ拉低
  54.   Delay_DS18B20(80);   //精确延时,大于480us
  55.   DQ = 1;         //拉高总线
  56.   Delay_DS18B20(34);
  57. }
  58. /*****读一个字节*****/
  59. unsigned char ReadOneChar(void)
  60. {
  61.   unsigned char i=0;
  62.   unsigned char dat = 0;
  63.   for (i=8;i>0;i--)
  64.   {
  65.     DQ = 0;     // 给脉冲信号
  66.     dat>>=1;
  67.     DQ = 1;     // 给脉冲信号
  68.     if(DQ)
  69.     dat|=0x80;
  70.     Delay_DS18B20(4);
  71.   }
  72.   return(dat);
  73. }

  74. void WriteOneChar(unsigned char dat)
  75. {
  76.   unsigned char i=0;
  77.   for (i=8; i>0; i--)
  78.   {
  79.     DQ = 0;
  80.     DQ = dat&0x01;
  81.     Delay_DS18B20(5);
  82.     DQ = 1;
  83.     dat>>=1;
  84.   }
  85. }
  86. /*****读取温度*****/
  87. unsigned int ReadTemperature(void)
  88. {
  89.   unsigned char a=0;
  90.   unsigned char b=0;
  91.   unsigned int t=0;
  92.   float tt=0;
  93.   Init_DS18B20();
  94.   WriteOneChar(0xCC);  //跳过读序号列号的操作
  95.   WriteOneChar(0x44);  //启动温度转换
  96.   Init_DS18B20();
  97.   WriteOneChar(0xCC);  //跳过读序号列号的操作
  98.   WriteOneChar(0xBE);  //读取温度寄存器
  99.   a=ReadOneChar();     //读低8位
  100.   b=ReadOneChar();    //读高8位
  101.   t=b;
  102.   t<<=8;
  103.   t=t|a;
  104.   tt=t*0.0625;
  105.   t= tt*10+0.5;     //放大10倍输出并四舍五入
  106.   return(t);
  107. }

  108. //按键扫描
  109. void KEY_SCAN( void )
  110. {
  111.         if( KEY == 0 )
  112.         {
  113.                   delay5ms();
  114.                  if( KEY == 0 )
  115.                  {
  116.                    delay5ms();
  117.                    while( !KEY );
  118.                    KEY_TIMES++;
  119.                    if( KEY_TIMES > 1 )
  120.                    {
  121.                             KEY_TIMES = 0;
  122.                    }
  123.                      LCD_WriteCom( 0x80 );
  124.                      LCD1602_Write_char("                ");
  125.                          LCD_WriteCom( 0x80+0x40 );
  126.                      LCD1602_Write_char("                ");
  127.                  }
  128.         }

  129.         if( KEY_Set == 0 )
  130.         {
  131.                   delay5ms();
  132.                  if( KEY_Set == 0 )
  133.                  {
  134.                    delay5ms();
  135.                    while( !KEY_Set );
  136.                    KEY_Set_TIMES++;
  137.                    if( KEY_Set_TIMES > 1 )
  138.                    {
  139.                             KEY_Set_TIMES = 0;
  140.                    }
  141.                      LCD_WriteCom( 0x80 );
  142.                      LCD1602_Write_char("                ");
  143.                          LCD_WriteCom( 0x80+0x40 );
  144.                      LCD1602_Write_char("                ");
  145.                 }
  146.         }
  147. }

  148. //设置心率告警值
  149. void KEY_Set_Rate( void )
  150. {
  151.            if( KEY_ADD == 0 )
  152.         {
  153.                   delay5ms();
  154.                  if( KEY_ADD == 0 )
  155.                  {
  156.                    delay5ms();
  157.                    while( !KEY_ADD );
  158.                    Xintiao_H++;
  159.                    if( Xintiao_H >= 160 )
  160.                    {
  161.                             Xintiao_H = 160;
  162.                    }
  163.                  }
  164.         }
  165.         if( KEY_DEC == 0 )
  166.         {
  167.                   delay5ms();
  168.                  if( KEY_DEC == 0 )
  169.                  {
  170.                    delay5ms();
  171.                    while( !KEY_DEC );
  172.                    Xintiao_H--;
  173.                    if( Xintiao_H <= 60 )
  174.                    {
  175.                             Xintiao_H = 60;
  176.                    }
  177.                  }
  178.         }
  179. }
  180. //=====================================================================================
  181. //=====================================================================================
  182. //=====================================================================================


  183. void main()          //主函数
  184. {
  185. InitLcd();

  186.   while(1)                          //进入循环
  187.   {
  188.           KEY_SCAN();
  189.         getdata=Adc0832(0);                                            
  190.         temp=getdata/2-5;
  191.         if( temp >  Xintiao_H )
  192.         {
  193.                  speaker = 0;
  194.         }
  195.         else
  196.         {
  197.                 speaker = 1;
  198.         }
  199.         temp = 0;
  200.          if( KEY_Set_TIMES == 0 )
  201.          {
  202.                 if( KEY_TIMES == 1 )
  203.                 {
  204.                     getdata=Adc0832(0);
  205.                   if(14<getdata<243)                                       //当压力值介于15kpa到115kpa之间时,遵循线性变换
  206.                          {                           
  207. //                                  int vary=getdata;                                                //y=(115-15)/(243-13)*X+15kpa                        
  208.                                 temp=getdata*10/2-50;                        //测试时补偿值为9.3                                                                                                         
  209. //                                temp=(int)(press*10);                  //放大10倍,便于后面的计算
  210.                             if(temp != ppress)
  211.                             {
  212.                               ppress = temp;
  213.                               OverFlg = 1;
  214.                             }                                                                                            
  215.                                 dispbuf[3]=temp/1000;                                     //取压力值百位
  216.                                 dispbuf[2]=(temp%1000)/100;                            //取压力值十位
  217.                                 dispbuf[1]=((temp%1000)%100)/10;                    //取压力值个位
  218.                                 dispbuf[0]=((temp%1000)%100)%10;                        //取压力值十分位
  219.                                 LCD_WriteCom( 0x80 );
  220.                                 LCD1602_Write_char( "   heart rate   " );
  221.                                 LCD_WriteCom( 0x80 + 0x40 );
  222.                             LCD1602_Write_char("Rate:");
  223.                                 LCD_WriteData( 0x30 + dispbuf[3] );
  224.                                 LCD_WriteData( 0x30 + dispbuf[2] );
  225.                                 LCD_WriteData( 0x30 + dispbuf[1] );
  226.                                 LCD_WriteData( '.' );
  227.                                 LCD_WriteData( 0x30 + dispbuf[0] );
  228.                         }
  229.                 }
  230.                 if( KEY_TIMES == 0 )
  231.                 {
  232.                         lcd_1602_word(0x80,16,"  temperature  ");          //初始化显示
  233.                         wendu=ReadTemperature();
  234.                         lcd_1602_word(0xc0,10," Temp:    ");//显示第二行数据
  235.                         LCD_WriteCom(0x80+0x40+10);
  236.                         LCD_WriteData(wendu/100+0x30);
  237.                         LCD_WriteData(wendu%100/10+0x30);
  238.                         LCD_WriteData('.');
  239.                         LCD_WriteData(wendu%100%10+0x30);
  240.                         LCD_WriteData(0xdf);
  241.                         LCD_WriteData('C');
  242.                 }
  243.         }
  244.         else
  245.         {
  246.                 KEY_Set_Rate();
  247.                 dispbuf[3]=Xintiao_H/100;                                         //取设置压力值百位
  248.                 dispbuf[2]=Xintiao_H%100/10;                                //取设置压力值十位
  249.                 dispbuf[1]=Xintiao_H%10;                                            //取设置压力值个位
  250.                 LCD_WriteCom( 0x80  );
  251.                 LCD1602_Write_char( " Set heart rate " );
  252.                 LCD_WriteCom( 0x80 + 0x40 );
  253.             LCD1602_Write_char("warning:");
  254.                 LCD_WriteData( 0x30 + dispbuf[3] );
  255.                 LCD_WriteData( 0x30 + dispbuf[2] );
  256.                 LCD_WriteData( 0x30 + dispbuf[1] );
  257.         }
  258.   }
  259. }


  260. /**Adress_Com显示地址,Num_Adat显示字符数量,Adress_Data显示字符串内容**/
  261. void lcd_1602_word(uchar Adress_Com,uchar Num_Adat,uchar *Adress_Data)
  262. {
  263. uchar a=0;
  264. uchar Data_Word;
  265. LCD_WriteCom(Adress_Com); //选中地址
  266. for(a=0;a<Num_Adat;a++)   //for循环决定显示字符个数
  267.   {
  268.    Data_Word=*Adress_Data;          //读取字符串数据
  269.    LCD_WriteData(Data_Word);  //显示字符串
  270.    Adress_Data++;                          //显示地址加一
  271.   }
  272. }

  273. /***************1602函数*******************/
  274. void LCD_WriteData(uchar LCD_1602_DATA)         /********LCD1602数据写入***********/
  275. {
  276. delay5ms();  //操作前短暂延时,保证信号稳定
  277. LCD_E=0;
  278. LCD_RS=1;
  279. LCD_RW=0;
  280. _nop_();
  281. LCD_E=1;
  282. LCD_DATA=LCD_1602_DATA;
  283. LCD_E=0;
  284. LCD_RS=0;
  285. }

  286. /********LCD1602命令写入***********/
  287. void LCD_WriteCom(uchar LCD_1602_COM)
  288. {
  289. delay5ms();//操作前短暂延时,保证信号稳定
  290. LCD_E=0;
  291. LCD_RS=0;
  292. LCD_RW=0;
  293. _nop_();
  294. LCD_E=1;
  295. LCD_DATA=LCD_1602_COM;
  296. LCD_E=0;
  297. LCD_RS=0;
  298. }


  299. void InitLcd()                   //初始化液晶函数
  300. {
  301. delay5ms();
  302. delay5ms();
  303. LCD_WriteCom(0x38); //display mode
  304. LCD_WriteCom(0x38); //display mode
  305. LCD_WriteCom(0x38); //display mode
  306. LCD_WriteCom(0x06); //显示光标移动位置
  307. LCD_WriteCom(0x0c); //显示开及光标设置
  308. LCD_WriteCom(0x01); //显示清屏
  309. delay5ms();
  310. delay5ms();
  311. }

  312. void delay5ms(void)   //5ms延时函数
  313. {
  314.     unsigned char a,b;
  315.     for(b=185;b>0;b--)
  316.         for(a=12;a>0;a--);
  317. }
  318. /*=========================================
  319. //LCD1602写字符串
  320. =========================================*/
  321. void LCD1602_Write_char( unsigned char *prointer )                                   //1602 字符串    处理
  322. {
  323.     while( *prointer != '\0' )
  324.     {
  325.         LCD_WriteData( *prointer );
  326.         prointer++;
  327.     }
  328. }

  329. /************
  330. 读ADC0832函数
  331. ************/

  332. //采集并返回
  333. unsigned int Adc0832(unsigned char channel)     //AD转换,返回结果
  334. {
  335.     unsigned char i=0;
  336.     unsigned char j;
  337.     unsigned int dat=0;
  338.     unsigned char ndat=0;

  339.     if(channel==0)channel=2;
  340.     if(channel==1)channel=3;
  341.     ADDI=1;
  342.     _nop_();
  343.     _nop_();
  344.     ADCS=0;//拉低CS端
  345.     _nop_();
  346.     _nop_();
  347.     ADCLK=1;//拉高CLK端
  348.     _nop_();
  349.     _nop_();
  350.     ADCLK=0;//拉低CLK端,形成下降沿1
  351.     _nop_();
  352.     _nop_();
  353.     ADCLK=1;//拉高CLK端
  354.     ADDI=channel&0x1;
  355.     _nop_();
  356.     _nop_();
  357.     ADCLK=0;//拉低CLK端,形成下降沿2
  358.     _nop_();
  359.     _nop_();
  360.     ADCLK=1;//拉高CLK端
  361.     ADDI=(channel>>1)&0x1;
  362.     _nop_();
  363.     _nop_();
  364.     ADCLK=0;//拉低CLK端,形成下降沿3
  365.     ADDI=1;//控制命令结束
  366.     _nop_();
  367.     _nop_();
  368.     dat=0;
  369.     for(i=0;i<8;i++)
  370.     {
  371.         dat|=ADDO;//收数据
  372.         ADCLK=1;
  373.         _nop_();
  374.         _nop_();
  375.         ADCLK=0;//形成一次时钟脉冲
  376.         _nop_();
  377.         _nop_();
  378.         dat<<=1;
  379.         if(i==7)dat|=ADDO;
  380.     }  
  381.     for(i=0;i<8;i++)
  382.     {
  383.         j=0;
  384.         j=j|ADDO;//收数据
  385.         ADCLK=1;
  386.         _nop_();
  387.         _nop_();
  388.         ADCLK=0;//形成一次时钟脉冲
  389.         _nop_();
  390.         _nop_();
  391.         j=j<<7;
  392.         ndat=ndat|j;
  393.         if(i<7)ndat>>=1;
  394.     }
  395.     ADCS=1;//拉低CS端
  396.     ADCLK=0;//拉低CLK端
  397.     ADDO=1;//拉高数据端,回到初始状态
  398.     dat<<=8;
  399.     dat|=ndat;
  400.     return(dat);            //return ad k
  401. }
复制代码


三厘米的雾 发表于 2023-1-5 11:02:51 | 显示全部楼层
你好大佬,我这个proteus的程序打不开
51806706f656a23be7185a064fda603.png
 楼主| coolice 发表于 2023-1-5 15:58:25 | 显示全部楼层
三厘米的雾 发表于 2023-1-5 11:02
你好大佬,我这个proteus的程序打不开

这个是因为你没有给仿真文件里的单片机关联hex文件,打开仿真文件,给图中单片机设置上hex文件即可。
hex文件在附件解压后的目录:脉搏体温检测仪+压力\脉搏体温检测仪+压力\KEIL工程
1.png 2.png 3.png 1.gif
Benett 发表于 2023-3-16 08:27:42 | 显示全部楼层
多谢分享!
nfymm 发表于 2023-6-23 17:48:50 | 显示全部楼层
您好我想问一下这个报告里面的程序是不是和keil里的程序不一样啊
 楼主| coolice 发表于 2023-6-23 21:39:32 | 显示全部楼层
nfymm 发表于 2023-6-23 17:48
您好我想问一下这个报告里面的程序是不是和keil里的程序不一样啊

这个附件之前只放了文章里所述的仿真文件和对应的c语言程序,里面后来加了个文档,这个文档只是从别处收集过来的参考内容,方便大家学习而已。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|手机版|小黑屋|ELEOK |网站地图

GMT+8, 2024-4-12 19:11

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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