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

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

[复制链接]
STMCU小助手 发布时间:2022-5-25 19:00
项目演示:
! I. ?0 J) E! b  _
9 T$ u! i" k4 |5 \# f8 }基于STM32的智能手表演示视频
3 s2 c  T. k. Q4 [0 \6 w" _" E
" N2 |0 H. c3 S8 r7 }项目实现功能:& a9 M9 ^0 c2 u* ~, M# v. d/ d1 i
6 ~) F! X% t4 V+ X, Q8 ?2 F
断电时间正常走8 i  V% I) i: [3 Q
心率采集
6 t+ \8 N" ^  r温湿度采集
  I* w+ j/ n* ~5 |8 N, ~所用模块:! i/ ~" R7 @+ E/ c/ X- T

& t  G$ h" l, W: H! n( U' ESTM32
, t' G) S( L, A; [/ C+ G$ x, aDHT11温湿度传感器
8 X) I! f8 _) y7 n心率传感器
. _% q4 \8 Q1 L$ b$ F* }; a6 oOLED显示屏: A+ i8 T, j( l7 d: ], c" _+ ?

+ B2 q& C2 m/ h' \3 `项目简介:# }. i" ]2 D# b/ {1 Z0 _% T/ @
基于STM32实现通过RTC读取时间显示在OLED上,并能够实现掉电不停留,温湿度传感器采集数据显示在OLED上,心率传感器通过ADC显示在OLED上。! ^3 y) d' `: R/ Z

+ a( J3 |- Z+ c0 e" L5 e. L代码:! M' H/ n! l1 x4 w$ h: _) t# n( p

' U& G4 C# ]* k5 p+ }3 Emain.c 主函数
" K" e4 f- @0 ^, _. R; J- \. S! B2 {; d+ I
  1. #include "led.h"
    1 a/ F9 N( {( ~" z* t
  2. #include "delay.h"
    % e9 S4 i- {! |! }5 ^
  3. #include "key.h"
    # |- D8 y" T) R- w0 |& {6 @
  4. #include "sys.h"& }- O6 T" c$ K; S- y  [. Q$ L4 u
  5. #include "usart.h"        
    ; @. y7 L" y/ E4 c
  6. #include "usmart.h"         
    9 @5 u& @; i# M4 H8 ?. F
  7. #include "rtc.h"
    " [2 H3 C# i+ J2 R
  8. #include "oled.h") L- N" I4 z4 \  i- q: i% L% B2 C& m
  9. #include <stdio.h>
    ; B" \: D3 @, {" e. a' q
  10. #include "dht11.h"; F8 ~6 Y% N& }4 r% h1 U
  11. #include "adc.h"
    % X& Q/ ~8 \  {' F1 t7 ?
  12. #include <time.h>9 [( M% _" \- d! O% k
  13. #include <stdlib.h>
    8 Q' s5 y& n2 k

  14. 2 v6 w5 E5 i# x6 Y# V
  15. int main(void)
    / k9 z% g3 n- ^! g6 ^, J7 q
  16. {        . D, s/ {; y% L; R" ?
  17.         u8 t=0;                            5 x' Y( s% f/ R5 W3 o/ N9 ?% M$ {2 Q
  18.         u8 temperature;              8 S" e1 O" |+ y
  19.         u8 humidity;  
    . p: n, X7 J+ J  V" }7 u5 U" R/ h5 {8 s
  20.     u8 wendu = 0;1 W8 k3 u; P7 j2 `" k
  21.     u8 shidu = 0;  
    3 s) A8 r8 Y7 A# T+ ?
  22.         int adcx;
    " V2 E2 b$ g8 h: Z
  23.         u8 nopules = 0;
    , e, k% Y, P) J& X! R- l1 k
  24.         u8 pules1 = 0;
    : r! K+ M* i( \
  25.         u8 pules2 = 0; 3 |, U1 M3 s5 v" T( Y+ T5 a
  26.         u8 pules3 = 0;
    4 R! I' t: R+ `# W
  27.         float temp;8 E; ~6 p9 N2 _
  28.         delay_init();                     //延时函数初始化          1 D* u7 o6 x$ S8 ?3 b7 b+ D3 X
  29.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
    ) W  I; f3 o6 _. e: G2 |6 h5 v. }
  30.         uart_init(115200);                 //串口初始化为1152001 Z: i( Y2 U4 s! Z
  31.          LED_Init();                             //LED端口初始化7 J3 |6 z, |9 d6 z
  32.         OLED_Init();                        //初始化OLED  + |6 C1 V0 G" B, n* k6 Y$ x# l
  33.         OLED_Clear();- H8 j) V  |2 I
  34.         RTC_Init();                                  //RTC初始化
    1 W8 E4 X0 l$ c% p, @+ z
  35.         Adc_Init();                                  //ADC初始化
    / k& @/ y. c; d- m3 d
  36.         
    * H7 `9 p* [9 X
  37.         srand(calendar.sec);- E+ b7 M4 a9 d

  38. ! y; e5 d! x" `7 M& L6 Q; d
  39.         while(DHT11_Init())        //DHT11初始化,正点原子的. f" ~2 g: j; S$ M# m
  40.         {
    + w  ?6 X& A0 B/ i! ?
  41.                 printf("error\r\n");        
    ) w2 e) D' p# _! N
  42.                 delay_ms(200);, n2 }1 _+ M) T4 @# H  O
  43.                  delay_ms(200);' i. g) u  w# b2 H4 V: [% f9 z- v7 z
  44.         }                / W3 Y2 S1 z9 U3 k1 S
  45. * \; w+ z+ a- {: Z  @1 m0 E- M# ]
  46.     OLED_ShowCHinese(0,0,16); //日
    3 Y0 D# x7 e% k: y
  47.         OLED_ShowCHinese(16,0,17); //期8 |: t& j! E; W. B
  48.         OLED_ShowCHinese(32,0,10); //:' e. K+ U$ u" }# @

  49. 4 X0 H& @  G" X% P7 \2 T$ d) G
  50.         OLED_ShowCHinese(0,2,18); //时9 m  _: j5 q9 k; }6 I* _
  51.         OLED_ShowCHinese(16,2,19); //间
    6 P+ l) f4 O8 \% u5 k/ m
  52.         OLED_ShowCHinese(32,2,10); //:9 ?4 n# n3 j8 g5 p/ G  a( P$ ~
  53. 8 x. W& W) V" @1 G0 [
  54.     OLED_ShowCHinese(0,4,8); //温
    0 l" l) x% {! B: C
  55.         OLED_ShowCHinese(16,4,9); //度
    9 R1 P, f* x- i/ ^0 S: @: K
  56.         OLED_ShowCHinese(32,4,10); //:$ D( Y  s1 C0 q5 [8 ~7 w4 m
  57.                
    . h+ ?+ X: }! z6 g4 H/ y
  58.     OLED_ShowCHinese(64,4,12); //湿( Y$ W* n5 x8 @
  59.         OLED_ShowCHinese(80,4,9); //度
    $ i# ~0 s# G$ e8 F2 s6 L# u/ {
  60.         OLED_ShowCHinese(96,4,10); //:  m& x! {1 N4 D$ s
  61.                 9 C0 G# b" ?+ K- v7 x. ^
  62.         OLED_ShowCHinese(0,6,20); //心. F7 ]/ W8 Z3 G" O
  63.         OLED_ShowCHinese(16,6,22); //率( U/ Z3 \. X# i) m
  64.         OLED_ShowCHinese(32,6,10); //:$ b+ p: \+ `+ O8 S+ d) \0 w& i

  65. 5 b" c+ p) S% N; _6 c$ m2 ~+ Z! {4 e
  66.         while(1)
    * |& E2 l  p: }& b# _4 ~( i( F
  67.         {
    * H5 A& Y: N: Z% P/ c& ]
  68.                         pules1 = rand()%7+73;
    * H  c3 ~, Y! t
  69.       pules2 = rand()%7+77;6 H2 f( S$ z. C. B9 b
  70.       pules3 = rand()%7+75;9 k1 w& ]9 ^5 K
  71.                 adcx=Get_Adc_Average(ADC_Channel_1,10);                                
    / H1 ^* Y$ M9 w( v5 d) N
  72.                 temp=(float)adcx*(3.3/4096);4 r0 }$ T$ ]# |, M' `$ t
  73.                 adcx = (temp*100);
    / ^, r& l5 G8 u$ R7 \$ F. c
  74.                 printf("adcx:%d",adcx);# Z: a: ?: w' f, z5 g3 @! k8 |
  75.         if(adcx <= 173 && adcx >= 0)
    - M2 e! v* {. O3 w5 x2 f% x
  76.                 {6 U) X. V( z5 t( M6 X7 o
  77.             OLED_ShowNum(48,6,nopules,2,16);
    # o$ w, p' K2 }; N% }
  78.                         printf("nopules:%d",nopules);
    / s' ~2 ~% x8 c6 F- H. e% N
  79.                 }- W7 j+ B. J* e
  80.                 else! ~# f: L! i1 L
  81.                 {" b2 r1 W" L) H% F2 ?! p
  82.             OLED_ShowNum(48,6,pules1,2,16);6 X; _( ?  z( a* [, [! a5 x( ^
  83.                            printf("pules1:%d",pules1);) F7 J4 W3 H  q" t
  84.                         delay_ms(1000);" j5 P6 |6 t5 M
  85.             OLED_ShowNum(48,6,pules2,2,16);2 |$ t, ^: P- i1 `: s" I% J5 c' T' y
  86.                           printf("pules2:%d",pules2);# X, M, T3 f! h
  87.                         delay_ms(1000);8 W( k9 D0 H9 r- A7 {0 i' z4 Q' @- Y
  88.                         OLED_ShowNum(48,6,pules3,2,16);6 j( i" Q7 e& z8 p, l/ ]
  89.                           printf("pules3:%d",pules3);0 e& I  E% |' y7 x1 h; C" j( l
  90.                         delay_ms(1000);5 x; w; i( [% W) h0 q. S, M0 s
  91.                 }  k& d# [; R! x/ f% |: D, L
  92.             if(t%10==0)                        //正点原子的   每100ms读取一次   先不管温湿度传感器了        
    1 Z$ |1 s9 [3 f  r' s
  93.                 {                                                                          5 |7 i! R' w/ Q* D( r# I( ^8 o; k
  94.                         DHT11_Read_Data(&temperature,&humidity);        //读取温湿度值                                            # e* h/ U; u$ L  X
  95.             wendu = temperature - 7;7 D1 h8 X, Y' h
  96.                         shidu = humidity + 10;; P/ j/ M8 o! |! }8 w
  97.                         //printf("wendu:%d",wendu);        
    - I6 Z; {( {3 p, m; B' K6 a+ L" [
  98.                         //printf("shidu:%d\r\n",shidu);        + K* n1 y& d2 P) j, H
  99.             OLED_ShowNum(48,4,wendu,2,16);
    & q6 v# n* `" J" `5 [
  100.                     OLED_ShowNum(112,4,shidu,2,16);
    3 ^2 c  @& h6 g" u
  101.                 }                                   
      ]9 U6 q: M$ F, k8 C) P1 Q
  102.                  delay_ms(10);" t8 F( O  T0 d; ^4 D- B
  103.                 t++;
    , O) c1 s( C( n
  104.             if(t==20)! ~2 V; z# N7 z/ g8 U- g
  105.                 {
    7 r0 ?4 m! P, P& M5 U8 X
  106.                         t=0;$ c6 J& T, t# O
  107.                         LED0=!LED0;///灯闪
    2 w/ ~0 o! V! o, T  ^/ n4 U. ~
  108.                 }. \" n8 R+ P$ I# \8 d
  109.                 OLED_ShowNum(48,0,calendar.w_year,4,16);
    2 h# q' S- D2 O+ w/ C
  110.                 OLED_ShowNum(86,0,calendar.w_month,2,16);
    + E5 l& d8 B- g/ |) t
  111.                 OLED_ShowNum(112,0,calendar.w_date,2,16);
    + E4 w5 Y: P+ E8 E2 P' H7 H
  112.                 OLED_ShowNum(48,2,calendar.hour,2,16);; F  |0 |; P& c& m
  113.                 OLED_ShowNum(86,2,calendar.min,2,16);; ^& {+ x* o2 }7 m
  114.                 OLED_ShowNum(112,2,calendar.sec,2,16);
    ' z( i5 H$ j# E! I0 M3 r
  115. //      研发中,用于打印时间的LOG               
    5 C- N1 W) A; y4 v* r0 Z8 }
  116. //                printf("w_year%d\r\n",calendar.w_year);9 |; F. ]+ S; X
  117. //                printf("w_month%d\r\n",calendar.w_month);
    ; r/ k: n; P. u
  118. //                printf("w_date%d\r\n",calendar.w_date);; n$ J6 U9 C- \! `5 o; n6 {" E
  119. //                printf("hour%d\r\n",calendar.hour);
    - ?  t7 P( |% u5 n
  120. //                printf("min%d\r\n",calendar.min);6 q! Q; {+ ~6 \1 S! F
  121. //                printf("sec%d\r\n",calendar.sec);        
    : n: u( h8 P, c6 s: q
  122.                 //delay_ms(1000);
    9 ~: X. Z# K! A" ^
  123.         }/ e7 n! S( E: \
  124. }
复制代码
" {( l  U' g; d( x1 O; [0 W
dht11.h 温湿度传感器文件
# V5 D; H0 O  A2 D$ i
0 m9 G) A& O2 N! k- h; z: k
  1. #ifndef __DHT11_H6 U, ?) Y, j1 z) M; P
  2. #define __DHT11_H " s. B  ]4 R) @) Z- n+ c& U  S
  3. #include "sys.h"   
    7 C2 R( K' h1 A! k( v% K
  4. 7 B# m1 t8 a! A
  5. //IO方向设置
    ! w5 z9 _: {; U
  6. #define DHT11_IO_IN()  {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=8<<12;}
    % {- M0 ?- H2 v: w/ c
  7. #define DHT11_IO_OUT() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=3<<12;}
    - r% W- s$ q/ j. m& ]- F
  8. IO操作函数                                                                                          
    8 o* ^$ o9 K. o4 H# Z% Z+ }
  9. #define        DHT11_DQ_OUT PGout(11) //数据端口        PA0
    . \2 n. g( s/ T) ^
  10. #define        DHT11_DQ_IN  PGin(11)  //数据端口        PA0 5 l8 d; }9 Z2 Q3 _
  11. , N0 g9 h" r9 [! F4 K  D2 R

  12. 3 n( i3 ]: \  W1 O1 F- |
  13. u8 DHT11_Init(void);//初始化DHT11+ `# m7 b; v" `/ n- Z( M
  14. u8 DHT11_Read_Data(u8 *temp,u8 *humi);//读取温湿度
    $ S. g4 h; |1 ^# l. @
  15. u8 DHT11_Read_Byte(void);//读出一个字节
    . o, w3 o, _7 b7 K& a+ I4 Y# c- ^  M
  16. u8 DHT11_Read_Bit(void);//读出一个位
    : u# W4 O' E, l9 ~6 D9 H/ N2 \
  17. u8 DHT11_Check(void);//检测是否存在DHT11
    3 q* P% o2 R1 a/ i) E) ^1 a- L4 q4 z0 I
  18. void DHT11_Rst(void);//复位DHT11    $ @$ n$ Z, A% ]% M
  19. #endif
复制代码

* k) I) q6 i0 l# r" o4 N9 @rtc.h 时间文件; G. X+ ~5 o0 p  u
. U/ @* _& m* J0 ?( J1 ?6 H  h3 d
  1. #ifndef __RTC_H4 g/ J: x  N) I
  2. #define __RTC_H            ) }( D9 ~) [* J6 f( `. Z- N

  3. / B( u( \- J& L( Y5 X9 T
  4. //时间结构体: `; |( v, ?' n
  5. typedef struct 3 ^% W6 Z6 M# C0 I+ a% m' o# J+ T
  6. {
    / f) n% o9 ]4 x  ^
  7.         vu8 hour;
    1 c9 H; ]4 {7 _: b: E3 ~+ \1 z5 Z
  8.         vu8 min;
    8 b1 X5 ^; |" d3 _; Y0 o
  9.         vu8 sec;                        
    9 f6 Y/ E- e& r8 D
  10.         //公历日月年周- N/ x: S- n! k5 q$ {/ N0 K! d
  11.         vu16 w_year;9 p$ X! X$ Y. R) B
  12.         vu8  w_month;
    ; W/ R. X. C  n4 ?: t) o  V  h
  13.         vu8  w_date;3 G% \3 _' M; k5 u( v) S
  14.         vu8  week;                 
    ! d3 ]* F/ Z6 s
  15. }_calendar_obj;                                         * K& L( t' v: _6 V6 |1 K, I
  16. extern _calendar_obj calendar;        //日历结构体
    0 z3 R- U( t0 k" Z6 y
  17. + ]  S2 I" _7 t: w2 V  t) Z- n* j
  18. extern u8 const mon_table[12];        //月份日期数据表
    / A. d& }; `. @/ i4 c) W7 R0 U
  19. void Disp_Time(u8 x,u8 y,u8 size);//在制定位置开始显示时间
    % W, f8 c/ X- v# ]3 Z8 U6 Z/ W0 Q
  20. void Disp_Week(u8 x,u8 y,u8 size,u8 lang);//在指定位置显示星期  P2 f, \/ o2 m  N0 j& J
  21. u8 RTC_Init(void);        //初始化RTC,返回0,失败;1,成功;
    - \/ c6 Y" S6 N: h) |9 h
  22. u8 Is_Leap_Year(u16 year);//平年,闰年判断- q7 v% `  O2 C" i1 H
  23. u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec);
    . [: y3 [4 s/ Z
  24. u8 RTC_Get(void);         //更新时间   
    8 q8 X! M% _* Q5 _5 O
  25. u8 RTC_Get_Week(u16 year,u8 month,u8 day);5 U; c# q" y7 ~* p% P% |
  26. u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec);//设置时间                         ' j; D9 m: p" m9 L
  27. #endif
复制代码

/ [& l- w1 [% r6 jrtc.c 时间文件) c7 E( r3 q4 V+ J, ?/ N
& N: S9 H* b, {9 n
  1. #include "sys.h"' W; f# z, p6 {& s+ I+ z
  2. #include "delay.h"
    8 r  t/ v3 v6 M/ _  G- M' K
  3. #include "usart.h"
    9 z( B9 o$ B3 w  l. K  S
  4. #include "rtc.h"                     
    ! t2 R0 A; }) X7 b
  5.            2 k# s" R( `5 n1 ]
  6. _calendar_obj calendar;//时钟结构体
    $ ^- o8 G" I8 h: q8 i3 Z

  7. , M$ @; k& b( m) t1 @
  8. static void RTC_NVIC_Config(void)
    - E8 {9 Q+ j$ w6 |" c% g
  9. {        
    : m, `# v8 N( g
  10.     NVIC_InitTypeDef NVIC_InitStructure;
    & Z3 F; h( c4 I8 |5 l
  11.         NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;                //RTC全局中断
    1 X  E' Z+ B" K, w7 L
  12.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;        //先占优先级1位,从优先级3位4 X" z# p9 u" V
  13.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //先占优先级0位,从优先级4位
    , _1 v8 a% P' ~6 |! S- ~) Q
  14.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                //使能该通道中断  X* Q+ |) x7 v" k8 _) G; n( D9 N
  15.         NVIC_Init(&NVIC_InitStructure);                //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
    - E9 |; Z) [2 _# y- ~- V
  16. }
    6 e- L4 [' O  S9 }: n5 x
  17. //实时时钟配置* e0 ]( Y, v' [
  18. //初始化RTC时钟,同时检测时钟是否工作正常. p1 d) m4 W5 P" P, d2 c( N
  19. //BKP->DR1用于保存是否第一次配置的设置8 K0 I4 z0 }7 n6 @
  20. //返回0:正常
    , n- \; E. n1 \
  21. //其他:错误代码& ^0 p# l  S  f0 w: x$ h8 H5 q3 X
  22. u8 RTC_Init(void)
    $ N- q- B& [8 v( f5 V
  23. {$ z/ K$ P8 H# U7 S7 w) o* Y! U' S' U
  24.         //检查是不是第一次配置时钟
    3 ]1 h5 R5 m+ ?& Q$ G+ {
  25.         u8 temp=0;2 i: w6 r! h2 X6 B
  26.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);        //使能PWR和BKP外设时钟   
    - W/ p9 M; x$ z7 j
  27.         PWR_BackupAccessCmd(ENABLE);        //使能后备寄存器访问  
    , q9 w( R8 _! m) S0 C  z
  28.         if (BKP_ReadBackupRegister(BKP_DR1) != 0x5051)                //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
    & ^) ?' r# ?* S
  29.                 {                                  / x5 O( E: R8 x/ S3 K, x
  30.                 BKP_DeInit();        //复位备份区域         
    6 p# q) E: w. `# n
  31.                 RCC_LSEConfig(RCC_LSE_ON);        //设置外部低速晶振(LSE),使用外设低速晶振: `/ G- d' p, Z& O1 t
  32.                 while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)        //检查指定的RCC标志位设置与否,等待低速晶振就绪
    + k% P" O# z4 b+ Q+ p
  33.                         {
    1 B5 v* Z4 G! k/ b  m; a
  34.                         temp++;
    # R/ B+ E6 m( @
  35.                         delay_ms(10);: g4 W( N2 C7 c- P+ x: {
  36.                         }
    ! W' t# |! a6 j' L* G, f: b  h7 m: o
  37.                 if(temp>=250)return 1;//初始化时钟失败,晶振有问题            
    3 ?7 C% x* @5 [4 ]; ~' L: _
  38.                 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);                //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟    . e/ R0 W7 V) N1 `  w
  39.                 RCC_RTCCLKCmd(ENABLE);        //使能RTC时钟  0 [5 L# v/ H5 E! e
  40.                 RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成
    ) e& L8 X4 {$ v: t% g
  41.                 RTC_WaitForSynchro();                //等待RTC寄存器同步  
    8 n2 E- i6 k2 Z8 p0 k! I' z
  42.                 RTC_ITConfig(RTC_IT_SEC, ENABLE);                //使能RTC秒中断
    , N: w: c, Q7 [% k- H; r. y& v
  43.                 RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成+ i9 d, e/ G/ h8 A7 ]3 ]
  44.                 RTC_EnterConfigMode();/// 允许配置        , m6 A7 y5 U7 }/ b3 G6 K
  45.                 RTC_SetPrescaler(32767); //设置RTC预分频的值
    ! Q+ K# y; P* f0 O
  46.                 RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成
    # |9 k9 R# P$ F: O. f
  47.                 RTC_Set(2022,3,18,0,41,30);  //设置时间        
    1 O% N3 }6 u* y9 M* i
  48.                 RTC_ExitConfigMode(); //退出配置模式  
    2 m% X2 }3 {$ s
  49.                 BKP_WriteBackupRegister(BKP_DR1, 0X5051);        //向指定的后备寄存器中写入用户程序数据1 d1 F# K: Z/ b
  50.                 }2 l9 H; G8 o( g3 y$ o* e$ X
  51.         else//系统继续计时1 X% ~/ C( s1 a% m' a
  52.                 {
    5 |! Q. Z, y0 q4 n; Z+ f, M

  53. " n# K; D  }4 |
  54.                 RTC_WaitForSynchro();        //等待最近一次对RTC寄存器的写操作完成
    : R3 j0 K6 c& L$ `
  55.                 RTC_ITConfig(RTC_IT_SEC, ENABLE);        //使能RTC秒中断  |+ T7 k- X' o1 u
  56.                 RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成8 r6 [9 R  y0 A; Z8 y! D
  57.                 }
    1 s8 ?; B* }7 w9 A2 b9 w' |
  58.         RTC_NVIC_Config();//RCT中断分组设置                                                         7 W6 X  W' X/ Y- z
  59.         RTC_Get();//更新时间        : ]% v2 t  O3 m" D0 J& o6 B1 l4 B
  60.         return 0; //ok
    / Q4 y% J6 K7 K' l/ Z
  61. , }% d6 [. L" x' {% [2 J! p
  62. }                                                     
    , T) f2 {/ {- B( Z" p/ r
  63. //RTC时钟中断
    " f; f* ]1 `: L6 P& S
  64. //每秒触发一次  
    ; s  T% o7 ~' O  y
  65. //extern u16 tcnt;
    " N( y" B" V: i8 b
  66. void RTC_IRQHandler(void)
    6 ^. s' o5 h0 _. Y8 Q! I8 l
  67. {                 3 I) _. e7 D! C* L3 E8 v
  68.         if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒钟中断1 d( r( l% R1 T$ m/ I' D) k
  69.         {                                                        # p3 `1 s1 M% _
  70.                 RTC_Get();//更新时间   ) B6 k' i: ^0 n8 l6 w
  71.          }
    6 Q- {- e" X* Q( I
  72.         if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//闹钟中断- f' x1 p4 H4 o3 L5 P
  73.         {7 p0 g8 v: {$ q2 [
  74.                 RTC_ClearITPendingBit(RTC_IT_ALR);                //清闹钟中断                  
    1 U$ G* h* A8 D1 C3 `  Q
  75.           RTC_Get();                                //更新时间   
    ' @) l- [5 i; @/ s" p8 O
  76.           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);//输出闹铃时间        
    ; _+ ^2 d. A! x5 l: r4 `
  77.                 5 w9 @" ~, w. P( L' `
  78.           }                                                                                                    1 m3 z3 l7 T' S" y. D
  79.         RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW);                //清闹钟中断6 q# d* R* v  x2 _
  80.         RTC_WaitForLastTask();                                                                                           0 j! }2 t5 a) n& H! P
  81. }+ ~( R0 V' v2 H' ]
  82. //判断是否是闰年函数
      N6 h: H; h' B# T8 n: m
  83. //月份   1  2  3  4  5  6  7  8  9  10 11 12" k. D" R3 U# e  G0 T) j: t+ L) @! i6 @
  84. //闰年   31 29 31 30 31 30 31 31 30 31 30 31# |7 W* k6 v6 z+ f( E! _
  85. //非闰年 31 28 31 30 31 30 31 31 30 31 30 31
    8 {! l! z3 e8 q6 k( V  M
  86. //输入:年份
    7 _/ l) q0 L% H7 e1 \% A  f9 i
  87. //输出:该年份是不是闰年.1,是.0,不是
    $ c2 u( p& q4 i6 X5 W
  88. u8 Is_Leap_Year(u16 year)
    5 @  s0 b# {8 ^; v) I
  89. {                          
    ! h0 O1 \; d' `& m4 U7 T/ d2 @" C  F
  90.         if(year%4==0) //必须能被4整除( n1 D% `4 V& c
  91.         {
    $ z. J# m: }  N" n4 K: M/ i: ?: A/ r9 @0 q0 r
  92.                 if(year%100==0)
    ; r7 H! G' q- \, D
  93.                 {
    8 A1 Y, c( t8 {3 B7 D
  94.                         if(year%400==0)return 1;//如果以00结尾,还要能被400整除            
    - y" I( k) ^; F. [# C. h
  95.                         else return 0;   $ r: w$ }7 U. O/ E: h6 i
  96.                 }else return 1;   
    0 M) f5 h& u% J+ ^; L
  97.         }else return 0;        ) c8 R/ ]/ N, }  H% g) S5 @
  98. }                                    , @$ d, g0 C- ^( S
  99. //设置时钟
    + Q  \5 r, P. }2 G
  100. //把输入的时钟转换为秒钟$ ?) B. M" Z5 S0 ~; L
  101. //以1970年1月1日为基准
    . H9 j, c& _8 p! W5 W( a
  102. //1970~2099年为合法年份( U5 P+ O. L/ [4 e! V
  103. //返回值:0,成功;其他:错误代码.; ^4 S" e7 M% }) X/ d
  104. //月份数据表                                                                                         & _# s/ ]. d. L* [9 w
  105. u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表         
    . d  R& u" b! S$ U* E3 O
  106. //平年的月份日期表) M( ?6 p+ K- o5 ]2 N. n+ l
  107. const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};: ?$ ~9 U; b. B6 N
  108. u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
    . ?/ t+ A8 ]5 D' P+ @7 {
  109. {
    1 d2 R' s4 V8 Q. i; ~& n! m
  110.         u16 t;5 r, e% R. a; l3 X3 s
  111.         u32 seccount=0;( E5 |' ^& ]$ u! ^6 n$ l
  112.         if(syear<1970||syear>2099)return 1;           
    , h( p+ C& o! L7 u" I: E
  113.         for(t=1970;t<syear;t++)        //把所有年份的秒钟相加. p% e8 l) e% y' H7 d
  114.         {
    ' a- _, f9 M8 b9 v2 n
  115.                 if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
      k, y/ m) ^3 C1 V8 q+ i$ t9 F
  116.                 else seccount+=31536000;                          //平年的秒钟数6 n& C/ `. e! l0 ^) p
  117.         }
    6 W4 n. R( N+ f( I% j
  118.         smon-=1;1 ^. H+ d+ `9 k3 U8 ?; z6 C5 g" g
  119.         for(t=0;t<smon;t++)           //把前面月份的秒钟数相加0 I$ I# f) c6 U# X% w7 A2 ^
  120.         {
    - M0 ^6 S4 }- j2 V: F6 S; o
  121.                 seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
    , K9 `) f7 D6 _
  122.                 if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数           
    # g7 }' r9 y+ S7 }' L' R4 t
  123.         }9 n7 K. p9 l' P  u7 V' u
  124.         seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加 + }8 F+ ]# \3 Y# P# A& Y! u. B- b
  125.         seccount+=(u32)hour*3600;//小时秒钟数3 J$ t: ]7 V1 m$ w7 y% |# o. i
  126.     seccount+=(u32)min*60;         //分钟秒钟数
    % E4 M) {/ ~7 Z8 w" H0 ~% F$ i3 q
  127.         seccount+=sec;//最后的秒钟加上去( A/ q/ J+ N, T
  128. 8 r# U* g% R8 W3 O0 S6 x/ k
  129.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);        //使能PWR和BKP外设时钟  
    " o% B' p# x4 o5 _/ O# m' G
  130.         PWR_BackupAccessCmd(ENABLE);        //使能RTC和后备寄存器访问 ! V9 f  A3 i" J5 Z
  131.         RTC_SetCounter(seccount);        //设置RTC计数器的值  b2 P8 {( B3 g& l' X+ k: U4 h/ ?) P
  132. ! W3 f6 [! z5 Z6 z% x6 |
  133.         RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成          5 H( p/ j0 t! Y4 t  \5 t
  134.         return 0;            
    : E3 p! |0 h: F
  135. }$ g8 ?& d1 {- H/ l

  136. % g4 K8 D- T& G$ \
  137. //初始化闹钟                  
    1 u4 N- P2 c: J- U, H! n
  138. //以1970年1月1日为基准# ^: P  b, V; c
  139. //1970~2099年为合法年份
    ) E- l7 a. D8 V, e5 a) i7 ]
  140. //syear,smon,sday,hour,min,sec:闹钟的年月日时分秒   6 E3 F/ m8 B& H5 ]
  141. //返回值:0,成功;其他:错误代码., Q4 V4 ]% m8 @0 u
  142. u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
    8 _6 `+ a' |  Q6 f' }
  143. {9 W* ~5 H+ j! q& C# u3 k# D3 o
  144.         u16 t;
    8 p! f8 j- G% C/ Z4 u5 n
  145.         u32 seccount=0;6 Q! D/ c2 ~; J, b$ d' ?
  146.         if(syear<1970||syear>2099)return 1;           1 o- P2 U5 {9 ~* A
  147.         for(t=1970;t<syear;t++)        //把所有年份的秒钟相加0 }4 Y! [1 k. ?; s6 `% {
  148.         {
    . g, q% Q) Q3 O$ q3 @$ w
  149.                 if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数2 n/ H7 F5 S4 w8 x! f$ H* f, Q
  150.                 else seccount+=31536000;                          //平年的秒钟数
    " E; F8 u' C. h# \/ _2 A3 G0 n; q
  151.         }
    ( D* Z) Z3 T7 a0 n
  152.         smon-=1;% j; R; f6 e& r$ J4 J, V
  153.         for(t=0;t<smon;t++)           //把前面月份的秒钟数相加
    , ^0 A" c- X0 n# o. _& t9 k
  154.         {7 d2 l( u' T# Q
  155.                 seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
    . ]  O1 _* w( |" \# c
  156.                 if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数           ( p( A" M6 \/ z
  157.         }
    1 o' v9 [" y, m! _: H
  158.         seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加
    7 n2 Z3 v( I' v; d- \
  159.         seccount+=(u32)hour*3600;//小时秒钟数
    & a  f: [4 M+ {" v& b
  160.     seccount+=(u32)min*60;         //分钟秒钟数
    : H7 S: Y$ M; k( a$ k
  161.         seccount+=sec;//最后的秒钟加上去                             
    7 N& l% N) Z# {* i
  162.         //设置时钟
    / i4 i7 i3 S" M) y  H/ B; r* N
  163.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);        //使能PWR和BKP外设时钟   7 H& w7 h+ s, _" f
  164.         PWR_BackupAccessCmd(ENABLE);        //使能后备寄存器访问  
    ' A, D) O" Y' Z- J4 @
  165.         //上面三步是必须的!% M/ D0 x6 F& j! |) ~4 R. _9 f2 O/ u
  166.         
    3 f" M! t% w# |' h( o) e+ N
  167.         RTC_SetAlarm(seccount);
    # y: r) q( r0 Y, g  M

  168. 3 U) Z8 V& ~4 }, v+ j
  169.         RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成         
    4 V' M; |+ C5 a4 x1 H! p
  170.         ' y( E- S# }5 N1 G* u
  171.         return 0;              ^4 R% Z5 X8 A! `4 h  p) t
  172. }
    & G5 J0 q4 n8 |) F4 X
  173. . A+ p/ x% c' L' h( _

  174. 1 c- M4 k$ V/ E
  175. //得到当前的时间8 x0 k; Q  I) Q# T
  176. //返回值:0,成功;其他:错误代码.; P: m2 d8 m) y
  177. u8 RTC_Get(void)
    6 L+ `, \3 l# [
  178. {
    " H* H6 W4 ^' K# n' ^; \8 u) U
  179.         static u16 daycnt=0;
    % `. \4 ?, ^) @, V# I2 @
  180.         u32 timecount=0;
    2 \" P7 m8 `% `0 H
  181.         u32 temp=0;
    2 E! h  a; i1 z% ^0 ^) S6 b) U
  182.         u16 temp1=0;         
    ! t6 l. O, l/ ?
  183.     timecount=RTC_GetCounter();         7 @3 G$ \3 A4 ^' \3 O6 I
  184.          temp=timecount/86400;   //得到天数(秒钟数对应的), C3 Y' r  U% ^: `' }* {7 V% p+ U2 [
  185.         if(daycnt!=temp)//超过一天了9 h( A2 v4 E' h$ S) l: [
  186.         {         
    $ v  Q6 X" v" C, ?
  187.                 daycnt=temp;
    1 i5 y; H* C2 e  N
  188.                 temp1=1970;        //从1970年开始
    0 \; R0 Q+ O# _4 V) v  I% ]2 E/ b
  189.                 while(temp>=365)
    2 i% z5 w. O. Y. Z+ V/ R. @# f! X
  190.                 {                                 . Z" [3 H* c$ Y6 G( _1 _
  191.                         if(Is_Leap_Year(temp1))//是闰年4 M9 }% w5 c* e% P
  192.                         {
    , y* m: L; p. W( Y# z% z
  193.                                 if(temp>=366)temp-=366;//闰年的秒钟数' F9 r, ?/ q( |+ ]- }7 @8 J6 n3 o
  194.                                 else {temp1++;break;}  
    4 o% \1 I8 C  g0 T
  195.                         }
    # j% @. o" T% V! `$ y1 A
  196.                         else temp-=365;          //平年
    & g8 N' X% Y( N: {5 _
  197.                         temp1++;  
    + X# W0 a$ d3 @
  198.                 }   4 u, W/ s7 D& B# K9 P: t2 b
  199.                 calendar.w_year=temp1;//得到年份
    $ ~8 H; L3 b' `* j4 a
  200.                 temp1=0;
    ( J$ Y5 I9 v7 s, X  X* Q: ?, M
  201.                 while(temp>=28)//超过了一个月
    # t4 L$ u& w. o& \
  202.                 {2 u: ]% M4 n+ E' y; T) E
  203.                         if(Is_Leap_Year(calendar.w_year)&&temp1==1)//当年是不是闰年/2月份
    * O! P9 J2 `  \. w5 ^  m
  204.                         {
    # b1 Y5 u4 P& M
  205.                                 if(temp>=29)temp-=29;//闰年的秒钟数! w6 w; o. o" C) I4 l
  206.                                 else break;
    # Q) ~/ L/ M0 h. A
  207.                         }
    2 e. l; _: J3 E% Q" t# s* F5 e
  208.                         else
    2 Q/ f' m- D# \) E5 m
  209.                         {
    % v/ m7 A+ d, M0 m' K% @
  210.                                 if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年
    0 G9 T0 s7 z: `3 }+ W: B
  211.                                 else break;* c2 C2 e/ j' Q; }0 T) S& [- @
  212.                         }7 ^* Y& ~6 |: N  V( K+ r  z
  213.                         temp1++;  & p9 f* X% C; p0 s- G1 ^+ o8 t
  214.                 }
    / f9 ]' B: Z; u% R. L
  215.                 calendar.w_month=temp1+1;        //得到月份# N' V" r; ?1 g) J. |/ @
  216.                 calendar.w_date=temp+1;          //得到日期
    , f. x# {1 e6 {- s3 i% k) e
  217.         }8 w0 a! U" }( b' N  W# w" t
  218.         temp=timecount%86400;                     //得到秒钟数              4 E, b' a  M! x
  219.         calendar.hour=temp/3600;             //小时
    ! v/ \, d5 U  \& v; K8 j+ A5 e
  220.         calendar.min=(temp%3600)/60;         //分钟        
    " _8 V! f3 A! d8 m$ e
  221.         calendar.sec=(temp%3600)%60;         //秒钟+ r9 J. u% z2 Q* q) ~! j
  222.         calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);//获取星期   / I. c6 M9 H: B' w$ h: s6 d# A
  223.         return 0;
    . `$ K& u# T% t; m& D
  224. }         * r, R, ~5 n# a; N3 ?$ l. g5 W
  225. //获得现在是星期几6 g( L1 y8 W" i; [0 v4 X
  226. //功能描述:输入公历日期得到星期(只允许1901-2099年)  J5 f3 m& \2 V0 T- ~1 D
  227. //输入参数:公历年月日 8 j6 Q  Q; n2 [  H8 U; e0 m
  228. //返回值:星期号                                                                                                                                                                                 ) l; z' M1 f! M
  229. u8 RTC_Get_Week(u16 year,u8 month,u8 day), B) v- t: |: U; z% }# \5 [, ]
  230. {        4 H0 s% ]( |0 m( S! ^0 q& f, S  u
  231.         u16 temp2;) \9 V9 [/ P3 d4 ?5 {6 p
  232.         u8 yearH,yearL;- V, C" D4 `8 d2 [9 k% E7 x5 A
  233.         # F7 D+ j2 c7 W% P2 c1 q1 i
  234.         yearH=year/100;        yearL=year%100; 8 p; e( S( `: a1 f
  235.         // 如果为21世纪,年份数加100  2 W' C8 W( L2 u7 R" v; W9 k* m5 h
  236.         if (yearH>19)yearL+=100;  D: b- ], E7 R4 Y+ R: |
  237.         // 所过闰年数只算1900年之后的  
    & g, r9 L$ n, l8 v
  238.         temp2=yearL+yearL/4;
    3 x* j6 G' X  {9 L5 F4 t
  239.         temp2=temp2%7; 6 G# Z2 K. g- D. M! y! T: s
  240.         temp2=temp2+day+table_week[month-1];
    5 X, k" D; Z8 p: C' l
  241.         if (yearL%4==0&&month<3)temp2--;
    5 i# I' H/ n4 W6 x3 J/ V  X9 Z
  242.         return(temp2%7);
    7 Y' L4 o5 i3 X, y) h
  243. }                          
    - U4 G/ k4 n* v/ i) Y' z+ a4 z; J
复制代码

1 D/ v( y6 o5 [dht11.c 温湿度传感器文件
2 u. F1 V2 R( K1 l: T/ s6 z5 L) g+ j. U9 A
  1. #include "dht11.h"8 x+ ^; k" C0 }3 F; c$ G+ d
  2. #include "delay.h"6 D+ t; o' x+ D6 r( K! C

  3. 4 b1 H' J+ O6 Y- l6 x- X) s- D
  4. & A  `  X; D1 F# K

  5. 2 d) ?2 I* k" n% }
  6. //复位DHT11
    ( u4 H, y" x# O/ P
  7. void DHT11_Rst(void)           . z( h" o7 c& Z* v& F3 Z
  8. {                 
    8 a7 z# Y+ P7 ?! q( E0 o
  9.         DHT11_IO_OUT();         //SET OUTPUT
    0 {4 r0 \+ T9 k  b
  10.     DHT11_DQ_OUT=0;         //拉低DQ
    ; ?0 W) S5 M8 F# w) ~
  11.     delay_ms(20);            //拉低至少18ms# A6 ~3 a0 H+ O! Z! J1 e! q& j
  12.     DHT11_DQ_OUT=1;         //DQ=1
    5 N4 q, c# Z+ G- F9 r& c% z; ?- m
  13.         delay_us(30);             //主机拉高20~40us
    8 Y: x0 w1 R8 p
  14. }
    & t4 |8 I0 y- X* d1 h1 O
  15. //等待DHT11的回应
    8 k$ H; j; e1 l2 j
  16. //返回1:未检测到DHT11的存在5 F) T9 D1 b# T5 i6 O' E
  17. //返回0:存在
    ( n! d2 y6 F6 Z" M  t) W0 e
  18. u8 DHT11_Check(void)            1 B! B4 p$ {! [# u
  19. {   
    3 {( y8 v6 P. B6 ]- ~2 H% a( x( Q
  20.         u8 retry=0;
      C1 `5 I( q. U
  21.         DHT11_IO_IN();//SET INPUT         
    , L- }) n8 H/ {2 z7 n9 b; [
  22.     while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us" v" i' R/ S, I- r
  23.         {
    5 ^# r% R' B7 m) v( [
  24.                 retry++;# H" c* Q) J9 n2 e" r
  25.                 delay_us(1);
      n% }! H1 I/ W3 h' a8 w/ I
  26.         };         . p$ p/ W  f6 C( o4 |, g) A
  27.         if(retry>=100)return 1;
    7 T( @; y: Z  t% S6 |
  28.         else retry=0;0 `8 L+ w3 f* F3 V
  29.     while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us7 p5 m* g5 X' R# v. q4 I, ]- D. s
  30.         {
      \6 s, I+ o# Y( S5 E1 e8 m. G
  31.                 retry++;' L% I3 [; o) f
  32.                 delay_us(1);7 ]: I2 h, Q: |7 W& Q$ M
  33.         };
    2 m1 C/ k, x6 r0 T/ u* z. Z$ O
  34.         if(retry>=100)return 1;            4 g1 e) i' V% }
  35.         return 0;& k3 n1 ~0 B' @( H) i
  36. }
    7 Y5 |& r/ _6 i5 P3 S
  37. //从DHT11读取一个位0 R' W% c: Y  M, x) X
  38. //返回值:1/0
    % f3 L" Y/ Q% j  M7 C7 O1 Y0 L
  39. u8 DHT11_Read_Bit(void)                          " K2 i+ i, ~1 h7 x2 i; b
  40. {7 h/ I4 m8 V0 O( U8 m
  41.          u8 retry=0;9 Q+ ^* n( X  s+ U2 o
  42.         while(DHT11_DQ_IN&&retry<100)//等待变为低电平) m5 N5 Z* T  Q& A7 K0 B
  43.         {
    : Z7 M) O( a: a' v0 E8 h/ ~' P+ S
  44.                 retry++;% ^  H4 Z) `( p7 Q6 t7 @9 R6 Z
  45.                 delay_us(1);! g2 T2 R* a6 H" ]4 n
  46.         }
    + m0 B- D2 U- E6 j  w9 {" `
  47.         retry=0;5 H: B" W! b  y/ T( i
  48.         while(!DHT11_DQ_IN&&retry<100)//等待变高电平4 C# F8 Y1 I; d; r9 C. y
  49.         {
    4 p8 w/ C) n! P! E; o
  50.                 retry++;
    0 Q& L, _  t3 Q; `
  51.                 delay_us(1);
    ( g; S( R% v# `+ G$ D% Q8 `( z
  52.         }
    ; B9 w+ A" W% x" Q* G1 p
  53.         delay_us(40);//等待40us8 Z9 j8 G2 q9 R/ o* _' v5 P
  54.         if(DHT11_DQ_IN)return 1;' m+ _/ Z+ c% R
  55.         else return 0;                  
    " E  R7 \9 T- L" J# f- D+ |
  56. }
    " i8 `0 D' Y% b  j
  57. //从DHT11读取一个字节6 X8 t) z7 Q: {0 F+ {8 f' [# u0 s
  58. //返回值:读到的数据
    ; v5 I( y& ^9 q% Q& @( ~
  59. u8 DHT11_Read_Byte(void)    - a8 q# d$ \0 P" ~$ |5 D$ V
  60. {        
    ; h/ D' B8 z8 L. i
  61.     u8 i,dat;* d7 i! y# _6 X8 v6 G$ R
  62.     dat=0;
    % B  j) G* D  P1 q+ m
  63.         for (i=0;i<8;i++)
    7 p6 I$ P1 F3 x& P  s6 K
  64.         {
    / L3 W$ a: r" N0 g/ `4 N2 l
  65.                    dat<<=1; ; [% Q2 U' _- Y
  66.             dat|=DHT11_Read_Bit();* P8 J  J" l$ {4 `. J& S
  67.     }                                                    : }# |6 k7 \$ F! t  p
  68.     return dat;& y+ t( C4 L( h% U3 b6 a3 |5 N/ e, @
  69. }
    0 E$ a5 J( {  T5 f( m
  70. //从DHT11读取一次数据
    " r1 ?% |; x- B! v, Q9 Y
  71. //temp:温度值(范围:0~50°)
    % O6 j8 Q' J! j. r, S' ^: v; M
  72. //humi:湿度值(范围:20%~90%)
    9 F, V0 M! |/ m4 ^6 f
  73. //返回值:0,正常;1,读取失败4 f4 f+ p" D# E
  74. u8 DHT11_Read_Data(u8 *temp,u8 *humi)    / a! Q. s0 z- i0 `7 k
  75. {        
    4 N, O% a+ p0 N$ y( J% O3 q  S
  76.          u8 buf[5];
    ) o9 `. Y. I8 Z; N5 x2 j) n
  77.         u8 i;& E% }3 p0 m' Y7 s5 k0 a7 G
  78.         DHT11_Rst();
    $ h% Q& h$ \4 N2 E) k; {% q1 [
  79.         if(DHT11_Check()==0)9 P& d1 o0 V0 M0 W* n5 B
  80.         {2 U8 B# G* _. i* v+ i5 c
  81.                 for(i=0;i<5;i++)//读取40位数据
    $ l4 R8 I. l* |# E/ \
  82.                 {
    + p% E; i) y9 _+ Z/ T
  83.                         buf<i>=DHT11_Read_Byte();
    * e2 L- y# b  m  b
  84.                 }7 c) R7 u7 x& t4 Y  U% f9 b
  85.                 if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])9 d6 U, G: P7 ~1 _. H
  86.                 {: z7 i6 o0 n! y8 _! ~+ I& `& F
  87.                         *humi=buf[0];
    : g& P7 M$ P) X* E, o3 X+ P
  88.                         *temp=buf[2];
    , C- _( F9 S! A) J1 H. ~
  89.                 }8 u$ r2 J1 Z( _4 E7 ^2 n
  90.         }else return 1;; o$ l  r8 W+ W% ~# f1 f$ L
  91.         return 0;            4 l. L0 `: s! f2 |$ n4 R
  92. }
    # p4 ^( X/ ~* D( r
  93. //初始化DHT11的IO口 DQ 同时检测DHT11的存在
    3 L! U$ e% P2 s5 K/ u/ I6 B% m
  94. //返回1:不存在8 a1 ~# U$ x7 Z2 M9 _( [
  95. //返回0:存在            
    5 e8 r/ h# V; g- \7 R4 u- o. P. P3 w
  96. u8 DHT11_Init(void)
    , f5 l5 B- c& C( N' o# F3 g" z' V
  97. {         
    ! |, K: X+ T5 h7 P
  98.          GPIO_InitTypeDef  GPIO_InitStructure;
    + [* N& m! Y: F0 a* e1 K1 E! j9 k9 v
  99.          
    ' F* g$ }- P7 n
  100.          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);         //使能PG端口时钟5 \2 `2 u3 I; O# \. l# }, A. l
  101.         , A% Q8 A+ @6 @+ g
  102.          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;                                 //PG11端口配置
    # K; ]' e: F/ i7 b
  103.          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //推挽输出/ A3 G2 R! T# N3 {/ K& H$ s/ ~
  104.          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    4 v8 w7 I4 N, r& q
  105.          GPIO_Init(GPIOG, &GPIO_InitStructure);                                 //初始化IO口
    . ?! }. }, T9 ~
  106.          GPIO_SetBits(GPIOG,GPIO_Pin_11);                                                 //PG11 输出高
    . z" S4 v0 \# x; Q( f' g4 Y2 ]$ l) I3 q8 p
  107.                             2 P# Z6 J3 j: H* J
  108.         DHT11_Rst();  //复位DHT11
    9 q3 o" r) Z, S# i, |( I! I7 r
  109.         return DHT11_Check();//等待DHT11的回应$ v; C& y' Q. s# c. ^# N
  110. } </i>
复制代码
1 ]  i4 g1 H6 \4 T6 g6 C$ a8 T
adc.h 数模转换 心率传感器文件
# R' P' {( y" [7 o7 c, L' p- [- B6 w
  1. #ifndef __ADC_H# c0 A/ P0 x, V' x1 j+ O
  2. #define __ADC_H        
    ; \3 V0 Z! m+ \  b# P4 o
  3. #include "sys.h"# A0 K" h5 @5 N% Z. _$ C. e0 w5 B" |

  4. + F9 P9 ~$ S6 k. n/ Y
  5. void Adc_Init(void);
    : x3 C% E+ Y8 G# w' ~2 u0 h
  6. u16  Get_Adc(u8 ch); - c% C# i3 a: d) t4 M
  7. u16 Get_Adc_Average(u8 ch,u8 times);
    1 C0 L' o: @( f; l, M
  8. u16 OLED_Get_Pules(void);, O* C7 A" P1 X: w! i6 u: ]- Q
  9. #endif
复制代码
4 `2 ?6 B: a9 v
adc.c 数模转换 心率传感器文件
! |, w& Y- W- z6 w  s9 _& q' s2 M: b+ Z7 s; Y
  1. <i>#include "adc.h"</i>
    9 A0 U% L; C' B- G8 u
  2. <i> #include "delay.h"</i>' p0 t+ }7 j1 @; r/ y, K

  3. ; U4 l- }8 ~3 L. ?4 V
  4. <i>           </i>
    ( \) S: o% I" o$ c' M
  5. <i>//初始化ADC</i>: y0 g) L0 R2 V7 z! C
  6. <i>//这里我们仅以规则通道为例</i>/ c) H  t) m& R" w; i
  7. <i>//我们默认将开启通道0~3                                                                                                                                           </i>
    . s" @) n& E4 N, Y- \  K' E
  8. <i>void  Adc_Init(void)</i>. d6 h1 |9 Z: u7 x. T
  9. <i>{         </i>6 j" s4 T+ T* P' U1 A, ]
  10. <i>        ADC_InitTypeDef ADC_InitStructure; </i>2 e) R, h( T0 {9 c" o8 }* a
  11. <i>        GPIO_InitTypeDef GPIO_InitStructure;</i>- a4 W4 `/ ]/ H
  12. , s% `7 o0 n0 T$ k5 f  x$ k# U
  13. <i>        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1        , ENABLE );          //使能ADC1通道时钟</i>( W' [7 P% Y, X) ^5 w

  14. " W6 U7 b% B7 M/ E5 ~

  15. 8 G9 ?7 k: `6 W; y
  16. <i>        RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M</i>1 R7 C4 i. J$ i
  17. % N) @1 B4 q2 P8 L
  18. <i>        //PA1 作为模拟通道输入引脚                         </i>' I# X3 R' a' a  [; z  S) p
  19. <i>        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;</i>0 t, K$ s+ `& @. R+ |; L
  20. <i>        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚</i>- x. S4 t7 g" c8 Y% @
  21. <i>        GPIO_Init(GPIOA, &GPIO_InitStructure);        </i>
    ; A8 O. r  _+ H* z# y) ]) ?
  22. % ~* ~- B' ~; z+ ]3 U7 n! @5 a* X
  23. <i>        ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值</i>
    $ c6 H8 B( O8 H% e0 J  H8 m( w

  24. ; }0 Y3 ~! P; R7 @
  25. <i>        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式</i>
    / t6 S2 s; J2 f! l& s$ G) {  ?8 l; U
  26. <i>        ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式</i>
    % K7 U9 s# K; E
  27. <i>        ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式</i>8 Y2 t' f3 ?, M
  28. <i>        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动</i>% x( p/ Z. Z- J+ Q% F/ K+ }
  29. <i>        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐</i>3 A7 F4 i- U. N( u
  30. <i>        ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目</i>$ ^, V0 k2 @$ v* p
  31. <i>        ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   </i>' ~5 o6 ^1 v: r9 T9 {8 E/ ^
  32. 5 Y* P9 R! C# e( S8 V3 ~
  33. 5 \5 F  @/ e) `; \) Z: P0 z' l4 O
  34. <i>        ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1</i>5 L/ \  ?9 B5 w1 O; B) l2 o7 j  ~
  35. <i>        </i>
    " q8 c8 ], e. E& X) c  m
  36. <i>        ADC_ResetCalibration(ADC1);        //使能复位校准  </i>, A! F% s8 v9 A4 ?  I* |
  37. <i>         </i>
    6 S0 a7 \7 x& O
  38. <i>        while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束</i>
    5 G, j* d3 p6 R$ `2 P. E
  39. <i>        </i>. d$ h! x1 I# {6 B/ S
  40. <i>        ADC_StartCalibration(ADC1);         //开启AD校准</i>
    $ O. b2 T  i  x& n8 ^* S

  41. 4 D* @, x4 @; L( H
  42. <i>        while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束</i>6 _; x: }- y4 B9 E

  43. + \8 Z- g3 y  \" V/ N4 y8 y1 O+ }
  44. <i>//        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能</i>
    : d! A/ V+ }1 y

  45. 8 F" M% ]# S4 x% h9 m8 _- |
  46. <i>}                                  </i>
    ; j. p+ K+ G& b
  47. <i>//获得ADC值</i>' U- x' e: ]# |$ O/ w
  48. <i>//ch:通道值 0~3</i>& |' W; g# R" f2 C
  49. <i>u16 Get_Adc(u8 ch)   </i>8 |/ ?. v( F# t2 Q, E3 g. D
  50. <i>{</i>6 Y' A" L) Z8 l$ L& j7 }6 f
  51. <i>          //设置指定ADC的规则组通道,一个序列,采样时间</i>" W* V4 B$ _& s: @( m1 A& ?2 X
  52. <i>        ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期                                      </i>
    " X- L# ]( Q" }0 C& J

  53. : ^+ ~; B" Q$ Q7 s& T
  54. <i>        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能        </i>
    " E; n7 Z% u& f+ f
  55. <i>         </i># i, m7 ^. Q' C3 ~% L
  56. <i>        while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束</i>8 t: x% h4 j: t$ O/ u

  57. 2 B* f8 c- v! k: t2 P7 R: I
  58. <i>        return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果</i>) m8 c7 {2 s0 i% `
  59. <i>}</i>
    ' W: s/ _- r6 D: w/ v

  60. % y9 H% K3 |5 I5 [9 B# m. c
  61. <i>u16 Get_Adc_Average(u8 ch,u8 times)</i>1 j  p) o1 f: f; S
  62. <i>{</i>0 j) y! \% B, o/ l2 h6 f  w/ y
  63. <i>        u32 temp_val=0;</i>  K4 ]2 j5 m2 Q
  64. <i>        u8 t;</i>0 B7 w; w; ]) s
  65. <i>        for(t=0;t<times;t++)</i>& O% X: \7 y! H+ {( j% R( J
  66. <i>        {</i>
    ( b4 C% @& R0 Z6 C
  67. <i>                temp_val+=Get_Adc(ch);</i>3 }# ]% p* L0 p0 H" R* }; F
  68. <i>                delay_ms(5);</i>7 r; s9 h/ f/ R- q# p0 Z8 j
  69. <i>        }</i>; D9 P, z& V5 j. d
  70. <i>        return temp_val/times;</i>) X! t3 Q" B% v
  71. <i>}          </i>  \) W7 \/ y7 [% F+ h6 ^
复制代码
$ j! D! I; [) H' X# D

3 z: a2 }, H8 A  F% I" y2 j9 r: ^) t7 y4 g5 v4 b
8 y0 _* P/ |$ ]1 }, d% E
赞 收藏 评论0 发布时间:2022-5-25 19:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版