Осциллирующий сигнал на цифровом выходе AVR ATmega32U4

Я настроил свой Atmel ATMega32U4 с реле (используя NPN-транзистор для управления подачей 5 В на реле, а не управляя им напрямую с микроконтроллера). Я хочу использовать PD4 в качестве цифрового выхода для управления состоянием реле. Поскольку позже я буду использовать связь через USB, у меня подключен внешний кварцевый генератор, поэтому я установил соответствующий предохранитель и оставил остальные по умолчанию.

Когда я запускаю очень простую программу, подобную приведенной ниже, которая должна просто включать реле один раз, вместо этого я слышу, как реле быстро включается и выключается с частотой около 10 Гц.

#include <avr/io.h>

int main(void)
{
    // toggle PD4 as an output
    DDRD |= _BV(4);

    // set output high
    PORTD |= _BV(4);
}

Я заметил, что закомментирование строки PORTD |= _BV(4); останавливает колебание, но, конечно, это не решает мою проблему. В любом случае, кажется, что эта линия создает проблему.

Я использую Atmel Studio 6.2, программирую JTAG через программатор Atmel-ICE.

Приняв дикий удар в темноте, я предполагаю, что это может иметь какое-то отношение к альтернативной функции PD4 как ICP1/ADC8, как показано в datasheet (раздел 10.3.3, стр. 78), но я не знаю, как отключить эту функцию.

У кого-нибудь есть идеи, где я ошибаюсь?


person Sean    schedule 12.12.2016    source источник
comment
Вы не указали ссылку на таблицу данных, в которой подробно описаны альтернативные функции. Для PD4 нет альтернативных выходных функций, это либо вход АЦП, либо вход триггера таймера, поэтому, возможно, микросхема сбрасывается, что отключит реле, когда PORTD перейдет в три состояния. Что происходит после выхода из main()? Вы пытались поставить while(1); цикл после настройки PORTD, поэтому main() не завершается, посмотрите, стабилен ли тогда вывод? Вы пробовали управлять реле с контакта на другом порту? У вас есть последовательный резистор, управляющий базой транзистора, диод на катушке реле?   -  person barny    schedule 12.12.2016
comment
@barny, я попробовал цикл while (1) и получил те же результаты. Реле управляется резистором и диодом, как вы упомянули. Я не пробовал другой порт, потому что он находится на печатной плате, которую я распечатал, но я могу взломать что-нибудь вместе, если ничего не работает. Знаете ли вы, можно ли отключить функцию трех состояний этого порта?   -  person Sean    schedule 12.12.2016
comment
Когда ЦП сбрасывается, порты по умолчанию устанавливаются на входы, т. Е. Высокоимпедансные, что отключает ваше реле. Вы не можете и не хотите изменить это поведение. У вас есть осциллограф или другой способ посмотреть на сигнал на порту? У вас в схеме нет ничего похожего на аппаратный сторожевой таймер, который бы сбрасывал ЦП?   -  person barny    schedule 13.12.2016
comment
@barny, я посмотрел на сигнал на порту в то время, и он содержал ВЫСОКИЙ импульс каждые 100 мс или около того, а в остальное время был НИЗКИМ. Возможно, что-то быстро выключает и включает микроконтроллер, и он запускает программу, прежде чем снова выключиться и повторить цикл. Чтобы исследовать это, я думаю, я могу добавить большую задержку перед настройкой выхода вывода. Если реле все еще колеблется, я, вероятно, могу исключить проблему с циклическим включением питания микроконтроллера.   -  person Sean    schedule 13.12.2016
comment
@barny, оказывается, это действительно был сторожевой пес. Я думал, что отключил его, установив для предохранителя WDTON значение false, но, по-видимому, он все еще был включен. Добавление MCUSR &= ~(1 << WDRF); в начало моей функции main() остановило колебания. Спасибо за вашу помощь, очень признателен!   -  person Sean    schedule 13.12.2016


Ответы (1)


Проблема была в сторожевом таймере. Установка фьюза WDTON (сторожевой таймер всегда включен) в false не помогла с проблемой колебаний — я полагаю, что установка его в false гарантирует, что он всегда включен, но не гарантирует, что он определенно < em>выкл. Помещение следующей строки в main() сделало:

MCUSR &= ~(1 << WDRF);

Вам также необходимо импортировать заголовок сторожевого таймера avr/wdt.h вверху вашего скрипта или в файле заголовка:

#include <avr/wdt.h>

Итак, теперь код гласит:

#include <avr/io.h>
#include <avr/wdt.h>

int main(void)
{
    // turn off watchdog
    MCUSR &= ~(1 << WDRF);

    // toggle PD4 as an output
    DDRD |= _BV(4);

    // set output high
    PORTD |= _BV(4);

    // wait
    while(1)
    {
        // do nothing
    }
}
person Sean    schedule 13.12.2016
comment
@BenceKaulics, я сделаю, как только мне разрешат (придется подождать 20 часов)! - person Sean; 14.12.2016