-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathpwm.c
117 lines (110 loc) · 4.62 KB
/
pwm.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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//
// pwm.c
// cxg-60ewt
//
// Created by Leonid Mesentsev on 26/11/2019.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#include <stm8s.h>
#include <pwm.h>
/******************************************************************************
*
* Initialize PWM
* in: mode, channels to use
*
* To generate the PWM signals the TIM2 peripheral must be configured as follows:
* ● Output state enabled for each channel
* ● Output compare active low for each channel
* ● Preload register enabled for each channel
* ● PWM output signal frequency = 125 Hz:
* – The timer source clock frequency is 16 MHz (fCPU by default) and the prescaler is
* set to 7 to obtain a TIM2 counter clock of 125 kHz (16000000 / 2^7 = 125000)
* – PWM output signal frequency can be set according to the following equation:
* PWM output signal frequency = TIM2 counter clock/(TIM2_ARR + 1)
* (in our case TIM2_ARR = 999, so PWM output signal frequency is 125 Hz) (125000 / (999 + 1) = 125)
* ● PWM mode for each channel. To obtain a different PWM duty cycle value on each channel the TIM2_CCRxx register must be set according to this equation:
* Channel x duty cycle = [TIM2_CCRxx/(TIM2_ARR + 1)] * 100
* (CCRXX / (999 + 1)) * 100 = 0.1 * CCRXX, поэтому duty_cycle в функции PWM_duty умножен на 10 (стр. 96)
*
* ПОМНИТЕ: если вы изменили ARR, не забудьте пересчитать CCRXX! Прежде чем изменять значения в этом файле, внимательно прочтите и пймите формулу,
* наче PWM может не завестись, что приведет к 0 на управляющем пине и, следовательно, к неконтролируемому нагреву ТЭНа.
*
* By default we have:
* – Channel 1: TIM2_CCR1x register value is 500, so channel 1 of TIM2 generates a PWM signal with a frequency of 2 KHz and a duty cycle of 50%.
* – Channel 2: TIM2_CCR2x register value is 750, so channel 2 of TIM2 generates a PWM signal with a frequency of 2 KHz and a duty cycle of 75%.
* – Channel 3: TIM2_CCR3x register value is 250, so channel 3 of TIM2 generates a PWM signal with a frequency of 2 KHz and a duty cycle of 25%.
*
*/
void PWM_init(uint8_t ch)
{
TIM2_PSCR = 7; /* 16000000 / (2^7 * (1 + 999)) = 125 Hz */
int _TIM2_ARR = 999; /* 125 Hz */
TIM2_ARRH = (_TIM2_ARR >> 8) & 0xff;
TIM2_ARRL = _TIM2_ARR & 0xff;
if (ch & PWM_CH1)
{
TIM2_CCR1H = 0;
TIM2_CCR1L = 0;
TIM2_CCMR1 = 0x68; /* PWM mode 1, use preload register */
TIM2_CCER1 |= 0x01; /* output enable, normal polarity */
}
if (ch & PWM_CH2)
{
TIM2_CCR2H = 0;
TIM2_CCR2L = 0;
TIM2_CCMR2 = 0x68;
TIM2_CCER1 |= 0x10;
}
if (ch & PWM_CH3)
{
TIM2_CCR3H = 0;
TIM2_CCR3L = 0;
TIM2_CCMR3 = 0x68;
TIM2_CCER2 |= 0x01;
}
TIM2_CR1 = 0x81; /* use TIM2_ARR preload register, enable */
}
/******************************************************************************
*
* Set duty count
* in: channel(s), new duty count (times 1/2 microsecond)
*/
void PWM_duty(uint8_t ch, uint16_t duty)
{
duty = duty * 10;
uint8_t dH, dL;
dH = (duty >> 8) & 0xff;
dL = duty & 0xff;
if (ch & PWM_CH1)
{
TIM2_CCR1H = dH;
TIM2_CCR1L = dL;
}
if (ch & PWM_CH2)
{
TIM2_CCR2H = dH;
TIM2_CCR2L = dL;
}
if (ch & PWM_CH3)
{
TIM2_CCR3H = dH;
TIM2_CCR3L = dL;
}
}