测量运动自行车速度,上传给上位机软件,处理VR视频播放。正好公司有现成的stm32f1系列单片机开发板,所以我就想到了使用它来实现这个小功能。
# ^( f8 F! {, v, z7 O7 w
5 i' Q8 y6 H2 X1 T) h1. 硬件配置:
- R8 X6 }1 c. s) `6 z" Q) \ @) s5 P/ F) D
1.1. 运动自行车;' U# V4 O9 K" }, j
" [( z) g" U# d/ x
; E$ E2 [9 H6 o( q* v5 ~
# |1 U& O0 g- q& M8 l( z5 l
1.2. 磁感应开关与专用磁铁;
5 k3 b" e* J5 H8 X
4 ?3 m" c! n, h8 D# n, E8 n: c m/ a8 A' d; E) K* Y
2 X8 B V( x) X9 l& P7 G
1.3. 基于Stm32f103zet6芯片的开发板(七星虫),如下图;
' r, X: C! b# C6 \; j3 U+ P
' k# u# x3 e; y
) T) _( [0 g# e3 j1 G9 p, ?; E3 g* \4 V) Q6 y
1.4. 连接线若干;
& E! Z) r/ b# _: f% a# s7 Y0 Q7 }* b
1.5. miniusb线缆,用于给开发板供电及串口通信。% {+ y1 D4 B0 m+ P+ J) g; F3 T
% }% y9 n: ?# Z4 ]) Z/ U V+ x
! h5 g3 m$ s. y& l% P/ P# U, r6 b# \6 A x- k
2. 系统描述与框图:
. E9 W# K1 r. g r. b- k
2 [3 G1 E3 o0 V" x9 H运动自行车车轮上安装5只磁铁,通过磁感应开关检测磁铁产生信号,接入stm32开发板PE0引脚。测量出的速度值通过串口发送给PC上位机软件(mini usb线缆连接)。硬件框图如下:
! i8 ?( ]1 c" Z; E1 y1 I9 u# L; E+ ~% o% Q
+ u+ e- l1 R! X6 Y4 |+ l6 k' T2 _2 Z9 w w* C
4 N; ~" ^7 D! t7 b
1 g$ L6 L# X: w0 b, c3. 软件实现
- N2 t0 h2 e, D" d- Q, Y* ]* R1 v) ]& y& x( F2 O5 }: ?
3.1.设定开发板PE0引脚下降沿中断,在引脚中断服务函数里累计中断次数(即磁感应开关感应到磁铁的次数),同时每累计10次LED2交换一次状态。外部初始化代码及中断服务函数如下:
1 R5 V7 K4 }& E( H
4 V/ t9 V& R" W+ C4 u# C7 h- void EXTIX_Init(void)" p% Q8 n% M9 U- Y9 A$ `; P3 C8 A
- {
2 z9 }. V0 N. T* P7 ~9 V& ^ - EXTI_InitTypeDef EXTI_InitStructure;
/ R/ b8 } i3 L9 M# z1 ~8 J - NVIC_InitTypeDef NVIC_InitStructure;9 @7 l* m! y% Z1 p* c$ v
- GPIO_InitTypeDef GPIO_InitStructure;
) w2 ~' C! U0 F7 r3 H' U& p - // 引脚端口初始化 PE0
" X; D1 A+ _+ d! l a7 i: u - GPIO_InitStructure.GPIO_Pin = DEF_BIT_00;
7 s7 z5 B; y A% j" c n- K - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
- |9 H4 t2 E# V& _0 ^4 o$ O - GPIO_Init(GPIOE, &GPIO_InitStructure);
* K0 ^" s$ d! C% ~ - // 启 AFIO 时钟
7 f0 k1 c! }& _ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
. W Z$ U) U/ }0 @ - //GPIOE.0 中断线以及中断初始化配置,下降沿触发% u+ O. g; S9 O+ h
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource0);// 配置中断线为0
4 V$ d6 X- C4 _' s$ \# U* o - EXTI_InitStructure.EXTI_Line=EXTI_Line0;
% }8 F3 n9 U+ ]2 v8 _8 E - EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;# b1 s/ I2 r# X$ J% ~ }& T
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发
0 A) ]( q* Q, J4 E8 W+ T; w - EXTI_InitStructure.EXTI_LineCmd = ENABLE;0 [7 T, @5 t3 }; F9 n" V" i
- EXTI_Init(&EXTI_InitStructure); // 初始化中断线参数" H0 q) z- G' n- @
8 a# ^$ t; F- i/ z- NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按键外部中断通道
7 ]; u4 t: W' N - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2,4 r6 z% X; K6 U. p) A& D
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级 2
0 \/ r- i. l* O7 \ - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道* i8 B. x* Q2 Y4 k
- NVIC_Init(&NVIC_InitStructure); // 初始化 NVIC
5 d3 M4 O: _ U& G7 @ - }- i `2 d9 p1 K3 |" I
- // 外部中断0服务程序
' }. {2 h' R- g9 e) `1 y - long long lSpeedCnt = 0;2 q4 k) i! S/ l; T5 E
- void EXTI0_IRQHandler(void)
% i/ [6 w B. E2 m. ]0 C& ?: w - {
. h& {) e i! E8 Q - OSIntEnter(); // 告诉ucosii系统进入中断3 ~3 u% D }/ M! l" v' h1 A; B N ?
7 D. S7 W# w3 m& g6 g% X& B- if(GPIO_ReadInputDataBit(GPIOE, DEF_BIT_00)==0) // PE0检测到下降沿4 g( K) e$ b# W1 z$ Q& v) u
- {' K9 k1 U8 }# G; E& C5 M
- // 累计中断次数,每隔10次改变led1状态" n( X. |* L7 C$ o8 g
- if(!((lSpeedCnt++)%10))* T! G0 T1 N2 } p- J6 C% R
- {
' ~% Q# N9 B/ k. |0 W - BSP_LED_Toggle(2);
) m; p! ?! F" x; R- P( u - }
, A$ Y V, N7 a - }/ Z8 s& J8 K& T
- EXTI_ClearITPendingBit(EXTI_Line0); // 清除LINE0上的中断标志位
9 F6 i. M- L3 [# C, Z
L* I" x0 X; x- [' f5 j- OSIntExit // 告诉ucosii系统退出中断
( a( t% k I7 D* P' Q, B0 v - }
复制代码 * k) e3 L0 J( g% |3 M: b. x7 n- E& w$ `
. k u( u, ]1 |% P3.2.在启用一个定时器中断,周期为1s,在定时器中断服务函数里计算自行车的速度。计算方式如下:v = p / μ * C,其中:v是速度:m/s,p是磁感应开关感应频率, μ为车轮上安装磁铁个数:5,C为自行车车轮周长:1.38m。定时器中断初始化代码及中断服务函数如下:1 s, J% y8 ?4 i0 D' r$ c6 h
/ o- M0 a! j+ l- /*******************************************************************************# ^9 v/ T5 F* `8 c2 d6 H
- * Function Name : BSP_TIM2_Init
; j4 H; w/ f* ]2 h - * Description : Compute return latest speed measurement
# W* C2 N2 v8 T6 d5 f3 ]9 N& w; ]8 n - * Input : None! j/ y+ b s" G) G: d
- * Output : s16
6 w6 c- G) W" h# } f4 n - * Return : Return the speed in 0.1 Hz resolution.
# p2 T: D8 u/ e& i3 t# t - *******************************************************************************/6 U& P" k- v9 B2 \& I$ Q7 Q) T
- static void BSP_TIM2_Init(u16 arr, u16 psc)
4 _0 i7 W& F8 Q - {% r/ J, [# V9 K3 {1 y5 q
- TIM_TimeBaseInitTypeDef bsp_tim2_init;
7 E# u* V0 M( q) D# _) S
. b. ? |( }7 @" l3 e7 e- //使能TIM2时钟, K* Z5 G* o: `% E- C
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);3 l* R# F& r8 h, G6 G
- ! q/ Q& }0 E) ?+ k6 c: H* A
- Q! p2 R! c, ^9 C! X
- TIM_DeInit(TIM2);
3 ^0 x3 @1 ^9 k! h - TIM_TimeBaseStructInit(&bsp_tim2_init);
# u0 X+ d/ T( g$ [4 i# G8 h) {8 ] - //TIM2初始化
! W* a. |: G! \6 Y' u - bsp_tim2_init.TIM_Prescaler = psc; //时钟预分频 定时器每隔 (psc+1)/72 us计数一次/ z, c9 o# q( ] [/ R u& s6 ^
- bsp_tim2_init.TIM_CounterMode = TIM_CounterMode_Up; //向上计数5 J+ b. o; y2 e; u9 E$ p! ?, {! Q: e
- bsp_tim2_init.TIM_Period = arr; //计数满(arr+1)次更新重装载寄存器数据% [3 b- r: E" d: y7 x. E! E' @
- bsp_tim2_init.TIM_ClockDivision = TIM_CKD_DIV1; //时钟不分频
2 y4 ?3 s3 D4 J; v- Y/ ^ - // bsp_tim2_init.TIM_RepetitionCounter = ; //高级定时器用,这里不需设置, L) q; p- B5 H
- TIM_TimeBaseInit(TIM2, &bsp_tim2_init); //初始化定时器, ?7 p% ]2 I6 n& y# X
- & D) {( N6 F% _! s9 B- U _% C
- //设置定时器TIM2中断
9 @1 a$ B! V. u& O" d* p3 a - TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //设置定时器更新中断
) z* \5 i, p9 I0 X: Q+ F# _! K- g - TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除中断标志,防止刚上电时进一次中断- \, I6 e0 \! N6 T
, g( }4 i* w; [% ~ P% Y- //初始化中断2 {# {3 z- f! Q, o
- BSP_NVIC_Init(TIM2_IRQn, 3, 3);
6 G( e+ H- {! N5 H - . {' a {7 w" m6 |$ A0 P- u
- //使能定时器TIM2. y* }- |$ K9 f
- TIM_Cmd(TIM2, ENABLE);
% t. Z1 `# ~& N1 c- a) x0 j - }
复制代码- long long lvalCur;
4 J5 F; E4 |5 u$ f' O - long long lValPrev;
* t* q" F6 p& m- u0 j$ Y - float fSpeedVal;3 K! w. B, X: |
- void TIM2_IRQHandler(void)& Q$ }' }) S, o& G
- {' X1 c2 ~" E! q* S
- OSIntEnter(); // 告诉ucosii系统进入中断/ S1 x, O( Q5 }. E# D3 m
7 A. u3 r- x- x0 ]- if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
0 ]; E. w; s+ _& @0 @ - {
, N/ m L4 f# o7 [. g8 q: X8 G - extern long long lSpeedCnt;
$ n- z+ C4 L! ~4 f% U% k# a
& D1 I# j8 K' g, M5 C2 L V- lvalCur = lSpeedCnt;
/ d3 `' I! k# T: n/ H; A( N - fSpeedVal = (float)lvalCur - (float)lValPrev;
) x) n) N% T- z: D6 f ~' X- _ - fSpeedVal /= 5.0;
( L- S" `* p/ t( p( {' F y - fSpeedVal *= 1.38; : p7 V* {. E) y
- lValPrev = lvalCur;
# X# w$ i0 X" q- g3 h - TIM_ClearFlag(TIM2, TIM_IT_Update);
8 h& p) X6 `2 I- o+ s* U9 P - }' ^; O- H, m4 r& a; y t
- OSIntExit(); // 告诉ucosii系统退出中断4 g& r0 H4 H, j9 Y# L H
! H7 a7 U- c% y& `- }
复制代码
0 Q1 \! l* [4 b/ D4 j' Z! G: V3.3.系统共有两个任务,其中一个任务每50ms发送一次速度值给PC机,另一个控制LED1闪烁,周期100ms,用于指示系统正常运行。
0 p$ i$ {( c2 J4 h6 q+ \1 i! g6 d9 ?* d4 u- P/ T: P* P( g
第一个任务中运行代码如下:
5 V% ?5 ]3 f' O" S
( j( E% \$ S. p- D0 X' _! w G( r) `- while(DEF_TRUE)
) M/ }( H o6 L- _ - {
1 x% v0 B6 }9 h- b2 D' ? - extern float fSpeedVal;
) Z' w% _1 @9 N- q+ m - if((int)(fSpeedVal*100) > 9999)6 s& _- U9 |! s1 u
- {' Z6 W& q$ l+ Z
- printf("9999"); 8 X& C( O' a) K
- }
* W' E7 l' D/ S$ S( s/ L - else if((int)(fSpeedVal*100) > 999)
0 S, w' C |5 } - {- {! k4 \* d+ a# o
- printf("%d",(int)(fSpeedVal*100)); o* J; y2 [0 f
- }
5 E5 i/ l s9 o( |2 C1 f - else if((int)(fSpeedVal*100) > 99)/ o' j: ]! x0 F& d6 W o. g5 y
- {
+ d5 U p2 a! O9 J - printf("0%d",(int)(fSpeedVal*100)); 0 Q2 W1 O$ r% a
- }
5 _/ j% {8 }! P' F - else if((int)(fSpeedVal*100) > 9)9 Y$ {5 Y" q) A* u, D& p5 d; X
- {
, u8 I9 S5 S% t: v& k - printf("00%d",(int)(fSpeedVal*100));
/ P( Y$ B+ u, z! ] - }; n, z8 {+ h/ L8 `8 w- X3 e: Q7 R
- else
5 C4 o# Y% T; o) u2 E* o( A" [ - {
0 }8 i* \3 K2 R - printf("000%d",(int)(fSpeedVal*100));
% E0 j- w, N, i - }
# m0 A- A, c, v/ \& U: Q - 4 u1 l" H6 H) h, K- K- a" C
- OSTimeDlyHMSM(0, 0, 0, 80);7 ^" g. U$ B$ q9 U9 m/ ]; E6 {
- }
复制代码 " s0 J% D' K# [) Z1 Q
第二个任务中代码如下:5 [: G3 R. \/ H; y/ \3 T4 ~
3 l4 w7 o c% \$ o# y
- while (DEF_TRUE)
% C" p/ f; M, Y; j& p0 ]- }; i* _$ y& s - {
) j" W# ~! M# c% D - BSP_LED_Toggle(1);
4 @& q4 W% v1 ?9 F5 m" D - OSTimeDlyHMSM(0, 0, 0, 100);! L5 P! P, z4 J7 E' |
- }
复制代码 : n Q+ o, Y7 E2 O
整体运行稳定,满足项目需求。
( y$ C9 J7 w: I, x1 y4 V
7 m. E g2 d! e/ G( Q* C7 @2 h4 C6 j6 ]* A K! p
|