LPCXpresso Урок 14. PWM. Синхронный ШИМ на таймере.

Прежде чем завершить курс для новичков рассмотрим такую всеми любимую и всем надоевшую тему как ШИМ.

Схема

Для данного урока нам надо подключить пару светодиодов к выводам P1.9 и P1.10 платы, через ток ограничительные резисторы (номиналом 100 Ом – 1 кОм):

Если вдруг под рукой у вас не завалялось ни одного светодиода, то можно поступить и так:


Немного теории

Синхронный ШИМ будем формировать аппаратно. Для этого задействуем 16-ти битный таймер 1 CT16B1. Выбран он просто, потому что все его выводы занимают, на мой взгляд, менее ценные выводы. Остальные же делят шину отладки, SPI, АЦП. В общем, поделить их не проблема, но не станем морочиться.
По работе таймера в режиме ШИМ в UM10375 есть несколько правил (раздел 14.8.13), вот они:
  1. Все выводы ШИМ устанавливаются в низкий уровень в начале каждого ШИМ цикла (счётчик таймера в 0), если их значения сравнения не равны нулю.
  2. Каждуй вывод ШИМ устанавливается в высокий уровень когда достигнуто его значение сравнения. Если значение сравнения не достигается (например, когда оно больше длины ШИМ), то вывод остаётся с низком уровне.
  3. Если в регистр совпадения записывается значение сравнения больше длины ШИМ и вывод ШИМ уже имеет высокий уровень, то ШИМ сигнал будет установлен в низкий уровень в начале следующего цикла.
  4. Если регистр сравнения имеет то же значение что и значение сброса таймера (длина ШИМ), то вывод ШТМ будет сброшен в низкий уровень в следующий такт. Таким образом, ШИМ сигнал всегда будет содержать один импульс высокого уровня длительностью в один такт с периодом равным длине ШИМ (значением сброса таймера).
  5. Если регистр сравнения установлен в 0, то ШИМ вывод будет установлен в высокий уровень (и останется в нем в дальнейшем) когда таймер сбросится в нулевое значение. Вывод ШИМ не будет устанавливаться в низкий уровень в начале цикла.

Пишем программу

Это будет самая простая программа без применения библиотек, кроме CMSIS. Функцию для ШИМ я не буду помещать в библиотеку LPC13xx_Lib, можете сделать это самостоятельно, если посчитаете нужным. Код как всегда прокомментирован, и сомневаюсь, что я смогу добавить к ним что-то ещё.
Начнём как обычно с инициализации. Передаётся функции один параметр – период ШИМ в микросекундах:
void PWM16_init(uint16_t period)
{
	LPC_SYSCON->SYSAHBCLKCTRL |= (1<<8);	// Разрешаем тактирование для таймера Timer1_16
	LPC_TMR16B1->PR  = SystemCoreClock / 1000000;	// Предделитель для получения частоты 1МГц

	LPC_IOCON->PIO1_9	&= ~0x07;
	LPC_IOCON->PIO1_9	|= 0x01;	// Вывод на Timer1_16 MAT0
	LPC_IOCON->PIO1_10	&= ~0x07;
	LPC_IOCON->PIO1_10	|= 0x02;	// Вывод на Timer1_16 MAT1

	LPC_TMR16B1->PWMC	= (1<<3)	// Разрешаем Match3 - по нему будет сброс
				| (1<<0)	// Разрешаем PWM0
				| (1<<1)	// Разрешаем PWM1
				;

	LPC_TMR16B1->MR3 = period - 1;	// В регистр сравнения MR3 период ШИМ (-1 т.к. сброс идет «после» установленного значения)
	LPC_TMR16B1->MR0 = period/2;	// Значение сравнения ШИМ0
	LPC_TMR16B1->MR1 = period/2;	// Значение сравнения ШИМ1

	LPC_TMR16B1->MCR = (2<<9);		// Режим Сброс счётчика TC при его совпадении с MR3

	LPC_TMR16B1->TCR = (1<<0);		// Разрешить счет Timer1_16
}

Примеры временных диаграмм есть в UM10375 раздел 14.9.
Код из архива содержит ещё несколько закомментированных строк. В режиме ШИМ они нам безразличны, но имеют значение при работе выводов в режиме сравнения. Желающие могут изучить их самостоятельно, я же не придумал для них подходящей демонстрации.
Функция установки периода ШИМ просто заносит в соответствующий регистр сравнения переданное ей значение:
void PWM16_set(uint8_t num, uint16_t value)
{
	if(num) {
		LPC_TMR16B1->MR1 = value;
	} else {
		LPC_TMR16B1->MR0 = value;
	}
}

Надо отметить что никакой «двойной буферизации» для данных регистров нет, и значение применяется сразу, как заносится в регистр. По этой причине могут возникнуть артефакты при записи нового значения. Например, TC=50, MR1=100 и вы записываете в него, скажем 20. В итоге значение сравнения не будет достигнуто в текущей итерации цикла ШИМ и вывод так и останется в низком уровне до достижения счетчиком значения 20 в следующей итерации цикла ШИМ.
Ну и наконец функция main
#define PWM_RERIOD	2000	/* Период ШИМ в микросекундах */
 
int main(void) {
	uint16_t pwm = 0;
	SysTick_Config(SystemCoreClock / 1000);	// настройка таймера на период 1мс
	PWM16_init(PWM_RERIOD);
	while(1) {
		PWM16_set(0, pwm);
		PWM16_set(1, PWM_RERIOD - pwm);
		delay_ms(100);
		pwm = (pwm < PWM_RERIOD) ? pwm + PWM_RERIOD/20 : 0;
	}
	return 0 ;
}

Алгоритм прост. Каждые 100мс значение ШИМ0 увеличивается и значение ШИМ1 уменьшается за 20 шагов.

Запуск

Запускаем на исполнение полученные 3176 байт кода и наблюдаем довольно «ступенчатое» изменение яркости светодиодов. Поскольку светодиоды у нас подключены к земле, то светодиод ШИМ0 будет уменьшать свою яркость, а светодиод ШИМ1 увеличивать. Такие заметные «ступеньки» из-за малого выбранного количества шагов (20 шагов у нас). Это некий компромисс, что бы и в отладчике не долго бегать для того, чтобы увидеть изменения, и при этом не сильно резко менять яркость.

Вместо заключения

ШИМ на всех таймерах (два 16-ти битных таймера и два 32-х битных) запускается одинаково. Разница только в используемых выводах, их количестве и в разрядности таймеров. ШИМ прост, оттого и урок такой короткий.
  • +2
  • 23 сентября 2011, 08:49
  • angel5a
  • 1
Файлы в топике: blinky_pwm.zip

Комментарии (8)

RSS свернуть / развернуть
че за фигня? решил почитать «курс молодого бойца» по икспрессе, пробую создать проект — ниче не получается… какой бы контроллер я не выьрал — все время такая херня вылазит…
forum.easyelectronics.ru/download/file.php?id=6671&t=1
0
либов нет. мож пути не так прописаны?
0
хз где они должны быть прописанны… я просто установил «с нуля» прогу… не пашет как в винде, так и под убунтой!.. щас полазаю подробно в настройках!
0
Либу CMSIS забыл поставить. Она в комплекте вроде бы идет, но надо галочки указать, чтобы встала.
0
дело чу-чуть сдвинулось к тому, что создать новый проект — получилось(ничего еще не писал в коде правда), а вот запустить образцы(блинки например) в дебаге — не получается… буду еще копаться…
0
кста, какая разница между CMSISv1 и v2?
0
уху)) получилось в дебаг вывести проект))) будет время — буду разгребать курс новичка)
0
Это хорошо. Но на будущее: Задавайте вопросы в соответствующих темах. В частности про открытие примеов есть соответствующий урок. Это позволит так же и остальным, столкнувшись с вашей проблемой — полячить на неё ответ, а не искать хуй знает где.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.