UCSR0B &= ~bit (RXEN0) // disable receiver PCICR |= bit (PCIE2) // enable pin change interrupts for D0 to D7 PCIFR |= bit (PCIF2) // clear any outstanding interrupts handle pin change interrupt for D0 to D7 here
The code below achieves what you are asking: #include Ideally this is how I would have designed our board but what we have works. This is not a problem if you are not using any other pin change interrupts on that port (PCINT16-PCINT23 in this case) So if you have more than one pin change enabled for the port, you have to determine which triggered the interrupt in the ISR. The only caveat with the port change interrupt is that the interrupt is shared across all the 8 pins that are enabled for that port. Setup an ISR for the pin change port 2 interrupt and continue as before. The actual current consumed by the ATMega328P is probably around 4uA.Īt look at the datasheet shows that the RX pin is also pin change interrupt pin 16 (PCINT16)īefore sleep: Set the port change interrupt mask bit in PCMSK2 for PCINT16, clear the pin change port 2 flag in PCIFR, enable the pin change port 2 interrupt (PCINT16-PCINT23) by setting PCIE2 in PCICR. The board with a few peripherals uses about 40uA when sleeping. This method gives absolutely no problems at all.
The PC interface software sends a dummy message every second to keep the device awake while the user has it connected for configuration etc. If a new message is receive the 30 second timer is reset. The device stays awake for 30 seconds after the last message is received in case of new messages. A single character would do it, but we send >wakeup\r hehe. To wake up the device we send a dummy message before transmission. This give some basic protection against losing messages, as incoming characters are not processed until a > is received. On the comms side of things we use a message protocol that has a start character > and end character \r. On wakeup, we check for the flag (there are other interrupt sources) INT0 interrupt service routine sets a flag and disables the interrupt void rx_interrupt() On sleep, INT0 low level interrupt is enabled //Clear software flag for rx interruptĪttachInterrupt(INT_RX, rx_interrupt, HIGH)
INT0 pin set to input or input pullup depending on how the RX line is driven.
So, bottom line, is there any option out there, to get less than 0.25mA at least, and also listen to serial port, without any hardware manipulation?įor example, waking up with long serial data input? I also read this article of Gammon, where you can disable some things, so you can get IDLE sleep with much lower power - but he didn't mention how exactly you get from this: power_adc_disable() I have found this link where you can connect in hardware the serial to the interrupt - which is dangerous so you can loose data, and moreover, I need these 2 interrupts pins. You will need to put it in IDLE mode, to listen to serial, but this would consume a few mA -bad. Would not wake it up with serial communication,according to this.
Setting the chip to deep sleep: set_sleep_mode (SLEEP_MODE_PWR_DOWN) I am using a custom PCB (not the UNO), with ATmega328p. So I would like to get as low current as possible, so that anything less that 100uA would be good - as long as I can listen to uart and interrupts for waking up. I have investigated the sleeps options of the ATmega328, and read a few articles about it, and I would like to understand if there are more options.