- int main(void)+ c5 n( o6 U! l; S( l. M6 t8 _
- { + O. r4 a5 G5 }2 `5 F' ~
- char str[10];
( n5 ?7 } m# y. J0 F8 @" P2 d - delay_init(); //延时函数初始化 1 c( H( \( w# V& }( Q* z
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
; G) r5 W5 l9 C4 w - uart_init(115200); //串口初始化为115200
5 { Z+ [' f6 P M2 b, x4 [ - LED_Init(); //初始化与LED连接的硬件接口
6 @- H" i& G0 O - EXTIX_Init(); //初始化外部中断输入/ m k/ Y" {1 C: d
- LCD_Init();
. i$ y/ O( [* a2 m" y) u - TIM3_PWM_Init(499,7199);
! s1 l6 J9 R( p: t; }. g! z1 n - TIM2_Init(4999,7199);
4 {8 o5 u+ I- E- R* T) p) ` - LED0=0; //先点亮红灯
$ c3 r8 h& {5 D - TIM_SetCompare2(TIM3,250);//设置CCR2的寄存器值为250占空比为50%5 ^8 \: L% ~4 O3 k- P6 L; ]$ `
- LCD_ShowString(45,125,200,30,16,"-----freqency-----");, S: I; S) e! p8 n1 G7 `5 D3 b" y
- LCD_ShowString(130,165,32,30,16,"HZ");3 v* I% T- h5 k$ g5 o! _
- while(1)
! i% q& ~; E, a0 O: O1 d - {
, G7 W2 X4 l% M$ [9 a5 M; D: j - freq=10000.0 / (float)time_of_circle;# A4 ?3 O7 ~6 A. C
- sprintf(str,"%.2f",freq);' t7 F/ u% ]: x1 E& {, K
- LCD_ShowString(50,165,64,30,16,str);
' Z4 m8 S8 p' o2 K( d - LCD_ShowString(45,125,200,30,16,"-----freqency-----");4 C" A/ ^9 P* d! N' D
- LCD_ShowString(130,165,32,30,16,"HZ");; X, v4 f5 s) c; s m9 r
- }
& `% c3 N D6 O' d0 } - }
复制代码
+ i8 ~, `% Q; [6 X( J3 z+ m2 i; b j/ y: }& K9 Y
) [. k5 ]6 R& L: u( O
5 m- i6 M# z) F( f3 c8 s0 p8 h4 T0 v& q7 O( [! D/ G+ t
. R. [5 r0 O5 d
6 x# o0 G) C1 l1 S/ M3 B3 [& J单片机产生频率为20HZ的占空比为50%方波 通过单片机产生方波很容易,设置寄存器ARR的值就能确定周期。设置CCRx的值就能设置设置占空比。 当CNT寄存值小于CCRx的值时输出低电平,大于CCRx的值时输出高电平,到达ARR的值时溢出。知道基本的原理后通过寄存器初始化和使能相关的寄存器就可以了。 这次实验采用TIM3 CH2不重映像,同时设置PWM模式为向上计数模式。配置步骤如下:
. K. N* @7 A' Q0 n& ` , J# \0 Y' K! L* J2 j1 L
$ k5 E2 O- V% A" Z9 B0 |2 [; C
1 ]% A! ~. q( K W+ V! [5 V& y% }1 V% u9 Q
- 开启TIM3时钟,并设置PA7为复用输出
- 初始化TIM3,设置TIM3的ARR和PSC值
- 设置TIM3_CH2的PWM模式,使能TIM3的CH2输出
- 使能TIM3
- 修改TIM3_CCR2来控制占空比
( _: g* v* L2 k; x" c+ F
3 `) V* c$ ]8 c6 a. P: |& ~6 k9 f
8 s5 z% s" q* E6 m) w- //TIM3 PWM部分初始化
# R& q6 ]9 n- R; _2 w! j5 l - //PWM输出初始化4 G1 X4 }, V7 P' S
- //arr:自动重装值
5 f9 a8 D2 p9 x0 S7 M. L% k - //psc:时钟预分频数& j2 J6 ^' P/ J* u: ]
- void TIM3_PWM_Init(u16 arr,u16 psc)
' ^' q4 }9 \( m9 W - {
$ Q5 U# A0 K5 O) @" U5 N - GPIO_InitTypeDef GPIO_InitStructure;) X- ` j# N% V4 B" {. {
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
9 I6 p1 t4 G: Z/ h8 O/ E - TIM_OCInitTypeDef TIM_OCInitStructure;
! n; w+ I5 t5 _ S6 ~1 K- g' h -
. U4 C/ {% u, i: [6 ~
) \. N. W! [% ?8 m1 ~/ J- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟1 D' q# z3 M4 U/ s+ n
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //①使能 GPIO 和 AFIO 复用功能时钟4 F% K9 e8 G, V: m4 k5 a
- // GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); //Timer3部分重映射 TIM3_CH2->PC7
1 d1 |7 J. h- Q1 U - ; E. l+ d9 `9 ^. U% p
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //TIM_CH2
" W1 R8 x: a2 e - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
* A; N7 @0 ]7 w; w, m - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
8 v- j& W0 b! {9 T4 u( w - GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA% v* e; B- N' w5 ]
-
& A: C$ g7 `! v; @" y! Z) K - //初始化TIM3
2 n% a3 z3 F6 K! w3 ~) A; G - TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
- v( K9 w, B$ _/ q- }8 }, T - TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 + s" f4 T W( m) ~) |$ M1 M
- TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim5 _- E ? D* B5 y% i$ g
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
# V! s) w# Y6 T$ K* x; |: A9 N9 Q - TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 L. d5 i1 ^/ K8 R/ [) K
-
/ a4 b, C8 {* F! I0 F - //初始化TIM3 Channel2 PWM模式 ; R& ], C/ o4 d" S( J+ p
- TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式26 K7 l% v8 J7 j4 b; I# R9 I
- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能3 A1 N+ r* s9 g4 u7 g' F4 u
- TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
7 Q& w; e) I, P: e/ U3 |/ K - TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC2
* {& W) x4 {7 @- v3 f* \/ f - ! R" l8 B; |1 h: i6 H0 Z9 o
- TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR2上的预装载寄存器
4 N/ C7 u* q1 K" a- h0 [ -
- s0 ?4 j1 S3 _3 \1 o - TIM_Cmd(TIM3, ENABLE); //使能TIM34 D w0 P8 @, G( ]% |- ]
- / G2 A* t% i7 m% c
- }
复制代码
. M- n+ B4 J! {& t
/ R1 C& b; b0 f! l 以上代码就完成了PWM的初始化,如果要产生20HZ的波形,那么就相当于要没50ms要溢出一次,那么我们可以设置arr的值为499,psc的值为7199。Tout= ((arr+1)*(psc+1))/Tclk=(499+1)* ( 7199+1)/72=50ms 。说明计数到500次为50ms,那么设置CCR2的值为250就可以实现占空比为50%。 8 z4 B& ~, Y4 }
单片机测量频率并显示
* A, B9 u- r+ p1 N/ C& w$ m7 Q( V测量频率的思路有很多种,网上有关于ADC测量电压,也有关于输入捕获的。但是上次电赛校赛,学长用的是外部中断结合定时器中断来实现的,思路也比较简单。就是下降沿触发外部中断,然后打开定时器计数。当再次进入外部中断时停止计数清楚相关的标志位。这样就得到了一个计数次数,通过计数次数就可以计算出电平经历变化用的时间,时间的倒数就是相关的频率。本次实验用的是外部中断三(EXTI3)对应PE3口。
+ y: A0 q/ y1 |2 l; _, ~ ?: h* |; `
7 m- A0 u4 k; R' @* o0 ^- q- void EXTIX_Init(void)
3 y+ @' s/ p, r9 g3 a - {6 J' ^+ ^( F+ U. ~; i/ n
-
* l$ g( l' F, W - EXTI_InitTypeDef EXTI_InitStructure;
) T- w( V3 I2 o+ E, J - NVIC_InitTypeDef NVIC_InitStructure;
' C# ~7 j+ M! i9 h7 e- o. H - - H2 H8 O W; m) k7 e
- KEY_Init(); // 按键端口初始化* o6 d' }$ `, B9 z7 f, F9 \
- ; s9 @% B- ~4 _5 y1 a3 C" r. i
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能复用功能时钟+ B; O9 |' G1 t# p) a- V
- & {8 s; P$ F, m3 J- M& I# e( {# L
- //GPIOE.3 中断线以及中断初始化配置 下降沿触发 //KEY1" U( {) t4 k! @! V6 }; R0 j4 P7 H
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);. B% D! r& ^6 r3 p# B
- EXTI_InitStructure.EXTI_Line=EXTI_Line3;' [+ U3 E1 e) M- |* _, ~- v
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
: g5 ^& @) @% g! ^1 ^* j - EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
6 ?0 Z0 k* A9 u6 m/ | - EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
# f. h7 \# _1 f0 V: V& n* D - 6 @9 J, ?5 I0 p4 F) t: I' n u& v
- NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //使能按键KEY1所在的外部中断通道 ?; m; {# ^4 N) G2 l# d4 b! J) F
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2 " N3 _2 G: b4 Y7 H1 Q. T5 K
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级1
8 B5 _+ G$ a$ C4 v: e- Q" Q% f8 h - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
& t3 M3 r% W9 `1 l H) H - NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器; O5 Y/ j* C7 `0 J) ^% p
- 0 w" @4 I- s. L$ }( y9 Y0 ?( z
- }
复制代码- void EXTI3_IRQHandler(void)2 l4 B- ^+ }- S# E
- {% S+ z" ~& S* s x" x c4 M; N
- if(half_cricle == 0)
; z6 F. X; b8 g [ i G3 K - {
( g, V6 B. c+ E w* h- e - TIM2->CNT = 0;
) _* J% Q7 v& i- m2 P7 M( X( [ - TIM_Cmd(TIM2, ENABLE); //使能TIMx
3 s. R2 h8 u i; f( B4 F - half_cricle = 1;( V3 C! Z, B7 p' t t1 {
- }& m0 \8 `% \5 f- I
- else if(half_cricle == 1)* F9 X* X" Q5 n
- {/ {3 J$ M" F; O3 u, X, ]8 v
- time_of_circle = TIM2->CNT;
$ t& ~) f6 j. _+ O! L - TIM2->CNT = 0;: |* _" M6 B3 L2 U( y) T
- TIM_Cmd(TIM2, ENABLE); //使能TIMx " d. G$ U- ?& R* G/ @
- }
/ N7 G& ^4 ^0 K- W) q- u - EXTI_ClearITPendingBit(EXTI_Line3);7 D/ g6 t4 T- k' D: z
- }
复制代码
. l* y; _$ g: H8 U- \& g3 k7 j5 X$ i" r8 }; m9 C3 t% \6 u
9 E; ?& ^2 A p) g9 c# g& r" ]/ i- [
, I& Q% S; e3 Y2 S( W! i- p0 k3 D7 {5 [- X+ f
定时器2初始化: - void TIM2_Init(u16 arr,u16 psc)# L" w U7 @( X3 ?. w! y+ x+ {
- {0 Q4 x( }3 u5 s; S6 ^, `8 z
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;8 [; t+ b f" J
- // NVIC_InitTypeDef NVIC_InitStructure;1 H* u1 o, e. G( F
; I; c* y3 F( h+ ~3 X" j. p- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能
6 _5 t' W! e ]) m% O
# o9 t5 i. E" Z+ q- {- TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到5000为500ms' n- W5 t+ E. g# b9 W
- TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率
& k! R. F3 P( e/ ~ - TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
" P/ i' \* H9 u1 z( g. I6 }+ y - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
+ { ^) e# ?8 z - TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 i# d! }9 v5 a4 x8 o2 i
- , W/ ~! @) h% N! j" }. V
- // TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断$ {& L- S$ s" }
- 7 d* s" e! J" H" d& J
- // NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
& c/ t% [. W0 T! x9 q, P* x) \ - // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级9 n& v+ b9 R, D) M/ N) ^5 @
- // NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
3 L' t9 n2 Y3 v! q8 j3 r5 L - // NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能6 S- y; \9 T1 M6 `
- // NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 $ @/ m4 O7 t6 F" M' w( A
- }
复制代码
1 |' v9 u: l9 L" L) N
! s/ f' {) M( a' o" Z9 J主函数: : o3 g% v# h0 Y
- int main(void), q" r5 N' e: e
- { 5 Z7 q- ?4 [! i8 O
- char str[10];
: w- d& @4 L7 l; a9 d7 R8 {' Y - delay_init(); //延时函数初始化
' T9 K9 \$ y' P - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级/ O7 x1 T3 Z) f! j( l' ]$ Q3 v
- uart_init(115200); //串口初始化为115200) s8 T3 X6 p( N* m
- LED_Init(); //初始化与LED连接的硬件接口
' F9 B5 Y9 W- i% i, M' R - EXTIX_Init(); //初始化外部中断输入; a5 j' _# P4 r0 ?
- LCD_Init();0 i D' M ^% R; s0 D
- TIM3_PWM_Init(499,7199);. q1 V% C' O8 Z1 \) \
- TIM2_Init(4999,7199);5 c8 Q% E( J* [7 i R' \# I
- LED0=0; //先点亮红灯
, ~9 O) a+ \9 T$ R - TIM_SetCompare2(TIM3,250);//设置CCR2的寄存器值为250占空比为50%
5 k }# X9 v1 w4 G# P9 o% C& ]; {$ W( F - LCD_ShowString(45,125,200,30,16,"-----freqency-----");
8 Y. Y. R6 @+ Y) ^' l - LCD_ShowString(130,165,32,30,16,"HZ");" m, |6 L+ s" P! h! c
- while(1)) Z6 S0 ?& u5 }! T0 T( j
- {
% ^# y6 D d) w+ e: _. J' [ - freq=10000.0 / (float)time_of_circle;8 q7 k5 d5 o+ E/ B7 r
- sprintf(str,"%.2f",freq);$ w: W1 h8 y0 P9 F" h8 ]- V2 ~
- LCD_ShowString(50,165,64,30,16,str);& u9 T1 ^! A: ?; Y* N' j
- LCD_ShowString(45,125,200,30,16,"-----freqency-----"); W3 p" V2 J' |% C1 h" Q( Q# P
- LCD_ShowString(130,165,32,30,16,"HZ");6 @6 I( N f# c4 z( [
- }
5 y3 X, B* I# v( {0 t - }
复制代码 : R# N0 i' `: v3 `$ _
6 o6 t( I9 a2 k. q( b
7 N# u) V' `: r$ k) F# z 以上就是几个主要的函数,用库函数配置比寄存器配置舒服多了,之前一直整寄存器版本的,现在接触库函数觉得实在是太方便啦!
8 R4 O' x5 f9 e2 A4 x! L0 ]) R( o# M3 N8 P [ }# v5 [
|