Быстрый ШИМ, работающий с int main(void), но не с void setup()
плата: Arduino Mega (ATMEGA2560)
Я хочу генерировать импульсы, используя таймер 1, настроенный как быстрый ШИМ. Вот мой код, который работает отлично:
#include <avr/io.h>
int main(void)
//void setup()
{
DDRB |= (1 << DDB5) | (1 << DDB6); // PWM outputs
ICR1 = 0x7FFF; // TOP
OCR1A = 0x3FFF; // 50% of ICR1
OCR1B = 0x3FFF; // 50% of ICR1
TCCR1A |= (1 << COM1A1) | (1 << COM1B1);
TCCR1A |= (1 << WGM11);
TCCR1B |= (1 << WGM12) | (1 << WGM13);
TCCR1B |= (1 << CS10);
}
void loop() {
}
Не понимаю, почему не работает void setup() вместо int main(void). Я работаю с Arduino IDE 1.8.2 и всегда использовал void setup(). В данном случае я использовал int main(void), потому что он используется в некоторых обучающих материалах, которые я нашёл, например, в этом: https://www.youtube.com/watch?v=O_Yqf_cugwE
РЕДАКТИРОВАНИЕ: Когда я говорю, что это не работает, на самом деле вместо сигналов ШИМ у меня просто постоянный выход 5 В на выводах OC1A и OC1B
@Mr. C, 👍1
Обсуждение1 ответ
Лучший ответ:
Если вы не определите свой собственный main(), ваша программа будет связана с
main(), предоставляемый основной библиотекой Arduino, который выглядит примерно так:
вот так (я немного упрощаю):
int main(void)
{
init(); // Инициализация ядра Arduino
setup(); // инициализация пользователя
for (;;)
loop(); // основной цикл пользователя
}
Функция ядра init() настраивает таймер 1 для 8-битной фазы
правильный ШИМ на частоте 490 Гц, что означает, что к тому времени, как ваш setup()
запускается, регистры управления таймером не находятся в состоянии по умолчанию
больше нет, и некоторые из их битов уже установлены в 1. Если вы затем
обновите эти регистры с помощью оператора |=, в результате вы получите смесь
конфигурация ядра и ваша собственная.
Это можно исправить, либо сначала обнулив эти регистры, либо, что еще лучше,
просто установив их значения с помощью оператора =, который имеет
эффект или установка каждого бита этих регистров в нужное вам значение.
Следующее работает независимо от того, используете ли вы базовую библиотеку Arduino:
#ifdef NOCORE
int main(void)
#else
void setup()
#endif
{
DDRB = _BV(PB5) | _BV(PB6);
TCCR1A = _BV(COM1A1)
| _BV(COM1B1)
| _BV(WGM11);
TCCR1B = _BV(WGM12)
| _BV(WGM13)
| _BV(CS10);
ICR1 = 0x7fff; // TOP
OCR1A = 0x3fff; // 50% of ICR1
OCR1B = 0x3fff; // 50% of ICR1
}
#ifndef NOCORE
void loop(){}
#endif
Обратите внимание:
- Управляющие регистры устанавливаются (
=), а не просто изменяются с помощью|= - Режим устанавливается до регистров сравнения выходных данных. Это связано с тем, что Настройка выходных регистров сравнения не работает должным образом, когда таймер находится в 8-битном режиме.
Спасибо, что указали на то, что порядок установки таймера может как-то влиять. Я понятия не имел. С вашим кодом у меня всё равно не работает. У вас была возможность протестировать?, @Mr. C
@Mr.C: Я проверил это (и всё работает) на Uno. Мне пришлось изменить DDRB на _BV(PB1) | _BV(PB2), чтобы соответствовать распиновке Uno. Обратите внимание, что в предыдущей версии ответа я по ошибке оставил настройку DDRB соответствующей Uno., @Edgar Bonet
После замены DDRB на _BV(PB1) | _BV(PB2) на соответствующие пины в MEga DDRB на _BV(PB5) | _BV(PB6) всё работает отлично, я этого не замечал. Большое спасибо @Edgar Bonet! После твоего объяснения функции init ядра мне стало понятнее, почему не работало void setup()., @Mr. C
- Управление скоростью вентилятора с помощью библиотеки Arduino PID
- Почему мой код прерывания не работает?
- Можно ли использовать цифровые контакты в качестве выхода ШИМ?
- Изменение ШИМ на Arduino Mega, контакты 9 и 10 на 20–25 кГц
- Корректный по фазе и частоте режим PWM Arduino Mega 2560
- ШИМ-сигнализация с Arduino: для чего использовать землю?
- Как измерить ультразвуковой датчик без импульсного метода?
- Выходная мощность и управление выводом Mega 2560
Попробуйте использовать
=вместо|=., @Edgar BonetИспользуя
=вместо|=, я теперь получаю выходное напряжение 0 В вместо 5 В. Сначала я попробовал инициализироватьTCCR1A = 0;иTCCR1B = 0;., @Mr. C