Блимаємо світлодіодом Mini64SE R6 використовуючи ШІМ

Доброго дня сьогодні ми продовжуємо вивчати мікроконтролери STM32 за допомогою плати Mini64SE R6. У минулій статті ми з вами запустили демо-проект який згенерував нам Eclipse.
Нагадаю в цьому проекті було запрограмовано блимання світлодіодом частотою раз за секунду. Сьогодні будемо керувати яскравістю свічення світлодіода за допомогою широтно-імпульсної модуляції.
100_9568

Так що ж таке ШІМ модуляція. Широтно-імпульсна модуляція (ШІМ — англ. PWM), або модуляція за тривалістю імпульсів (англ. PDM) — процес керування шириною (тривалістю)високочастотних імпульсів по закону, який задає низькочастотний сигнал. В електроніці це може бути керування середнім значенням вихідної напруги шляхом зміни тривалості замкнутого стану електронного (електромеханічного) ключа, наприклад, у схемі ключового стабілізатора напруги. У двійковій цифровій техніці, виходи в якій можуть приймати тільки одне з двох значень, наближення бажаного середнього рівня вихідного сигналу за допомогою ШІМ є абсолютно природним. Це з вікіпедії.


Як видно з малюнку розміщеного вище результуюча напруга на світлодіоді, а відповідно і яскравість свічення буде залежати від ширини импульсу логічної одиниці на виході якій буде керувати світлодіодом.

Перейдемо до нашого проекту в що згенерував нам Eclepse в попередній статті та внесемо зміни.

//Blue led
#define SYSTICK_FREQUENCY_HZ       1000

#define BLINK_PORT GPIOA
#define BLINK_PIN 5
#define BLINK_RCC_BIT RCC_APB2Periph_GPIOA

#define BLINK_TICKS SYSTICK_FREQUENCY_HZ/10

//Yellow led
#define PWM_PORT GPIOB
#define PWM_PIN 1
#define PWM_RCC_BIT RCC_APB2Periph_GPIOB

Це налагодження виводів які керують світлодіодами: Порт, пін , біт включення тактування порта.  Також тут задається часовий інтервал який задає частоту зміни яскравості свічення в нашому випадку це 10разів в секунду.
Перейдемо до основного кода.

int
int
main(void)
{
/* Use SysTick as reference for the timer */
SysTick_Config(SystemCoreClock / SYSTICK_FREQUENCY_HZ);

Ініциалізуємо системний таймер періодом спрацювання 1 секунда

/* GPIO Periph clock enable */
RCC_APB2PeriphClockCmd(BLINK_RCC_BIT, ENABLE);
RCC_APB2PeriphClockCmd(PWM_RCC_BIT, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);

Подаємо тактування на порти світлодіодів та таймер TIM3 саме на його CH4 канал під’єднано жовтий світлодіод плати Mini64SER6

GPIO_InitTypeDef GPIO_InitStructure;

/* Configure pin in output push/pull mode */
GPIO_InitStructure.GPIO_Pin = (1 << BLINK_PIN);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(BLINK_PORT, &GPIO_InitStructure);

Ініціалізуємо вивід керування синім світлодіодом

GPIO_InitStructure.GPIO_Pin = (1 << PWM_PIN); GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(PWM_PORT, &GPIO_InitStructure);

Ініціалізуємо вивід керування жовтим світлодіодом тип зазначено як вивід з альтернативною функцією.

TIM3->CCER |=TIM_CCER_CC4E; //Allow timer use CH4 pin

Дозволяємо використовувати CH4 канал таймера TIM3

TIM3->CCMR2|=( TIM_CCMR2_OC4M_0|TIM_CCMR2_OC4M_1|TIM_CCMR2_OC4M_2);//Select inverce PWM on CH4 pin

Налагоджуємо інверсній ШІМ на каналі CH4

TIM3->CR1 |= TIM_CR1_CEN;// Starting timer

Запускаємо таймер

int seconds = 0;
uint32_t pwm_arr[]={0,65000,60000,55000,50000,45000,40000,35000,20000,1000,500,0};//Array of brightness levels of the led

Масив з рівнями яскравості свічення світлодіода

uint8_t i;
/* Infinite loop */
while (1)
{
GPIO_SetBits(BLINK_PORT, (1 << BLINK_PIN));
for (i=1;i<=11;i++) 
{ 
  TIM3->CCR4=pwm_arr[i];
  Delay(BLINK_TICKS);
}
GPIO_ResetBits(BLINK_PORT, (1 << BLINK_PIN));
++seconds;

Завантажуємо в регістр TIM3->CCR4 значення яскравості з масиву по порядку синій світлодіод блимає раз в секунду

Delay(1000);
++seconds;

GPIO_SetBits(BLINK_PORT, (1 << BLINK_PIN)); for (i=11;i>=1;i--)
{
  TIM3->CCR4=pwm_arr[i];
  Delay(BLINK_TICKS);
}
GPIO_ResetBits(BLINK_PORT, (1 << BLINK_PIN));
++seconds;

Завантажуємо в регістр TIM3->CCR4 значення яскравості з масиву в обратному порядку

Delay(1000);
++seconds;

#if defined(DEBUG)
/*
* Count seconds on the debug channel.
*/
printf("Second %d\n", seconds);
#endif
}
}

Ось ніби і все. Чіпляю відео роботи пристрою

Проект в Eclipce Mini64SER6
Ось ще стаття яку я використав при написанні коду.

Залишити відповідь