- int main(void). t, V ?% f0 H
- { + [# ^. d8 o& X! ~7 A, g o$ l
- char str[10];
& ^$ J9 [ ~0 | - delay_init(); //延时函数初始化
, o6 V, I+ P, I7 M/ C: d7 r. ^ - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
+ ~: d3 }: ^! Z3 ?; r - uart_init(115200); //串口初始化为115200( r9 w8 W+ i& K s7 L1 k; c9 M
- LED_Init(); //初始化与LED连接的硬件接口
( }8 F( ]# |- {( @ - EXTIX_Init(); //初始化外部中断输入
( X# |- ?, k a) ^; H" V - LCD_Init();) m) t6 z$ |& o
- TIM3_PWM_Init(499,7199);7 M5 M* R. ]+ b) M- F3 j9 h
- TIM2_Init(4999,7199);
Z6 T; [0 b+ c4 Y: e: s - LED0=0; //先点亮红灯- t, _; X \( z) t7 f* ?
- TIM_SetCompare2(TIM3,250);//设置CCR2的寄存器值为250占空比为50%
# j* p( R- F; C - LCD_ShowString(45,125,200,30,16,"-----freqency-----");6 M* k/ v2 I4 {2 z6 @# i$ f+ u
- LCD_ShowString(130,165,32,30,16,"HZ");
0 W- ?4 s; w4 E6 ]0 ~6 i" ` - while(1)
4 j8 W: D8 e6 T% x3 { - { 6 d! [3 C4 S) x9 s/ n# k/ b8 W( \# q
- freq=10000.0 / (float)time_of_circle;
' C; f+ q' e H8 g - sprintf(str,"%.2f",freq);- ~# P4 @2 z) Z# y8 `
- LCD_ShowString(50,165,64,30,16,str);
( c2 \$ o( j4 U6 k - LCD_ShowString(45,125,200,30,16,"-----freqency-----");4 {9 {; s6 G0 f( x* r8 l
- LCD_ShowString(130,165,32,30,16,"HZ");
8 z' H( t0 X3 e4 J - }
$ X# X0 g, e0 s% \4 d1 M - }
复制代码
% }' i6 Z) b" A6 a& J
3 |# ^$ l( y# Q0 A
" V( J( e L& L% e3 N1 j: d2 y6 U+ m+ ^4 q @+ ~& Z
8 h1 b/ p" |" [3 c$ S
/ H# [; U3 K0 |6 n$ e' ?) d! P' w) Y
) [8 I Z1 g& y/ |单片机产生频率为20HZ的占空比为50%方波 通过单片机产生方波很容易,设置寄存器ARR的值就能确定周期。设置CCRx的值就能设置设置占空比。 当CNT寄存值小于CCRx的值时输出低电平,大于CCRx的值时输出高电平,到达ARR的值时溢出。知道基本的原理后通过寄存器初始化和使能相关的寄存器就可以了。 这次实验采用TIM3 CH2不重映像,同时设置PWM模式为向上计数模式。配置步骤如下: % ]/ I9 Z; A6 {0 Y0 n4 Y
; Z3 h8 P7 x, h0 F& _" K, Y& u, R1 I1 S* @ Q; n; P
5 r. S1 i; X3 M$ M
2 t6 k0 {/ } c0 {- 开启TIM3时钟,并设置PA7为复用输出
- 初始化TIM3,设置TIM3的ARR和PSC值
- 设置TIM3_CH2的PWM模式,使能TIM3的CH2输出
- 使能TIM3
- 修改TIM3_CCR2来控制占空比
+ L+ F4 w- f- F( r/ o! q& v 6 A7 {( k% Q! ~+ ]6 j% Y0 Z, r
3 S2 l0 Y) R2 g: v7 t3 |0 M- //TIM3 PWM部分初始化
; l S' |# J1 ?: o - //PWM输出初始化$ a2 c4 s# W' ?# D
- //arr:自动重装值
" B: }7 [1 r( N) D1 X - //psc:时钟预分频数- T8 e0 M/ [) v
- void TIM3_PWM_Init(u16 arr,u16 psc)
3 u5 e: Y* f6 p, u( v& F+ R6 A: j - {
5 q, _) j, y" b8 n x6 I/ X2 p) n - GPIO_InitTypeDef GPIO_InitStructure;
- d: V4 a8 l% m+ Y1 e4 f+ d - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;* \0 \! P# R! k% A. l
- TIM_OCInitTypeDef TIM_OCInitStructure;4 @* G9 h0 \) p
- , {+ O( B- y( ]' z
- 9 a/ I9 i5 I# [5 C
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟! r0 e! H+ K, i1 e3 ^. o1 T
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //①使能 GPIO 和 AFIO 复用功能时钟
% N2 s0 ~6 n9 A) H - // GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); //Timer3部分重映射 TIM3_CH2->PC7
9 d2 ~% |5 Y5 B9 N/ b2 c/ [ -
: X3 N5 k+ t# [. Z - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //TIM_CH2
% o' g5 J0 S* g, a! k$ ` - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+ F& r; t) Q" W/ z8 p9 X - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
& m# D, n2 x* n$ J! M" n2 T N - GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA
9 U9 N, w7 e$ H! E( I' u - % k2 z9 o# E3 o" l; N1 b
- //初始化TIM3
7 z0 u! m. v& w, [4 Q$ `, F - TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
- ] b- h' s, v+ O - TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
5 R+ u" Q+ g9 R- t - TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim5 F# k9 X6 b* ?
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式% n/ T$ i* s1 I" v
- TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位" S7 o! ^* j9 a; W0 k
-
" s2 L( }0 o1 b - //初始化TIM3 Channel2 PWM模式
/ M3 t. M9 Q4 _7 u5 U - TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式26 C% x- b& Q& E
- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
8 e8 {; d9 ]2 c. [; p$ q - TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
7 O' C/ b3 \; P5 o' o8 |# Q - TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC2
' I- \( ], i/ C, Z. r$ Y - 2 u2 T a; M! A9 [% |& `
- TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR2上的预装载寄存器
, l+ i! v' ]8 }, I -
) E: K& a& m/ J3 t( R. J1 H, r3 M4 e - TIM_Cmd(TIM3, ENABLE); //使能TIM31 {& A* b+ h2 P$ W2 ]% o# \
- ) x. H& _1 M$ s' `2 ?; ^ G. u/ P* ]
- }
复制代码 # D8 J8 O3 A7 P+ Q
& M R, g$ f4 |9 | 以上代码就完成了PWM的初始化,如果要产生20HZ的波形,那么就相当于要没50ms要溢出一次,那么我们可以设置arr的值为499,psc的值为7199。Tout= ((arr+1)*(psc+1))/Tclk=(499+1)* ( 7199+1)/72=50ms 。说明计数到500次为50ms,那么设置CCR2的值为250就可以实现占空比为50%。 4 T6 R* i0 f u! ^$ s: Y2 P
单片机测量频率并显示) x% O5 J6 p2 j9 g
测量频率的思路有很多种,网上有关于ADC测量电压,也有关于输入捕获的。但是上次电赛校赛,学长用的是外部中断结合定时器中断来实现的,思路也比较简单。就是下降沿触发外部中断,然后打开定时器计数。当再次进入外部中断时停止计数清楚相关的标志位。这样就得到了一个计数次数,通过计数次数就可以计算出电平经历变化用的时间,时间的倒数就是相关的频率。本次实验用的是外部中断三(EXTI3)对应PE3口。 1 w+ @% O* s7 K6 ?$ I( o
% H, {$ V: F/ v# h! P) N" V
- void EXTIX_Init(void)
& w. O; x* v. c* F* } - {
2 S; g4 [3 c* f8 F* q* L( N -
; m b2 I5 u1 _! j' _& p- e$ N - EXTI_InitTypeDef EXTI_InitStructure;
/ W5 m6 K5 t, `' S" M - NVIC_InitTypeDef NVIC_InitStructure;
$ T! M$ M6 g4 R4 H, V - " i0 H G* L0 {/ d; j% a3 ~
- KEY_Init(); // 按键端口初始化
$ s% U4 R4 D. e3 M* t - 8 z/ ^; G: F- s2 D# C( |7 C
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能复用功能时钟
1 F' N- i6 _; x -
- H& S$ O* @: c9 V# l. S - //GPIOE.3 中断线以及中断初始化配置 下降沿触发 //KEY1
$ [& W( N+ W2 ?9 C* _6 O - GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
5 V, j2 }1 j% B+ D3 M2 ?3 R: d - EXTI_InitStructure.EXTI_Line=EXTI_Line3;, h2 M) d9 [0 r5 c$ O" l
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
) I! u, B$ y* m }" Y: Y9 n - EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
2 r6 x* w( y- i - EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器+ O8 ?) S6 P9 L+ w; f7 q0 Q9 O4 i9 U
9 [* E+ {+ r) ~- NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //使能按键KEY1所在的外部中断通道
+ P9 Z8 y& U4 w3 { - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2 ; N2 I, j/ @' @( l
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级1 * Z0 i8 E3 _) b% N' w
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
8 y; D) s* m* y - NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器4 x5 I; [, s9 m; Q, [* k
- 3 i7 K. `/ |5 l9 s1 r- d) w
- }
复制代码- void EXTI3_IRQHandler(void)
1 s1 {( S: V6 V- n8 y/ L; j3 H - {) c6 i( l: l! y3 t
- if(half_cricle == 0). \! b7 G& V4 z, M# m. u! ^
- {# E- c; |1 q0 J1 r
- TIM2->CNT = 0;' H8 g- P, k' F. r
- TIM_Cmd(TIM2, ENABLE); //使能TIMx
( K$ C% B9 Q6 L& t2 @: { - half_cricle = 1;: ^+ H7 ?" V: U! h
- }
# T5 ~; `& k, m# ~( B3 @ - else if(half_cricle == 1) A2 A& g% V& B0 z1 w
- {& h: N3 N$ A3 N5 O+ c- k
- time_of_circle = TIM2->CNT;( w; S, O% K; b0 `6 n
- TIM2->CNT = 0;2 o3 w7 f4 y: ?# _7 m
- TIM_Cmd(TIM2, ENABLE); //使能TIMx . A/ i9 o' L) y; r* q
- }% s! a8 L& e6 k
- EXTI_ClearITPendingBit(EXTI_Line3);0 @7 ?4 E/ `, p
- }
复制代码 ) x1 b# d3 N9 ?; l
0 u- w6 k2 N$ b4 V0 Z6 T0 A; Z
; W4 m( i+ g7 Y
8 O/ P( B" o% n. T
3 U+ G- Y( @% U* o, ~2 T定时器2初始化: - void TIM2_Init(u16 arr,u16 psc)
+ W$ g( H8 U! { - {7 S7 b7 H- D9 }- Y" Q' T
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;( a* l0 s* Y( S! K, I! C7 t# n4 O o
- // NVIC_InitTypeDef NVIC_InitStructure;) v" @3 C9 ~/ H' H
3 q$ q0 K9 y* v; E1 ^- `- y/ @& O, y- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能0 R8 T- k4 w g/ r- ]
" M1 ]. R+ S8 R/ n- d- TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到5000为500ms4 w! |, i2 X3 k- P
- TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率
y+ ?" n+ F$ g3 M- O) \" b" L - TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
) i& y7 h q) k3 c - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
, r3 B% s1 ~8 Q5 g8 D: } - TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
/ K7 ]2 e: y" M$ O* _ -
1 }: W0 X% C( w' d9 D6 j - // TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
% A# C7 ]2 B/ e* ~+ V* z - 1 T6 Y# E4 v& l
- // NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断; S- S* n2 I# i* Y
- // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级; E" o }' }7 f& _- w
- // NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
$ D+ y6 t0 k* Y7 e - // NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
; |* G9 x0 O% D5 b) `0 r; ` - // NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
/ t" w& A, m( f ^/ {0 o; J9 d - }
复制代码 2 J8 a$ T8 q: Q' [8 `0 e4 _7 u
" I. K6 y7 @8 ^$ O" y3 ]
主函数:
3 u x* q/ r& b& P2 E
- int main(void)
, K5 x6 W: Z! D" D( D' i! Q - {
5 B" ^7 K3 l, c8 q0 c. } - char str[10];& j3 C5 |+ U9 M! T
- delay_init(); //延时函数初始化
( u3 \6 t r0 o1 i# M/ I7 s - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级& u8 e4 P' V7 Q$ z" a, P! H2 A% G
- uart_init(115200); //串口初始化为115200
# K* N2 Y! q/ M0 o1 g9 M; S - LED_Init(); //初始化与LED连接的硬件接口 - m3 _/ J- R* [& ~% T& A
- EXTIX_Init(); //初始化外部中断输入) T0 S* m* s. `* K5 ]5 q* H, @- U% V6 Y
- LCD_Init();$ R; |7 F1 ~$ u1 ]* B/ n
- TIM3_PWM_Init(499,7199);& o' U/ R% ~$ r
- TIM2_Init(4999,7199);
l+ I* r, [7 f0 A( X5 s - LED0=0; //先点亮红灯
( I2 D, ]% Q0 H! }# o* C! u- C/ \3 }6 v - TIM_SetCompare2(TIM3,250);//设置CCR2的寄存器值为250占空比为50%
6 y# U+ | m9 h: _ - LCD_ShowString(45,125,200,30,16,"-----freqency-----");
+ p' ]8 c. {" H9 x3 k - LCD_ShowString(130,165,32,30,16,"HZ");0 `% R$ M6 U0 n4 C4 R
- while(1)
* Y1 [! }0 k) [* ~1 e! | - {
, l, `: [( }% P' ]% M9 q2 M) A - freq=10000.0 / (float)time_of_circle;
8 Y, i3 A, W+ H" h+ H4 G1 X6 ] - sprintf(str,"%.2f",freq);
6 Z( H; P- j6 }# ^; w - LCD_ShowString(50,165,64,30,16,str);
; f0 g) b; `) u, r* v - LCD_ShowString(45,125,200,30,16,"-----freqency-----");
3 r+ o) P% ]6 R; p9 h0 R - LCD_ShowString(130,165,32,30,16,"HZ");6 s2 p. p. V* ~7 ^; o& x
- }
8 B$ {9 k% q3 O5 n4 k* Y3 j& ~ - }
复制代码
! u# |) M- A% M- b3 C* r& n& @3 J) u0 v, |. R) j/ Q
+ o& J' _% N4 g$ {! m
以上就是几个主要的函数,用库函数配置比寄存器配置舒服多了,之前一直整寄存器版本的,现在接触库函数觉得实在是太方便啦!
, O; P8 C; z+ h# s% h
3 V/ n6 w! U4 U, e3 e8 ] |