|
硬件设计 硬件电路非常简单,只使用到开发板上的 LED(D7),因为 D7 指示灯接在 PC6 管脚,而通过对 TIM3_CH1 复用功能完全重映射就可以映射到 PC6 脚。所以可以通过 TIM3 的 CH1输出PWM 信号,实现 D7 指示灯呼吸灯的控制。
3 `' P/ b1 c9 Y% ~5 ?! Z
软件设计 所要实现的功能是:通过 TIM3 的 CH1 输出一个 PWM 信号,控制D7 指示灯由暗变亮,再由亮变暗,类似于人的呼吸。程序框架如下: (1)初始化 PC6 管脚为PWM 输出功能 (2)PWM 输出控制程序 在前面介绍通用定时器PWM配置步骤时,就已经讲解如何初始化 PWM。下面我们打开“\4--实验程序\库函数版\13. PWM 呼吸灯实验”工程,在 APP工程组中可以看到添加了 pwm.c 文件,在 StdPeriph_Driver 工程组中添加了stm32f10x_tim.c 库文件。定时器操作的库函数都放在 stm32f10x_tim.c 和stm32f10x_tim.h 文件中,所以使用到定时器功能就必须加入 stm32f10x_tim.c文件,同时还要包含对应的头文件路径。
; M& Z% s8 y; ^# k. x
TIM3 通道 1的 PWM初始化函数 要使用定时器的 PWM 输出功能,我们必须先对它进行配置。TIM3 通道 1 的PWM 初始化代码如下: - /**************************************************************2 m# Z3 _- r, R( d, y+ Y
- * 函 数 名 : TIM3_CH1_PWM_Init! O8 `& S- S! f9 E
- * 函数功能 : TIM3 通道 1 PWM 初始化函数
! {9 i# N3 h! f6 S) } - * 输 入 : per:重装载值psc:分频系数$ [, p7 j* Y3 L$ R# |+ n6 U
- * 输 出 : 无
8 C# t/ M- W, P7 ^) Q, j - ****************************************************************/
9 b' e$ k) x8 L0 G- _1 r: E - void TIM3_CH1_PWM_Init(u16 per,u16 psc)" [5 ^) `' f/ E7 A/ H& L. ]8 p z7 D
- {
# z+ Y" s( H# R7 r7 ` - TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;) \# v& f5 M' s; [
- TIM_OCInitTypeDef TIM_OCInitStructure;
0 ?- T3 C% h7 m0 ?; Z - GPIO_InitTypeDef GPIO_InitStructure;
! _" y' b7 o. k, @$ n3 I$ r - /* 开启时钟 */) O- v0 Y; x, @- j Q* G
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
& o5 m" O, f' v5 W9 _ - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
" P; l( z$ n0 P& |, t, Y - RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
7 u- v- a; Q" E( f6 b% X' v - /* 配置 GPIO 的模式和IO 口 */
7 o; ~+ K9 e1 K# l# y, _. p) _ - GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;+ f9 k7 V4 P, H* H
- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;& K8 V% q# V5 j
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
u5 t# B$ r$ T( ` - GPIO_Init(GPIOC,&GPIO_InitStructure);) G/ O$ e( q. T2 c
- GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);//改变指定管脚" O7 _' ?, o2 V; h6 N; v" o
- 的映射
" w' h; v; K6 \ N5 J, _& ~7 B* G( H3 a - TIM_TimeBaseInitStructure.TIM_Period=per; //自动装载值2 {) i% K, L& U; }/ n$ {
- TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数% h( z; z9 u: W2 ]. c, k2 j
- TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;+ k+ v6 E" n! C5 P& ?* k
- TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;* q8 `, Z' a- e& d/ }
- //设置向上计数模式' U9 S! c9 V- d R/ L4 E9 T6 ]
- TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);1 U) Q7 i; v3 n n2 V: E7 d
- TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;7 P& Y9 C# { j: e1 {; O" K
- TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;! [0 t, t2 v' m9 ]1 Y- [# f
- TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;$ o% n( q3 Y9 g W3 x6 t- {
- TIM_OC1Init(TIM3,&TIM_OCInitStructure); //输出比较通道1初始化
$ a# c% p! E" Q; j7 U' C - TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能 TIMx 在
+ S G6 k/ y) r/ w- J9 P - CCR1 上的预装载寄存器6 h+ p5 r- n {
- TIM_ARRPreloadConfig(TIM3,ENABLE);//使能预装载寄存器
& A0 T2 C$ }1 H4 [9 n& l - TIM_Cmd(TIM3,ENABLE); //使能定时器
- n1 s% `$ H6 @0 v) M& ]4 C, c - }
复制代码
# R1 U- n% Z' x# F
在 TIM3_CH1_PWM_Init()函数中,首先使能 GPIOC 端口时钟、TIM3 时钟和AFIO时钟,其次配置 TIM3_CH1 为完全复用重映射功能,并将 PC6 管脚模式配置为复用推挽输出。然后配置定时器结构体 TIM_TimeBaseInitStructure,初始化PWM 输出参数,由于我们的 LED 指示灯是低电平点亮,而我们希望当 CCR1 的值小的时候,LED 暗, CCR1 值大的时候,LED 亮,所以我们设置为 PWM1 模式,输出极性为低电平,使能 PWM 输出。最后就是开启 TIM3。这一过程在前面步骤介绍中已经提了。程序中我们看到最后调用了 TIM_OC1PreloadConfig()和TIM_ARRPreloadConfig,他们是用来使能 TIM3 在 CCR1 上的预装载寄存器和自动重装载寄存器,第一个库函数必须调用,第二个的话如果不调用也没有关系。 TIM3_CH1_PWM_Init()函数有两个参数,用来设置定时器的自动装载值和分频系数,方便大家修改 PWM频率。 其实如果你会使用通用定时器 TIM3 的 CH1 输出 PWM,那么其他通用定时器通道都一样。 9 D9 x- z7 i- d2 a4 [8 u
主函数 编写好 PWM 初始化函数后,接下来就可以编写主函数了,代码如下: - /***************************************************************
v: `* n3 d6 J# g/ v - * 函 数 名 : main
7 g& H, z q' d' _( } - * 函数功能 : 主函数
" w% i- u4 d7 o9 J - * 输 入 : 无& b, e5 q s( Q$ n
- * 输 出 : 无0 {* a( L7 |* Z N- _
- ****************************************************************/
: R+ M( J. o' ]# E - int main()
& B- O8 o" G7 q F$ e - {6 A, }- Y1 N! J- e) b- s
- u16 i=0;
" _7 Z9 ^( n( n& R2 r V9 W - u8 fx=0;
3 g, @4 R6 ?* T) b/ X) f - SysTick_Init(72);
' x7 z) l3 x- ]5 d* }* |! f: H - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2 组8 h( L/ D8 x0 A/ D+ }6 X* K3 v9 N
- LED_Init();
8 P& A% e" f. Q* ^' G - TIM3_CH1_PWM_Init(500,72-1); //频率是 2Kh
" m+ y5 m9 E3 s* Q6 G2 x - while(1)3 ] L- B# F/ h, T9 B
- {: P8 ~" j) ~) E! \/ J% d
- if(fx==0)' d9 v- Q" ~- k7 z
- {
1 [5 _. H$ w; M - i++;0 w7 u) ^1 @8 h" d+ G) ]
- if(i==300)
! z' A4 }0 J. ^# V, v, v0 m0 x - {
9 G) O& r" |; {1 C* ?# A0 z - fx=1;* o* S- \) A, I; B L p& q
- }
" a$ [, I; u& s, c: s I2 r; Q - }- U& X5 n8 S$ `+ T0 l, {1 d' w
- else" {1 B" G: c1 ]# o
- {/ h9 z9 n" I' V4 l, B
- i--;' c- _' c, v5 {# j) ]
- if(i==0) C5 Q T3 d' L2 z$ v! \
- {
# m1 O$ n) {7 g1 O4 j s; o - fx=0;# I7 w8 H- l2 [, N
- }
2 H% ~, b' w$ ^$ S! @6 W, w - }
0 }: u" e' G$ E; g+ m o+ ? - TIM_SetCompare1(TIM3,i); //i 值最大可以取 499,因为 ARR最大值是 499.) H0 t" f9 E+ h8 |" P* \& X( {
- delay_ms(10);9 ~7 \' m0 ?6 ^7 |& j
- }
# r9 N+ W8 `. E/ h$ q+ d - }
复制代码
& a' {1 } h3 A/ ] o- r: g1 E
主函数实现的功能很简单,首先初始化对应的硬件端口时钟和 IO 口,然后调用我们前面编写的 TIM3_CH1_PWM_Init 函数, 这里我们设定定时器自动重装载值为 500,预分频系数为72-1,定时周期即为 500us,频率即为 2KHz,这里为什么减 1在定时器中断已经介绍。 初始化后,定时器开始工作,PC6 开始输出 PWM 波形,波形频率为 2K,你也可以修改这个频率值,但是要注意,不能将频率设置过大,否则会看到 D7 指示灯有明显的闪烁。通过变量 fx 控制 i 的方向,如果 fx=0,i 值累加,否则递减,然后将这个变化的 i 值传递给TIM_SetCompare1 函数, 这个函数功能是改变占空比的,因此可以实现 D1 指示灯亮度的调节,呈现呼吸灯的效果。程序中将 i 值控制在 300 内,主要是因为 PWM 输出波形占空比达到这个值时,D1 指示灯亮度变化就不明显了,而且我们在初始化定时器时,将自动重装载值设置为499,所以这个i 值也不能超过。 将工程程序编译后下载到开发板内,可以看到 D7 指示灯由暗变亮,再由亮变暗,呈现呼吸灯的效果。 # j1 g2 \# M0 I" h. Q
|