B001-Atmega16-中断(GCC-AVR)-(ques=3)
来源:互联网 发布:网络嗅探器win7 编辑:程序博客网 时间:2024/05/24 01:43
编译器 :AVR Studio 4.19 + avr-toolchain-installer-3.4.1.1195-win32.win32.x86
芯片型号:ATmega16
芯片主频:8MHz
-------------------------------------------------------------------------------------------------------------------------------------
待解决问题数量 = 3
-------------------------------------------------------------------------------------------------------------------------------------
AVR-GCC中断概述
1、需要包含头文件interrupt.h、它定义了中断函数:#define ISR(vector, [attributes])
2、中断函数一般的格式:
ISR(interrupt_number)
{
}
这里缺省的attributes默认为ISR_BLOCK,表示进入中断后禁止全局中断,这也就禁止了中断嵌套
3、中断号定义在iom16.h中,中断向量地址越低,优先级越高
4、中断标志位会在执行中断程序的时候被自动清0,所以不需要手动清0
-------------------------------------------------------------------------------------------------------------------------------------
中断配置的步骤:
1、配置中断源的触发方式2、允许中断
3、清除中断标志位
4、开启总中断
-------------------------------------------------------------------------------------------------------------------------------------
AVR-GCC中断的写法
如定时器2的中断的例子:
#include <avr/interrupt.h>
……
……
ISR(TIMER2_OVF_vect)
{
PORTA ^= (1 << PA0);
}
完整的定时器2 中断测试详见这篇文章的第一步(普通模式):http://blog.csdn.net/manon_des_source/article/details/51564339
-------------------------------------------------------------------------------------------------------------------------------------
不同编译器的中断写法:
中断是编译器自己实现的,在不同的编译器中,中断函数的定义和写法不一样:
1、旧版GCC-AVR使用signal.h中的SIGNAL(SIG_INTERRUPT0)
2、ICC-AVR的写法是:#pragma interruput_handler TIM1_OVF: 6
-------------------------------------------------------------------------------------------------------------------------------------
伪中断BADISR_vect
作用:
1、程序中需要使用ISR(BADISR_vect){ },用来捕获未定义中断函数的中断
2、如果某个被允许的中断产生了中断请求,但程序中又没有定义它的中断函数,那么系统可能会执行到错误的程序
|<-------------- 待测试 question-001
3、没有包含interrupt.h的文件中的ISR()都不是中断函数、因为编译器找不到定义,将其视为int (int)类型的普通函数,这种ISR请求可以被BADISR_vect这个伪中断捕获
-------------------------------------------------------------------------------------------------------------------------------------
测试准备:
1、在Drv_Timer2.c中允许定时器2溢出中断,并定义定时器2 中断函数如下:
同时屏蔽中断头文件interrupt.h:
让ISR(TIMER2_OVF_vect)被编译器视为int (int)类型的普通函数
这样,定时器2 允许中断,但又没有自己的中断函数
2、在main.c中定义伪中断BADISR_vect如下(包含中断头文件interrupt.h):
……
3、在上面两个函数内都放置断点,进入调试模式
测试结果:
1、每次按下F5、在定时器2 溢出时,中断都会跳转到ISR(BADISR_vect),而不是ISR(TIMER2_OVF_vect)
同时PA1引脚的电平翻转,而PA0引脚无变化。
2、取消在Drv_Timer2.c中对中断头文件interrupt.h的屏蔽,重新进入调试。
此时、每次按下F5、在定时器2 溢出时,中断都会跳转到ISR(TIMER2_OVF_vect),而不是ISR(BADISR_vect)
同时PA0引脚的电平翻转,而PA1引脚无变化。
3、这个测试说明,伪中断BADISR_vect 确实捕捉到了未定义中断函数的中断求情。
-------------------------------------------------------------------------------------------------------------------------------------
伪中断捕捉多个中断
1、第1步:T1用CTC控制300us中断一次,T2用CTC控制200us中断一次。
在比较匹配中断中翻转PA1和PA3引脚、他们的波形应该和比较匹配引脚OC1A和OC2的波形一致。
可以使用比较匹配中断输出方波、以测试CTC的时间 ( 比较匹配引脚来输出的方波也可以测试 ) 。
伪中断BADISR_vect中控制PA7引脚输出方波。
测试代码:
// ==========================================================================================================// 主函数// ==========================================================================================================#include <avr/io.h>#include <avr/interrupt.h>#include "Drv_Timer.h"#include "system.h"#include "config.h"// ==========================================================================================================// 伪中断BADISR_vect// // ==========================================================================================================ISR(BADISR_vect){ PORTA ^= (1 << PA7);}// ==========================================================================================================// main函数// ==========================================================================================================int main(void){ // ------------------------------------------------------------------------------------------------------ // 关全局中断 cli(); // 系统初始化 sys_init(); // PA[7,3,1]初始化为输出0 DDRA = (1 << DDA1) | (1 << DDA3) | (1 << DDA7); PORTA &= ~((1 << PA1 ) | (1 << PA3 ) | (1 << PA7 )); // 定时器1 初始化:CTC模式、COM1A启用(取反)、COM1B不启用、8预分频 Drv_Timer1_init(T1_WGM_CTC, T1_COM_MODE_TOGGLE, T1_COM_MODE_NONE, T1_CLK_SOURCE_CLK_8); // 设置TCTN1=0、OCR1A=300、OCR1B=0、ICR1=0 Drv_Timer1_set_TCNT1_OCR1A_OCR1B_ICR1(0, 300, 0, 0); // 使能OCF1A中断 Drv_Timer1_INT_Enable(INT_MODE_OCF1A, ENABLE); // 定时器2 初始化:CTC模式、COM2启用(取反)、8预分频 Drv_Timer2_init(T2_WGM_CTC, T2_COM_MODE_TOGGLE, T2_CLK_SOURCE_CLK_8); // 设置TCTN2=0、OCR2=200 Drv_Timer2_set_TCNT2_OCR2(0, 200); // 使能OCF2中断 Drv_Timer2_INT_Enable(INT_MODE_OCF, ENABLE); // PD[7,5]初始化为输出0(比较匹配引脚) DDRD = (1 << DDA5) | (1 << DDD7); PORTD &= ~((1 << PA5 ) | (1 << PD7 )); // 开全局中断 sei(); // ------------------------------------------------------------------------------------------------------ while(1) { } return 0;}
示波器输出如下:
CH1是OCR2中断输出的方波,CH2是OCR1A中断输出的方波。
可以看到、T1每300us中断一次,T2每200us中断一次,说明时间输出OK。
OC1A引脚和OC2引脚的波形和上面2个中断中PA1和PA3的波形一致。
而伪中断BADISR_vect中控制的PA7引脚就没有波形输出。
2、屏蔽上面的2个中断。
这样、就只有比较匹配引脚输出波形,而中断中的引脚就没有波形输出。
而PA7有引脚输出。
3、在伪中断BADISR_vect中放置断点,进入DEBUG。
测试结果:
1、第1次进入中断时、PA7引脚翻转,OC2引脚翻转,OCR1A引脚不变,说明是OC2发生比较匹配。
2、第2次进入中断时、PA7引脚翻转, OC2引脚不变,OCR1A引脚翻转,说明是OC1A发生比较匹配。
3、这说明伪中断BADISR_vect可以捕捉多个中断。
-------------------------------------------------------------------------------------------------------------------------------------
中断挂起测试
1、一个中断源发出中断请求后、这个中断应该被挂起,进入等待响应队列。
如果全局中断打开,且没有比该中断优先级更高的中断,那么这个中断就应该被立即执行。
否则、该中断需要继续留在等待队列,除非认为清除它的中断标志来删除该中断。
测试准备:
1、假如现在只有INT0中断,且关闭全局中断SREG.I = 0,等待500ms后、INT0中断到来,等待500ms,开全局中断SREG.I = 1。
这个时候,INT0会得到执行么,会进入INT0中断服务函数么?
|<---- 待测试-question-002
如果INT0可以被执行,虽然INT0被延后了500ms才被执行,但说明INT0在这500ms内是被挂起的,没有被忽略。
-------------------------------------------------------------------------------------------------------------------------------------
中断嵌套
1、使用ICP1做红外接收的话,需要ICP1中断的优先级最高,而且要允许中断嵌套。
测试准备:
1、只使用TOV0中断和INT0中断。
2、在TOV0中断服务函数中写入死循环:
ISR(TIMER0_OVF_vect,ISR_NOBLOCK){ while(flag_INT) { }}
3、、在INT0中断中写入退出循环的代码:
volatile uint8_t flag_INT = 0;ISR(INT0_vect<span style="font-family: Arial, Helvetica, sans-serif;">, ISR_NOBLOCK</span>){ flag_INT = 0;}
3、在这两个中断中放入断点,进入DEBUG。
测试结果:
1、
|<----待测试-question-003
-------------------------------------------------------------------------------------------------------------------------------------
中断向量表
代码:
功能:使用外部中断1控制PORTB0的亮灭。
在如下代码中可以看到、上电加载完毕后,程序跳转到复位向量,而外部中断1发生时、程序跳转到外部中断1的中断向量。
; sample.asm; 运行环境 atmelage16 8M晶振; .include "m16def.inc" ;包含atmelage16定义文件.org $0000 ;中断向量表地址; ===========================================================================================================; 中断向量表; 地址范围:[0x000,0x029]、包含了21个中断、每个中断向量占用2个字节; BOOTRST未被编程=1,GICR.IVSEL=0时,复位向量地址=0x0000,ISR向量的起始地址=0x0002(见中文数据手册P44.Table19); ===========================================================================================================jmp RESET ;复位中断jmp EXT_INT0 ;外部中断0jmp EXT_INT1 ;外部中断1jmp TIMER2_COMP ;定时器2比较中断jmp TIMER2_OVF ;定时器2溢出中断jmp TIMER1_CAPT ;定时器1捕捉中断jmp TIMER1_COMPA ;定时器1比较匹配A中断jmp TIMER1_COMPB ;定时器1比较匹配B中断jmp TIMER1_OVF ;定时器1溢出中断jmp TIMER0_OVF ;定时器0溢出中断jmp SPI_STC ;SPI传输完成中断jmp USART_RXC ;USART接收完成中断jmp USART_UDRE ;USART数据寄存器空中断jmp USART_TXC ;USART发生结束中断jmp ADC_OVER ;ADC转换结束中断jmp EEPROM_READY ;EEPROM就绪中断jmp ANA_COMP ;模拟比较器中断jmp TWI_INTERFACE ;TWI接口中断jmp EXT_INT2 ;外部中断2jmp TIMER0_COMP ;定时器2比较匹配中断jmp SPM_READY ;保存程序存储器内容就绪中断.org $002A ;主程序入口地址,跳过中断向量区; ===========================================================================================================; 主程序; ===========================================================================================================main:; -----------------------------------------------------------------------------------------------------------; PORTB0设置为输出1ldi r20, $01out DDRB, r20out PORTB, r20; -----------------------------------------------------------------------------------------------------------; 设置INT1中断; PORTD3/INT1设为输入、输出高、使能上拉ldi r20, $F7out DDRD, r20ldi r20, $FFout PORTD, r20; 使能全局总中断in r20, SREGsbr r20, $80out SREG, r20; 设置INT1为低电平触发in r20, MCUCRcbr r20, $0Cout MCUCR, r20; 使能INT1in r20, GICRsbr r20, $80out GICR, r20; -----------------------------------------------------------------------------------------------------------; 死循环loop_main:jmp loop_main;ret ;main函数不是rcall指令进来的、不需要返回; 中断服务程序; ===========================================================================================================; 复位中断服务函数; ===========================================================================================================RESET:; -----------------------------------------------------------------------------------------------------------; 设置堆栈指针SPldi r20,high(RAMEND);high获取RAMEND高字节的立即数,将立即数装入r20out sph,r20 ;将获取到的堆栈高字节立即数送堆栈寄存器SP高字节中ldi r20,low(RAMEND) ;low获取RAMEND低位立即数,将立即数装入r20out spl,r20 ;将获取到的堆栈低字节立即数送堆栈寄存器SP低字节中; -----------------------------------------------------------------------------------------------------------; 跳转到main函数rjmp mainreti; 外部中断0EXT_INT0:reti; ===========================================================================================================; 外部中断1; ===========================================================================================================EXT_INT1:push r20push r21in r20, PINBldi r21, 0x01eor r20, r21out PORTB, r20pop r20pop r21reti;定时器2比较中断TIMER2_COMP:reti;定时器2溢出中断TIMER2_OVF:reti;定时器1捕捉中断TIMER1_CAPT:reti;定时器1比较匹配A中断TIMER1_COMPA:reti;定时器1比较匹配B中断TIMER1_COMPB:reti;定时器1溢出中断TIMER1_OVF:reti;定时器0溢出中断TIMER0_OVF:reti;SPI传输完成中断SPI_STC:reti;USART接收完成中断USART_RXC:reti;USART数据寄存器空中断USART_UDRE:reti;USART发生结束中断USART_TXC:reti;ADC转换结束中断ADC_OVER:reti;EEPROM就绪中断EEPROM_READY:reti;模拟比较器中断ANA_COMP:reti;TWI接口中断TWI_INTERFACE:reti;外部中断2EXT_INT2:reti;定时器2比较匹配中断TIMER0_COMP:reti;保存程序存储器内容就绪中断SPM_READY:reti
测试结果:
1、复位时:程序跳转到RESET向量
2、外部中断1发生时、程序进入外部中断1的中断向量:
- B001-Atmega16-中断(GCC-AVR)-(ques=3)
- B001-Atmega16-看门狗WDT-(ques=1)
- B001-Atmega16-定时器2-(ques=4)
- B001-Atmega16-定时器1-(ques=1)
- B001-Atmega16-PORTA的定义-(ques=1)
- AVR单片机(ATMEGA16)外部中断程序
- B001-Atmega16-数码管
- B001-Atmega16-SPI Flash
- B001-Atmega16-TFT-(未开始)
- B001-Atmega16-汇编-地址空间分配
- B001-Atmega16-对齐模式和大小端
- B001-Atmega16-位域的汇编实现
- 透析avr-gcc的中断处理原理
- 透析avr-gcc的中断处理原理
- AVR的GCC中断向量说明
- ATmega16单片机(AVR)主要特点总结
- AVR单片机(ATMEGA16)控制蜂鸣器
- AVR单片机(ATMEGA16)定时器程序
- 响应式编程思想(一)
- IOS-下载地址&评价地址
- leetcode No6. ZigZag Conversion
- 【QTP】获取WinListView表中所有信息
- git补丁应用git apply *.patch
- B001-Atmega16-中断(GCC-AVR)-(ques=3)
- maven项目报错:cvc-elt.1: Cannot find the declaration of element 'beans'.
- ios 内存使用陷阱
- git图解。通俗易懂
- C++实践——存储班长信息的学生类
- Android开发笔记(一百零六)支付缴费SDK
- bash小命令-
- java ssl编程
- Asp.net GridView 应用实例