Atmel:中断后无法转向主
Atmel : can't turn to the main after interruption
我用的是atmega328P,如图所示
当执行中断时,程序不会回到main执行程序的其余部分?
我做了 2 个功能;一个在端口 C 中闪烁,另一个在端口 D 中闪烁
端口 D(中断)中的 Led 工作正常,但主端口 C 的 Led 未执行
有问题吗??
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define ACK 0x01
void portc_led(void)
{
PORTC|=(1<<5);
_delay_ms(100);
PORTC=(0<<5) ;
_delay_ms(100);
PORTC|=(1<<5);
_delay_ms(100);
PORTC=(0<<5) ;
_delay_ms(100);
}
void portd_led(void)
{
PORTD|=(1<<7);
_delay_ms(1000);
PORTD=(0<<7) ;
_delay_ms(100);
PORTD|=(1<<7);
_delay_ms(1000);
PORTD=(0<<7) ;
_delay_ms(100);
PORTD|=(1<<7);
_delay_ms(1000);
PORTD=(0<<7) ;
_delay_ms(100);
PORTD|=(1<<7);
_delay_ms(1000);
PORTD=(0<<7) ;
_delay_ms(100);
}
int main(void)
{
DDRB |= (1<<2)|(1<<3)|(1<<5); // SCK, MOSI and SS as outputs
DDRB &= ~(1<<4); // MISO as input
SPCR |= (1<<MSTR); // Set as Master
SPCR |= (1<<SPR0)|(1<<SPR1); // divided clock by 128
SPCR |= (1<<SPIE); // Enable SPI Interrupt
SPCR |= (1<<SPE); // Enable SPI
DDRC= 0xFF ; // set PORT C as output
DDRD = 0xFF ;
sei();
spi_send_data(ACK);
portc_led();
}
ISR(SPI_STC_vect)
{
portd_led();
}
您的代码中有两个概念性错误:
只要中断服务程序是运行ning,main函数就可以运行.
在 portc_led()
之后,main()
函数 returns。根据编译器系统(可能是某些 GCC)的 运行time 环境,它最终 运行 陷入无限循环,什么都不做。只有中断不断触发。
首先,您的代码将出现 编译错误! 因为您没有提供对 spi_send_data
函数的引用
但让我们假设您将它包含在这段代码之上
分析你的代码
你这么说
interruption is executed , the program doesn't turn back to the main
程序执行路径肯定会回到主程序...它会去哪里?! :)
代码将执行 portc_led
函数一次( 且仅执行一次 )可能在中断之前或可能在中断之后或可能在函数之间发生中断......
所以也许 portc_led
已经在中断之前执行了,但你没有看到它,因为它只在 400 ms
中执行!在完成中断之后无事可做,只需等待其他中断! ..
简单的解决方案: 尝试将 portc_led
中的 100ms
延迟更改为更大的延迟,您会看到 ...
提高练习技巧的小建议
- 看看这段代码
PORTB=(0<<5)
相当于 portB=0b00000000
当您尝试清除寄存器中的单个位时,您会清除所有寄存器的位!这不好...使用此代码 PORTB&=~(1<<5)
清除单个位,使 portc 和 0b11101111 之间的比特位和仅更改单个位并保持其他位不变
- 始终在中断例程中使其尽可能小...只需提高标志并在主循环中处理...read more way you should make it small routine
- 你的程序没有主循环!! (有时称为超级循环)..
这个循环只是一个无限循环,在你的系统初始化和 运行 一遍又一遍之后出现......一些编译器在主例程的末尾添加空的无限循环而其他编译器不添加......这是一个很好的做法即使您不使用它,也要在主例程中有一个主循环!让您的程序保持活力
修改代码
不是下面的代码不会并行(同时)执行消隐,它会串联执行(不是同时)..如果你喜欢并行消隐使用portc_led
中的定时器中断代替延迟/或使用 RTOS(有点高级的主题)
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define ACK 0x01
volatile char spi_interupt_flag = 0;
void portd_led(void)
{
// this will blank led in pd7 for 3 sec
for(char i=0;i<6;i++){
PORTD^=(1<<PD7) ; // toggle pd7
_delay_ms(500); // you will see 500 ms blank
}
}
int main(void)
{
DDRB |= (1<<2)|(1<<3)|(1<<5); // SCK, MOSI and SS as outputs
DDRB &= ~(1<<4); // MISO as input
SPCR |= (1<<MSTR); // Set as Master
SPCR |= (1<<SPR0)|(1<<SPR1); // divided clock by 128
SPCR |= (1<<SPIE); // Enable SPI Interrupt
SPCR |= (1<<SPE); // Enable SPI
DDRC= 0xFF ; // set PORT C as output
DDRD = 0xFF ;
sei();
spi_send_data(ACK); // this code will make compile error if you not provide a source for implementation
while(1){
if (spi_interupt_flag)
{
//this code only execute when data received from SPI
portd_led(); //do whatever you want to do for handle it
spi_interupt_flag = 0; //reset the flag again
}
PORTC^=(1<<PC5); //toggle pc5 for ever
_delay_ms(1000); // pc5 will toggle every 1 sec unless ther is interupt
}
}
ISR(SPI_STC_vect)
{
// just set a flag for handle interrupt in main
spi_interupt_flag = 1;
}
我用的是atmega328P,如图所示 当执行中断时,程序不会回到main执行程序的其余部分? 我做了 2 个功能;一个在端口 C 中闪烁,另一个在端口 D 中闪烁 端口 D(中断)中的 Led 工作正常,但主端口 C 的 Led 未执行 有问题吗??
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define ACK 0x01
void portc_led(void)
{
PORTC|=(1<<5);
_delay_ms(100);
PORTC=(0<<5) ;
_delay_ms(100);
PORTC|=(1<<5);
_delay_ms(100);
PORTC=(0<<5) ;
_delay_ms(100);
}
void portd_led(void)
{
PORTD|=(1<<7);
_delay_ms(1000);
PORTD=(0<<7) ;
_delay_ms(100);
PORTD|=(1<<7);
_delay_ms(1000);
PORTD=(0<<7) ;
_delay_ms(100);
PORTD|=(1<<7);
_delay_ms(1000);
PORTD=(0<<7) ;
_delay_ms(100);
PORTD|=(1<<7);
_delay_ms(1000);
PORTD=(0<<7) ;
_delay_ms(100);
}
int main(void)
{
DDRB |= (1<<2)|(1<<3)|(1<<5); // SCK, MOSI and SS as outputs
DDRB &= ~(1<<4); // MISO as input
SPCR |= (1<<MSTR); // Set as Master
SPCR |= (1<<SPR0)|(1<<SPR1); // divided clock by 128
SPCR |= (1<<SPIE); // Enable SPI Interrupt
SPCR |= (1<<SPE); // Enable SPI
DDRC= 0xFF ; // set PORT C as output
DDRD = 0xFF ;
sei();
spi_send_data(ACK);
portc_led();
}
ISR(SPI_STC_vect)
{
portd_led();
}
您的代码中有两个概念性错误:
只要中断服务程序是运行ning,main函数就可以运行.
在
portc_led()
之后,main()
函数 returns。根据编译器系统(可能是某些 GCC)的 运行time 环境,它最终 运行 陷入无限循环,什么都不做。只有中断不断触发。
首先,您的代码将出现 编译错误! 因为您没有提供对 spi_send_data
函数的引用
但让我们假设您将它包含在这段代码之上
分析你的代码
你这么说
interruption is executed , the program doesn't turn back to the main
程序执行路径肯定会回到主程序...它会去哪里?! :)
代码将执行 portc_led
函数一次( 且仅执行一次 )可能在中断之前或可能在中断之后或可能在函数之间发生中断......
所以也许 portc_led
已经在中断之前执行了,但你没有看到它,因为它只在 400 ms
中执行!在完成中断之后无事可做,只需等待其他中断! ..
简单的解决方案: 尝试将 portc_led
中的 100ms
延迟更改为更大的延迟,您会看到 ...
提高练习技巧的小建议
- 看看这段代码
PORTB=(0<<5)
相当于portB=0b00000000
当您尝试清除寄存器中的单个位时,您会清除所有寄存器的位!这不好...使用此代码PORTB&=~(1<<5)
清除单个位,使 portc 和 0b11101111 之间的比特位和仅更改单个位并保持其他位不变 - 始终在中断例程中使其尽可能小...只需提高标志并在主循环中处理...read more way you should make it small routine
- 你的程序没有主循环!! (有时称为超级循环).. 这个循环只是一个无限循环,在你的系统初始化和 运行 一遍又一遍之后出现......一些编译器在主例程的末尾添加空的无限循环而其他编译器不添加......这是一个很好的做法即使您不使用它,也要在主例程中有一个主循环!让您的程序保持活力
修改代码
不是下面的代码不会并行(同时)执行消隐,它会串联执行(不是同时)..如果你喜欢并行消隐使用portc_led
中的定时器中断代替延迟/或使用 RTOS(有点高级的主题)
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define ACK 0x01
volatile char spi_interupt_flag = 0;
void portd_led(void)
{
// this will blank led in pd7 for 3 sec
for(char i=0;i<6;i++){
PORTD^=(1<<PD7) ; // toggle pd7
_delay_ms(500); // you will see 500 ms blank
}
}
int main(void)
{
DDRB |= (1<<2)|(1<<3)|(1<<5); // SCK, MOSI and SS as outputs
DDRB &= ~(1<<4); // MISO as input
SPCR |= (1<<MSTR); // Set as Master
SPCR |= (1<<SPR0)|(1<<SPR1); // divided clock by 128
SPCR |= (1<<SPIE); // Enable SPI Interrupt
SPCR |= (1<<SPE); // Enable SPI
DDRC= 0xFF ; // set PORT C as output
DDRD = 0xFF ;
sei();
spi_send_data(ACK); // this code will make compile error if you not provide a source for implementation
while(1){
if (spi_interupt_flag)
{
//this code only execute when data received from SPI
portd_led(); //do whatever you want to do for handle it
spi_interupt_flag = 0; //reset the flag again
}
PORTC^=(1<<PC5); //toggle pc5 for ever
_delay_ms(1000); // pc5 will toggle every 1 sec unless ther is interupt
}
}
ISR(SPI_STC_vect)
{
// just set a flag for handle interrupt in main
spi_interupt_flag = 1;
}