41.呼吸灯与SPWM波¶

41.5.2.5. 定时器中断服务函数¶

定时器的中断服务函数见 代码清单:SPWM-14。

代码清单:SPWM-14 定时器中断服务函数(stm32f10x_it.c文件)¶

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76/*电压幅值等级数*/

#define AMPLITUDE_CLASS 256

//控制输出波形的频率

__IO uint16_t period_class = 1;

extern uint16_t indexWave[];

extern __IO uint32_t rgb_color;

/* 呼吸灯中断服务函数 */

void BRE_TIMx_IRQHandler(void)

{

static uint16_t pwm_index = 0; //用于PWM查表

static uint16_t period_cnt = 0; //用于计算周期数

static uint16_t amplitude_cnt = 0; //用于计算幅值等级

//TIM_IT_Update

if (TIM_GetITStatus(BRE_TIMx, TIM_IT_Update) != RESET) {

amplitude_cnt++;

//每个PWM表中的每个元素有AMPLITUDE_CLASS个等级,

//每增加一级多输出一次脉冲,即PWM表中的元素多使用一次

//使用256次,根据RGB颜色分量设置通道输出

if (amplitude_cnt > (AMPLITUDE_CLASS-1)) {

period_cnt++;

//每个PWM表中的每个元素使用period_class次

if (period_cnt > period_class) {

pwm_index++; //标志PWM表指向下一个元素

//若PWM表已到达结尾,重新指向表头

if ( pwm_index >= POINT_NUM) {

pwm_index=0;

}

period_cnt = 0; //重置周期计数标志

}

amplitude_cnt=0; //重置幅值计数标志

} else {

//每个PWM表中的每个元素有AMPLITUDE_CLASS个等级,

//每增加一级多输出一次脉冲,即PWM表中的元素多使用一次

//根据RGB颜色分量值,设置各个通道是否输出当前的PWM表元素表示的亮度

//红

if (((rgb_color&0xFF0000)>>16) >= amplitude_cnt) {

//根据PWM表修改定时器的比较寄存器值

BRE_TIMx->BRE_RED_CCRx = indexWave[pwm_index];

} else {

//比较寄存器值为0,通道输出高电平,该通道LED灯灭

BRE_TIMx->BRE_RED_CCRx = 0;

}

//绿

if (((rgb_color&0x00FF00)>>8) >= amplitude_cnt) {

//根据PWM表修改定时器的比较寄存器值

BRE_TIMx->BRE_GREEN_CCRx = indexWave[pwm_index];

} else {

//比较寄存器值为0,通道输出高电平,该通道LED灯灭

BRE_TIMx->BRE_GREEN_CCRx = 0;

}

//蓝

if ((rgb_color&0x0000FF) >= amplitude_cnt) {

//根据PWM表修改定时器的比较寄存器值

BRE_TIMx->BRE_BLUE_CCRx = indexWave[pwm_index];

} else {

//比较寄存器值为0,通道输出高电平,该通道LED灯灭

BRE_TIMx->BRE_BLUE_CCRx = 0;

}

}

TIM_ClearITPendingBit (BRE_TIMx, TIM_IT_Update); //必须要清除中断标志位

}

}

本中断服务函数相对于单色呼吸灯例程增加了对拟合曲线电压等级的控制,它是利用计数变量amplitude_cnt、

电压分级宏AMPLITUDE_CLASS以及电压等级变量rgb_color实现的,其实现原理如下:

为便于讲解,先假设用于配置拟合波形周期长度的period_class值为1,即在控制周期长度时,

每个PWM表中的元素只使用1次(关于period_class的作用请复习前面单色呼吸灯实验中的说明)。

在这个基础上增加对电压的分级,用于控制拟合波形的输出电压,本实验中由宏AMPLITUDE_CLASS控制,其值为256,即可输出256种不同的电压等级。

该宏值在中断中会与amplitude_cnt进行比较(第25行),amplitude_cnt每次进入中断加1,

当amplitude_cnt大于AMPLITUDE_CLASS时才会进入周期配置的判断,以便使PWM表指向下一个元素,也就是说增加电压分级配置后,

遍历每个PWM表元素时,每个元素会增加256个周期。

在这256个周期内,会进入控制电压等级的处理(第42~73行),处理的过程是使用电压等级值rgb_color与amplitude_cnt进行比较,

本实验中rgb_color包含红绿蓝三个通道的电压值,各通道的取值范围是[0:255],与RGB888颜色格式一致。当通道的电压值R/G/B数据大于amplitude_cnt时,

向该通道的比较寄存器赋予PWM表中当前指向的元素值,否则赋予0值。根据定时器的配置可知,比较寄存器中的值就是该通道输出低电平的时间,

即LED灯亮的时间,所以,在256个周期时间内,各通道有R/G/B个周期会点亮LED灯当前PWM表元素表示的时间。

例如:

若红色通道值R=0,那么R值在256个周期内,均小于amplitude_cnt,通道输出高电平,红色LED灯一直灭,

此时\(\frac{T_{R\_ LED\_ ON}}{T_{\text{CLASS}}} = \frac{0}{256}\) ;

若绿色通道值G=128,那么G值在前128个周期内大于amplitude_cnt,通道输出当前PWM表元素表示时间的低电平,绿色LED灯亮128个周期,

此时\(\frac{T_{G\_ LED\_ ON}}{T_{\text{CLASS}}} = \frac{128}{256}\) ;

若蓝色通道值B=200,那么B值在前200个周期内大于amplitude_cnt,通道输出当前PWM表元素表示时间的低电平,蓝色LED灯亮200个周期,

此时\(\frac{T_{B\_ LED\_ ON}}{T_{\text{CLASS}}} = \frac{200}{256}\)。

所以,三个通道控制的LED灯点亮的时间比例即为RGB888颜色值表示的量,混合后可得到该颜色。

又由于PWM表中的元素值则表示了混合颜色的亮度,把PWM表遍历一遍,即控制混合颜色亮度呈PWM表变化,即可得到该颜色的呼吸灯效果。

当周期倍数period_class=1,电压分级数量AMPLITUDE_CLASS=5,电压等级分别为3和1时,

输出的PWM波形如图 电压等级分别为3和1时的PWM波形 所示。

推广至当period_class不等于1时,遍历PWM表中的每个元素需要进入定时器中断AMPLITUDE_CLASS*period_class次,设定时器的中断周期为T_timer,

那么输出的拟合曲线周期为T_timer *AMPLITUDE_CLASS*period_class。