为什么这个用于ATMega128的AVR代码表现出这种行为?

huangapple go评论72阅读模式
英文:

Why does this AVR code for ATMega128 behave the way it does?

问题

I see you're looking for help with your code behavior on an ATMega128 microcontroller when running it in Proteus. It seems like you want to configure the microcontroller to enter sleep mode and wake up only when there's a USART0 receive interrupt. Here's the translated portion of your text:

我有以下的ATMega128代码:

一些库和函数未被使用,因为我还没有完全完成代码,因为我在这个问题上已经卡了几天了。

Your explanation mentions that the main function is stuck in an infinite loop, and you expect the configuration functions to run only once, with the CPU going into sleep mode and waking up on USART0 receive interrupts. You're wondering what might be causing this issue.

It's challenging to diagnose the issue without a detailed analysis of your code and the Proteus simulation setup. However, it's essential to ensure that your USART0 receive interrupt (USART0_RX_vect) is correctly configured and that there are no other unexpected interrupts or conditions that might be preventing the microcontroller from entering sleep mode.

You might want to double-check your interrupt configuration and ensure that the USART0 receive interrupt is the only source waking up the microcontroller from sleep. Additionally, make sure that your USART0 receive buffer is being properly cleared after processing incoming data.

If you continue to experience issues, you might consider posting your code and simulation setup details on a relevant electronics or microcontroller forum for more in-depth assistance from the community.

英文:

I have the following code for ATMega128:

Some libraries and functions are not used as I haven't completed the code completely because I am stuck at this problem for days now.

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/delay.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define F_CPU		8000000UL
#define BAUDRATE	9600
#define UBRR_VALUE	((F_CPU)/(16UL*BAUDRATE))-1 //For UBRR registers

#define MASTER_WATCHDOG_MENU	"\rEnter MS WD Choice (& period):\rA-30ms\rB-250ms\rC-500ms\rYour input:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/delay.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define F_CPU		8000000UL
#define BAUDRATE	9600
#define UBRR_VALUE	((F_CPU)/(16UL*BAUDRATE))-1 //For UBRR registers
#define MASTER_WATCHDOG_MENU	"\rEnter MS WD Choice (& period):\rA-30ms\rB-250ms\rC-500ms\rYour input:\0"
#define SLAVE_WATCHDOG_MENU		"\rEnter SLV WD Choice (& period):\rA-0.5s\rB-1.0s\rC-2.0s\rYour input:\0"
#define USER_MENU				"\rEnter choice (and period): 1-Mem Dump 2-Last Entry 3-Restart\rYour input:\0"
void ConfigureXMEMMode(void){
MCUCR |= (1 << SRE); 
XMCRA = 0;			 
XMCRB = (1 << XMM2) | (0 << XMM1) | (1 << XMM0);
}
void ConfigureUSARTInterfaces(void){
UBRR0H = (unsigned char)(UBRR_VALUE >> 8);
UBRR0L = (unsigned char)(UBRR_VALUE);
UBRR1H = (unsigned char)(UBRR_VALUE >> 8);
UBRR1L = (unsigned char)(UBRR_VALUE);
UCSR0B = (1<<RXEN0) | (1<<RXCIE0) | (1<<TXEN0) | (1<<TXCIE0); 
UCSR1B = (1<<RXEN1) | (1<<RXCIE1) | (1<<TXEN1) | (1<<TXCIE1);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
UCSR1C = (1 << UCSZ01) | (1 << UCSZ00);
}
void USART0_TransmitByte(unsigned char byteToTransmit){
while(!(UCSR0A & (1<<UDRE0))); 
UDR0 = byteToTransmit;
}
void USART0_TransmitString(unsigned char *stringToTransmit){
unsigned char i = 0;
for(i = 0; stringToTransmit[i] != '\0'; i++){
USART0_TransmitByte(stringToTransmit[i]);
}
}
void USART1_TransmitByte(unsigned char byteToTransmit){
while(!(UCSR1A & (1<<UDRE1)));
UDR1 = byteToTransmit;
}
void USART1_TransmitString(unsigned char *stringToTransmit){
unsigned char i = 0;
for(i = 0; stringToTransmit[i] != '\0'; i++){
USART1_TransmitByte(stringToTransmit[i]);
}
}
unsigned char USART0_ReceiveByte(void){
while(!(UCSR0A & (1<<RXC0))); 
return UDR0; 
}
unsigned char USART1_ReceiveByte(void){
while(!(UCSR1A & (1<<RXC1)));
return UDR1;
}
void ConfigureWatchdogTimer(void){
while(EECR & (1 << EEWE)); 
EEARH = 0x00; 
EEARL = 0x00; 
EECR  = 1 << EERE; 
if(EEDR == 0xFF){
EEARL = 0x01;
if(EEDR == 0xFF){
EECR = 0 << EERE;
ConfigureMasterWD();
}
}
while(EECR & (1 << EEWE));
EEARH = 0x00;
EEARL = 0x02;
EECR  = 1 << EERE;
if(EEDR == 0xFF){
EEARL = 0x03;
if (EEDR == 0xFF){
EECR = 0 << EERE;
ConfigureSlaveWD();
}
}
}
void ConfigureMasterWD(){
USART0_TransmitString(MASTER_WATCHDOG_MENU);
unsigned char userInput = USART0_ReceiveByte();
switch(userInput){
case 'A': case 'a':
WDTCR = (1 << WDE) | (0 << WDP2) | (0 << WDP1) | (1 << WDP0); //30ms
break;
case 'B': case 'b':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (0 << WDP0); //250ms
break;
case 'C': case 'c':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (1 << WDP0); //500ms
break;
}
USART0_TransmitString("\rDone!\r");
}
void ConfigureSlaveWD(){
USART0_TransmitString(SLAVE_WATCHDOG_MENU);
unsigned char userInput = USART0_ReceiveByte();
switch(userInput){
case 'A': case 'a':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (1 << WDP0); //500ms
break;
case 'B': case 'b':
WDTCR = (1 << WDE) | (1 << WDP2) | (1 << WDP1) | (0 << WDP0); //1.0s
break;
case 'C': case 'c':
WDTCR = (1 << WDE) | (1 << WDP2) | (1 << WDP1) | (1 << WDP0); //2.0s
break;
}
USART0_TransmitString("\rDone!\r");
}
void Sleep(){
sei();
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_enable();
sleep_cpu();
}
void WakeUp(){
sleep_disable();
cli();
}
int main(void){
ConfigureXMEMMode();
ConfigureUSARTInterfaces();
ConfigureWatchdogTimer();
USART0_TransmitString("ATMEGA128 TO USART0");
USART1_TransmitString("ATMEGA128 TO USART1");
Sleep();
while(1);
}
ISR(USART0_RX_vect){
WakeUp();
new_user_read_char = UDR0;
USART1_TransmitByte(UDR0);
Sleep();
}
" #define SLAVE_WATCHDOG_MENU "\rEnter SLV WD Choice (& period):\rA-0.5s\rB-1.0s\rC-2.0s\rYour input:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/delay.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define F_CPU		8000000UL
#define BAUDRATE	9600
#define UBRR_VALUE	((F_CPU)/(16UL*BAUDRATE))-1 //For UBRR registers
#define MASTER_WATCHDOG_MENU	"\rEnter MS WD Choice (& period):\rA-30ms\rB-250ms\rC-500ms\rYour input:\0"
#define SLAVE_WATCHDOG_MENU		"\rEnter SLV WD Choice (& period):\rA-0.5s\rB-1.0s\rC-2.0s\rYour input:\0"
#define USER_MENU				"\rEnter choice (and period): 1-Mem Dump 2-Last Entry 3-Restart\rYour input:\0"
void ConfigureXMEMMode(void){
MCUCR |= (1 << SRE); 
XMCRA = 0;			 
XMCRB = (1 << XMM2) | (0 << XMM1) | (1 << XMM0);
}
void ConfigureUSARTInterfaces(void){
UBRR0H = (unsigned char)(UBRR_VALUE >> 8);
UBRR0L = (unsigned char)(UBRR_VALUE);
UBRR1H = (unsigned char)(UBRR_VALUE >> 8);
UBRR1L = (unsigned char)(UBRR_VALUE);
UCSR0B = (1<<RXEN0) | (1<<RXCIE0) | (1<<TXEN0) | (1<<TXCIE0); 
UCSR1B = (1<<RXEN1) | (1<<RXCIE1) | (1<<TXEN1) | (1<<TXCIE1);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
UCSR1C = (1 << UCSZ01) | (1 << UCSZ00);
}
void USART0_TransmitByte(unsigned char byteToTransmit){
while(!(UCSR0A & (1<<UDRE0))); 
UDR0 = byteToTransmit;
}
void USART0_TransmitString(unsigned char *stringToTransmit){
unsigned char i = 0;
for(i = 0; stringToTransmit[i] != '\0'; i++){
USART0_TransmitByte(stringToTransmit[i]);
}
}
void USART1_TransmitByte(unsigned char byteToTransmit){
while(!(UCSR1A & (1<<UDRE1)));
UDR1 = byteToTransmit;
}
void USART1_TransmitString(unsigned char *stringToTransmit){
unsigned char i = 0;
for(i = 0; stringToTransmit[i] != '\0'; i++){
USART1_TransmitByte(stringToTransmit[i]);
}
}
unsigned char USART0_ReceiveByte(void){
while(!(UCSR0A & (1<<RXC0))); 
return UDR0; 
}
unsigned char USART1_ReceiveByte(void){
while(!(UCSR1A & (1<<RXC1)));
return UDR1;
}
void ConfigureWatchdogTimer(void){
while(EECR & (1 << EEWE)); 
EEARH = 0x00; 
EEARL = 0x00; 
EECR  = 1 << EERE; 
if(EEDR == 0xFF){
EEARL = 0x01;
if(EEDR == 0xFF){
EECR = 0 << EERE;
ConfigureMasterWD();
}
}
while(EECR & (1 << EEWE));
EEARH = 0x00;
EEARL = 0x02;
EECR  = 1 << EERE;
if(EEDR == 0xFF){
EEARL = 0x03;
if (EEDR == 0xFF){
EECR = 0 << EERE;
ConfigureSlaveWD();
}
}
}
void ConfigureMasterWD(){
USART0_TransmitString(MASTER_WATCHDOG_MENU);
unsigned char userInput = USART0_ReceiveByte();
switch(userInput){
case 'A': case 'a':
WDTCR = (1 << WDE) | (0 << WDP2) | (0 << WDP1) | (1 << WDP0); //30ms
break;
case 'B': case 'b':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (0 << WDP0); //250ms
break;
case 'C': case 'c':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (1 << WDP0); //500ms
break;
}
USART0_TransmitString("\rDone!\r");
}
void ConfigureSlaveWD(){
USART0_TransmitString(SLAVE_WATCHDOG_MENU);
unsigned char userInput = USART0_ReceiveByte();
switch(userInput){
case 'A': case 'a':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (1 << WDP0); //500ms
break;
case 'B': case 'b':
WDTCR = (1 << WDE) | (1 << WDP2) | (1 << WDP1) | (0 << WDP0); //1.0s
break;
case 'C': case 'c':
WDTCR = (1 << WDE) | (1 << WDP2) | (1 << WDP1) | (1 << WDP0); //2.0s
break;
}
USART0_TransmitString("\rDone!\r");
}
void Sleep(){
sei();
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_enable();
sleep_cpu();
}
void WakeUp(){
sleep_disable();
cli();
}
int main(void){
ConfigureXMEMMode();
ConfigureUSARTInterfaces();
ConfigureWatchdogTimer();
USART0_TransmitString("ATMEGA128 TO USART0");
USART1_TransmitString("ATMEGA128 TO USART1");
Sleep();
while(1);
}
ISR(USART0_RX_vect){
WakeUp();
new_user_read_char = UDR0;
USART1_TransmitByte(UDR0);
Sleep();
}
" #define USER_MENU "\rEnter choice (and period): 1-Mem Dump 2-Last Entry 3-Restart\rYour input:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/delay.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define F_CPU		8000000UL
#define BAUDRATE	9600
#define UBRR_VALUE	((F_CPU)/(16UL*BAUDRATE))-1 //For UBRR registers
#define MASTER_WATCHDOG_MENU	"\rEnter MS WD Choice (& period):\rA-30ms\rB-250ms\rC-500ms\rYour input:\0"
#define SLAVE_WATCHDOG_MENU		"\rEnter SLV WD Choice (& period):\rA-0.5s\rB-1.0s\rC-2.0s\rYour input:\0"
#define USER_MENU				"\rEnter choice (and period): 1-Mem Dump 2-Last Entry 3-Restart\rYour input:\0"
void ConfigureXMEMMode(void){
MCUCR |= (1 << SRE); 
XMCRA = 0;			 
XMCRB = (1 << XMM2) | (0 << XMM1) | (1 << XMM0);
}
void ConfigureUSARTInterfaces(void){
UBRR0H = (unsigned char)(UBRR_VALUE >> 8);
UBRR0L = (unsigned char)(UBRR_VALUE);
UBRR1H = (unsigned char)(UBRR_VALUE >> 8);
UBRR1L = (unsigned char)(UBRR_VALUE);
UCSR0B = (1<<RXEN0) | (1<<RXCIE0) | (1<<TXEN0) | (1<<TXCIE0); 
UCSR1B = (1<<RXEN1) | (1<<RXCIE1) | (1<<TXEN1) | (1<<TXCIE1);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
UCSR1C = (1 << UCSZ01) | (1 << UCSZ00);
}
void USART0_TransmitByte(unsigned char byteToTransmit){
while(!(UCSR0A & (1<<UDRE0))); 
UDR0 = byteToTransmit;
}
void USART0_TransmitString(unsigned char *stringToTransmit){
unsigned char i = 0;
for(i = 0; stringToTransmit[i] != '\0'; i++){
USART0_TransmitByte(stringToTransmit[i]);
}
}
void USART1_TransmitByte(unsigned char byteToTransmit){
while(!(UCSR1A & (1<<UDRE1)));
UDR1 = byteToTransmit;
}
void USART1_TransmitString(unsigned char *stringToTransmit){
unsigned char i = 0;
for(i = 0; stringToTransmit[i] != '\0'; i++){
USART1_TransmitByte(stringToTransmit[i]);
}
}
unsigned char USART0_ReceiveByte(void){
while(!(UCSR0A & (1<<RXC0))); 
return UDR0; 
}
unsigned char USART1_ReceiveByte(void){
while(!(UCSR1A & (1<<RXC1)));
return UDR1;
}
void ConfigureWatchdogTimer(void){
while(EECR & (1 << EEWE)); 
EEARH = 0x00; 
EEARL = 0x00; 
EECR  = 1 << EERE; 
if(EEDR == 0xFF){
EEARL = 0x01;
if(EEDR == 0xFF){
EECR = 0 << EERE;
ConfigureMasterWD();
}
}
while(EECR & (1 << EEWE));
EEARH = 0x00;
EEARL = 0x02;
EECR  = 1 << EERE;
if(EEDR == 0xFF){
EEARL = 0x03;
if (EEDR == 0xFF){
EECR = 0 << EERE;
ConfigureSlaveWD();
}
}
}
void ConfigureMasterWD(){
USART0_TransmitString(MASTER_WATCHDOG_MENU);
unsigned char userInput = USART0_ReceiveByte();
switch(userInput){
case 'A': case 'a':
WDTCR = (1 << WDE) | (0 << WDP2) | (0 << WDP1) | (1 << WDP0); //30ms
break;
case 'B': case 'b':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (0 << WDP0); //250ms
break;
case 'C': case 'c':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (1 << WDP0); //500ms
break;
}
USART0_TransmitString("\rDone!\r");
}
void ConfigureSlaveWD(){
USART0_TransmitString(SLAVE_WATCHDOG_MENU);
unsigned char userInput = USART0_ReceiveByte();
switch(userInput){
case 'A': case 'a':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (1 << WDP0); //500ms
break;
case 'B': case 'b':
WDTCR = (1 << WDE) | (1 << WDP2) | (1 << WDP1) | (0 << WDP0); //1.0s
break;
case 'C': case 'c':
WDTCR = (1 << WDE) | (1 << WDP2) | (1 << WDP1) | (1 << WDP0); //2.0s
break;
}
USART0_TransmitString("\rDone!\r");
}
void Sleep(){
sei();
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_enable();
sleep_cpu();
}
void WakeUp(){
sleep_disable();
cli();
}
int main(void){
ConfigureXMEMMode();
ConfigureUSARTInterfaces();
ConfigureWatchdogTimer();
USART0_TransmitString("ATMEGA128 TO USART0");
USART1_TransmitString("ATMEGA128 TO USART1");
Sleep();
while(1);
}
ISR(USART0_RX_vect){
WakeUp();
new_user_read_char = UDR0;
USART1_TransmitByte(UDR0);
Sleep();
}
" void ConfigureXMEMMode(void){ MCUCR |= (1 << SRE); XMCRA = 0; XMCRB = (1 << XMM2) | (0 << XMM1) | (1 << XMM0); } void ConfigureUSARTInterfaces(void){ UBRR0H = (unsigned char)(UBRR_VALUE >> 8); UBRR0L = (unsigned char)(UBRR_VALUE); UBRR1H = (unsigned char)(UBRR_VALUE >> 8); UBRR1L = (unsigned char)(UBRR_VALUE); UCSR0B = (1<<RXEN0) | (1<<RXCIE0) | (1<<TXEN0) | (1<<TXCIE0); UCSR1B = (1<<RXEN1) | (1<<RXCIE1) | (1<<TXEN1) | (1<<TXCIE1); UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); UCSR1C = (1 << UCSZ01) | (1 << UCSZ00); } void USART0_TransmitByte(unsigned char byteToTransmit){ while(!(UCSR0A & (1<<UDRE0))); UDR0 = byteToTransmit; } void USART0_TransmitString(unsigned char *stringToTransmit){ unsigned char i = 0; for(i = 0; stringToTransmit[i] != '
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/delay.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define F_CPU		8000000UL
#define BAUDRATE	9600
#define UBRR_VALUE	((F_CPU)/(16UL*BAUDRATE))-1 //For UBRR registers
#define MASTER_WATCHDOG_MENU	"\rEnter MS WD Choice (& period):\rA-30ms\rB-250ms\rC-500ms\rYour input:\0"
#define SLAVE_WATCHDOG_MENU		"\rEnter SLV WD Choice (& period):\rA-0.5s\rB-1.0s\rC-2.0s\rYour input:\0"
#define USER_MENU				"\rEnter choice (and period): 1-Mem Dump 2-Last Entry 3-Restart\rYour input:\0"
void ConfigureXMEMMode(void){
MCUCR |= (1 << SRE); 
XMCRA = 0;			 
XMCRB = (1 << XMM2) | (0 << XMM1) | (1 << XMM0);
}
void ConfigureUSARTInterfaces(void){
UBRR0H = (unsigned char)(UBRR_VALUE >> 8);
UBRR0L = (unsigned char)(UBRR_VALUE);
UBRR1H = (unsigned char)(UBRR_VALUE >> 8);
UBRR1L = (unsigned char)(UBRR_VALUE);
UCSR0B = (1<<RXEN0) | (1<<RXCIE0) | (1<<TXEN0) | (1<<TXCIE0); 
UCSR1B = (1<<RXEN1) | (1<<RXCIE1) | (1<<TXEN1) | (1<<TXCIE1);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
UCSR1C = (1 << UCSZ01) | (1 << UCSZ00);
}
void USART0_TransmitByte(unsigned char byteToTransmit){
while(!(UCSR0A & (1<<UDRE0))); 
UDR0 = byteToTransmit;
}
void USART0_TransmitString(unsigned char *stringToTransmit){
unsigned char i = 0;
for(i = 0; stringToTransmit[i] != '\0'; i++){
USART0_TransmitByte(stringToTransmit[i]);
}
}
void USART1_TransmitByte(unsigned char byteToTransmit){
while(!(UCSR1A & (1<<UDRE1)));
UDR1 = byteToTransmit;
}
void USART1_TransmitString(unsigned char *stringToTransmit){
unsigned char i = 0;
for(i = 0; stringToTransmit[i] != '\0'; i++){
USART1_TransmitByte(stringToTransmit[i]);
}
}
unsigned char USART0_ReceiveByte(void){
while(!(UCSR0A & (1<<RXC0))); 
return UDR0; 
}
unsigned char USART1_ReceiveByte(void){
while(!(UCSR1A & (1<<RXC1)));
return UDR1;
}
void ConfigureWatchdogTimer(void){
while(EECR & (1 << EEWE)); 
EEARH = 0x00; 
EEARL = 0x00; 
EECR  = 1 << EERE; 
if(EEDR == 0xFF){
EEARL = 0x01;
if(EEDR == 0xFF){
EECR = 0 << EERE;
ConfigureMasterWD();
}
}
while(EECR & (1 << EEWE));
EEARH = 0x00;
EEARL = 0x02;
EECR  = 1 << EERE;
if(EEDR == 0xFF){
EEARL = 0x03;
if (EEDR == 0xFF){
EECR = 0 << EERE;
ConfigureSlaveWD();
}
}
}
void ConfigureMasterWD(){
USART0_TransmitString(MASTER_WATCHDOG_MENU);
unsigned char userInput = USART0_ReceiveByte();
switch(userInput){
case 'A': case 'a':
WDTCR = (1 << WDE) | (0 << WDP2) | (0 << WDP1) | (1 << WDP0); //30ms
break;
case 'B': case 'b':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (0 << WDP0); //250ms
break;
case 'C': case 'c':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (1 << WDP0); //500ms
break;
}
USART0_TransmitString("\rDone!\r");
}
void ConfigureSlaveWD(){
USART0_TransmitString(SLAVE_WATCHDOG_MENU);
unsigned char userInput = USART0_ReceiveByte();
switch(userInput){
case 'A': case 'a':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (1 << WDP0); //500ms
break;
case 'B': case 'b':
WDTCR = (1 << WDE) | (1 << WDP2) | (1 << WDP1) | (0 << WDP0); //1.0s
break;
case 'C': case 'c':
WDTCR = (1 << WDE) | (1 << WDP2) | (1 << WDP1) | (1 << WDP0); //2.0s
break;
}
USART0_TransmitString("\rDone!\r");
}
void Sleep(){
sei();
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_enable();
sleep_cpu();
}
void WakeUp(){
sleep_disable();
cli();
}
int main(void){
ConfigureXMEMMode();
ConfigureUSARTInterfaces();
ConfigureWatchdogTimer();
USART0_TransmitString("ATMEGA128 TO USART0");
USART1_TransmitString("ATMEGA128 TO USART1");
Sleep();
while(1);
}
ISR(USART0_RX_vect){
WakeUp();
new_user_read_char = UDR0;
USART1_TransmitByte(UDR0);
Sleep();
}
'; i++){ USART0_TransmitByte(stringToTransmit[i]); } } void USART1_TransmitByte(unsigned char byteToTransmit){ while(!(UCSR1A & (1<<UDRE1))); UDR1 = byteToTransmit; } void USART1_TransmitString(unsigned char *stringToTransmit){ unsigned char i = 0; for(i = 0; stringToTransmit[i] != '
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/delay.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define F_CPU		8000000UL
#define BAUDRATE	9600
#define UBRR_VALUE	((F_CPU)/(16UL*BAUDRATE))-1 //For UBRR registers
#define MASTER_WATCHDOG_MENU	"\rEnter MS WD Choice (& period):\rA-30ms\rB-250ms\rC-500ms\rYour input:\0"
#define SLAVE_WATCHDOG_MENU		"\rEnter SLV WD Choice (& period):\rA-0.5s\rB-1.0s\rC-2.0s\rYour input:\0"
#define USER_MENU				"\rEnter choice (and period): 1-Mem Dump 2-Last Entry 3-Restart\rYour input:\0"
void ConfigureXMEMMode(void){
MCUCR |= (1 << SRE); 
XMCRA = 0;			 
XMCRB = (1 << XMM2) | (0 << XMM1) | (1 << XMM0);
}
void ConfigureUSARTInterfaces(void){
UBRR0H = (unsigned char)(UBRR_VALUE >> 8);
UBRR0L = (unsigned char)(UBRR_VALUE);
UBRR1H = (unsigned char)(UBRR_VALUE >> 8);
UBRR1L = (unsigned char)(UBRR_VALUE);
UCSR0B = (1<<RXEN0) | (1<<RXCIE0) | (1<<TXEN0) | (1<<TXCIE0); 
UCSR1B = (1<<RXEN1) | (1<<RXCIE1) | (1<<TXEN1) | (1<<TXCIE1);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
UCSR1C = (1 << UCSZ01) | (1 << UCSZ00);
}
void USART0_TransmitByte(unsigned char byteToTransmit){
while(!(UCSR0A & (1<<UDRE0))); 
UDR0 = byteToTransmit;
}
void USART0_TransmitString(unsigned char *stringToTransmit){
unsigned char i = 0;
for(i = 0; stringToTransmit[i] != '\0'; i++){
USART0_TransmitByte(stringToTransmit[i]);
}
}
void USART1_TransmitByte(unsigned char byteToTransmit){
while(!(UCSR1A & (1<<UDRE1)));
UDR1 = byteToTransmit;
}
void USART1_TransmitString(unsigned char *stringToTransmit){
unsigned char i = 0;
for(i = 0; stringToTransmit[i] != '\0'; i++){
USART1_TransmitByte(stringToTransmit[i]);
}
}
unsigned char USART0_ReceiveByte(void){
while(!(UCSR0A & (1<<RXC0))); 
return UDR0; 
}
unsigned char USART1_ReceiveByte(void){
while(!(UCSR1A & (1<<RXC1)));
return UDR1;
}
void ConfigureWatchdogTimer(void){
while(EECR & (1 << EEWE)); 
EEARH = 0x00; 
EEARL = 0x00; 
EECR  = 1 << EERE; 
if(EEDR == 0xFF){
EEARL = 0x01;
if(EEDR == 0xFF){
EECR = 0 << EERE;
ConfigureMasterWD();
}
}
while(EECR & (1 << EEWE));
EEARH = 0x00;
EEARL = 0x02;
EECR  = 1 << EERE;
if(EEDR == 0xFF){
EEARL = 0x03;
if (EEDR == 0xFF){
EECR = 0 << EERE;
ConfigureSlaveWD();
}
}
}
void ConfigureMasterWD(){
USART0_TransmitString(MASTER_WATCHDOG_MENU);
unsigned char userInput = USART0_ReceiveByte();
switch(userInput){
case 'A': case 'a':
WDTCR = (1 << WDE) | (0 << WDP2) | (0 << WDP1) | (1 << WDP0); //30ms
break;
case 'B': case 'b':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (0 << WDP0); //250ms
break;
case 'C': case 'c':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (1 << WDP0); //500ms
break;
}
USART0_TransmitString("\rDone!\r");
}
void ConfigureSlaveWD(){
USART0_TransmitString(SLAVE_WATCHDOG_MENU);
unsigned char userInput = USART0_ReceiveByte();
switch(userInput){
case 'A': case 'a':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (1 << WDP0); //500ms
break;
case 'B': case 'b':
WDTCR = (1 << WDE) | (1 << WDP2) | (1 << WDP1) | (0 << WDP0); //1.0s
break;
case 'C': case 'c':
WDTCR = (1 << WDE) | (1 << WDP2) | (1 << WDP1) | (1 << WDP0); //2.0s
break;
}
USART0_TransmitString("\rDone!\r");
}
void Sleep(){
sei();
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_enable();
sleep_cpu();
}
void WakeUp(){
sleep_disable();
cli();
}
int main(void){
ConfigureXMEMMode();
ConfigureUSARTInterfaces();
ConfigureWatchdogTimer();
USART0_TransmitString("ATMEGA128 TO USART0");
USART1_TransmitString("ATMEGA128 TO USART1");
Sleep();
while(1);
}
ISR(USART0_RX_vect){
WakeUp();
new_user_read_char = UDR0;
USART1_TransmitByte(UDR0);
Sleep();
}
'; i++){ USART1_TransmitByte(stringToTransmit[i]); } } unsigned char USART0_ReceiveByte(void){ while(!(UCSR0A & (1<<RXC0))); return UDR0; } unsigned char USART1_ReceiveByte(void){ while(!(UCSR1A & (1<<RXC1))); return UDR1; } void ConfigureWatchdogTimer(void){ while(EECR & (1 << EEWE)); EEARH = 0x00; EEARL = 0x00; EECR = 1 << EERE; if(EEDR == 0xFF){ EEARL = 0x01; if(EEDR == 0xFF){ EECR = 0 << EERE; ConfigureMasterWD(); } } while(EECR & (1 << EEWE)); EEARH = 0x00; EEARL = 0x02; EECR = 1 << EERE; if(EEDR == 0xFF){ EEARL = 0x03; if (EEDR == 0xFF){ EECR = 0 << EERE; ConfigureSlaveWD(); } } } void ConfigureMasterWD(){ USART0_TransmitString(MASTER_WATCHDOG_MENU); unsigned char userInput = USART0_ReceiveByte(); switch(userInput){ case 'A': case 'a': WDTCR = (1 << WDE) | (0 << WDP2) | (0 << WDP1) | (1 << WDP0); //30ms break; case 'B': case 'b': WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (0 << WDP0); //250ms break; case 'C': case 'c': WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (1 << WDP0); //500ms break; } USART0_TransmitString("\rDone!\r"); } void ConfigureSlaveWD(){ USART0_TransmitString(SLAVE_WATCHDOG_MENU); unsigned char userInput = USART0_ReceiveByte(); switch(userInput){ case 'A': case 'a': WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (1 << WDP0); //500ms break; case 'B': case 'b': WDTCR = (1 << WDE) | (1 << WDP2) | (1 << WDP1) | (0 << WDP0); //1.0s break; case 'C': case 'c': WDTCR = (1 << WDE) | (1 << WDP2) | (1 << WDP1) | (1 << WDP0); //2.0s break; } USART0_TransmitString("\rDone!\r"); } void Sleep(){ sei(); set_sleep_mode(SLEEP_MODE_IDLE); sleep_enable(); sleep_cpu(); } void WakeUp(){ sleep_disable(); cli(); } int main(void){ ConfigureXMEMMode(); ConfigureUSARTInterfaces(); ConfigureWatchdogTimer(); USART0_TransmitString("ATMEGA128 TO USART0"); USART1_TransmitString("ATMEGA128 TO USART1"); Sleep(); while(1); } ISR(USART0_RX_vect){ WakeUp(); new_user_read_char = UDR0; USART1_TransmitByte(UDR0); Sleep(); }

When simulate this code on Proteus, I see that the whole main function is in an infinite loop as the virtual terminal continuously repeats the ConfigureWatchdogTimer() function. However, the behavior that I expect is, configuration functions only run once, the CPU goes to sleep mode and only wakes up when an interrupt happens, which for this code is receiving a byte on usart0. What am I missing here or what is it that I am not understanding?
The interrupt that I wrote somewhat works as if I constantly spam a character, that character does show up in the other terminal every once in a while.

Behavior that I get on Proteus when I run this code on ATMega128
为什么这个用于ATMega128的AVR代码表现出这种行为?

答案1

得分: 4

偶尔的代码重启是一种通常表明存在某些未处理中断处理程序的迹象。

例如,您在 ConfigureUSARTInterfaces 中已启用了接收(RXCIEn)和发送(TXCIEn)中断,如下所示:

    UCSR0B = (1<<RXEN0) | (1<<RXCIE0) | (1<<TXEN0) | (1<<TXCIE0);
    UCSR1B = (1<<RXEN1) | (1<<RXCIE1) | (1<<TXEN1) | (1<<TXCIE1);

但仅为 USART0_RX_vect 定义了处理程序。

要么为其他 USART 中断定义 ISR,要么在 USART 配置中禁用(不设置)相应的 TXCIE/RXCIE 位。

英文:

Occasional code restart is a usual sign of some missed interrupt handler.

For example, you have receive (RXCIEn) and transmission (TXCIEn) interrupts enabled for both USARTs in ConfigureUSARTInterfaces:

    UCSR0B = (1&lt;&lt;RXEN0) | (1&lt;&lt;RXCIE0) | (1&lt;&lt;TXEN0) | (1&lt;&lt;TXCIE0); 
    UCSR1B = (1&lt;&lt;RXEN1) | (1&lt;&lt;RXCIE1) | (1&lt;&lt;TXEN1) | (1&lt;&lt;TXCIE1);

but have only handler for USART0_RX_vect.

Either define ISRs for other USARTs interrupts, or disable (do not set) corresponding TXCIE/RXCIE-bits in USART configurations

答案2

得分: 1

你的代码在概念上是错误的。它可能看起来运行正常,但实际上并不是这样。

如果你的代码除了USART0_RX之外没有产生其他中断,它最终会由于堆栈溢出而崩溃,因为你从未从ISR中返回,而是嵌套它们。如果有其他中断源并且它们的处理程序为空,而且发生得足够频繁(例如,像你的TX中断),它将意外地(这不是你应该这样做的方式,但只是一个副作用)防止中断嵌套,并导致相关的堆栈溢出,但你的MCU不会进入睡眠状态,它将在main()函数的最后的while(1)中忙循环。

有什么问题:

  1. 睡眠应该进入主循环,而不是在它之前。也就是说,你的main()函数的结尾应该大致如下:while (1) {处理所有事件(); 准备进入睡眠(); 进入睡眠模式(); 禁用睡眠();},因此在发生中断并运行ISR后,主循环会唤醒,处理与中断相关的任何事件,然后再次进入睡眠模式。
  2. 除非你确切地知道你在做什么(不好意思,你不知道),否则你不应该在ISR中使用sleep_cpu(),也不应该使用sei()/cli()。坚决不要这样做。让ISR尽快完成并从主循环中调用sleep_cpu()。
  3. 通常,ISR中的长时间阻塞代码可能会引发难以调试的问题。再次强调,如果你不知道在做什么以及为什么要这样做,遵循一个经验法则,即ISR应该在最短可能的时间内运行完毕。它处理需要立即响应的任何硬件,并设置一个标志(信号量)供主循环处理“慢速”处理的其余部分。

关于使用sleep_cpu()。请注意,从SLEEP指令唤醒后,代码流不会继续执行。它首先进入相应的ISR(取决于唤醒MCU的事件),只有当ISR完成后,代码才会跳回到SLEEP指令之后。

英文:

Your code is conceptually wrong. It can look like it is working properly, but it is not.

If your code generates no other interrupts than USART0_RX, it will eventually crash with stack overflow, because you are never returning from ISR but nesting them. If there are other interrupt sources with empty handler occurring often enough (like your TX interrupt), it will accidentally (=it is not how you are supposed to do it, but only a side-effect) prevent the interrupt nesting with related stack overflow, but your MCU won't be sleeping, it will busy-loop on last while(1) in the main() instead.

What is wrong:

  1. The sleep should go into main loop, not before it. That is, end of your main() function should look approximately like: while (1) {do_handle_all events(); prepare_sleep(); sleep_cpu(); disable_sleep();} so after an interrupt occurring and ISR being run the main loop wakes up, handles any event related to the interrupt and goes to sleep again.
  2. Except if you know EXACTLY what are you doing (and no, you do not, sorry) you shall never use sleep_cpu() and neither sei()/cli() in the ISR. Full stop. Let the ISR finish ASAP and call sleep_cpu() from the main loop.
  3. Generally any long blocking code in ISR has potential to cause hard to debug issues. Again, if you do not know what and why are you doing, stick to rule of thumb that ISR has run and finish in shortest possible time. It handles whatever hardware needs immediate(!) response and sets a flag (semaphore) for main loop to handle "slow" rest of processing.

Regarding the use of sleep_cpu(). Note that code flow will not continue from SLEEP instruction after wake up. It goes first into respective ISR (depending on event which woke up the MCU) and only when ISR is completed, code jumps back after the SLEEP instruction.

huangapple
  • 本文由 发表于 2023年5月30日 03:59:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76360030.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定