使用 atmega16 和外部中断的七段项目
Seven segment project using atmega16 and external interrupts
我一直在 proteus 仿真的 AVR 微控制器 atmega16 上做一个简单的项目。
项目是:
当我按下按钮时,它会将七段增加到数字 9 之后,如果我们再次按下按钮,它会溢出并且 return 再次变为 0.
当我在 while 循环代码中更改 (flag=1;) 位置时,它会给我不同的输出,我的意思是当我按下按钮时,它在按下后没有响应。
可能需要再次按下按钮才能增加七段 proteus simulation
唯一正常工作的代码是在退出前设置 flag=1;
(第二个 if 和 else 条件)
所以我的问题是当我更改代码中的 flag=1;
语句位置时实际发生了什么。
#include<avr/io.h>
#include<avr/interrupt.h>
char flag=1;
char num=0;
void INT2_Init(void){
DDRB&=~(1<<2);
SREG|=(1<<7);
GICR|=(1<<INT2);
MCUCSR|=(1<<ISC2);
}
ISR(INT2_vect){
flag=0;
GIFR|=(1<<INTF2);
}
int main(void){
DDRC=0x0f;
PORTC=0;
DDRB&=~(1<<2);
INT2_Init();
while(1){
if(flag==0){
if(num>8){
num=0;
PORTC=(PORTC&0xf0)|num;
}
else{
num++;
PORTC=(PORTC&0xf0)|num;
}
}
flag=1;
}
}
我不太清楚你在问什么。您只是难以理解代码吗?我的评论有帮助吗?
#include<avr/io.h>
#include<avr/interrupt.h>
char flag=1;
char num=0;
void INT2_Init(void){
DDRB&=~(1<<2);
SREG|=(1<<7);
GICR|=(1<<INT2);
MCUCSR|=(1<<ISC2);
}
// sets flag to 0 on external interrupt (button press)
ISR(INT2_vect){
flag=0;
GIFR|=(1<<INTF2);
}
int main(void){
DDRC=0x0f;
PORTC=0;
DDRB&=~(1<<2);
INT2_Init();
while(1){
// if flag was set to 0 in external interrupt -> increment (or overflow) number on segment display
if(flag==0){
if(num>8){
num=0;
PORTC=(PORTC&0xf0)|num;
}
else{
num++;
PORTC=(PORTC&0xf0)|num;
}
}
// reset the flag to 1 to prevent num from being incremented continuously
flag=1;
}
}
我建议将 flag=1;
移到 if
中以明确意图,即每次按下按钮时语句只执行一次。
while(1) {
// if flag was set to 0 in external interrupt -> increment (or overflow) number on segment display
if(flag==0){
// reset the flag to 1 to prevent num from being incremented continuously
flag=1;
if(num>8){
num=0;
PORTC=(PORTC&0xf0)|num;
}
else{
num++;
PORTC=(PORTC&0xf0)|num;
}
}
}
还建议使用自描述变量名。例如 buttonWasPressed
而不是 flag
。这使得这样的代码更容易阅读。
如果主代码中的某个变量发生变化而中断,则必须对其进行标记volatile
。否则,编译器可能会决定缓存变量值并在循环中忽略它的读取。
volatile char flag=1;
其次,注意标志变量何时何地发生变化。例如:
while(1){
// at this point flag is 0, comparison failed
if(flag==0) {
...
}
// Interrupt happens here, changing flag to 0
// Then flag is immediately reset, thus flag change is missed in the loop
flag=1;
}
改为考虑使用这样的模式:
while (1) {
cli(); // disabling interrupts ensuring no interrupt happens inside
if (flag==0) {
...
}
flag = 1;
sei(); // re-enable interrupts
}
或者,在这种情况下,它可以更简单
while (1) {
if (flag==0) {
flag = 1; // Reset flag only if it set, right after comparison
...
}
}
我一直在 proteus 仿真的 AVR 微控制器 atmega16 上做一个简单的项目。
项目是:
当我按下按钮时,它会将七段增加到数字 9 之后,如果我们再次按下按钮,它会溢出并且 return 再次变为 0.
当我在 while 循环代码中更改 (flag=1;) 位置时,它会给我不同的输出,我的意思是当我按下按钮时,它在按下后没有响应。
可能需要再次按下按钮才能增加七段 proteus simulation
唯一正常工作的代码是在退出前设置 flag=1;
(第二个 if 和 else 条件)
所以我的问题是当我更改代码中的 flag=1;
语句位置时实际发生了什么。
#include<avr/io.h>
#include<avr/interrupt.h>
char flag=1;
char num=0;
void INT2_Init(void){
DDRB&=~(1<<2);
SREG|=(1<<7);
GICR|=(1<<INT2);
MCUCSR|=(1<<ISC2);
}
ISR(INT2_vect){
flag=0;
GIFR|=(1<<INTF2);
}
int main(void){
DDRC=0x0f;
PORTC=0;
DDRB&=~(1<<2);
INT2_Init();
while(1){
if(flag==0){
if(num>8){
num=0;
PORTC=(PORTC&0xf0)|num;
}
else{
num++;
PORTC=(PORTC&0xf0)|num;
}
}
flag=1;
}
}
我不太清楚你在问什么。您只是难以理解代码吗?我的评论有帮助吗?
#include<avr/io.h>
#include<avr/interrupt.h>
char flag=1;
char num=0;
void INT2_Init(void){
DDRB&=~(1<<2);
SREG|=(1<<7);
GICR|=(1<<INT2);
MCUCSR|=(1<<ISC2);
}
// sets flag to 0 on external interrupt (button press)
ISR(INT2_vect){
flag=0;
GIFR|=(1<<INTF2);
}
int main(void){
DDRC=0x0f;
PORTC=0;
DDRB&=~(1<<2);
INT2_Init();
while(1){
// if flag was set to 0 in external interrupt -> increment (or overflow) number on segment display
if(flag==0){
if(num>8){
num=0;
PORTC=(PORTC&0xf0)|num;
}
else{
num++;
PORTC=(PORTC&0xf0)|num;
}
}
// reset the flag to 1 to prevent num from being incremented continuously
flag=1;
}
}
我建议将 flag=1;
移到 if
中以明确意图,即每次按下按钮时语句只执行一次。
while(1) {
// if flag was set to 0 in external interrupt -> increment (or overflow) number on segment display
if(flag==0){
// reset the flag to 1 to prevent num from being incremented continuously
flag=1;
if(num>8){
num=0;
PORTC=(PORTC&0xf0)|num;
}
else{
num++;
PORTC=(PORTC&0xf0)|num;
}
}
}
还建议使用自描述变量名。例如 buttonWasPressed
而不是 flag
。这使得这样的代码更容易阅读。
如果主代码中的某个变量发生变化而中断,则必须对其进行标记volatile
。否则,编译器可能会决定缓存变量值并在循环中忽略它的读取。
volatile char flag=1;
其次,注意标志变量何时何地发生变化。例如:
while(1){
// at this point flag is 0, comparison failed
if(flag==0) {
...
}
// Interrupt happens here, changing flag to 0
// Then flag is immediately reset, thus flag change is missed in the loop
flag=1;
}
改为考虑使用这样的模式:
while (1) {
cli(); // disabling interrupts ensuring no interrupt happens inside
if (flag==0) {
...
}
flag = 1;
sei(); // re-enable interrupts
}
或者,在这种情况下,它可以更简单
while (1) {
if (flag==0) {
flag = 1; // Reset flag only if it set, right after comparison
...
}
}