Невозможно установить рабочий цикл на 0% с помощью пользовательского PWM
Я пытаюсь управлять нагревательным элементом с помощью PWM с помощью Arduino Nano, но проблема в том, что даже если я установлю рабочий цикл на 0, он даст крошечный всплеск.
Я хочу сгенерировать квадратную волну 1 Гц, и именно поэтому я переопределяю регистры ШИМ по умолчанию.
Вот код:
// Настройка быстрого ШИМ на Arduino Uno при 1 Гц на цифровом выводе D9
void setup() {
// набор контактов ввода-вывода
pinMode(LDR_INPUT, INPUT); // A0
pinMode(HEATER_OUTPUT, OUTPUT); // D9
// Включить ШИМ-выход OC1A на цифровых выводах 9
TCCR1A = _BV(COM1A1) | _BV(WGM11);
// Установить быстрый ШИМ и прескалер 256 на таймере 1
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS12);
// Установите частоту ШИМ на 1 Гц: 16 МГц/(256 * 1 Гц) - 1 = 62499
ICR1 = 62499;
// OCR1A = 32149; // это дает мне рабочий цикл 50%, работает нормально
OCR1A = 0; // но это не работает
//разрешить задержку запуска ШИМ-таймеров
delay(10);
}
Для тестирования я подключил светодиод к ШИМ - контакту (D9), и это шипы от считывания LDR с аналогового контакта A0 (у меня нет осциллографа).
Я получаю те же результаты с Nano и Uno. Моя версия IDE - 1.8.14.
Как я могу решить эту проблему?
Вот моя функция контроля температуры:
void Compute()
{
unsigned long now = millis();
int timeChange = (now - lastTime);
if(timeChange>=SampleTime)
{
/*Вычислить все рабочие переменные ошибки*/
double error = Setpoint - temprature;
if (error <= 0)
{
Output = 0;
Serial.println("level: 0");
}
else if (error <= 1)
{
Output = 5;
Serial.println("level: 1");
}
else if (error <= 2)
{
Output = 30;
Serial.println("level: 2");
}
else if (error <= 3)
{
Output = 50;
Serial.println("level: 3");
}
else if (error <= 10)
{
Output = 60;
Serial.println("level: 4");
}
else if (error <= 100)
{
Output = 200;
Serial.println("level: 5");
}
else
{
Output = 255;
Serial.println("level: 6");
}
analogWrite(HEATER_OUTPUT, Output);
//OCR1A = map(Output, 0, 255, 0, 62499);
delay(10);
lastErr = error;
lastTime = now;
}
}
Проблема в том, что после того, как я переопределяю регистры PWM, analogWrite()
кажется испорченным. Это не работает, и для всех значений вывода
результат почти одинаков.
ОБНОВЛЕНИЕ 22/06/2021
Я все еще пытаюсь исправить это, если я использую analogWrite()
или digitalWrite ()
, чтобы отключить ШИМ-вывод, дальнейшие изменения в правилах OCR1A не действуют. какие бы значения я ни давал OCR1A, вывод остается низким, если я вручную делаю вывод высоким с помощью digitalWrite или analogWrite, вывод остается высоким навсегда, изменения в
OCR1A
не принимаются во внимание.
Я написал тестовую функцию
void testPWM3() {
Serial.println("f: 1Hz | on 0s");
digitalWrite(HEATER_OUTPUT, LOW); // выключите шим-вывод, чтобы получить полный (рабочий цикл 0%)
delay(5000);
/*
После отключения вывода с помощью digitalWrite() дальнейшие изменения в OCR1A reg не принимаются в действие
*/
digitalWrite(HEATER_OUTPUT, HIGH);
Serial.println("f: 1Hz | on 125ms");
OCR1A = 1953;
delay(5000);
Serial.println("f: 1Hz | on 250ms");
OCR1A = 3906;
delay(5000);
Serial.println("f: 1Hz | on 500ms");
OCR1A = 7812;
delay(5000);
Serial.println("f: 1Hz | on 1sec");
digitalWrite(HEATER_OUTPUT, HIGH); // это работает
delay(5000);
}
Любые советы по этому поводу будут очень полезны, спасибо
@Sumithran, 👍2
2 ответа
Вот как это должно быть. В этом быстром режиме ШИМ рабочий цикл
равен (OCR1A+1)/(ICR1+1)
. Если вы хотите, чтобы рабочий цикл был равен нулю, вы должны
отключить ШИМ и повернуть вывод на низкий
уровень.
Это то, что делает Arduino analogWrite()
: он рассматривает
значение 0 как особый случай. Обратите внимание, что 255 также рассматривается как особый
случай, хотя это бесполезно.
Edit 1: о том, что analogWrite()
испорчен.
analogWrite(9, value)
устанавливает OCR1A
в значение от 1 до 254 (0 и
255 обрабатываются по-разному). Рабочий цикл, который вы получаете, выглядит следующим образом:
Я писал раньше (OCR1A+1)/(ICR1+1)
. Это не то, что ожидает ваша тестовая
функция.
Я предлагаю вам отказаться от analogWrite()
и вместо этого установить непосредственно OCR1A
.
Edit 2: После того, как вы взяли под контроль ШИМ-канал на низком уровне,
записав непосредственно в аппаратные регистры, вы не должны использовать
функции Arduino digitalWrite()
или analogWrite()
на
соответствующем выводе. Эти функции предполагают, что эти аппаратные регистры
управляются исключительно ядром Arduino, и они будут возиться с ними таким
образом, что, скорее всего, сломают вашу программу.
Чтобы установить рабочий цикл равным нулю, отключите режим ШИМ и установите вывод в положение НИЗКИЙ УРОВЕНЬ:
TCCR1A &= ~_BV(COM1A1); // отключить ШИМ на выводе OC1A = PB1
PORTB &= _BV(PB1); // установить PB1 в НИЗКОЕ значение
Быстрая ШИМ работает таким образом: при рабочем цикле 0% выходной сигнал устанавливается на высокий уровень на 1 цикл при TOP+1 для неинвертированного режима ШИМ и на низкий уровень для инвертированного режима. Если вы хотите иметь непрерывный низкий выходной сигнал, вам необходимо использовать фазовую коррекцию или ШИМ с коррекцией фазы и частоты.
- avrdude ser_open() can't set com-state
- Управление скоростью вентилятора с помощью библиотеки Arduino PID
- Как устранить шум от вентилятора 12 В с ШИМ-управлением на низкой скорости
- Генерация частоты ШИМ выше 125 кГц с помощью Arduino Uno
- Увеличить разрядность PWM
- Как вывести истинное аналоговое напряжение на выходной контакт
- Как отправить команду AT на sim800l с помощью SoftwareSerial
- ПИД-регулятор для управления скоростью двигателя
Спасибо за ваш ответ, я пробовал это, но analogWrite не работает должным образом в моем случае, обновил вопрос., @Sumithran
Вы имеете в виду, что не работаете должным образом так, как *отличается* от того, как этот ответ прекрасно объясняет?, @timemage
@timemage, это отличный ответ, я получил то, что он говорит, с помощью
analogWrite ()
я получаю чистый ШИМ, но с analogWrite(9,128) я должен получить рабочий цикл 50%, но то, что я получаю,-это действительно тонкий импульс.., @SumithranRe “_analogWrite(9,128) Я должен получить рабочий цикл 50%_”: Нет, это не так. Прочтите мой ответ внимательнее., @Edgar Bonet
о, черт меня побери, значит, чтобы получить 50%, я должен отдать половину ICR1, верно?.., @Sumithran
Привет, я все еще пытаюсь это исправить, если я использую
analogWrite ()
, чтобы отключить вывод PWM, дальнейшие изменения в правилах OCR1A не будут действовать. какие бы значения я ни давал OCR1A, выход остается низким, если я вручную делаю вход высоким с помощью digitalWrite или analogWrite, контакт остается высоким навсегда, изменения в OCR1A не принимаются во внимание... Любые советы по этому поводу будут очень полезны, спасибо, @Sumithran