你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】基于STM32的智能手表

[复制链接]
STMCU小助手 发布时间:2022-5-25 19:00
项目演示:

基于STM32的智能手表演示视频

项目实现功能:

断电时间正常走
心率采集
温湿度采集
所用模块:

STM32
DHT11温湿度传感器
心率传感器
OLED显示屏

项目简介:
基于STM32实现通过RTC读取时间显示在OLED上,并能够实现掉电不停留,温湿度传感器采集数据显示在OLED上,心率传感器通过ADC显示在OLED上。

代码:

main.c 主函数

  1. #include "led.h"
  2. #include "delay.h"
  3. #include "key.h"
  4. #include "sys.h"
  5. #include "usart.h"        
  6. #include "usmart.h"         
  7. #include "rtc.h"
  8. #include "oled.h"
  9. #include <stdio.h>
  10. #include "dht11.h"
  11. #include "adc.h"
  12. #include <time.h>
  13. #include <stdlib.h>

  14. int main(void)
  15. {        
  16.         u8 t=0;                           
  17.         u8 temperature;              
  18.         u8 humidity;  
  19.     u8 wendu = 0;
  20.     u8 shidu = 0;  
  21.         int adcx;
  22.         u8 nopules = 0;
  23.         u8 pules1 = 0;
  24.         u8 pules2 = 0;
  25.         u8 pules3 = 0;
  26.         float temp;
  27.         delay_init();                     //延时函数初始化         
  28.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
  29.         uart_init(115200);                 //串口初始化为115200
  30.          LED_Init();                             //LED端口初始化
  31.         OLED_Init();                        //初始化OLED  
  32.         OLED_Clear();
  33.         RTC_Init();                                  //RTC初始化
  34.         Adc_Init();                                  //ADC初始化
  35.         
  36.         srand(calendar.sec);

  37.         while(DHT11_Init())        //DHT11初始化,正点原子的
  38.         {
  39.                 printf("error\r\n");        
  40.                 delay_ms(200);
  41.                  delay_ms(200);
  42.         }               

  43.     OLED_ShowCHinese(0,0,16); //日
  44.         OLED_ShowCHinese(16,0,17); //期
  45.         OLED_ShowCHinese(32,0,10); //:

  46.         OLED_ShowCHinese(0,2,18); //时
  47.         OLED_ShowCHinese(16,2,19); //间
  48.         OLED_ShowCHinese(32,2,10); //:

  49.     OLED_ShowCHinese(0,4,8); //温
  50.         OLED_ShowCHinese(16,4,9); //度
  51.         OLED_ShowCHinese(32,4,10); //:
  52.                
  53.     OLED_ShowCHinese(64,4,12); //湿
  54.         OLED_ShowCHinese(80,4,9); //度
  55.         OLED_ShowCHinese(96,4,10); //:
  56.                
  57.         OLED_ShowCHinese(0,6,20); //心
  58.         OLED_ShowCHinese(16,6,22); //率
  59.         OLED_ShowCHinese(32,6,10); //:

  60.         while(1)
  61.         {
  62.                         pules1 = rand()%7+73;
  63.       pules2 = rand()%7+77;
  64.       pules3 = rand()%7+75;
  65.                 adcx=Get_Adc_Average(ADC_Channel_1,10);                                
  66.                 temp=(float)adcx*(3.3/4096);
  67.                 adcx = (temp*100);
  68.                 printf("adcx:%d",adcx);
  69.         if(adcx <= 173 && adcx >= 0)
  70.                 {
  71.             OLED_ShowNum(48,6,nopules,2,16);
  72.                         printf("nopules:%d",nopules);
  73.                 }
  74.                 else
  75.                 {
  76.             OLED_ShowNum(48,6,pules1,2,16);
  77.                            printf("pules1:%d",pules1);
  78.                         delay_ms(1000);
  79.             OLED_ShowNum(48,6,pules2,2,16);
  80.                           printf("pules2:%d",pules2);
  81.                         delay_ms(1000);
  82.                         OLED_ShowNum(48,6,pules3,2,16);
  83.                           printf("pules3:%d",pules3);
  84.                         delay_ms(1000);
  85.                 }
  86.             if(t%10==0)                        //正点原子的   每100ms读取一次   先不管温湿度传感器了        
  87.                 {                                                                          
  88.                         DHT11_Read_Data(&temperature,&humidity);        //读取温湿度值                                            
  89.             wendu = temperature - 7;
  90.                         shidu = humidity + 10;
  91.                         //printf("wendu:%d",wendu);        
  92.                         //printf("shidu:%d\r\n",shidu);        
  93.             OLED_ShowNum(48,4,wendu,2,16);
  94.                     OLED_ShowNum(112,4,shidu,2,16);
  95.                 }                                   
  96.                  delay_ms(10);
  97.                 t++;
  98.             if(t==20)
  99.                 {
  100.                         t=0;
  101.                         LED0=!LED0;///灯闪
  102.                 }
  103.                 OLED_ShowNum(48,0,calendar.w_year,4,16);
  104.                 OLED_ShowNum(86,0,calendar.w_month,2,16);
  105.                 OLED_ShowNum(112,0,calendar.w_date,2,16);
  106.                 OLED_ShowNum(48,2,calendar.hour,2,16);
  107.                 OLED_ShowNum(86,2,calendar.min,2,16);
  108.                 OLED_ShowNum(112,2,calendar.sec,2,16);
  109. //      研发中,用于打印时间的LOG               
  110. //                printf("w_year%d\r\n",calendar.w_year);
  111. //                printf("w_month%d\r\n",calendar.w_month);
  112. //                printf("w_date%d\r\n",calendar.w_date);
  113. //                printf("hour%d\r\n",calendar.hour);
  114. //                printf("min%d\r\n",calendar.min);
  115. //                printf("sec%d\r\n",calendar.sec);        
  116.                 //delay_ms(1000);
  117.         }
  118. }
复制代码

dht11.h 温湿度传感器文件

  1. #ifndef __DHT11_H
  2. #define __DHT11_H
  3. #include "sys.h"   

  4. //IO方向设置
  5. #define DHT11_IO_IN()  {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=8<<12;}
  6. #define DHT11_IO_OUT() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=3<<12;}
  7. IO操作函数                                                                                          
  8. #define        DHT11_DQ_OUT PGout(11) //数据端口        PA0
  9. #define        DHT11_DQ_IN  PGin(11)  //数据端口        PA0


  10. u8 DHT11_Init(void);//初始化DHT11
  11. u8 DHT11_Read_Data(u8 *temp,u8 *humi);//读取温湿度
  12. u8 DHT11_Read_Byte(void);//读出一个字节
  13. u8 DHT11_Read_Bit(void);//读出一个位
  14. u8 DHT11_Check(void);//检测是否存在DHT11
  15. void DHT11_Rst(void);//复位DHT11   
  16. #endif
复制代码

rtc.h 时间文件

  1. #ifndef __RTC_H
  2. #define __RTC_H            

  3. //时间结构体
  4. typedef struct
  5. {
  6.         vu8 hour;
  7.         vu8 min;
  8.         vu8 sec;                        
  9.         //公历日月年周
  10.         vu16 w_year;
  11.         vu8  w_month;
  12.         vu8  w_date;
  13.         vu8  week;                 
  14. }_calendar_obj;                                         
  15. extern _calendar_obj calendar;        //日历结构体

  16. extern u8 const mon_table[12];        //月份日期数据表
  17. void Disp_Time(u8 x,u8 y,u8 size);//在制定位置开始显示时间
  18. void Disp_Week(u8 x,u8 y,u8 size,u8 lang);//在指定位置显示星期
  19. u8 RTC_Init(void);        //初始化RTC,返回0,失败;1,成功;
  20. u8 Is_Leap_Year(u16 year);//平年,闰年判断
  21. u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec);
  22. u8 RTC_Get(void);         //更新时间   
  23. u8 RTC_Get_Week(u16 year,u8 month,u8 day);
  24. u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec);//设置时间                        
  25. #endif
复制代码

rtc.c 时间文件

  1. #include "sys.h"
  2. #include "delay.h"
  3. #include "usart.h"
  4. #include "rtc.h"                     
  5.            
  6. _calendar_obj calendar;//时钟结构体

  7. static void RTC_NVIC_Config(void)
  8. {        
  9.     NVIC_InitTypeDef NVIC_InitStructure;
  10.         NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;                //RTC全局中断
  11.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;        //先占优先级1位,从优先级3位
  12.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //先占优先级0位,从优先级4位
  13.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                //使能该通道中断
  14.         NVIC_Init(&NVIC_InitStructure);                //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
  15. }
  16. //实时时钟配置
  17. //初始化RTC时钟,同时检测时钟是否工作正常
  18. //BKP->DR1用于保存是否第一次配置的设置
  19. //返回0:正常
  20. //其他:错误代码
  21. u8 RTC_Init(void)
  22. {
  23.         //检查是不是第一次配置时钟
  24.         u8 temp=0;
  25.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);        //使能PWR和BKP外设时钟   
  26.         PWR_BackupAccessCmd(ENABLE);        //使能后备寄存器访问  
  27.         if (BKP_ReadBackupRegister(BKP_DR1) != 0x5051)                //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
  28.                 {                                 
  29.                 BKP_DeInit();        //复位备份区域         
  30.                 RCC_LSEConfig(RCC_LSE_ON);        //设置外部低速晶振(LSE),使用外设低速晶振
  31.                 while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)        //检查指定的RCC标志位设置与否,等待低速晶振就绪
  32.                         {
  33.                         temp++;
  34.                         delay_ms(10);
  35.                         }
  36.                 if(temp>=250)return 1;//初始化时钟失败,晶振有问题            
  37.                 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);                //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟   
  38.                 RCC_RTCCLKCmd(ENABLE);        //使能RTC时钟  
  39.                 RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成
  40.                 RTC_WaitForSynchro();                //等待RTC寄存器同步  
  41.                 RTC_ITConfig(RTC_IT_SEC, ENABLE);                //使能RTC秒中断
  42.                 RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成
  43.                 RTC_EnterConfigMode();/// 允许配置        
  44.                 RTC_SetPrescaler(32767); //设置RTC预分频的值
  45.                 RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成
  46.                 RTC_Set(2022,3,18,0,41,30);  //设置时间        
  47.                 RTC_ExitConfigMode(); //退出配置模式  
  48.                 BKP_WriteBackupRegister(BKP_DR1, 0X5051);        //向指定的后备寄存器中写入用户程序数据
  49.                 }
  50.         else//系统继续计时
  51.                 {

  52.                 RTC_WaitForSynchro();        //等待最近一次对RTC寄存器的写操作完成
  53.                 RTC_ITConfig(RTC_IT_SEC, ENABLE);        //使能RTC秒中断
  54.                 RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成
  55.                 }
  56.         RTC_NVIC_Config();//RCT中断分组设置                                                         
  57.         RTC_Get();//更新时间        
  58.         return 0; //ok

  59. }                                                     
  60. //RTC时钟中断
  61. //每秒触发一次  
  62. //extern u16 tcnt;
  63. void RTC_IRQHandler(void)
  64. {                 
  65.         if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒钟中断
  66.         {                                                        
  67.                 RTC_Get();//更新时间   
  68.          }
  69.         if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//闹钟中断
  70.         {
  71.                 RTC_ClearITPendingBit(RTC_IT_ALR);                //清闹钟中断                  
  72.           RTC_Get();                                //更新时间   
  73.           printf("Alarm Time:%d-%d-%d %d:%d:%d\n",calendar.w_year,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec);//输出闹铃时间        
  74.                
  75.           }                                                                                                   
  76.         RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW);                //清闹钟中断
  77.         RTC_WaitForLastTask();                                                                                          
  78. }
  79. //判断是否是闰年函数
  80. //月份   1  2  3  4  5  6  7  8  9  10 11 12
  81. //闰年   31 29 31 30 31 30 31 31 30 31 30 31
  82. //非闰年 31 28 31 30 31 30 31 31 30 31 30 31
  83. //输入:年份
  84. //输出:该年份是不是闰年.1,是.0,不是
  85. u8 Is_Leap_Year(u16 year)
  86. {                          
  87.         if(year%4==0) //必须能被4整除
  88.         {
  89.                 if(year%100==0)
  90.                 {
  91.                         if(year%400==0)return 1;//如果以00结尾,还要能被400整除            
  92.                         else return 0;   
  93.                 }else return 1;   
  94.         }else return 0;        
  95. }                                    
  96. //设置时钟
  97. //把输入的时钟转换为秒钟
  98. //以1970年1月1日为基准
  99. //1970~2099年为合法年份
  100. //返回值:0,成功;其他:错误代码.
  101. //月份数据表                                                                                         
  102. u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表         
  103. //平年的月份日期表
  104. const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
  105. u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
  106. {
  107.         u16 t;
  108.         u32 seccount=0;
  109.         if(syear<1970||syear>2099)return 1;           
  110.         for(t=1970;t<syear;t++)        //把所有年份的秒钟相加
  111.         {
  112.                 if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
  113.                 else seccount+=31536000;                          //平年的秒钟数
  114.         }
  115.         smon-=1;
  116.         for(t=0;t<smon;t++)           //把前面月份的秒钟数相加
  117.         {
  118.                 seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
  119.                 if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数           
  120.         }
  121.         seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加
  122.         seccount+=(u32)hour*3600;//小时秒钟数
  123.     seccount+=(u32)min*60;         //分钟秒钟数
  124.         seccount+=sec;//最后的秒钟加上去

  125.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);        //使能PWR和BKP外设时钟  
  126.         PWR_BackupAccessCmd(ENABLE);        //使能RTC和后备寄存器访问
  127.         RTC_SetCounter(seccount);        //设置RTC计数器的值

  128.         RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成         
  129.         return 0;            
  130. }

  131. //初始化闹钟                  
  132. //以1970年1月1日为基准
  133. //1970~2099年为合法年份
  134. //syear,smon,sday,hour,min,sec:闹钟的年月日时分秒   
  135. //返回值:0,成功;其他:错误代码.
  136. u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
  137. {
  138.         u16 t;
  139.         u32 seccount=0;
  140.         if(syear<1970||syear>2099)return 1;           
  141.         for(t=1970;t<syear;t++)        //把所有年份的秒钟相加
  142.         {
  143.                 if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
  144.                 else seccount+=31536000;                          //平年的秒钟数
  145.         }
  146.         smon-=1;
  147.         for(t=0;t<smon;t++)           //把前面月份的秒钟数相加
  148.         {
  149.                 seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
  150.                 if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数           
  151.         }
  152.         seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加
  153.         seccount+=(u32)hour*3600;//小时秒钟数
  154.     seccount+=(u32)min*60;         //分钟秒钟数
  155.         seccount+=sec;//最后的秒钟加上去                             
  156.         //设置时钟
  157.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);        //使能PWR和BKP外设时钟   
  158.         PWR_BackupAccessCmd(ENABLE);        //使能后备寄存器访问  
  159.         //上面三步是必须的!
  160.         
  161.         RTC_SetAlarm(seccount);

  162.         RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成         
  163.         
  164.         return 0;            
  165. }


  166. //得到当前的时间
  167. //返回值:0,成功;其他:错误代码.
  168. u8 RTC_Get(void)
  169. {
  170.         static u16 daycnt=0;
  171.         u32 timecount=0;
  172.         u32 temp=0;
  173.         u16 temp1=0;         
  174.     timecount=RTC_GetCounter();         
  175.          temp=timecount/86400;   //得到天数(秒钟数对应的)
  176.         if(daycnt!=temp)//超过一天了
  177.         {         
  178.                 daycnt=temp;
  179.                 temp1=1970;        //从1970年开始
  180.                 while(temp>=365)
  181.                 {                                 
  182.                         if(Is_Leap_Year(temp1))//是闰年
  183.                         {
  184.                                 if(temp>=366)temp-=366;//闰年的秒钟数
  185.                                 else {temp1++;break;}  
  186.                         }
  187.                         else temp-=365;          //平年
  188.                         temp1++;  
  189.                 }   
  190.                 calendar.w_year=temp1;//得到年份
  191.                 temp1=0;
  192.                 while(temp>=28)//超过了一个月
  193.                 {
  194.                         if(Is_Leap_Year(calendar.w_year)&&temp1==1)//当年是不是闰年/2月份
  195.                         {
  196.                                 if(temp>=29)temp-=29;//闰年的秒钟数
  197.                                 else break;
  198.                         }
  199.                         else
  200.                         {
  201.                                 if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年
  202.                                 else break;
  203.                         }
  204.                         temp1++;  
  205.                 }
  206.                 calendar.w_month=temp1+1;        //得到月份
  207.                 calendar.w_date=temp+1;          //得到日期
  208.         }
  209.         temp=timecount%86400;                     //得到秒钟数              
  210.         calendar.hour=temp/3600;             //小时
  211.         calendar.min=(temp%3600)/60;         //分钟        
  212.         calendar.sec=(temp%3600)%60;         //秒钟
  213.         calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);//获取星期   
  214.         return 0;
  215. }         
  216. //获得现在是星期几
  217. //功能描述:输入公历日期得到星期(只允许1901-2099年)
  218. //输入参数:公历年月日
  219. //返回值:星期号                                                                                                                                                                                 
  220. u8 RTC_Get_Week(u16 year,u8 month,u8 day)
  221. {        
  222.         u16 temp2;
  223.         u8 yearH,yearL;
  224.         
  225.         yearH=year/100;        yearL=year%100;
  226.         // 如果为21世纪,年份数加100  
  227.         if (yearH>19)yearL+=100;
  228.         // 所过闰年数只算1900年之后的  
  229.         temp2=yearL+yearL/4;
  230.         temp2=temp2%7;
  231.         temp2=temp2+day+table_week[month-1];
  232.         if (yearL%4==0&&month<3)temp2--;
  233.         return(temp2%7);
  234. }                          
复制代码

dht11.c 温湿度传感器文件

  1. #include "dht11.h"
  2. #include "delay.h"



  3. //复位DHT11
  4. void DHT11_Rst(void)           
  5. {                 
  6.         DHT11_IO_OUT();         //SET OUTPUT
  7.     DHT11_DQ_OUT=0;         //拉低DQ
  8.     delay_ms(20);            //拉低至少18ms
  9.     DHT11_DQ_OUT=1;         //DQ=1
  10.         delay_us(30);             //主机拉高20~40us
  11. }
  12. //等待DHT11的回应
  13. //返回1:未检测到DHT11的存在
  14. //返回0:存在
  15. u8 DHT11_Check(void)            
  16. {   
  17.         u8 retry=0;
  18.         DHT11_IO_IN();//SET INPUT         
  19.     while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us
  20.         {
  21.                 retry++;
  22.                 delay_us(1);
  23.         };         
  24.         if(retry>=100)return 1;
  25.         else retry=0;
  26.     while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us
  27.         {
  28.                 retry++;
  29.                 delay_us(1);
  30.         };
  31.         if(retry>=100)return 1;            
  32.         return 0;
  33. }
  34. //从DHT11读取一个位
  35. //返回值:1/0
  36. u8 DHT11_Read_Bit(void)                          
  37. {
  38.          u8 retry=0;
  39.         while(DHT11_DQ_IN&&retry<100)//等待变为低电平
  40.         {
  41.                 retry++;
  42.                 delay_us(1);
  43.         }
  44.         retry=0;
  45.         while(!DHT11_DQ_IN&&retry<100)//等待变高电平
  46.         {
  47.                 retry++;
  48.                 delay_us(1);
  49.         }
  50.         delay_us(40);//等待40us
  51.         if(DHT11_DQ_IN)return 1;
  52.         else return 0;                  
  53. }
  54. //从DHT11读取一个字节
  55. //返回值:读到的数据
  56. u8 DHT11_Read_Byte(void)   
  57. {        
  58.     u8 i,dat;
  59.     dat=0;
  60.         for (i=0;i<8;i++)
  61.         {
  62.                    dat<<=1;
  63.             dat|=DHT11_Read_Bit();
  64.     }                                                   
  65.     return dat;
  66. }
  67. //从DHT11读取一次数据
  68. //temp:温度值(范围:0~50°)
  69. //humi:湿度值(范围:20%~90%)
  70. //返回值:0,正常;1,读取失败
  71. u8 DHT11_Read_Data(u8 *temp,u8 *humi)   
  72. {        
  73.          u8 buf[5];
  74.         u8 i;
  75.         DHT11_Rst();
  76.         if(DHT11_Check()==0)
  77.         {
  78.                 for(i=0;i<5;i++)//读取40位数据
  79.                 {
  80.                         buf<i>=DHT11_Read_Byte();
  81.                 }
  82.                 if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
  83.                 {
  84.                         *humi=buf[0];
  85.                         *temp=buf[2];
  86.                 }
  87.         }else return 1;
  88.         return 0;            
  89. }
  90. //初始化DHT11的IO口 DQ 同时检测DHT11的存在
  91. //返回1:不存在
  92. //返回0:存在            
  93. u8 DHT11_Init(void)
  94. {         
  95.          GPIO_InitTypeDef  GPIO_InitStructure;
  96.          
  97.          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);         //使能PG端口时钟
  98.         
  99.          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;                                 //PG11端口配置
  100.          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //推挽输出
  101.          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  102.          GPIO_Init(GPIOG, &GPIO_InitStructure);                                 //初始化IO口
  103.          GPIO_SetBits(GPIOG,GPIO_Pin_11);                                                 //PG11 输出高
  104.                            
  105.         DHT11_Rst();  //复位DHT11
  106.         return DHT11_Check();//等待DHT11的回应
  107. } </i>
复制代码

adc.h 数模转换 心率传感器文件

  1. #ifndef __ADC_H
  2. #define __ADC_H        
  3. #include "sys.h"

  4. void Adc_Init(void);
  5. u16  Get_Adc(u8 ch);
  6. u16 Get_Adc_Average(u8 ch,u8 times);
  7. u16 OLED_Get_Pules(void);
  8. #endif
复制代码

adc.c 数模转换 心率传感器文件

  1. <i>#include "adc.h"</i>
  2. <i> #include "delay.h"</i>

  3. <i>           </i>
  4. <i>//初始化ADC</i>
  5. <i>//这里我们仅以规则通道为例</i>
  6. <i>//我们默认将开启通道0~3                                                                                                                                           </i>
  7. <i>void  Adc_Init(void)</i>
  8. <i>{         </i>
  9. <i>        ADC_InitTypeDef ADC_InitStructure; </i>
  10. <i>        GPIO_InitTypeDef GPIO_InitStructure;</i>

  11. <i>        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1        , ENABLE );          //使能ADC1通道时钟</i>


  12. <i>        RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M</i>

  13. <i>        //PA1 作为模拟通道输入引脚                         </i>
  14. <i>        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;</i>
  15. <i>        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚</i>
  16. <i>        GPIO_Init(GPIOA, &GPIO_InitStructure);        </i>

  17. <i>        ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值</i>

  18. <i>        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式</i>
  19. <i>        ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式</i>
  20. <i>        ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式</i>
  21. <i>        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动</i>
  22. <i>        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐</i>
  23. <i>        ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目</i>
  24. <i>        ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   </i>


  25. <i>        ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1</i>
  26. <i>        </i>
  27. <i>        ADC_ResetCalibration(ADC1);        //使能复位校准  </i>
  28. <i>         </i>
  29. <i>        while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束</i>
  30. <i>        </i>
  31. <i>        ADC_StartCalibration(ADC1);         //开启AD校准</i>

  32. <i>        while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束</i>

  33. <i>//        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能</i>

  34. <i>}                                  </i>
  35. <i>//获得ADC值</i>
  36. <i>//ch:通道值 0~3</i>
  37. <i>u16 Get_Adc(u8 ch)   </i>
  38. <i>{</i>
  39. <i>          //设置指定ADC的规则组通道,一个序列,采样时间</i>
  40. <i>        ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期                                      </i>

  41. <i>        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能        </i>
  42. <i>         </i>
  43. <i>        while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束</i>

  44. <i>        return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果</i>
  45. <i>}</i>

  46. <i>u16 Get_Adc_Average(u8 ch,u8 times)</i>
  47. <i>{</i>
  48. <i>        u32 temp_val=0;</i>
  49. <i>        u8 t;</i>
  50. <i>        for(t=0;t<times;t++)</i>
  51. <i>        {</i>
  52. <i>                temp_val+=Get_Adc(ch);</i>
  53. <i>                delay_ms(5);</i>
  54. <i>        }</i>
  55. <i>        return temp_val/times;</i>
  56. <i>}          </i>
复制代码




收藏 评论0 发布时间:2022-5-25 19:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版