Реклама ⓘ
Главная » Микроконтроллеры
Призовой фонд
на апрель 2024 г.
1. 100 руб.
От пользователей

Реклама ⓘ

Программный ШИМ на STM8L

В данной статье я хочу рассказать о программном создании ШИМ-регулятора на STM8L-Discovery. Проект полностью переносим на другие микроконтроллеры типа STM8. Процесс переноса описан неоднократно, в т.ч. и мной в статье Термометр на STM8L-Discovery

Итак для начала разберёмся, что такое ШИМ. Широтно-импульсная модуляция - это процесс управления средней мощностью в нагрузке за счет изменения коэффициента заполнения сигнала прямоугольной формы. По определению средняя мощность Pсредняя= U2среднее/Rнагрузки. Не будем вдаваться в математические подробности, просто отмечу, что Uсреднее = Umax*t1/t2. Отношение t1/t2 ещё называют коэффициентом заполнения.

Пояснения на рисунке 1.

Таким образом, наша задача генерировать прямоугольные импульсы с различным коэффициентом заполнения. Она, в свою очередь, сводится к тому, чтобы управлять ножкой микроконтроллера, переводя её то в положение "1", то в положение "0". Кажется, что мы получили простое решение задачи: бесконечный цикл, где мы поднимаем выход, ждем, опускаем выход, ждем. Есть одно но: бесконечный цикл подвесит ядро, поэтому никаких других функций после запуска ШИМ мы выполнить не сможем (можно, конечно, извернуться и что-нибудь придумать с прерываниями, но это уже извращения). Поэтому я предлагаю другой способ - с прерываниями от таймера. Смысл такой: таймер дает прерывания, скажем, раз в 10 нс - это и будет нашим минимальным значением длительности импульса, или МЗДИ. Далее, возьмем период в 256 МЗДИ. Теперь нам нужна переменная, в которой будет храниться значение длительности импульса - от 0 до 255; соответственно коэффициент заполнения будет от 0 до 1, а средняя мощность нагрузки от 0% до 100%. Теперь посмотри на мою реализацию данного алгоритма

int _q, count;

//описание прерывания
#pragma vector = 27
__interrupt void tim4_ovf( void )
{
  if ( count < _q ) // если от начала периода прошло меньше времени импульса
    PC_ODR_bit.ODR5 = 1; //то на выходе "1"
  else //иначе
    PC_ODR_bit.ODR5 = 0; //"0"
  count++; //увеличим счетчик времени
  if ( count >= 256 ) //если период закончился
    count = 0; //сбросим счетчик
  TIM4_SR1_bit.UIF = 0; //выйдем из прерывания
}

void line_PWM( int q )
{
  asm( "RIM" );  //разрешаю прерывания
  CLK_PCKENR1_bit.PCKEN12 = 1; // подаю тактирование
  TIM4_PSCR = 0x00; //ставлю предделители
  TIM4_ARR = 0x0D;
  TIM4_IER_bit.UIE = 1; //ставлю биты конфигурации 
  TIM4_CR1_bit.URS = 1;
  TIM4_EGR_bit.UG = 1;
  TIM4_CR1_bit.CEN = 1;  //запускаю таймер
  count = 0; //сброс счетчика прерываний
  PC_DDR_bit.DDR5 = 1; //нога на выход
  PC_CR1_bit.C15 = 1;
  _q = q; //сохранили аргумент команды - длительность импульса
}

Эта штука очень хорошо работает, но имеет один недостаток - он проявляется при работе со светодиодами. Дело в том, что наш глаз нелинеен, а потому при линейном нарастании мощности на низкой яркости видимая яркость света нарастает быстрее, чем на высокой яркости при одинаковой скорости нарастания мощности. Причина в том, что реакция наших органов чувств ближе к экспоненциальной, поэтому для видимого равномерного нарастания яркости необходимо в действительности изменять ее логарифмически. Для этого я использовал другую функцию, которая автоматически подбирает из массива нужное значение длительности импульса. В ходе расчёта этого массива я для простоты использовал не логарифмическую зависимость, а близкую к ней параболическую.

const int table[256] = {0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
1,
1,
1,
1,
1,
2,
2,
2,
2,
2,
3,
3,
3,
3,
4,
4,
4,
4,
5,
5,
5,
5,
6,
6,
6,
7,
7,
7,
8,
8,
9,
9,
9,
10,
10,
11,
11,
11,
12,
12,
13,
13,
14,
14,
15,
15,
16,
16,
17,
17,
18,
18,
19,
19,
20,
20,
21,
22,
22,
23,
23,
24,
25,
25,
26,
27,
27,
28,
29,
29,
30,
31,
31,
32,
33,
33,
34,
35,
36,
36,
37,
38,
39,
40,
40,
41,
42,
43,
44,
44,
45,
46,
47,
48,
49,
50,
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,
79,
80,
81,
82,
83,
84,
85,
87,
88,
89,
90,
91,
93,
94,
95,
96,
97,
99,
100,
101,
102,
104,
105,
106,
108,
109,
110,
112,
113,
114,
116,
117,
118,
120,
121,
122,
124,
125,
127,
128,
129,
131,
132,
134,
135,
137,
138,
140,
141,
143,
144,
146,
147,
149,
150,
152,
153,
155,
156,
158,
160,
161,
163,
164,
166,
168,
169,
171,
172,
174,
176,
177,
179,
181,
182,
184,
186,
188,
189,
191,
193,
195,
196,
198,
200,
202,
203,
205,
207,
209,
211,
212,
214,
216,
218,
220,
222,
224,
225,
227,
229,
231,
233,
235,
237,
239,
241,
243,
245,
247,
249,
251,
253,
255
};

void LED_PWM( int q )
{
  
  line_PWM( table[q] );
}

В главном файле напишем простую обвязочку для тестирования функций ШИМ

void delay( void )
{
  for ( int i =0; i < 20; i++ );
}

int main()
{
  CLK_CKDIVR = 0;
  while ( true )
  {
    for ( long int i = 0; i <= 255; i++ )
    {
      line_PWM(i);
      delay();
    }
    for ( long int i = 255; i >= 0; i-- )
    {
      LED_PWM(i);
      delay();
    }
  }
  return 0;
}

Для подключения мощных нагрузок к плате обязательно надо использовать транзисторный ключ, иначе можно сжечь контроллер. При индуктивной нагрузке необходимо добавить диод.

Прикрепленные файлы:

Теги:

Опубликована: 0 0
Я собрал 0 0
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 0 Проголосовало: 0 чел.

Комментарии (3) | Я собрал (0) | Подписаться

0
Константин #
Подскажите пожалуйста - реально ли собрать шим с регулировкой по скважности для инверторного сварочного аппарата, полного моста? Аналоговые заколупался паять - все не стабильно, ступенька срывается, ключи горят... Нужен именно программный ШИМ!
Ответить
0

[Автор]
Стальной #
Всё реально. Только зачем?
Ответить
0

[Автор]
Стальной #
На всякий случай пример аппаратного шим, таймер 2, вывод PB0

CLK_CKDIVR = 0;
CLK_PCKENR1_bit.PCKEN10 = 1;
TIM2_PSCR_bit.PSC = 0x00;
TIM2_ARRH = 0xFF;
TIM2_ARRL = 0xFF;
TIM2_CR1_bit.URS = 1;

TIM2_CR1_bit.CMS = 1;
TIM2_CR1_bit.ARPE = 1;
TIM2_BKR_bit.MOE = 1;
TIM2_CCER1_bit.CC1E = 1;
TIM2_CCMR1_bit.OC1PE = 1;
TIM2_BKR_bit.OSSI = 0;
TIM2_CCER1_bit.CC1P = 0;
TIM2_CCR1H = 0x7F;
TIM2_CCR1L = 0xFF;
TIM2_CCMR1_bit.OC1M = 6;
TIM2_EGR_bit.UG = 1;
TIM2_IER_bit.UIE = 1;
TIM2_CR1_bit.CEN = 1;
TIM2_CCR1 - значение счетных регистров, при котором закончится импульс
Сам не особо проник в детали пока что, но вдруг кому пригодится.
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется напряжение?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

AVR-программатор USB ASP
AVR-программатор USB ASP
LC-измеритель LC100-A Набор для сборки - LED лампа
вверх