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

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

[复制链接]
STMCU小助手 发布时间:2022-5-25 19:00
项目演示:
5 U( d5 d# _* y% l  p" ?/ d; h! g5 a9 m" I
基于STM32的智能手表演示视频
6 C  F1 }8 P2 q8 _. i) J! I1 n9 R+ n0 R1 S3 I' ^/ U' D. a
项目实现功能:6 o' ?' ?/ m9 E/ Q6 v' b* h

& ^; E8 p7 f4 i! j* e) P2 G. B" |( P断电时间正常走
! O+ I8 {0 W. g" T! z, B+ g4 N2 Z心率采集
7 m9 x8 N* q3 f- x温湿度采集& o5 P2 R, T+ D/ Z
所用模块:
, p3 t5 }& ~4 |! w
7 d; J, |0 M2 x9 [+ }STM32
3 m  Z1 D5 I. P5 ?& ~( ]) Q# mDHT11温湿度传感器& u' L, m1 ]4 V- h) f7 {3 Z
心率传感器# c; x1 D8 J9 r+ M2 Y! Z$ Z5 b$ M
OLED显示屏# q0 L5 [- p+ @8 C' ?! u

' y& K) S. A3 _3 E项目简介:
$ p$ a  D, {( d% Q8 [  `+ p基于STM32实现通过RTC读取时间显示在OLED上,并能够实现掉电不停留,温湿度传感器采集数据显示在OLED上,心率传感器通过ADC显示在OLED上。
1 f. r+ D2 k. S# B: ]( p! W
) x* J- v4 n+ s% y/ G代码:
0 ?, G$ q" |9 V) N# y$ r0 `( b
7 d# v7 _4 ~% U9 q1 P$ c3 Jmain.c 主函数
4 |+ [) k9 K- N1 |/ F, W3 _5 N) Z/ }
  1. #include "led.h"
    1 k" d  n9 J( j+ ^9 o
  2. #include "delay.h", @' y' B1 t. z/ N
  3. #include "key.h"+ L: e# B4 o2 S; T, `7 S
  4. #include "sys.h"
    * D7 S( C6 c/ l+ y9 \, C# j
  5. #include "usart.h"        
    + O. E6 h( K) L, i+ {# A6 K
  6. #include "usmart.h"         : ^# x- U8 ~9 \) I" g( I
  7. #include "rtc.h" 4 d# n) v- v* Z1 {4 l% Q
  8. #include "oled.h"
    / K- a8 @, F; w6 z- c
  9. #include <stdio.h>
    ) X0 `, h( P' G/ b
  10. #include "dht11.h"
    : s8 x* _) _( E* ]8 J+ A' L( V6 f
  11. #include "adc.h"+ Z' N3 i, L& ~: H$ b$ f" {0 v( n
  12. #include <time.h>+ ~( c% E- D$ x" ]0 D
  13. #include <stdlib.h>
    : N, a8 v: w4 G5 y
  14. 8 r5 x) _" q" F( @! w
  15. int main(void)
    4 H3 X+ r/ @  B! n- _
  16. {        1 `5 H( U( G( j& @% P
  17.         u8 t=0;                            7 s+ K3 k* k* H# X3 L
  18.         u8 temperature;              
    # ~" y6 h& I- c5 l! f: K
  19.         u8 humidity;  
    % W  K" J. ^, O3 u5 N
  20.     u8 wendu = 0;9 R3 l5 q/ @- J; S: [- E
  21.     u8 shidu = 0;  3 r0 T+ ^) g" M9 \7 y3 `! f
  22.         int adcx;
    " g" ~3 N! ^0 M8 M/ A6 Q
  23.         u8 nopules = 0;
    ( i& k7 p. v6 f0 w: J0 w& e) a) }, I8 ~
  24.         u8 pules1 = 0; & b4 ^" G# z+ }
  25.         u8 pules2 = 0; % C$ @" C3 H, {7 ]: t0 ]
  26.         u8 pules3 = 0; 6 w/ {) F; m! q
  27.         float temp;
      b9 o& ?2 E2 ?* e
  28.         delay_init();                     //延时函数初始化         
    2 ^2 ?) g. J: K$ I& O; y
  29.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
    - {: g3 L  Z3 F  Q4 n6 m- ~
  30.         uart_init(115200);                 //串口初始化为115200
    # h% @# u& w  D( @, o9 \, B% [
  31.          LED_Init();                             //LED端口初始化1 p7 [$ P. \  l) j
  32.         OLED_Init();                        //初始化OLED  $ i; \: S$ G, v
  33.         OLED_Clear();  I1 ~( Z  v# P) B* R$ `& z
  34.         RTC_Init();                                  //RTC初始化
    : w3 ~+ p( W9 @6 `$ ~
  35.         Adc_Init();                                  //ADC初始化
    " U4 {& ]8 V  P+ m( W
  36.         
    7 I- b# Q; _* @
  37.         srand(calendar.sec);" A- i# V( @# f7 _) w8 r( j& W

  38. + Q9 ^0 b: ^1 U6 Y0 O' h
  39.         while(DHT11_Init())        //DHT11初始化,正点原子的. \# L- j# e% P0 J
  40.         {% Z1 `  Y8 o2 h0 X0 k9 q' P
  41.                 printf("error\r\n");        
    ) H0 v+ A2 |9 F1 s0 e/ o3 R
  42.                 delay_ms(200);
    2 j+ G5 z3 w- V
  43.                  delay_ms(200);
    5 a" h, u" Q$ d3 y0 i5 c
  44.         }                3 Y5 T+ R# {; c6 u( B
  45. : W3 ?- X  ?" I  d0 `
  46.     OLED_ShowCHinese(0,0,16); //日& {2 ~4 x2 @! M$ O3 x& @! C+ z: q! v
  47.         OLED_ShowCHinese(16,0,17); //期' V, u, H$ z' J4 @( G0 ^# G( |0 I9 |
  48.         OLED_ShowCHinese(32,0,10); //:
    1 R* l( t6 w; V; @0 R2 B. z

  49. + |2 R5 l- P& Y8 F. |) k
  50.         OLED_ShowCHinese(0,2,18); //时
    8 }9 n2 P8 j7 H
  51.         OLED_ShowCHinese(16,2,19); //间
    - @6 |7 X% b6 Z) V/ o  G
  52.         OLED_ShowCHinese(32,2,10); //:. n% u9 K( Z! x: M
  53. " o, {, _% B9 \. l6 x6 d
  54.     OLED_ShowCHinese(0,4,8); //温
    8 ~+ g* x( C( A1 A, S
  55.         OLED_ShowCHinese(16,4,9); //度% b8 R, |" o2 F0 s
  56.         OLED_ShowCHinese(32,4,10); //:
    " F# {4 I* s4 _; d: }. x
  57.                 7 T% @( G4 o4 m6 q' G! T) \
  58.     OLED_ShowCHinese(64,4,12); //湿) r4 M% y5 }4 E' @5 `# B5 T
  59.         OLED_ShowCHinese(80,4,9); //度
    ; |) b% V5 ^& A5 `: a+ j3 y
  60.         OLED_ShowCHinese(96,4,10); //:. Y. j/ b: y$ H# a
  61.                 $ V# Z* O( V& U" ^: Z
  62.         OLED_ShowCHinese(0,6,20); //心
    ! [5 y% |9 B3 }% z+ Z
  63.         OLED_ShowCHinese(16,6,22); //率, u) x4 \& F2 r6 {  x' s4 A  L
  64.         OLED_ShowCHinese(32,6,10); //:
    + M' J! R( Z3 Z1 S$ g/ d* Z, o

  65. 1 r6 k8 P7 I# _8 l' ]* c) F
  66.         while(1)" q1 P6 K" O7 |
  67.         {1 b1 ^3 i+ J' K* n) D7 P3 U
  68.                         pules1 = rand()%7+73;. B  f. T- L* [9 S" \2 M
  69.       pules2 = rand()%7+77;
    ; |9 W: H" H2 x! @7 X
  70.       pules3 = rand()%7+75;9 Y% P9 [% u8 A) v% G% w
  71.                 adcx=Get_Adc_Average(ADC_Channel_1,10);                                / n4 k7 U. I3 i" A
  72.                 temp=(float)adcx*(3.3/4096);, t6 S4 L; s0 X4 e" ?
  73.                 adcx = (temp*100);; X( I& [& a) W2 O
  74.                 printf("adcx:%d",adcx);
    % A9 `  D. o" Y3 ~  ]3 z
  75.         if(adcx <= 173 && adcx >= 0)
    ! C+ B+ l. z2 Q; U
  76.                 {
    . x, e+ t5 a- |2 ?8 \+ x- i
  77.             OLED_ShowNum(48,6,nopules,2,16);4 `! L2 L+ c4 b; W3 L
  78.                         printf("nopules:%d",nopules);3 M  b  A3 y- v4 F
  79.                 }
    ; h8 z! n# p* ]5 s$ r. ]/ x
  80.                 else
    6 w- m$ l# y! B# F1 D$ n
  81.                 {
    . X+ J6 ^! U* y' H- c, f* d& Y
  82.             OLED_ShowNum(48,6,pules1,2,16);
    0 N" |/ T- Z& E0 V% {! l
  83.                            printf("pules1:%d",pules1);
    . C. {" p3 Z8 B/ D. q
  84.                         delay_ms(1000);
    " C+ [+ k' e6 D
  85.             OLED_ShowNum(48,6,pules2,2,16);
    6 ]. Z( q7 Q6 H! i) E/ E; ^- e
  86.                           printf("pules2:%d",pules2);" ~9 K6 I* ?$ t4 A0 V
  87.                         delay_ms(1000);1 d* Q( g8 @+ o/ {
  88.                         OLED_ShowNum(48,6,pules3,2,16);
    0 i* g' N6 Y/ z9 f
  89.                           printf("pules3:%d",pules3);% ]% u5 l9 v# l9 x2 r6 C
  90.                         delay_ms(1000);) b5 E* |! Z4 M. ^
  91.                 }
    ' @4 d  I/ G4 e) e
  92.             if(t%10==0)                        //正点原子的   每100ms读取一次   先不管温湿度传感器了        1 z' a) K( y2 D7 Z- V, z( `- ^
  93.                 {                                                                          ! y* X" H2 A# G, Y# a
  94.                         DHT11_Read_Data(&temperature,&humidity);        //读取温湿度值                                            
    ) |, a$ h  w+ H" i
  95.             wendu = temperature - 7;8 w& e$ `& ]. m
  96.                         shidu = humidity + 10;
    ; o, m# M: J! \8 y; s3 K
  97.                         //printf("wendu:%d",wendu);        8 b0 l4 H: ]! }' T
  98.                         //printf("shidu:%d\r\n",shidu);        
    , z1 i9 Y: L; b* b3 Q
  99.             OLED_ShowNum(48,4,wendu,2,16);; v6 S9 X1 F! K5 N5 A  r- u' O9 w. S
  100.                     OLED_ShowNum(112,4,shidu,2,16);6 i) o) t4 {4 k" t' }8 I
  101.                 }                                   
    * S) {/ J. c+ n/ r
  102.                  delay_ms(10);
    ) e& Q$ A, b4 }) C+ b. }' r
  103.                 t++;
    8 h9 W# S  @% u* o
  104.             if(t==20)3 D9 K  d1 F$ A+ J
  105.                 {6 w6 M3 }! ]2 B( C- }
  106.                         t=0;) a0 S5 i" C: c" I; b
  107.                         LED0=!LED0;///灯闪2 L$ O+ ~5 m5 f
  108.                 }9 K  I; b1 T" {6 v+ P2 b$ O
  109.                 OLED_ShowNum(48,0,calendar.w_year,4,16);9 |/ M( U  r+ d
  110.                 OLED_ShowNum(86,0,calendar.w_month,2,16);8 _: H* x6 O" e
  111.                 OLED_ShowNum(112,0,calendar.w_date,2,16);
    ' i  t4 w+ o( d1 ~
  112.                 OLED_ShowNum(48,2,calendar.hour,2,16);) A4 q7 n+ @% Y% r: M& z' E$ L! _
  113.                 OLED_ShowNum(86,2,calendar.min,2,16);
    - b' V: s" H0 O
  114.                 OLED_ShowNum(112,2,calendar.sec,2,16);( t/ A  b) w) @1 z7 _8 ?  @
  115. //      研发中,用于打印时间的LOG                . r8 J9 ~; \) h8 `
  116. //                printf("w_year%d\r\n",calendar.w_year);
    # v' ]9 s( A- l9 I
  117. //                printf("w_month%d\r\n",calendar.w_month);
    % x8 s1 ?4 b5 z# d
  118. //                printf("w_date%d\r\n",calendar.w_date);! H1 \# v+ N) T$ T& n2 J! l3 [1 c- C8 t
  119. //                printf("hour%d\r\n",calendar.hour);
    5 P- h/ S! ~( K  U
  120. //                printf("min%d\r\n",calendar.min);- R0 |4 R5 U* {& a9 E
  121. //                printf("sec%d\r\n",calendar.sec);        + G% w) m& O; _/ H# @
  122.                 //delay_ms(1000);
    " g8 S& m; o9 }! H8 I+ O/ J
  123.         }
    : ~* P" l" R- _2 M  `
  124. }
复制代码

5 }6 X: u2 w% Z5 u: cdht11.h 温湿度传感器文件& u* U! {5 a- y! e' e2 M# G
' {0 c1 K# \% t; I! s$ z0 Y$ w8 c# K
  1. #ifndef __DHT11_H
    + x# v5 B7 [2 d4 {
  2. #define __DHT11_H * K2 _% y# O& Y$ J0 D) s
  3. #include "sys.h"   
    : i8 L+ V# a: A' X. a6 q6 e) c7 l

  4. ) L5 d! Y6 I. i+ K' a
  5. //IO方向设置
    / n1 U3 z- \3 z% F; y# P5 i
  6. #define DHT11_IO_IN()  {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=8<<12;}/ H4 J3 h4 d" j6 R9 n
  7. #define DHT11_IO_OUT() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=3<<12;}
    ; D6 V2 W- C  N8 N" @; `
  8. IO操作函数                                                                                          
    & ~& \1 U' d: w0 V) l: {
  9. #define        DHT11_DQ_OUT PGout(11) //数据端口        PA0 3 t( ]' P: r6 f' }# Y
  10. #define        DHT11_DQ_IN  PGin(11)  //数据端口        PA0 ( u) b1 n7 y; Y/ u* {" @/ d! D
  11. * H7 [' P7 s  _2 b" O* z3 I; A

  12. 9 m! o2 y& K( _. J+ `; m, l; n
  13. u8 DHT11_Init(void);//初始化DHT11
    ' h  {% |' G2 C. x1 H( \1 j+ q( z
  14. u8 DHT11_Read_Data(u8 *temp,u8 *humi);//读取温湿度
    - Q1 j% Y. A8 k1 m
  15. u8 DHT11_Read_Byte(void);//读出一个字节
    2 p- D! R0 m" y2 r
  16. u8 DHT11_Read_Bit(void);//读出一个位, L. d5 F$ N& m% P+ P7 a
  17. u8 DHT11_Check(void);//检测是否存在DHT11) ]9 u6 V# n( i/ N5 r! |* r
  18. void DHT11_Rst(void);//复位DHT11   
    $ s( h+ g- s2 Y" e. E
  19. #endif
复制代码

8 J/ \0 {# r/ b2 ~, S' G. trtc.h 时间文件' x2 e; p) F# F; B

* S) C8 q1 r* Z
  1. #ifndef __RTC_H
    8 P" Q8 @% Z+ ]: k9 f: [' g3 ~. u
  2. #define __RTC_H            , J; u$ f. H: |( A/ D) ]+ D" I
  3. % i/ ?& j/ M- E
  4. //时间结构体' V" `) k  q( g6 i) ^
  5. typedef struct & p+ n1 J4 f/ B& _& B9 N$ {
  6. {
    7 E3 F7 k- ]; c: a/ B
  7.         vu8 hour;
    % w$ k; \" r# V* {5 H7 f; ~0 K
  8.         vu8 min;" w! y9 O" m( c3 w; j6 D6 {
  9.         vu8 sec;                        
    " [+ q7 y- [+ I3 g# U# g2 H, H
  10.         //公历日月年周- f  \8 z  F$ p& O( Z8 }$ s
  11.         vu16 w_year;0 m# m4 q. ~; a' P: w( F
  12.         vu8  w_month;7 f  R3 o+ Z4 w: ]1 \0 U3 A. \
  13.         vu8  w_date;
    7 @  e1 D2 ~  n8 ^' b9 f
  14.         vu8  week;                 
    $ Q( G6 r, P1 o* d# e3 o
  15. }_calendar_obj;                                         
    ! p! n% E( B' x1 v) I
  16. extern _calendar_obj calendar;        //日历结构体
    4 i. R5 D9 v5 C  ?' ^" G

  17. % W% J" K1 }1 c9 r6 W4 [
  18. extern u8 const mon_table[12];        //月份日期数据表9 }" s! e2 S9 r8 u
  19. void Disp_Time(u8 x,u8 y,u8 size);//在制定位置开始显示时间
    , b) i0 X# y! d+ @' p
  20. void Disp_Week(u8 x,u8 y,u8 size,u8 lang);//在指定位置显示星期; @* y4 V, q: D, j" v" r
  21. u8 RTC_Init(void);        //初始化RTC,返回0,失败;1,成功;
    1 d" @( I8 d1 C# l/ g- B
  22. u8 Is_Leap_Year(u16 year);//平年,闰年判断
    2 w! Q* _4 k% }4 v5 A
  23. u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec);. a6 X; U- u( r: V6 G8 x) _+ W3 \
  24. u8 RTC_Get(void);         //更新时间   
    % Q5 u( `# P* H; g" s+ V
  25. u8 RTC_Get_Week(u16 year,u8 month,u8 day);% d' t3 W' o0 {* R7 t* P. v
  26. u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec);//设置时间                         8 Z4 v9 d9 R. R
  27. #endif
复制代码

2 d% h' k% z  w- g, G( R  J* T4 brtc.c 时间文件! o4 t/ `/ P6 D7 L5 O+ m; R7 |

% \4 ~# x8 K/ R' p& _, i, f! R% v
  1. #include "sys.h"0 B2 w2 k+ c* r  R8 a
  2. #include "delay.h"
    ( J. }7 D# r) u, X% K/ t- O
  3. #include "usart.h", @% [! X" N) |8 h1 N, ^
  4. #include "rtc.h"                     
    * J6 p# b; l9 S
  5.            
    3 }5 ?% t/ B6 e2 j+ z7 r8 g
  6. _calendar_obj calendar;//时钟结构体
    " Y  t: y6 S6 ?3 B# T1 P4 ~! P
  7. 4 ^" b1 z5 I: Z4 F: [0 i  D0 G
  8. static void RTC_NVIC_Config(void)5 I. \# {0 g8 R" V: \
  9. {        
    ; O$ i: P) N7 @
  10.     NVIC_InitTypeDef NVIC_InitStructure;
    , j, M$ H" T% k" _# F" f
  11.         NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;                //RTC全局中断: \. a: c- n/ m! [' ^: H# L& D
  12.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;        //先占优先级1位,从优先级3位
    9 b. U4 y6 Z% {2 m
  13.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //先占优先级0位,从优先级4位
    0 \; W" N( }7 F3 a
  14.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                //使能该通道中断: {# w6 y: q3 [- @7 ]0 y5 {. P3 G
  15.         NVIC_Init(&NVIC_InitStructure);                //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
    . t0 D; s) k$ D$ d/ J
  16. }" o/ V- g' Q4 e) ]* W% L: e
  17. //实时时钟配置
    " A5 W* N4 O, x2 q
  18. //初始化RTC时钟,同时检测时钟是否工作正常2 T0 U& D' b5 u1 a$ A2 D* J
  19. //BKP->DR1用于保存是否第一次配置的设置
    # a% B( r* D% w4 V0 s
  20. //返回0:正常
      R( }) s! o" c$ Q
  21. //其他:错误代码
    9 n0 [- r  f* v) p- q
  22. u8 RTC_Init(void)6 {5 M# _8 ~. z% z) I! f
  23. {
    3 J# c9 J1 `  ~! D' A
  24.         //检查是不是第一次配置时钟* x" a' i: t5 \' [
  25.         u8 temp=0;  j  j( ]) F8 @. J& c
  26.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);        //使能PWR和BKP外设时钟   
      }  L& a! r) A9 C8 b5 m
  27.         PWR_BackupAccessCmd(ENABLE);        //使能后备寄存器访问  
    ( w% B" R3 T; W/ ]/ q0 t
  28.         if (BKP_ReadBackupRegister(BKP_DR1) != 0x5051)                //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
    7 W. _. v3 C5 [/ D" S9 D$ z/ i" K
  29.                 {                                  % u. C1 c) H/ t3 ^0 |
  30.                 BKP_DeInit();        //复位备份区域         
    * ]8 c2 P* j3 A7 f; g
  31.                 RCC_LSEConfig(RCC_LSE_ON);        //设置外部低速晶振(LSE),使用外设低速晶振
    # ?$ g$ y  B/ C0 g
  32.                 while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)        //检查指定的RCC标志位设置与否,等待低速晶振就绪0 i: Y, W8 V& e/ y) _% c2 ]
  33.                         {: w6 a) \* j) N4 s
  34.                         temp++;
    + \% I0 n- ?% x8 ~: {
  35.                         delay_ms(10);
    6 Y( ?% e. J" ]4 }) Z0 l
  36.                         }
    " ?8 m2 T/ O) W% c! e  A
  37.                 if(temp>=250)return 1;//初始化时钟失败,晶振有问题            
    / W' `0 O/ C% E; C
  38.                 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);                //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟   
    " u: |9 U$ V) U4 l0 {
  39.                 RCC_RTCCLKCmd(ENABLE);        //使能RTC时钟  / _" {4 }, Z3 b
  40.                 RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成% T( M% B5 |6 z7 h
  41.                 RTC_WaitForSynchro();                //等待RTC寄存器同步  , H1 W1 T9 k. ^3 r
  42.                 RTC_ITConfig(RTC_IT_SEC, ENABLE);                //使能RTC秒中断9 n$ q3 g1 M; {1 o$ j7 q1 d
  43.                 RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成0 u/ G. P2 n& E# ]; B- s
  44.                 RTC_EnterConfigMode();/// 允许配置        
    3 G5 I% a7 c( u/ s4 H  S
  45.                 RTC_SetPrescaler(32767); //设置RTC预分频的值
    " m- D; a1 R# L4 t+ `# H7 ?
  46.                 RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成
    8 j5 ]0 y; |  p5 q* W8 g9 v
  47.                 RTC_Set(2022,3,18,0,41,30);  //设置时间        
    ; p1 a4 z3 `+ n% Q" H! Z
  48.                 RTC_ExitConfigMode(); //退出配置模式  
    : ]( f% _3 E' N! h9 I' Z4 U
  49.                 BKP_WriteBackupRegister(BKP_DR1, 0X5051);        //向指定的后备寄存器中写入用户程序数据
    2 S# `  a- l/ [/ ?) {% E
  50.                 }: N' J/ g( v5 l6 o0 k+ u
  51.         else//系统继续计时
    ; \- E4 {' w; D5 f+ K& j! i# q  I
  52.                 {- l9 Z9 r+ f# D+ N  @
  53. " `0 c: [- z2 z& B2 X+ K
  54.                 RTC_WaitForSynchro();        //等待最近一次对RTC寄存器的写操作完成/ Y& H. n: Y) o1 e; z4 q+ O2 t
  55.                 RTC_ITConfig(RTC_IT_SEC, ENABLE);        //使能RTC秒中断& _$ n, g! H$ z4 W
  56.                 RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成
    ) W$ k3 W5 S2 S- s5 U. V; L% o
  57.                 }
      r$ P3 d: l+ _
  58.         RTC_NVIC_Config();//RCT中断分组设置                                                         
    7 X- W( C; [1 _0 @; N
  59.         RTC_Get();//更新时间        
    ! X+ j" |8 }& M, z, P
  60.         return 0; //ok
    1 o8 v1 r* F9 x+ a% T9 X
  61. * ^' F8 K) h4 q/ E2 [6 c* T
  62. }                                                     
    ' x1 D% ]* {  l0 `: c4 ?" K, ?! \
  63. //RTC时钟中断5 e- l6 S% @: U5 D* T
  64. //每秒触发一次  7 @6 T  x" |) z, Y0 L8 f
  65. //extern u16 tcnt;
    + `0 D* |$ D3 E: Q) o
  66. void RTC_IRQHandler(void); R+ E. O+ w1 ]' M4 [- c# o
  67. {                 & B: z% E% {$ j
  68.         if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒钟中断
    9 d4 ^% f  w& q
  69.         {                                                        
    , ?# v) j+ S! J, q% W, ]/ y) A
  70.                 RTC_Get();//更新时间   # F1 i& h$ |) C- x( ], N' M
  71.          }) I6 h$ M6 A% j' `  v! \& F
  72.         if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//闹钟中断6 X, w' h- y, S* t# X# b0 V
  73.         {. U/ x: U- J, S, S2 E* M
  74.                 RTC_ClearITPendingBit(RTC_IT_ALR);                //清闹钟中断                  
    6 s) _% L5 H) I* j: d
  75.           RTC_Get();                                //更新时间   
      A6 S% @. v& K! c( @0 B* i! q
  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);//输出闹铃时间        
    6 E) R4 b5 d7 D3 J/ H
  77.                
    " \5 C1 M" [2 O9 q9 W; W2 E1 ~
  78.           }                                                                                                   
    & z; ^; d2 B# F( {2 G
  79.         RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW);                //清闹钟中断( y/ o# f: `( X5 }9 H
  80.         RTC_WaitForLastTask();                                                                                          
    * ~" u% x7 _- l- v5 f6 I8 r
  81. }
    ! p' Y5 k7 r1 t4 `3 ~
  82. //判断是否是闰年函数" c* O- _- P' i* H3 b
  83. //月份   1  2  3  4  5  6  7  8  9  10 11 12( s* D! S; P8 {
  84. //闰年   31 29 31 30 31 30 31 31 30 31 30 31
      q2 i/ F$ z# @  [. [" v
  85. //非闰年 31 28 31 30 31 30 31 31 30 31 30 31) f8 u5 c  w. g$ `$ t2 [3 [
  86. //输入:年份
    , p5 q  N' i; \0 T4 b) F; V
  87. //输出:该年份是不是闰年.1,是.0,不是
    ! L) K" S; P, C* a' V& Y$ `
  88. u8 Is_Leap_Year(u16 year)- K' @: V% T  D+ x
  89. {                          
    % F7 a0 S9 e5 t! l1 L5 z
  90.         if(year%4==0) //必须能被4整除
    8 |, a- _/ t' \5 ]
  91.         { 2 x2 k9 T. {1 c+ m8 K0 j  T
  92.                 if(year%100==0)
    . V& t9 c4 K  ^
  93.                 { ' J0 S0 f+ Y; I
  94.                         if(year%400==0)return 1;//如果以00结尾,还要能被400整除            0 |6 A+ x2 Y2 }/ f1 ]4 J5 B! t
  95.                         else return 0;   
      D+ x9 y: J# q' N0 S  @4 L! ?! J/ D
  96.                 }else return 1;   8 a  Z7 k4 \: }! Q/ F
  97.         }else return 0;        % p  S2 D6 C9 J, M+ ^. L$ Q* _, m+ Z: b
  98. }                                    8 q+ a0 E2 ~; f) t: z; ~
  99. //设置时钟' x* \; G+ D2 O! W
  100. //把输入的时钟转换为秒钟9 V2 T4 U+ m$ }, B, L
  101. //以1970年1月1日为基准4 l6 `, |. R, _: M+ ~
  102. //1970~2099年为合法年份( q- N8 m4 D) g9 Z, P8 O2 F9 V! X
  103. //返回值:0,成功;其他:错误代码.. j/ [& r8 C3 \
  104. //月份数据表                                                                                         
    ' e6 c9 m! E+ |! M
  105. u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表          0 k6 O6 l  g  k3 J% X( u4 ^
  106. //平年的月份日期表
    " F- s" P0 X1 f
  107. const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
    & v% v& k6 y5 G* Q8 [: C
  108. u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
    " `# ~' h' s# ?) w6 M, A  S0 E8 P
  109. {
    " U5 |% f! ?8 H4 x& z/ r
  110.         u16 t;1 ^" q) N. l6 U* j3 Q3 K
  111.         u32 seccount=0;: z0 s/ b; [! Q% E! w  U$ o0 N0 Z
  112.         if(syear<1970||syear>2099)return 1;           ; b2 A+ v; T. x  c# a
  113.         for(t=1970;t<syear;t++)        //把所有年份的秒钟相加
    , s4 S. l( m0 Q1 H( H/ s
  114.         {
    : [' m5 ~! Y+ V0 f& d+ M2 k6 S. K
  115.                 if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数2 y/ f% `2 s0 P; ~5 M7 S( [
  116.                 else seccount+=31536000;                          //平年的秒钟数
    8 p( {; x! Z5 ]7 m3 }' J% s7 |
  117.         }
    9 z$ h3 y  \: b  k5 T* d
  118.         smon-=1;  F5 X- [$ G/ Z7 A3 R- p" z+ ^* N4 o
  119.         for(t=0;t<smon;t++)           //把前面月份的秒钟数相加6 {8 \1 R0 R) Q, H* e/ g
  120.         {
    % L4 j' i3 |8 p' K! h) c
  121.                 seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
    7 [* Y! ]7 }9 h% S0 v& \- r- q
  122.                 if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数           3 m+ _. Q0 c1 a' t% X
  123.         }- u, S+ K% ?5 L9 t' }. g8 I
  124.         seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加 " R( F8 N+ \, w, T' Q! z1 Y& J
  125.         seccount+=(u32)hour*3600;//小时秒钟数
    1 L3 A' p0 M' Q
  126.     seccount+=(u32)min*60;         //分钟秒钟数
    " i. r3 M  @! K/ W! ], o
  127.         seccount+=sec;//最后的秒钟加上去( F% [5 u: s, ?# K
  128.   S9 K* P$ G3 x1 M( Q/ @
  129.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);        //使能PWR和BKP外设时钟  : x, o0 ?0 t  X, o, ^$ h! m# R5 j
  130.         PWR_BackupAccessCmd(ENABLE);        //使能RTC和后备寄存器访问 % L9 x; z9 f2 I: A5 |
  131.         RTC_SetCounter(seccount);        //设置RTC计数器的值1 \. @  Z% Q7 Z- t- f% M9 d
  132. ; h) G( A: e( l# Y! A
  133.         RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成         
    $ G( v7 y+ t3 e* _( ?7 x6 f$ p
  134.         return 0;            2 `7 F/ `$ Z/ n  l2 w
  135. }' J- _) _/ y! o+ J! y

  136. . n, u) D. a1 |* ^9 w  e3 X
  137. //初始化闹钟                  2 X% N/ T& D9 d8 W
  138. //以1970年1月1日为基准) X; K/ y0 C/ ]
  139. //1970~2099年为合法年份
    2 i4 y+ u  I2 S' n  Q; p3 U
  140. //syear,smon,sday,hour,min,sec:闹钟的年月日时分秒   
    / r; ?4 W# x/ `3 f, q
  141. //返回值:0,成功;其他:错误代码.  ~/ h. M8 U  u  D' I- I
  142. u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
    / q2 [8 m+ V  K8 `' e: g
  143. {
    9 C0 q7 u) X/ K
  144.         u16 t;& ^8 C; d( p, C* ^
  145.         u32 seccount=0;
    1 ~/ c8 l. G4 W
  146.         if(syear<1970||syear>2099)return 1;           
    2 K3 U' g9 q4 h: b
  147.         for(t=1970;t<syear;t++)        //把所有年份的秒钟相加# g; d! {- t, F: Y; K
  148.         {
    9 p& f! w6 \) x9 W, k
  149.                 if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数4 q4 R/ J% K- D/ `2 i
  150.                 else seccount+=31536000;                          //平年的秒钟数
    " y" K7 b7 f: p- g% h
  151.         }
    ) Q1 ^+ `0 s# L' g: p" S
  152.         smon-=1;
    # l2 ?: J# ]" T5 U* a1 t8 k
  153.         for(t=0;t<smon;t++)           //把前面月份的秒钟数相加
    & N4 I6 \( u5 b( |" s, ~1 X6 V0 j9 N
  154.         {3 j4 F7 z6 a2 ?7 |4 M) `
  155.                 seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
    3 a( o: s* W$ x+ X
  156.                 if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数           ( Z8 {% P" ~! N/ r
  157.         }* y/ l5 F& B1 f/ t$ p7 ?
  158.         seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加 9 E, }! ?, Z; N, h5 x, O, R
  159.         seccount+=(u32)hour*3600;//小时秒钟数5 L+ @9 z, x9 v
  160.     seccount+=(u32)min*60;         //分钟秒钟数
    3 q" V+ R( v6 M% s% E! u3 t
  161.         seccount+=sec;//最后的秒钟加上去                             
    * Y+ N- H0 ^8 w' U* x, _
  162.         //设置时钟
    ; z8 p4 h" R9 u" {# Y1 d* N3 [
  163.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);        //使能PWR和BKP外设时钟   
    0 P# x0 c$ v- F8 t: b7 v
  164.         PWR_BackupAccessCmd(ENABLE);        //使能后备寄存器访问  
    3 V, O7 x" ^! K" j& I
  165.         //上面三步是必须的!/ Y  k) Y; V7 b) l5 V3 {
  166.         1 X( O' ?; i9 o# i5 A9 K
  167.         RTC_SetAlarm(seccount);
    . D: ^5 X7 `! b7 H( W* A" W
  168. 5 ~6 j" [+ S7 Y  [) K2 r
  169.         RTC_WaitForLastTask();        //等待最近一次对RTC寄存器的写操作完成          % ~  t( x8 |# i4 c$ e, y4 F5 H
  170.         
    ) O- N+ j6 R( M4 O* ]: `8 W
  171.         return 0;            
    8 o, j0 N5 Q: n/ d4 O& m/ @4 c3 V
  172. }
    . x4 m8 a/ @9 H% ^' ~

  173. " [* ?3 {7 R* t- Y* Q

  174. ' ]* l5 a: J! q
  175. //得到当前的时间! v8 O! h5 a" G' @: ^1 b" ]( j
  176. //返回值:0,成功;其他:错误代码.
    / S% j3 _3 M# w8 U$ R3 b, t0 K
  177. u8 RTC_Get(void)1 v: |+ m) |+ {+ [* n$ G; d
  178. {2 w# a9 D, `( t
  179.         static u16 daycnt=0;
    ! ]2 p7 T) p% t0 ?! p1 t
  180.         u32 timecount=0; ' n& g1 P1 E% r
  181.         u32 temp=0;
    8 ?5 N6 Q4 M! q7 W% O7 f
  182.         u16 temp1=0;         
    1 S" f( r' H; T0 f6 z3 A  m& O* u2 j
  183.     timecount=RTC_GetCounter();         6 z" X, B/ Q9 n0 q: R9 s  j7 p4 k
  184.          temp=timecount/86400;   //得到天数(秒钟数对应的)
    % x9 Z4 A' ^& C+ J. z2 g
  185.         if(daycnt!=temp)//超过一天了
    # e3 @& G4 b' k4 ^% ]  x5 i
  186.         {         
    * @6 v* L4 t$ V! W
  187.                 daycnt=temp;4 |2 V! S4 w" f" G! \+ h
  188.                 temp1=1970;        //从1970年开始% t. m0 `! k8 c2 G& K' v9 e' D( u% X" n
  189.                 while(temp>=365)
    # i- M( |1 I: L, q( i7 C$ D
  190.                 {                                 & B  w. ?5 k; z' k9 ?
  191.                         if(Is_Leap_Year(temp1))//是闰年4 g5 V& [$ h7 z- [' V) f/ t5 c) S; Z/ _
  192.                         {
    3 ^! x4 m$ D8 H6 C0 b$ E1 t0 g; O( {
  193.                                 if(temp>=366)temp-=366;//闰年的秒钟数
    4 ~( f6 q8 P& Y
  194.                                 else {temp1++;break;}  
    1 X" Q7 `+ C8 Y! p8 W
  195.                         }
    2 G) B, H" k- V$ z. ?; y
  196.                         else temp-=365;          //平年
    4 @& y; L9 G$ d# |* i
  197.                         temp1++;  $ r" h' j. k0 ]: _0 ^. i/ c
  198.                 }   2 A) `4 |8 O- h
  199.                 calendar.w_year=temp1;//得到年份  N: l. F7 ]/ [& j9 x+ _
  200.                 temp1=0;6 v7 J' \3 v2 ]4 P* b
  201.                 while(temp>=28)//超过了一个月
    0 n4 j  C; Z9 N; M; G# _( r. a
  202.                 {
    $ o4 X) x3 Q" i2 p; \5 X
  203.                         if(Is_Leap_Year(calendar.w_year)&&temp1==1)//当年是不是闰年/2月份
    " H5 H/ y( A' [  Y! K. f) M
  204.                         {
    / x6 [1 l6 W' ]# ]7 e8 _" U
  205.                                 if(temp>=29)temp-=29;//闰年的秒钟数
    & b, m/ M4 |6 T& ?+ z
  206.                                 else break; + w8 i# G  n  A3 p; @) g
  207.                         }; T* S8 S" i2 f' b: E
  208.                         else
    - D9 {! U7 v0 A) i8 o& F
  209.                         {
    ; I& A. Q$ a- m3 N# ]9 j6 j
  210.                                 if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年
    ) g4 s0 \& }  |' F3 S& N* D
  211.                                 else break;7 j& h' f. c2 i- u3 g0 T8 ?& A# |
  212.                         }
    ' d4 R8 S- h: q2 @3 f* w, y
  213.                         temp1++;  0 d' e) O% q" Z% v
  214.                 }6 I- L  v( E0 X$ j7 Y/ k9 R
  215.                 calendar.w_month=temp1+1;        //得到月份
    " c5 T5 B, |/ J' T. p6 j& a; X9 W
  216.                 calendar.w_date=temp+1;          //得到日期 8 ?* p4 t$ x+ E: v  e1 c; n
  217.         }  V8 F+ U4 `4 n. ~
  218.         temp=timecount%86400;                     //得到秒钟数              ) }# @, b% ^' P# j' F+ n
  219.         calendar.hour=temp/3600;             //小时5 z9 t7 G* `+ ^" `
  220.         calendar.min=(temp%3600)/60;         //分钟        
    , @! E: [) J! x9 L$ }8 ^1 S
  221.         calendar.sec=(temp%3600)%60;         //秒钟: f: O6 v$ B, B% i7 i% v2 }6 @8 |
  222.         calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);//获取星期   
    , Q# r+ J3 ~9 |# H5 w0 h6 |
  223.         return 0;
    . R6 f; a8 v3 q1 g& Q# E
  224. }         
    - w7 X! `' k$ e; k
  225. //获得现在是星期几
    ; T/ r5 Z  N1 c: `' l
  226. //功能描述:输入公历日期得到星期(只允许1901-2099年)
    6 e# M; W; }  `# p. e
  227. //输入参数:公历年月日
    : B. G7 X: ]) I0 q% [# b. A
  228. //返回值:星期号                                                                                                                                                                                 2 m- R7 ]7 T2 O: @" m0 m
  229. u8 RTC_Get_Week(u16 year,u8 month,u8 day)
    - f4 l) q& d+ g, A4 Z
  230. {        
    / Z9 j5 J+ B! n5 c' L
  231.         u16 temp2;* r0 `" s( q) f8 X
  232.         u8 yearH,yearL;' Z6 S/ j3 {: P: Q
  233.         ' }/ a4 Y; z  ^% c
  234.         yearH=year/100;        yearL=year%100;
    4 t( T( l6 S, \: u* |! ]$ H2 T
  235.         // 如果为21世纪,年份数加100  ) a% Y. z7 x4 R/ A2 |
  236.         if (yearH>19)yearL+=100;
    : P6 a( Q, \# P4 O' u
  237.         // 所过闰年数只算1900年之后的  ; H# g( L3 v8 D3 x& C/ f$ q
  238.         temp2=yearL+yearL/4;
    % O  g% B4 k. n! w1 J  a) j
  239.         temp2=temp2%7;
    1 w8 T9 D* g1 _, l- L
  240.         temp2=temp2+day+table_week[month-1];) _# e8 O; x& h) }' p
  241.         if (yearL%4==0&&month<3)temp2--;
    7 W/ b6 s$ Q& i7 Z( Q
  242.         return(temp2%7);, u& b7 P' O5 H% u9 t. C
  243. }                          
    & |! ?+ F) B; Y$ t/ s8 c) Q5 `4 p
复制代码

: g; v' d% \2 N. ?dht11.c 温湿度传感器文件4 o1 ^+ G- G; M& v1 Z* P9 e

! r' |8 M+ v" l- h: E9 W; R2 {. x
  1. #include "dht11.h"
    $ f1 y4 w( e" c
  2. #include "delay.h"! e% K/ ~0 N$ \- x
  3. + }9 h* J  n+ f8 s* {

  4. ( \3 Z+ y4 Y% t$ y& v) k4 {3 `
  5. / t- D( S  {& V6 q
  6. //复位DHT11
    5 `# ?: ?2 a# v
  7. void DHT11_Rst(void)           ; ~- M: P1 z# z/ J3 `
  8. {                 
    ) u" `) k) {3 u/ F9 L+ v
  9.         DHT11_IO_OUT();         //SET OUTPUT
    0 E* @3 q* [: q( B8 L! l
  10.     DHT11_DQ_OUT=0;         //拉低DQ
    9 Y" J, |! b  r2 h9 G
  11.     delay_ms(20);            //拉低至少18ms
    - ^& i! K8 @+ d; ]4 D; i+ a+ z# Z, a
  12.     DHT11_DQ_OUT=1;         //DQ=1
    1 g1 g, F; V8 C  g' W, k2 Y
  13.         delay_us(30);             //主机拉高20~40us9 Q9 r9 w: j0 p# C$ U* M
  14. }
    3 n; F( D$ S6 ]
  15. //等待DHT11的回应8 r$ S( B" T+ M* B& y1 r4 V
  16. //返回1:未检测到DHT11的存在
    % x& [" Z+ l  k* G  x) c' n
  17. //返回0:存在
    + ~% o+ b0 U2 a2 J+ j- w& ~0 C( E
  18. u8 DHT11_Check(void)              [) y! @: n1 v) E0 C: k- k
  19. {   
    6 M6 T3 u6 Z0 s
  20.         u8 retry=0;- Y5 ^, O) S& E* i5 ?
  21.         DHT11_IO_IN();//SET INPUT         , g: ~. w8 W! O4 N- ]4 I
  22.     while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us
    3 b: r* Q% F" z: m2 x5 @
  23.         {
    ! |( A8 u2 a5 n. J
  24.                 retry++;
    % Q0 E  g4 {* g" E8 w2 \
  25.                 delay_us(1);
    . r/ I2 G; \' b4 d- l8 y0 F
  26.         };         
    " n" o& C5 w8 H1 c
  27.         if(retry>=100)return 1;( h' n- s. t# W
  28.         else retry=0;. x4 L/ w! i+ ^& Z: O
  29.     while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us
    3 k7 U: U$ T7 }$ U0 ?
  30.         {8 k: j5 F( L+ D1 s; U8 _' c
  31.                 retry++;, Z4 ~0 i* N3 V0 a2 P
  32.                 delay_us(1);
    3 L) K" }  {( U6 {$ W  d8 Q6 H
  33.         };4 @. v+ E+ t$ B" n/ v( B, k# J
  34.         if(retry>=100)return 1;            
    - y( B. Q/ ^) D4 I
  35.         return 0;
    7 L6 {  w& e9 a+ Q/ ^5 Y
  36. }2 R0 A: j3 h2 N5 h8 _: C; I% s5 x
  37. //从DHT11读取一个位  Q+ }5 M5 A9 ?# t9 k
  38. //返回值:1/0- w2 m4 a' h1 E) c
  39. u8 DHT11_Read_Bit(void)                          + d9 N  k! a" ^1 I. `, l, a5 Q9 d
  40. {. R; ^/ W- V% o) z# O- m" m4 {4 d, \
  41.          u8 retry=0;
    ( B3 E! ]% [: c9 d3 L
  42.         while(DHT11_DQ_IN&&retry<100)//等待变为低电平" r) T2 I5 h. [, V( P, u% ^
  43.         {
    $ }9 [0 |) `- K' s2 ], }% {
  44.                 retry++;
    5 Y: z/ D5 h2 k- M
  45.                 delay_us(1);# F* [& r" v& @; ~( |$ n9 y
  46.         }
    # b  C$ s" t! |- a( }1 U: P
  47.         retry=0;
    ) k: Z. w2 f9 }/ [; ]
  48.         while(!DHT11_DQ_IN&&retry<100)//等待变高电平
    ( T: A- C0 m' a  E$ q6 a
  49.         {
    % Y# i( G$ S8 ~6 N, j9 r8 W% I, c
  50.                 retry++;5 F+ |+ P9 ^. F8 a: {
  51.                 delay_us(1);8 A: `( k3 c, v
  52.         }& ^) F# Q2 Y2 L5 F
  53.         delay_us(40);//等待40us
    $ T0 y3 P/ I3 m+ g
  54.         if(DHT11_DQ_IN)return 1;( }8 R1 j- k$ o) ]" |( @  c- V
  55.         else return 0;                   5 O2 b* [4 Q5 v. f; u, n
  56. }
    ; u0 f8 y! q# [* c5 k7 z7 ^1 ?9 {
  57. //从DHT11读取一个字节
    6 ?% E# q9 y/ u& q$ L! G6 q. a
  58. //返回值:读到的数据
    ' W; g# v/ |6 w
  59. u8 DHT11_Read_Byte(void)    9 P4 k  s/ t! D9 [7 v# k: I2 h
  60. {        ( J! S% ?! K8 c- K, Z$ g0 Q) D
  61.     u8 i,dat;
    ' S, w+ A$ _6 V' R& }
  62.     dat=0;
    % Y* Z" U8 o; H( A' w$ A
  63.         for (i=0;i<8;i++)
    # k( V* O4 D( E$ E& U7 x5 H( `
  64.         {2 @. `: U9 W7 u, ?
  65.                    dat<<=1; 4 E  V% i  |! t  D- A% a
  66.             dat|=DHT11_Read_Bit();
    9 ^/ f  r& u$ h' @6 B  t; V8 p
  67.     }                                                    1 U9 I% I& {8 p: T! _7 y, F0 R+ Y
  68.     return dat;
    " M* @2 }' H+ f+ }
  69. }
    3 z3 l3 G" ~% U, C8 Z8 B
  70. //从DHT11读取一次数据
    4 _+ `. U5 N0 W( o4 E5 j4 ]$ [; c0 w
  71. //temp:温度值(范围:0~50°)9 M/ G* V$ c- U5 E, L
  72. //humi:湿度值(范围:20%~90%)/ J& u0 }; @& H8 F: G6 w
  73. //返回值:0,正常;1,读取失败
    ; s( }5 y7 @% V
  74. u8 DHT11_Read_Data(u8 *temp,u8 *humi)   
    8 G5 b0 n9 ~' E( @9 D6 P0 i
  75. {        1 I; g4 O6 H8 t& ?+ k
  76.          u8 buf[5];4 Z# n  ~! D* `( u% F1 J: ?2 x, p
  77.         u8 i;' o  ]+ b1 d! i' }
  78.         DHT11_Rst();
    ( T' ?( J; \8 N6 w: _7 Y
  79.         if(DHT11_Check()==0)
    . d/ m$ F, ?% E
  80.         {
    * Z" t% Q& t+ Z, N: h! f* k6 O8 G
  81.                 for(i=0;i<5;i++)//读取40位数据
    2 e! m% K( j# f$ o  o! K+ k" Y
  82.                 {
    1 K7 X- O. E- K* Y
  83.                         buf<i>=DHT11_Read_Byte();7 N- n) s) Q4 @; h  s% W
  84.                 }5 U: P3 [- b5 f' A  d" T. \
  85.                 if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])% b+ H! f4 o& z" T) T5 ~
  86.                 {" R# c, U( {; ~# N% h
  87.                         *humi=buf[0];9 ]6 [* G2 a. W7 ]: B% x: t
  88.                         *temp=buf[2];
    ! q$ Y/ o( S8 S
  89.                 }+ W6 @8 o# Y6 _' v! G5 M- f
  90.         }else return 1;
    0 J; r1 K7 h0 H+ T# O9 S* A
  91.         return 0;            ; ~7 J- e7 q: y
  92. }
    ! }2 O% c: |; e5 m( ^3 j
  93. //初始化DHT11的IO口 DQ 同时检测DHT11的存在
    + g2 i, \$ f% V
  94. //返回1:不存在; x0 C! i: w+ ~+ ?0 |& m9 Y
  95. //返回0:存在            
    - |) q, T4 u$ _2 e
  96. u8 DHT11_Init(void)
    $ Q4 f9 _3 z" h; @1 o5 y, \# p. W
  97. {         
    ; F6 e3 `9 u4 k& X
  98.          GPIO_InitTypeDef  GPIO_InitStructure;8 I3 _4 p, v  F: O
  99.          : ]! U; c0 U2 ?, x( E5 f( ?" s$ }
  100.          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);         //使能PG端口时钟
      {! m3 z- \9 I
  101.         
    ( P& m  d3 J; Q4 U* @$ i  R
  102.          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;                                 //PG11端口配置
    7 Y1 t0 v& U" N8 j" ^  g! k% ^  T
  103.          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //推挽输出
    1 C8 Y1 m+ I! W7 j
  104.          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;# A! H7 g# z& e1 s: [
  105.          GPIO_Init(GPIOG, &GPIO_InitStructure);                                 //初始化IO口* e  _+ ?* E/ ?9 _/ x1 s1 R
  106.          GPIO_SetBits(GPIOG,GPIO_Pin_11);                                                 //PG11 输出高
    ' z. S* e$ i" q
  107.                             0 V, k8 N3 }3 n7 L
  108.         DHT11_Rst();  //复位DHT11
    2 R# _- C0 Y! e" d. B5 A/ `1 B) s
  109.         return DHT11_Check();//等待DHT11的回应. j0 `" P: n4 q8 g: v" Y" r0 ]; O
  110. } </i>
复制代码
6 C& ?- Q$ ~/ A, k1 d. N
adc.h 数模转换 心率传感器文件' L' {/ ^$ B; h1 t

, W- s: p+ X: Z8 s
  1. #ifndef __ADC_H7 ?* z9 N& B: R/ U# S. l
  2. #define __ADC_H        ) N/ }- r; H* {0 I! v
  3. #include "sys.h"' r; k1 R8 V, I" i: I
  4. 2 P0 ~2 I% _4 r
  5. void Adc_Init(void);
    0 C1 z' D4 W  ~$ A
  6. u16  Get_Adc(u8 ch);
    % W2 m. k0 k5 m9 k+ W5 t
  7. u16 Get_Adc_Average(u8 ch,u8 times); ) x6 ~4 R' q2 p' Y
  8. u16 OLED_Get_Pules(void);! ]* ]+ _, }' H' A- b) k  A" q
  9. #endif
复制代码

  D/ E' {" K6 {, H) ]/ z& ~4 tadc.c 数模转换 心率传感器文件& `% d, Y) j/ L; X7 y
8 f% z! L) l8 r9 j+ E
  1. <i>#include "adc.h"</i>
    6 f7 Q/ g# t6 F' E- H3 Q
  2. <i> #include "delay.h"</i>
    ; [, K8 F1 g1 r# z; d, Q( Q- l

  3. 2 U, j# G+ k3 C+ x! }( }7 g/ C
  4. <i>           </i>
    ; L3 l% \/ A8 X: ^' s* F% t' b
  5. <i>//初始化ADC</i>  r8 s% N, r4 ]: p3 d, ^
  6. <i>//这里我们仅以规则通道为例</i>
      A0 N, x& R! j$ K9 n( u4 a1 f
  7. <i>//我们默认将开启通道0~3                                                                                                                                           </i>
    8 I. U; f9 I8 d( E
  8. <i>void  Adc_Init(void)</i>, T6 V5 D7 w+ M# Z  H: Z
  9. <i>{         </i>) \% w. |/ V* Z7 r4 A& N+ x
  10. <i>        ADC_InitTypeDef ADC_InitStructure; </i>/ I0 h0 v. `2 h( Y
  11. <i>        GPIO_InitTypeDef GPIO_InitStructure;</i>7 @, y3 Z1 ?* P* \
  12. 2 w! A. ^% L+ _) B/ m( A
  13. <i>        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1        , ENABLE );          //使能ADC1通道时钟</i>
    4 d! u4 _2 `& ^1 g

  14. ( v9 ]9 o! y5 w9 o# A/ Q' J
  15. 7 P; K1 `6 o) ~: \& s
  16. <i>        RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M</i>
    + V& U( M6 ?$ I7 l
  17. 4 \% x( C' Q! r) |7 J7 N/ s% g
  18. <i>        //PA1 作为模拟通道输入引脚                         </i>' @9 X1 M/ h6 _  y, E  m, s- [
  19. <i>        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;</i>
    , c. |- S. u& C5 \+ e
  20. <i>        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚</i>; v( C3 b1 m7 Y4 s6 R8 A
  21. <i>        GPIO_Init(GPIOA, &GPIO_InitStructure);        </i>
    ( B0 n8 J! ~6 r$ r% w2 {3 O
  22. ; b( }& |0 z8 Y0 r! J; `
  23. <i>        ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值</i>  Q. q- ~  a2 z, [- m' T

  24. ; R6 p1 ^- O2 F+ C' ?* z: V
  25. <i>        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式</i>
    % x! f& [$ G, N  o# K: v( j
  26. <i>        ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式</i>' K7 g3 w) B; U
  27. <i>        ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式</i>0 F/ Y6 m- [0 F7 x) I7 m7 U
  28. <i>        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动</i>; G7 {8 Z- N  r" y9 k  P' ~
  29. <i>        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐</i>: n% v7 }* ^6 C/ G0 ?$ C) i: ]
  30. <i>        ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目</i>
    ! Z6 N& Z$ z& e% I1 e' E  z
  31. <i>        ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   </i>& g& x* `" s, I; ~) n
  32. ( |! E0 T' G3 h/ _  s" {
  33. 8 v1 Z+ m' }+ `
  34. <i>        ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1</i>
    9 }, ^, w+ c' n: s& b
  35. <i>        </i>
    2 k& I3 M, q+ \6 i
  36. <i>        ADC_ResetCalibration(ADC1);        //使能复位校准  </i>
    # }) c+ r1 |  h; w  B
  37. <i>         </i>
    ' B3 w0 [' ?& a! Y3 V5 U! ]
  38. <i>        while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束</i>+ p. I. O! b. Z8 I* l& \0 K
  39. <i>        </i>
    4 F% t" ?. ^7 A+ P
  40. <i>        ADC_StartCalibration(ADC1);         //开启AD校准</i>
    , v9 X2 Q: l& a, m% J2 s
  41. . `; h/ w/ z# h$ r' |
  42. <i>        while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束</i>
    5 J1 O" _0 ^! ~4 F& r: X& g
  43. * h. m. @) S2 u( X/ H6 ~
  44. <i>//        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能</i>
    7 T$ B  s* N* H$ m2 o, x  @
  45. % {$ c$ \, e1 |. i! x# Y
  46. <i>}                                  </i>! m2 x3 p$ ]7 A* z
  47. <i>//获得ADC值</i>6 T( Y; n0 k" c* D4 C8 W3 h  m
  48. <i>//ch:通道值 0~3</i>3 O6 E  y! ]$ v! |2 {
  49. <i>u16 Get_Adc(u8 ch)   </i>
    . y' o- X/ d5 q/ j
  50. <i>{</i>) `* Z/ y8 a' Q( b
  51. <i>          //设置指定ADC的规则组通道,一个序列,采样时间</i>( N& I! S" }- e+ D% M2 i5 J$ F. K' j
  52. <i>        ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期                                      </i>$ I8 I7 F& q$ q  S' m1 e- o

  53. % w" a6 H4 m9 K4 U0 j) O
  54. <i>        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能        </i>/ [+ a( L0 k: R+ U; q3 R* Y# ]) ]9 D
  55. <i>         </i>
    & ?9 q5 D" I% m+ a. Y
  56. <i>        while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束</i>7 s7 r, Y" e3 ^' F% @! y% H& B
  57. ; B! U  r/ B7 o
  58. <i>        return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果</i>1 F! R: v! a. D, J$ C/ B& I
  59. <i>}</i>' M9 ]# Z: {7 b- q( M( D
  60. : n+ n$ c2 u, Y! G* b
  61. <i>u16 Get_Adc_Average(u8 ch,u8 times)</i>" y& `; v$ X! R% h* C1 k
  62. <i>{</i>
    / i& n  U1 t( [2 k: y4 M
  63. <i>        u32 temp_val=0;</i>
    , r6 N. s3 z2 g1 \" A/ ?
  64. <i>        u8 t;</i>
    3 C; F! H( n5 `+ c8 N
  65. <i>        for(t=0;t<times;t++)</i>
    2 s+ f: \' X4 a; ^, b4 s3 D
  66. <i>        {</i>' S! J% _2 L) N2 j/ e5 L: R) t
  67. <i>                temp_val+=Get_Adc(ch);</i>, u& _( L4 y9 t; G) U
  68. <i>                delay_ms(5);</i>
    & H5 B0 g, L7 j2 G& }. f2 Q: w
  69. <i>        }</i>, ~2 B' o4 U. P. X2 B
  70. <i>        return temp_val/times;</i>
    1 g3 z6 y! ^/ J% ^
  71. <i>}          </i>" O5 w# q, l2 V& {' L: |+ K
复制代码
6 p6 k/ h8 U: V5 w3 R" k; ?
. d! Y% R7 P2 T# B* W
; O2 X4 y( c9 \" r6 v

# Q' e- B0 M! n2 L5 [: u- _. K9 i
收藏 评论0 发布时间:2022-5-25 19:00

举报

0个回答

所属标签

相似分享

官网相关资源

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