Установить TX, RX на LOW уровень перед сном, повторно включить uart после пробуждения

У меня есть ATmega1284P, и мне нужно, чтобы TXD0 (т.Е. Pin 9) был установлен на низкий уровень, прежде чем ложиться спать. После пробуждения я хочу восстановить связь UART0, чтобы она работала должным образом. Вот мой код:

Serial.begin(38400,SERIAL_8N1);

*do Stuff*

Serial.end();
//pinMode(9,OUTPUT);
//digitalWrite(9,LOW);      
//UCSR0B &= ~bit (RXEN0);  // disable receiver
//UCSR0B &= ~bit (TXEN0);  // disable transmitter
cli();           
set_sleep_mode (SLEEP_MODE_PWR_DOWN); 
sleep_enable();
// turn off brown-out enable in software
//MCUCR = bit (BODS) | bit (BODSE);  // turn on brown-out enable select
//MCUCR = bit (BODS);        // this must be done within 4 clock cycles of above
sleep_bod_disable();  //disable brown-out detection
sei();             // guarantees next instruction executed
sleep_cpu ();              // sleep within 3 clock cycles of above
sleep_disable();

//  UCSR0B |= bit (RXEN0);  // enable receiver
//  UCSR0B |= bit (TXEN0);  // enable transmitter  
//pinMode(9,OUTPUT);
//digitalWrite(9,HIGH);
//delay(100);
//pinMode(9,INPUT_PULLUP);
Serial.begin(38400,SERIAL_8N1);
delay(1000);
Serial.println("- Good Morning");

*do Stuff*

Вы можете увидеть в комментариях все разные вещи, которые я пробовал:

  • Использование Serial.end(), а затем, после пробуждения, Serial.begin()
  • Использование регистра UCSR0B
  • Используя digitalWrite, установите контакт на низкий уровень, а затем, после пробуждения, либо установите его на высокий, либо установите в качестве входного сигнала.

Все вышеперечисленные комбинации имеют общую проблему, заключающуюся в том, что процессор зависает после пробуждения, а серийный никогда не перезапускается для печати сообщения "Доброе утро", и программа не продолжает выполняться дальше.

, 👍-1

Обсуждение

Возможно, ваш терминал должен быть сброшен, так как вы закрыли последовательное соединение. Из моего опыта: простой вызов Serial.begin() не вызывает повторного подключения последовательного терминала. Я не уверен, но "Serial.println" может заблокироваться, и это будет причиной того, что ваша программа больше не будет выполняться. Опять же, это всего лишь догадки, но попробовать стоит. ;-) Работал ли спящий режим без последовательного выключения? Можете ли вы попробовать "дальнейшую обработку" без какого-либо "println", чтобы увидеть, блокируются ли отпечатки или нет? Можете ли вы распознать "дальнейшую обработку" без инструкций печати?, @Peter Paul Kiefer

Просто подсказка, как отметить проверенные альтернативы, которые легче понять и поддерживать, чем комментировать каждую строку: используйте условную компиляцию по #if 0 // try 1 ... #elif 1 // try 2 ... #эндиф., @the busybee

Попробуйте добавить delay (1000); после * do Stuff*. Я предполагаю, что данные все еще передаются по последовательному соединению, когда MCU переводится в спящий режим, что приводит к странным проблемам., @Gerben

Спасибо за предложения. Я попробовал их, прежде чем ко мне пришло решение, которое я опубликовал ниже. Просто одно предложение о комментарии @Gerben: действительно, обычно все еще есть данные перед сном, но лучший способ справиться с такими проблемами - использовать Serial.flush(). Конечно, и то, и другое будет работать нормально, @NickG


1 ответ


Лучший ответ:

1

Перепробовав множество различных альтернатив, оказалось, что моя ошибка заключалась в том, что я по глупости включил последовательную печать в свои процедуры ISR, доступ к которым осуществлялся при срабатывании моего прерывания, чтобы разбудить меня. В результате был вызван Serial.print, а Serial был закрыт (перед тем как выдать команду Serial.begin для его перезапуска), что разбило меня.

Дополнительно: Просто хотел прокомментировать использование Serial.print внутри ISRs. Хотя это может привести к неожиданным проблемам, подобным этой, или проблемам со временем (выполнение ISR займет слишком много времени), и это определенно плохая практика, иногда может быть полезно для целей отладки во время разработки напечатать там какое-то сообщение.

Печать сообщения занимает много времени, и ISR вернется до того, как сообщение будет полностью передано, что может вызвать сильную головную боль. Кроме того, прерывания отключены внутри ISR, поэтому функция delay() не работает для управления потоком. Лучший способ печати сообщений в ISR, с которым я сталкивался до сих пор, - это использование Serial.flush() перед выходом из ISR, убедившись, что сообщение полностью передано.

,

Вы должны держать ISR как можно короче, просто чтобы установить флаг или что-то в этом роде. Никогда не рекомендуется использовать доступ к вводу-выводу (например, Serial.print() в подпрограмме ISR, даже для целей отладки, делайте это вне ISR на основе флага, установленного ISR., @hcheung

Я бы посоветовал вам прочитать книгу Ника Гэммона [Прерывание].(http://gammon.com.au/interrupts )., @hcheung

Спасибо за предложение, я уже прочитал его, действительно отличный учебник. И да, хранение только флагов внутри ISR, безусловно, лучшая практика., @NickG