单片机与嵌入式
51单片机的寻址方式
51单片机的汇编指令系统
51汇编语言的伪指令
51汇编语言程序结构与程序示例
Keil C51程序设计
Keil C51的库函数
PIC单片机的基本结构
PIC单片机的汇编语言指令
PIC单片机的C语言编程
ATmega16单片机基本结构
ATmega16单片机的汇编语言
ATmega128单片机的结构
STM32单片机基础
使用STM32CubeMX开发STM32单片机
uC/OS-II嵌入式操作系统
uC/OS-II在STM32F10xx上的移植
FreeRTOS系统介绍
Linux系统介绍
Linux系统编程
嵌入式Linux编程
AVR单片机是1997年由ATMEL公司研发出的增强型内置Flash的RISC(Reduced Instruction Set CPU) 精简指令集高速8位单片机。AVR的单片机可以广泛应用于计算机外部设备、工业实时控制、仪器仪表、通讯设备、家用电器等各个领域。ATmega系列是AVR中的高档产品,增加了更多的接口功能,而且在省电性能、稳定性、抗干扰性以及灵活性方面考虑得更加周全和完善。 ATmega16是这个系列中的一款典型型号。
1. ATmega16单片机的特点:
1)ATmega16采用RISC结构的AVR内核:131条机器指令,大多数为单周期指令;32个8位通用工作寄存器;工作在16MHz时具有16MIPS的性能;配备只需要2个时钟周期的硬件乘法器。
2)片内存储器容量较大:16KB 程序存储器Flash,具有ISP功能,擦除次数大于1万次,采用BootLoad技术支持IAP功能;1KB的片内SRAM数据存储器,可实现3级锁定的程序加密;512字节EEPROM,擦写次数大于10万次。
3)片内含JTAG接口:可通过JTAG口对片内Flash、EEPROM、配置熔丝位和锁定加密位实现下载编程。
4)外围接口:2个带独立预置分频器的8位定时/计数器;1个带预置分频器并有比较、捕捉功能的16位定时/计数器;片内含独立振荡器的实时时钟RTC;4路PWM通道;8路10位ADC;面向字节的两线接口TWI(兼容I2C);1个可编程全双工的串行接口USART;1个可工作5)于主/从模式的SPI串行接口(支持ISP程序下载);片内模拟比较器;内含可编程的具有独立片内振荡器的看门狗定时器WDT。
6)其他特点:片内上电复位电路以及可编程的掉电检测复位电路BOD;片内含有1/2/4/8 MHz经过标定并可校正的RC振荡器,可作为系统时钟使用;多达21个各种类型的内外中断源;6种休眠模式支持节电方式工作。
7)宽电压高速度低功耗:工作电压范围4.5~5.5V,后缀L型的2.7~5.5V;运行速度0~16MHz,后缀L型的0~8MHz;1MHz/3V/25度时的典型电流1.1mA,空闲模式为0.35mA,掉电模式小于1uA。
8)芯片引脚和封装形式:32个可编程的I/O口;封装PDIP40、TQFP44和MLF44。
2. ATmega16的引脚名称定义:
Vcc:芯片内数字电路电源引脚。
AVcc:端口A和片内ADC模拟电路电源引脚。
AREF:使用ADC时,可作为外部ADC参考源的输入引脚。
GND:芯片接地引脚,使用时接地。
XTAL2:片内反相振荡放大器的输出端。
XTAL1:片内反相振荡放大器和内部时钟操作电路的输入端。
RESET-:芯片复位脚,一个最小脉冲宽度为1.5us的低电平将引起芯片的硬件复位。
其中I/O引脚共32个,分成PA、PB、PC和PD4个8位端口。 这些引脚都是可编程控制的多功能复用的I/O引脚。4个端口的第一功能是通用双向数字I/O口,其中每一位都可以由指令设置为独立的输入口或输出口。当设置为输入方式时,引脚内部还配置有上拉电阻。如果设置为输出方式,高电平能够输出20mA的电流,低电平可以吸收40mA的电流。
芯片复位后,所以I/O口的默认状态为输入方式,上拉无效。
3. 中央处理器CPU:
CPU是单片机的核心部分,它由算术逻辑单元ALU、程序计数器PC、指令寄存器、指令译码器和32个8位快速访问通用寄存器组组成。
1)运算逻辑单元ALU:
ALU的功能是进行算术运算和逻辑运算,可对半字节、单字节等数据进行操作,例如加、减、自动加1、自动减1、比较等算术运算和与、或、异或、求补、循环移位等逻辑操作。操作结果的状态,如产生进位、为零等状态信息将影响状态寄存器SREG相应的标志位。
ALU还包括一个布尔处理器,用来处理位操作,可执行置位、清0、取反等操作。
ALU还能实现无符号数、有符号数以及浮点数的硬件乘法操作。一次硬件乘法操作的时间为2个时钟周期。
2)程序计数器PC、指令寄存器和指令寄存器:
程序计数器PC用来存放下一条执行指令在程序存储器空间的地址(指向Flash空间),取出的指令存放在指令寄存器中,然后送入指令译码器产生各种控制信号,控制CPU的运行。
AVR一条指令的长度大多数为16位,还有少部分为32位,AVR的程序存储器结构实际上是以字(16位)为一个存储单元的。ATmega16的程序计数器为13位,对应片内8K字(16KB)的Flash程序存储器空间,因此不支持外部扩展程序存储器。
CPU在译码执行一条指令的同时,就将PC中指定的Flash单元中的指令取出,放入指令寄存器,构成了一级流水线运行方式,实现了一个时钟周期执行一条指令。采用这种结构,减少了取指令的次数,大大提高了CPU的运行速度。
3)通用工作寄存器:
命名为R0~R31的32个8位通用工作寄存器构成一个通用快速工作寄存器组。这32个通用工作寄存器与CPU中的ALU直接相连,提供和支持4种不同的数据输入/输出操作方式:提供8位源操作数并保存一个8位结果,提供两个8位源操作数并保存一个8位结果,提供两个8位源操作数并保存一个16位结果,提供一个16位源操作数并保存一个16位结果。这种结构进一步提高了指令的运行效率和速度。
AVR中的通用寄存器组与片内数据存储器SRAM处在相同的空间,32个通用寄存器被直接映射到数据空间的前32个地址,这种结构就可以利用地址指针寄存器X、Y和Z实现对通用寄存器组的间接寻址操作。
4. ATmega16的内部存储器:
1)支持ISP的Flash程序存储器:
AVR单片机包括1K~256KB的片内支持ISP的Flash程序存储器。由于AVR所有指令为16位或32位,故Flash程序存储器的结构为(512~128K)x16位。ATmega16单片机的程序存储器为8Kx16,程序计数器PC宽度为13,以此来对8K字程序存储器地址进行寻址,地址空间从$0000~$1FFF。
程序存储器的地址空间与数据存储器的地址空间是分开的,地址空间从$0000开始。如果要在程序存储器中使用常量表,则常量表可以被设在Flash地址空间中。
2)数据存储器SRAM:
ATmega16有1120个数据存储器,前96个地址为寄存器组和I/O寄存器(包括32个8位通用寄存器和64个8位I/O寄存器),地址空间为$0000~$001F和$0020~$005F。接下来的1024个地址是片内数据SRAM,地址空间为$0060~$045F。
CPU对SRAM数据存储器的寻址方式分为5种:直接寻址、带偏移量的间接寻址、间接寻址、带预减量的间接寻址和带后增量的间接寻址。寄存器组中,寄存器R26~R31具有间接寻址指针寄存器的特性。ALU可使用直接寻址的方式对整个存储器空间寻址;带偏移量的间接寻址方式可以寻址由寄存器Y和Z给出的基本地址附近的63个地址;当使用自动预减量和后增量的间接寻址方式时,3个16位的地址寄存器X、Y和Z都可作为间接寻址的地址指针寄存器,寄存器中的地址指针值将根据操作指令的不同,自动被增加或减小。
3)内部EEPROM存储器:
AVR单片机还包括64B~4KB的EEPROM数据存储器,它们被组织在一个独立的数据空间中,这个数据空间采用单字节读/写方式。EEPROM的使用寿命至少为10万次写/擦循环,用于存放一些需要掉电保护且比较固定的系统参数、表格等。
ATmega16的EEPROM容量是512字节,地址范围为$0000~$01FF。
EEPROM可以通过SPI、JTAG以及并行编程方式对其中的内容读出和编程写入,也可使用专用的指令对EEPROM访问操作。AVR采用芯片内部可校准的1MHz的RC振荡器作为访问EEPROM的定时时钟。EEPROM编程使用8448个时钟周期,典型值8.5ms。AVR单片机用通过指令访问EEPROM是用I/O空间的寄存器实现的,包括地址寄存器EEARH/ EEARL、数据寄存器EEDR和控制寄存器EECR。
EEPROM地址寄存器EEARH/ EEARL(地址$1F/1E或$003F/003E):
- |
- |
- |
- |
- |
- |
- |
EEAR8 |
EEAR7 |
EEAR6 |
EEAR5 |
EEAR4 |
EEAR3 |
EEAR2 |
EEAR1 |
EEAR0 |
位[15:9]:保留,读出始终为0。位[8:0]:EEPROM地址位。9位地址空间指定了512字节的EEPROM空间的地址位。系数初始化时其中的值不确定,在读EEPROM前必须写入一个正确的地址值。
EEPROM数据寄存器EEDR(地址$1D或$003D):
MSB |
|
|
|
|
|
|
LSB |
位[7:0]:EEPROM数据位。写EEPROM操作时,EEDR寄存器包含了将要写入EEPROM中的数据,EEAR寄存器给出其地址;读EEPROM操作时,EEAR寄存器指定地址,读出的数据在EEDR寄存器中。
EEPROM控制寄存器EECR(地址$1C或$003C):
- |
- |
- |
- |
EERIE |
EEMWE |
EEWE |
EERE |
位[7:4]:保留,读出始终为0。
EERIE:EEPROM准备好中断允许位。如果SREG中的I位置1,EERIE置1将使能EEPROM准备好中断,清0则屏蔽该中断。
EEMWE:EEPROM主机写入允许位。当EEMWE为1时,在EEWE为1的4个时钟周期内,将写数据到指定的地址;当EEMWE为0时,设置EEWE为1不能触发写EEPROM操作。当EEMWE被软件设置为1的4个时钟周期后,硬件自动清0该位。
EEWE:EEPROM写允许位,作为EEPROM写触发。当地址和数据正确设置后,EEMWE置1,EEWE写入1将启动数据写入到EEPROM的内部操作。
EERE:EEPROM读允许位,用于启动读取EEPROM操作。当EEAR寄存器设置了正确的地址后,将EERE置1将启动触发EEPROM读取操作。EEPROM读取操作只需要一个指令时间,可立即获得访问地址的数据。但当读取EEPROM时,CPU将暂停4个时钟周期,然后再执行下一条指令。在开始读取EEPROM前,程序应轮询EEWE标志,如果一个写EEPROM的操作正在进行,那么此时既不能读EEPROM,也不可以改变EEAR寄存器的内容。
写数据到EEPROM应按照如下步骤:
①等待EEWE位变为0;
②等待SPMCSR寄存器中的SPMEN位变为0;
③写新的EEPROM地址到寄存器EEAR(可选);
④写新的EEPROM数据到寄存器EEDR(可选);
⑤写逻辑1到EEMWE位,并同时写0到EEWE位;
⑥在置1到EEMWE后的4个时钟周期内,写逻辑1到EEWE位。
步骤②只适合当程序包含引导加载时,允许CPU对Flash编程,如果CPU从不更新Flash,则可以省略。
步骤⑤和步骤⑥之间发生中断将使写入过程失败,因为EEMWE超时,建议在所有以上步骤中清0全局中断允许标志位。
当写EEPROM操作所需的时间过后,EEWE位将被硬件自动清0.用户程序可以轮询EEWE标志等待其变为0。当EEWE置1后,CPU暂停2个时钟周期,然后再执行下一条指令。
在写EEPROM的过程中,系统可能会进入掉电休眠模式,此时写数据的工作不会停止,直到写入完成。但此后晶振仍然处于工作状态,系统不会完全进入掉电模式。所以,在进入掉电模式前完成对EEPROM的写入操作。
实际使用中会出现EEPROM数据被破坏的情况,原因是时钟未稳或电源电压不稳、正在写操作时突然掉电、操作时序流程被中断打断等。一般情况下,应采取以下一些措施解决:
·通过熔丝位BODLEVEL和BODEN的配置,正确选择芯片的掉电检测门限电压(4.0V/2.7V),并允许BOD功能,使得当系统电压低于门限电压时CPU不工作。
·通过对熔丝位SUT[1:0]和CKSEL[3:0]的配置,正确选择芯片的系统时钟,以及上电启动到开始执行程序之间的延时时间,使得系统电源稳定后再开始运行。这是因为,系统程序往往一开始就需要读取EEPROM中的数据,并进行设备的初始化设置。
·当EEPROM中有多余的空间时,可考虑使用双重备份数据的方法,或对写入的数据增加校验字节等。
·对EEPROM进行操作时,应尽量关闭中断响应。
写EEPROM汇编代码:
EEPROM_write:
;等待前面的写操作完成
sbic EECR,EEWE
rjmp EEPROM_write
;设置地址寄存器中地址(r18:r17)
out EEARH,r18
out EEARL,r17
;向数据寄存器写数据(r16)
out EEDR,r16
;置EEMWE为1
sbi EECR,EEMWE
;根据EEWE的设置,启动EEPROM写操作
sbi EECR,EEWE
ret
写EEPROM的C语言代码:
void EEPROM_write(unsigned int uiAddr, unsigned char ucData)
{
//等待前面的写完成
while(EECR&(1<<EEWE));
//设置地址和数据寄存器
EEAR=uiAddr;
EEDR=ucData;
//置EEMWE为1
EECR|=(1<<EEMWE);
//根据EEWE的设置,启动EEPROM写操作
EECR|=(1<<EEWE);
}
读EEPROM汇编代码:
EEPROM_read:
;等待前面的写操作完成
sbic EECR,EEWE
rjmp EEPROM_read
;设置地址寄存器中地址(r18:r17)
out EEARH,r18
out EEARL,r17
;根据EERE的设置,启动EEPROM读操作
sbi EECR,EERE
;从数据寄存器读数据
in r16,EEDR
ret
读EEPROM的C语言代码:
unsigned char EEPROM_read(unsigned int uiAddr )
{
//等待前面的写完成
while(EECR&(1<<EEWE));
//设置地址寄存器
EEAR=uiAddr;
//根据EERE的设置,启动EEPROM读操作
EECR|=(1<<EERE);
//从数据寄存器返回数据
return EEDR;
}
一些编译器开发环境提供了EEPROM操作的基本函数,用户可以直接使用。
4)通用寄存器组:
AVR指令集中,所有的通用寄存器操作指令均带有方向,并能在单一时钟周期中访问所有的寄存器。32个通用寄存器被直接映射到数据空间的前32个地址。
$0000 |
$0001 |
$0002 |
$0003 |
$0004 |
$0005 |
$0006 |
$0007 |
R0 |
R1 |
R2 |
R3 |
R4 |
R5 |
R6 |
R7 |
$0008 |
$0009 |
$000A |
$000B |
$000C |
$000D |
$000E |
$000F |
R8 |
R9 |
R10 |
R11 |
R12 |
R13 |
R14 |
R15 |
$0010 |
$0011 |
$0012 |
$0013 |
$0014 |
$0015 |
$0016 |
$0017 |
R16 |
R17 |
R18 |
R19 |
R20 |
R21 |
R22 |
R23 |
$0018 |
$0019 |
$001A |
$001B |
$001C |
$001D |
$001E |
$001F |
R24 |
R25 |
R26 |
R27 |
R28 |
R29 |
R30 |
R31 |
虽然可以使用访问SRAM的指令对32个通用寄存器进行访问,但最好是使用专用的寄存器访问指令,因为这类寄存器专用操作指令功能强大并且执行周期也短。
32个通用寄存器还是有一些区别的,尤其是R16~R31这16个寄存器能实现的操作比R0~R15要多,而且乘法指令仅适用于寄存器组中后半部的寄存器。
寄存器组最后的6个寄存器R26~R31具有特殊的功能,每两个合并成一个16位的寄存器,作为对数据存储器空间(使用X、Y、Z寄存器)以及程序存储器空间(仅使用Z寄存器)间接寻址的地址指针寄存器。在不同指令的寻址模式下,利用地址寄存器可实现地址指针的偏移、自动增量和减量等不同形式的间址寻址操作。
5. ATmega16的专用寄存器:
1)I/O寄存器:
表中列出了ATmega单片机的I/O寄存器的地址空间分配、名称和功能:
十六进制地址 |
名称 |
功能 |
$00($0020) |
TWBR |
TWI波特率寄存器 |
$01($0021) |
TWSR |
TWI状态寄存器 |
$02($0022) |
TWAR |
TWI从机地址寄存器 |
$03($0023) |
TWDR |
TWI数据寄存器 |
$04($0024) |
ADCL |
ADC数据寄存器低字节 |
$05($0025) |
ADCH |
ADC数据寄存器高字节 |
$06($0026) |
ADCSRA |
ADC控制和状态寄存器 |
$07($0027) |
ADMUX |
ADC多路选择器 |
$08($0028) |
ACSR |
模拟比较控制和状态寄存器 |
$09($0029) |
UBRRL |
USART波特率寄存器低8位 |
$0A($002A) |
UCSRB |
USART控制状态寄存器B |
$0B($002B) |
UCSRA |
USART控制状态寄存器A |
$0C($002C) |
UDR |
USART I/O数据寄存器 |
$0D($002D) |
SPCR |
SPI控制寄存器 |
$0E($002E) |
SPSR |
SPI状态寄存器 |
$0F($002F) |
SPDR |
SPI I/O数据寄存器 |
$10($0030) |
PIND |
D口外部输入引脚 |
$11($0031) |
DDRD |
D口数据方向寄存器 |
$12($0032) |
PORTD |
D口数据寄存器 |
$13($0033) |
PINC |
C口外部输入引脚 |
$14($0034) |
DDRC |
C口数据方向寄存器 |
$15($0035) |
PORTC |
C口数据寄存器 |
$16($0036) |
PINB |
B口外部输入引脚 |
$17($0037) |
DDRB |
B口数据方向寄存器 |
$18($0038) |
PORTB |
B口数据寄存器 |
$19($0039) |
PINA |
A口外部输入引脚 |
$1A($003A) |
DDRA |
A口数据方向寄存器 |
$1B($003B) |
PORTA |
A口数据寄存器 |
$1C($003C) |
EECR |
EEPROM控制寄存器 |
$1D($003D) |
EEDR |
EEPROM数据寄存器 |
$1E($003E) |
EEARL |
EEPROM地址寄存器低8位 |
$1F($003F) |
EEARH |
EEPROM地址寄存器高8位 |
$20($0040) |
UBRRH |
USART波特率寄存器高4位 |
UCSRC |
USART状态寄存器C |
|
$21($0041) |
WDTCR |
看门狗定时控制寄存器 |
$22($0042) |
ASSR |
异步模式状态寄存器 |
$23($0043) |
OCR2 |
定时/计数器2输出比较寄存器 |
$24($0044) |
TCNT2 |
定时/计数器2(8位) |
$25($0045) |
TCCR2 |
定时/计数器2控制寄存器 |
$26($0046) |
ICR1L |
定时/计数器1输入捕捉寄存器低8位 |
$27($0047) |
ICR1H |
定时/计数器1输入捕捉寄存器高8位 |
$28($0048) |
OCR1BL |
定时/计数器1输出比较寄存器B低8位 |
$29($0049) |
OCR1BH |
定时/计数器1输出比较寄存器B高8位 |
$2A($004A) |
OCR1AL |
定时/计数器1输出比较寄存器A低8位 |
$2B($004B) |
OCR1AH |
定时/计数器1输出比较寄存器A高8位 |
$2C($004C) |
TCNT1L |
定时/计数器1寄存器低8位 |
$2D($004D) |
TCNT1H |
定时/计数器1寄存器高8位 |
$2E($004E) |
TCCR1B |
定时/计数器1控制寄存器B |
$2F($004F) |
TCCR1A |
定时/计数器1控制寄存器A |
$30($0050) |
SFIOR |
特殊功能I/O寄存器 |
$31($0051) |
OSCCAL |
内部RC振荡器校准值寄存器 |
OCDR |
在线调试寄存器 |
|
$32($0052) |
TCNT0 |
定时/计数器0(8位) |
$33($0053) |
TCCR0 |
定时/计数器0控制寄存器 |
$34($0054) |
MCUCSR |
MCU控制和状态寄存器 |
$35($0055) |
MCUCR |
MCU控制寄存器 |
$36($0056) |
TWCR |
TWI控制寄存器 |
$37($0057) |
SPMCR |
程序存储器写控制寄存器 |
$38($0058) |
TIFR |
定时/计数器中断标志寄存器 |
$39($0059) |
TIMSK |
定时/计数器中断屏蔽寄存器 |
$3A($005A) |
GIFR |
通用中断标志寄存器 |
$3B($005B) |
GICR |
通用中断控制寄存器 |
$3C($005C) |
OCR0 |
T/C0计数器输出比较寄存器 |
$3D($005D) |
SPL |
堆栈指针寄存器低8位 |
$3E($005E) |
SPH |
堆栈指针寄存器高8位 |
$3F($005F) |
SREG |
状态寄存器 |
(括号外为I/O寄存器空间地址,括号内为数据寄存器空间的映射地址)
AVR单片机所有I/O口及外围接口的功能和配置均通过I/O寄存器进行设置和使用。CPU通过两种方法访问I/O寄存器:使用对I/O寄存器访问的IN、OUT专用指令和使用对SRAM访问的指令。
I/O寄存器地址范围在$00~$1F之间的寄存器(前32个)可以通过指令实现位操作和位判断跳转。SBI(置1)和CBI(清0)指令可直接对I/O寄存器中的每一位进行操作。使用SBIS(为1跳行)SBIC(为0跳转)指令能够对这些I/O寄存器中每个位的值进行检验判断,实现跳过一条指令执行下一条指令的跳转。
2)状态寄存器SREG:
状态寄存器SREG是一个8位标志寄存器,用来存放指令执行后的有关状态和结果的标志。SREG中各位状态通常是在指令的执行过程中自动形成,但也可以由用户根据需要用专用指令加以改变。与SREG中位操作有关的指令有置位、清0、为1转移、为0转移等,共36条指令与状态寄存器SREG相关联。SREG状态寄存器在I/O空间的地址为$3F($005F):
I |
T |
H |
S |
V |
N |
Z |
C |
I:全局中断使能位。为中断总控制开关,置位时表示CPU可以相应中断请求,清0时表示所有的中断禁止。如果全局中断使能位清0,则全局中断禁止,但单独的中断触发控制的值保持不变。响应中断后,I位由硬件清0,并由RETI指令置位,从而允许子序列的中断响应。
T:位复制存储。位复制指令BLD和BST使用T标志位作为源和目标。通用寄存器组中任何一个寄存器中的一位可通过BST指令复制到T中,而用BLD指令则可将T中的位值复制到通用寄存器组中的任何一个寄存器的一位中。
H:半进位标志位。在一些运算操作过程中有无半进位(低4位向高4位进、借位)的产生,该标志对于BCD码的运算和处理非常有用。
S:符号标志位。S位是负数标志位N和2的补码溢出标志位V异或,S=N⊕V。正常运算条件下(V=0,不溢出),S=N,即运算结果最高位作为符号是正确的。而当产生溢出时,V=1,此时N已经不能正确指示运算结果的正负,但S=N⊕V还是正确的。对于单(或多)字节有符号数据,执行减法或比较操作后,S标志能正确指示参与相减或比较的两个数的大小。
V:2的补码溢出标志位。2的补码溢出标志位V支持2的补码运算,为模2补码加、减运算溢出标志。溢出表示运算结果超过了正数(或负数)所能表示的范围。加法溢出表现为正+正=负,或负+负=正;减法溢出表现为正-负=负,或负-正=正。溢出时,运算结果最高位(N)取反才是真正的结果符号。
N:负数标志位。负数标志位直接取自运算结果的最高位。N=1时,表示运算结果为负,否则为正。但发生溢出时不能表示真实的结果。
Z:零值标志位。零值标志位表明在CPU运算和逻辑操作后,其结果是否为零。当Z=1时,表示结果为零。
C:进/借位标志。进位标志位表明在CPU的运算和逻辑操作过程有无发生进/借位。
以上这些标志位非常重要,对运算结果的判断处理要以相应的标志位为依据,标志位也是分支、循环控制的依据。采用汇编编写程序时,要注意指令对标志位的影响,并正确使用判断指令。
3)堆栈指针寄存器SP:
堆栈是由一块连续的SRAM空间和一个堆栈指针寄存器组成,主要应用于快速、便捷地保存临时数据、局部变量和中断调用或子程序调用的返回地址。堆栈是一种特殊的线性数据结构,数据的进出在堆栈的顶部进行,并遵循后进先出(LIFO)的原则。堆栈指针实际上就是堆栈顶部的地址,它随堆栈中数据的进出而变化。堆栈指针寄存器SP中保存着堆栈指针,即堆栈顶部的地址。
处在I/O地址空间的$3E($005E)和$3D($005D)的两个8位寄存器SPH和SPL构成了AVR单片机的16位堆栈指针寄存器SP。AVR单片机复位后,堆栈寄存器的初始值为SPH=$00,SPL=$00,因此用户程序必须首先对堆栈指针寄存器SP进行初始化设置。
AVR单片机的堆栈区建立在SRAM空间,16位的SP寄存器可以寻址的空间为64KB。由于AVR的堆栈是向下增长的,即新数据进入堆栈时栈顶指针的数据将减小,为了避免堆栈操作时改变寄存器的值,通常初始化时将SP的指针设在SRAM最高处。
对于具体的ATmega16,堆栈指针必须指向高于$0060的SRAM地址空间,初始化时应设在SRAM的最高端$045F处。
AVR堆栈有自动硬件进栈(执行调用指令、响应中断)、自动硬件出栈(执行调用返回指令RET和中断返回指令RETI)和人工进/出栈(进栈指令PUSH和出栈POP指令)等指令。
6. ATmega16熔丝位:
AVR单片机内部有多组与器件配置和运行环境相关的熔丝位,用户可以通过设定和配置熔丝位,使AVR具备不同的特性。ATmega16单片机出厂时,片内Flash和EEPROM是处在擦除状态(内容为$FF),且可以编程,器件配置熔丝位的默认值为使用内部1MHz的RC振荡器为系统时钟。
1)存储器加密锁定位:
ATmega16有2个加密锁定位LB1和LB2,用于设定对片内存储器的加密方式。用户可在编程方式下,对LB1和LB2不编程(1)或编程(0),从而获得对片内存储器不同的加密保护方式。
加密锁定位 |
保护方式 |
||
模式 |
LB2 |
LB1 |
|
1 |
1 |
1 |
无锁定方式(不加密),出厂状态 |
2 |
1 |
0 |
禁止对Flash、EEPROM、熔丝位的再编程 |
3 |
0 |
0 |
禁止对Flash、EEPROM、加密锁定位、熔丝位的再编程和校验 |
AVR手册中,使用Programmed(已编程)和Unprogrammed(未编程)定义加密位和熔丝位的状态。Unprogrammed表示熔丝位状态位1,Programmed表示状态为0。加密位与熔丝位可多次编程,加密锁定后(LB2/LB1=00),在外部不能通过任何方式读取芯片内部Flash和EEPROM中的数据,但熔丝位的状态仍然可以读取,不能修改配置。
需要重新下载程序,或芯片被加密锁定后,或发现熔丝位配置不对,都必须先在编程状态使用芯片擦除命令,清除芯片内部存储器中的数据,同时解除加密锁定,然后重新下载运行代码和数据、修改和配置相关熔丝位,最后再次配置芯片的加密锁定位。
芯片擦除命令是将Flash和EEPROM中的数据清除,并同时将两位锁定状态配置成无锁定状态(LB2/LB1=11)。但芯片擦除命令并不改变其他熔丝位的状态。
2)系统时钟类型的配置:
ATmega16可以使用多种类型的系统时钟,具体系统时钟类型的配置由CKOPT和CKSEL [3:0]共5个熔丝位设定。
ATmega16在片内集成了内部可校准的RC振荡器,能提供固定的1/2/4/8MHz的系统时钟,这些频率是在5V/25度时的标称值。通过设置CKOPT和CKSEL[3:0]可以选择4种RC振荡器之一作为系统时钟使用。
CKOPT |
CKSEL [3:0] |
工作频率范围(MHz) |
1 |
0001 |
1.0(出厂设定) |
1 |
0010 |
2.0 |
1 |
0011 |
4.0 |
1 |
0100 |
8.0 |
当产品对系统时钟的精度要求比较高,或需要使用一些特殊频率的系统时钟场合时,例如使用USART接口时系统时钟需要使用4.6080/7.3728/11.0592MHz,就要使用外接晶体,晶体频率可在0~16MHz之间选择。此时CKOPT和CKSEL[3:0]的配置如下表:
熔丝位 |
工作频率范围 |
C1、C2容量(pF) |
|
CKOPT |
CKSEL[3:0] |
||
1 |
101x |
0.4~0.9 |
仅适用于陶瓷振荡器 |
1 |
110x |
0.9~3.0 |
12~22 |
1 |
111x |
3.0~8.0 |
12~22 |
0 |
101x 110x 111x |
≥1.0 |
12~22 |
当CKOPT=0时,振荡器的输出振幅较大,容易起振,适合干扰大的场合以及使用的晶体超过8MHz时的情况下使用;而当CKTOPT=1时,振荡器的输出振幅较小,这样可以减小对电源的消耗,对外的电磁辐射也小。
3)功能熔丝位:
熔丝名称 |
说明 |
出厂 |
|
1 |
0 |
||
WDTON |
看门狗由软件控制 |
看门狗始终工作,软件只能调节溢出时间 |
1 |
SPIEN |
禁止ISP串行编程 |
允许ISP串行编程 |
0 |
JTAGEN |
禁止JTAG口 |
使能JTAG口 |
0 |
EESAVE |
芯片擦除时同时擦除EEPROM |
芯片擦除时不擦除EEPROM数据 |
1 |
BODEN |
禁止低电压检测功能 |
允许低电压检测功能 |
1 |
BODLEVEL |
低电压检测门槛电平为2.7V |
低电压检测门槛电平为4.0V |
1 |
OCDEN |
禁止JTAG口的在线调试功能 |
运行JTAG口的在线调试功能 |
1 |
4)有关Bootloader的熔丝:
①上电启动地址选择:
BOOTRST |
芯片上电后从地址0x0000开始运行 |
上电后从BOOT区开始执行 |
1 |
②Bootloader区大小设置:
BOOTSZ1 |
BOOTSZ0 |
BOOT区大小(字) |
BOOT区起始地址 |
出厂设置 |
0 |
0 |
1024 |
0x1C00 |
00 |
0 |
1 |
512 |
0x1E00 |
|
1 |
0 |
256 |
0x1F00 |
|
1 |
1 |
128 |
0x1F80 |
③对应用程序区的保护模式设置:
BLB0模式 |
BLB02 |
BLB01 |
对应用程序区的保护 |
Mode1 |
1 |
1 |
不限制SPM和LPM指令对应用程序区的操作(出厂设置) |
Mode2 |
1 |
0 |
禁止SPM指令对应用程序区的写操作 |
Mode3 |
0 |
0 |
禁止SPM指令对应用程序区的写操作 |
Mode4 |
0 |
1 |
在执行驻留在引导加载区的引导加载程序过程中,禁止其中的LPM指令对应用程序区的读操作。如果中断向量驻留在引导加载区,则在MCU执行驻留在应用程序区的程序过程中禁止中断响应 |
④对Bootloader区的保护模式设置:
BLB0模式 |
BLB02 |
BLB01 |
对应用程序区的保护 |
Mode1 |
1 |
1 |
不限制SPM和LPM指令对引导加载区的操作(出厂设置) |
Mode2 |
1 |
0 |
禁止SPM指令对引导加载区的写操作 |
Mode3 |
0 |
0 |
禁止SPM指令对引导加载区的写操作 |
Mode4 |
0 |
1 |
在执行驻留在应用程序区的应用程序过程中,禁止其中的LPM指令对引导加载区的读操作。如果中断向量驻留在应用程序区,则在MCU执行驻留在引导加载区的加载程序过程中禁止中断响应 |
5)有关系统时钟源的选择和上电启动延时时间的配置熔丝:
①系统时钟选择:
系统时钟源 |
CKSEL [3:0] |
外接石英/陶瓷晶体 |
1111~1010 |
外接低频晶体(32.768kHz) |
1001(RTC) |
外接RC振荡器 |
1000~0101 |
使用可校准的内部RC振荡器 |
0100~0001(出厂设置0001) |
外部时钟源 |
0000 |
②使用外部晶体时的工作模式配置:
熔丝位 |
工作频率范围 |
C1、C2容量 |
适用晶体 |
|
CKOPT |
CKSEL[3:1] |
|||
1 |
101 |
0.4~0.9 |
|
陶瓷晶体 |
1 |
110 |
0.9~3.0 |
12~22 |
石英晶体 |
1 |
111 |
3.0~8.0 |
12~22 |
|
1 |
101~111 |
≥1.0 |
12~22 |
注:对陶瓷振荡器所配的电容,按生产厂家说明配用。CKOPT=0时振荡器的输出振幅较大,适合干扰大的场合;CKOPT=1(默认),振荡器输出幅度较小,可以降低功耗,对外辐射也较小。
③使用外部晶体时的启动时间选择:
熔丝位 |
从掉电模式开始的启动时间 |
从复位开始的附加延时(ms)@Vcc=5.0V |
推荐使用场合 |
|
CKSEL0 |
SUT[1:0] |
|||
1 |
00 |
258CK |
4.1 |
陶瓷晶体,快速上升电源 |
1 |
01 |
258CK |
65 |
陶瓷晶体,慢速上升电源 |
1 |
10 |
1K CK |
- |
陶瓷晶体,BOD方式 |
1 |
11 |
1K CK |
4.1 |
陶瓷晶体,快速上升电源 |
1 |
00 |
1K CK |
65 |
陶瓷晶体,慢速上升电源 |
1 |
01 |
16K CK |
- |
石英晶体,BOD方式 |
1 |
10 |
16K CK |
4.1 |
石英晶体,快速上升电源 |
1 |
11 |
16K CK |
65 |
石英晶体,慢速上升电源 |
④使用外部低频晶体时的启动时间选择:
熔丝位 |
从掉电模式开始的启动时间 |
从复位开始的附加延时(ms)@Vcc=5.0V |
推荐使用场合 |
|
CKSEL[3:0] |
SUT[1:0] |
|||
1001 |
00 |
1K CK |
4.1 |
快速上升电源或BOD方式 |
1001 |
01 |
1K CK |
65 |
慢速上升电源 |
1001 |
10 |
32K CK |
65 |
要求振荡频率稳定的场合 |
1001 |
11 |
保留 |
注:使用32.768kHz晶体时,CKSEL应当编程1001。当CKOPT=0时,选择使用内部与XTAL1/XTAI2相连的电容,没有必要再外接电容,内部电容为36pF。
⑤使用外部RC振荡器时的模式配置:
熔丝位CKSEL[3:0] |
工作频率范围(MHz) |
|
熔丝位CKSEL[3:0] |
工作频率范围(MHz) |
0101 |
≤0.9 |
|
0111 |
3.0~8.0 |
0110 |
0.9~3.0 |
|
1000 |
8.0~12.0 |
注:频率的估算公式为1/(3RC)。电容C的容量至少为22pF。当CKOPT=0时,可以使用片内XTAL1与GND之间的36pF,此时不需要外接电容。
⑥使用外部RC振荡器时的启动时间选择:
熔丝位SUT[1:0] |
从掉电模式开始的启动时间 |
从复位开始的附加延时(ms)@Vcc=5.0V |
推荐使用场合 |
00 |
18 CK |
- |
BOD方式 |
01 |
18 CK |
4.1 |
快速上升电源 |
10 |
18 CK |
65 |
慢速上升电源 |
11 |
6 CK |
4.1 |
快速上升电源或BOD方式 |
⑦使用内部RC振荡器的不同工作模式:
熔丝位CKSEL[3:1] |
工作频率范围(MHz) |
0001 |
1.0(出厂设置) |
0010 |
2.0 |
0011 |
4.0 |
0100 |
8.0 |
可被校准的内部RC振荡器提供固定的1/2/4/8MHz的时钟,这些工作频率是在5V/25度下校准的。当MCU完成复位后,硬件将自动地装载校准值到OSCCAL寄存器中,从而完成对内部RC振荡器的频率校准。
⑧使用内部RC振荡器时的启动时间选择:
熔丝位 SUT[1:0] |
从掉电模式开始的启动时间 |
从复位开始的附加延时(ms)@Vcc=5.0V |
推荐使用场合 |
00 |
6 CK |
- |
BOD方式 |
01 |
6 CK |
4.1 |
快速上升电源 |
10(出厂设置) |
6 CK |
65 |
慢速上升电源 |
11 |
保留 |
⑨外部时钟源:
当CKSEL编程为0000时,使用外部时钟源作为系统时钟,外部时钟信号从XTAL1输入。如果CKOPT=0,则XTAL1与GND之间的片内36pF电容被使用。
⑩使用外部时钟源时的启动时间选择:
熔丝位SUT[1:0] |
从掉电模式开始的启动时间 |
从复位开始的附加延时(ms)@Vcc=5.0V |
推荐使用场合 |
00 |
6 CK |
- |
BOD方式 |
01 |
6 CK |
4.1 |
快速上升电源 |
10 |
6 CK |
65 |
慢速上升电源 |
11 |
保留 |
为保证MCU稳定工作,不能突然改变外部时钟频率,当频率突然变化超过2%时,将导致MCU工作异常。建议在MCU处于复位状态时改变外部时钟的频率。
6)系统时钟选择与启动延时配置一览表:
系统时钟源 |
休眠模式下唤醒启动延时时间 |
RESET复位启动延时时间(ms) |
熔丝状态配置 |
外部时钟 |
6 CK |
0 |
CKSEL=0000, SUT=00 |
外部时钟 |
6 CK |
4.1 |
CKSEL=0000, SUT=01 |
外部时钟 |
6 CK |
65 |
CKSEL=0000, SUT=10 |
内部RC振荡(1MHz) |
6 CK |
0 |
CKSEL=0001, SUT=00 |
内部RC振荡(1MHz) |
6 CK |
4.1 |
CKSEL=0001, SUT=01 |
内部RC振荡(1MHz)(出厂设置) |
6 CK |
65 |
CKSEL=0001, SUT=10 |
内部RC振荡(2MHz) |
6 CK |
0 |
CKSEL=0010, SUT=00 |
内部RC振荡(2MHz) |
6 CK |
4.1 |
CKSEL=0010, SUT=01 |
内部RC振荡(2MHz) |
6 CK |
65 |
CKSEL=0010, SUT=10 |
内部RC振荡(4MHz) |
6 CK |
0 |
CKSEL=0011, SUT=00 |
内部RC振荡(4MHz) |
6 CK |
4.1 |
CKSEL=0011, SUT=01 |
内部RC振荡(4MHz) |
6 CK |
65 |
CKSEL=0011, SUT=10 |
内部RC振荡(8MHz) |
6 CK |
0 |
CKSEL=0100, SUT=00 |
内部RC振荡(8MHz) |
6 CK |
4.1 |
CKSEL=0100, SUT=01 |
内部RC振荡(8MHz) |
6 CK |
65 |
CKSEL=0100, SUT=10 |
外部RC振荡(≤0.9MHz) |
18 CK |
0 |
CKSEL=0101, SUT=00 |
外部RC振荡(≤0.9MHz) |
18 CK |
4.1 |
CKSEL=0101, SUT=01 |
外部RC振荡(≤0.9MHz) |
18 CK |
65 |
CKSEL=0101, SUT=10 |
外部RC振荡(≤0.9MHz) |
6 CK |
4.1 |
CKSEL=0101, SUT=11 |
外部RC振荡(0.9~3.0MHz) |
18 CK |
0 |
CKSEL=0110, SUT=00 |
外部RC振荡(0.9~3.0MHz) |
18 CK |
4.1 |
CKSEL=0110, SUT=01 |
外部RC振荡(0.9~3.0MHz) |
18 CK |
65 |
CKSEL=0110, SUT=10 |
外部RC振荡(0.9~3.0MHz) |
6 CK |
4.1 |
CKSEL=0110, SUT=11 |
外部RC振荡(3.0~8.0MHz) |
18 CK |
0 |
CKSEL=0111, SUT=00 |
外部RC振荡(3.0~8.0MHz) |
18 CK |
4.1 |
CKSEL=0111, SUT=01 |
外部RC振荡(3.0~8.0MHz) |
18 CK |
65 |
CKSEL=0111, SUT=10 |
外部RC振荡(3.0~8.0MHz) |
6 CK |
4.1 |
CKSEL=0111, SUT=11 |
外部RC振荡(8.0~12.0MHz) |
18 CK |
0 |
CKSEL=1000, SUT=00 |
外部RC振荡(8.0~12.0MHz) |
18 CK |
4.1 |
CKSEL=1000, SUT=01 |
外部RC振荡(8.0~12.0MHz) |
18 CK |
65 |
CKSEL=1000, SUT=10 |
外部RC振荡(8.0~12.0MHz) |
6 CK |
4.1 |
CKSEL=1000, SUT=11 |
低频晶体(32.768kHz) |
1K CK |
4.1 |
CKSEL=1001, SUT=00 |
低频晶体(32.768kHz) |
1K CK |
65 |
CKSEL=1001, SUT=01 |
低频晶体(32.768kHz) |
32K CK |
65 |
CKSEL=1001, SUT=10 |
低频石英/陶瓷晶体(0.4~0.9MHz) |
258 CK |
4.1 |
CKSEL=1010, SUT=00 |
低频石英/陶瓷晶体(0.4~0.9MHz) |
258 CK |
65 |
CKSEL=1010, SUT=01 |
低频石英/陶瓷晶体(0.4~0.9MHz) |
1K CK |
0 |
CKSEL=1010, SUT=10 |
低频石英/陶瓷晶体(0.4~0.9MHz) |
1K CK |
4.1 |
CKSEL=1010, SUT=11 |
低频石英/陶瓷晶体(0.4~0.9MHz) |
1K CK |
65 |
CKSEL=1011, SUT=00 |
低频石英/陶瓷晶体(0.4~0.9MHz) |
16K CK |
0 |
CKSEL=1011, SUT=01 |
低频石英/陶瓷晶体(0.4~0.9MHz) |
16K CK |
4.1 |
CKSEL=1011, SUT=10 |
低频石英/陶瓷晶体(0.4~0.9MHz) |
16K CK |
65 |
CKSEL=1011, SUT=11 |
低频石英/陶瓷晶体(0.9~3.0MHz) |
258 CK |
4.1 |
CKSEL=1100, SUT=00 |
低频石英/陶瓷晶体(0.9~3.0MHz) |
258 CK |
65 |
CKSEL=1100, SUT=01 |
低频石英/陶瓷晶体(0.9~3.0MHz) |
1K CK |
0 |
CKSEL=1100, SUT=10 |
低频石英/陶瓷晶体(0.9~3.0MHz) |
1K CK |
4.1 |
CKSEL=1100, SUT=11 |
低频石英/陶瓷晶体(0.9~3.0MHz) |
1K CK |
65 |
CKSEL=1101, SUT=00 |
低频石英/陶瓷晶体(0.9~3.0MHz) |
16K CK |
0 |
CKSEL=1101, SUT=01 |
低频石英/陶瓷晶体(0.9~3.0MHz) |
16K CK |
4.1 |
CKSEL=1101, SUT=10 |
低频石英/陶瓷晶体(0.9~3.0MHz) |
16K CK |
65 |
CKSEL=1101, SUT=11 |
低频石英/陶瓷晶体(3.0~8.0MHz) |
258 CK |
4.1 |
CKSEL=1110, SUT=00 |
低频石英/陶瓷晶体(3.0~8.0MHz) |
258 CK |
65 |
CKSEL=1110, SUT=01 |
低频石英/陶瓷晶体(3.0~8.0MHz) |
1K CK |
0 |
CKSEL=1110, SUT=10 |
低频石英/陶瓷晶体(3.0~8.0MHz) |
1K CK |
4.1 |
CKSEL=1110, SUT=11 |
低频石英/陶瓷晶体(3.0~8.0MHz) |
1K CK |
65 |
CKSEL=1111, SUT=00 |
低频石英/陶瓷晶体(3.0~8.0MHz) |
16K CK |
0 |
CKSEL=1111, SUT=01 |
低频石英/陶瓷晶体(3.0~8.0MHz) |
16K CK |
4.1 |
CKSEL=1111, SUT=10 |
低频石英/陶瓷晶体(3.0~8.0MHz) |
16K CK |
65 |
CKSEL=1111, SUT=11 |
RESET复位启动延时时间,是当芯片RESET复位后附加的延时启动时间,这段时间可通过配置熔丝位选择不同的延时启动时间。休眠模式下唤醒启动延时时间,是在芯片处在休眠模式中的Power-Down和Power-Save两种模式下被唤醒后附加的启动延时时间。CK表示一个系统时钟脉冲,18CK则表示芯片被唤醒后还需要经过18个系统时钟脉冲后才正式开始启动运行。
AVR芯片的休眠模式有6种,Power-Down和Power-Save属于深度休眠模式,芯片中大部分时钟都停止工作以使耗电降到最小。然而一旦从这两种深度休眠模式中唤醒,CPU不能马上开始工作,因为芯片内部的各个时钟系统还需要一定时间才能进入到稳定的工作状态,因此需要延时启动。
7.ATmega16的上电运行及编程:
1)掉电检测复位BOD:
ATmega16有一个片内的BOD(Brown-out Detection)电源检测电路,用于在系统运行时对系统电压Vcc的检测,并与一个固定的阈值电压相比较。BOD检测阈值电压可通过BODLEVEL熔丝位设定为2.7V或4.0V。BOD检测阈值电压有迟滞效应,已避免系统电源的尖峰毛刺误触发BOD检测器。BOD检测电路可通过编程BODEN熔丝位来设置成有效或者无效。
2)正常程序执行工作方式:
硬件的复位操作将程序计数器置为0(PC=$0000),程序的执行总是从Flash地址的$0000开始的(非BOOTLOAD方式启动)。对于ATmega16,Flash地址空间的$0002~$0028是中断向量区,所以实际要开始运行的程序代码一般放在从$002A以后的程序地址空间中。标准的做法是在Flash的$0000单元中放置一条转移指令JMP或RJMP,使得CPU在复位重新启动后首先执行该转移指令,跳过中断向量区,转到执行实际程序的开始处。
3)SPI编程模式:
如果芯片带有SPI接口,支持SPI串行编程,通过以下方式将使芯片进入SPI编程状态:
·外部将SPI口的SCK引脚拉低,然后在RESET-上施加一个至少为2个系统周期以上的低电平脉冲。
·延时等待20ms后,由外部通过AVR的SPI口向芯片下发允许SPI编程的指令。
一旦芯片进入编程状态,就可以通过SPI口将运行代码写入AVR的程序寄存器,对片内的Flash和EEPROM进行擦除、数据的写入(包括运行代码)和数据的读出,以及实现对AVR配置熔丝位的设置、芯片型号的读取和加密位的锁定等操作了。
4)片内WDT:
WDT,俗称看门狗,实际上是一个独立的硬件定时/计数器,当它的计数值计满溢出时,会输出一个脉冲信号。在使用WDT的系统中,通常将WDT的溢出输出信号与微控制器的RESET-引脚连接。
软件设计时,必须保证程序每隔一定的时间(小于WDT溢出时间)输出一个清0WDT(俗称喂狗)信号,防止WDT溢出。在程序正常运行过程中,由于不停地定时“喂狗”,因此WDT永远不会溢出;但当程序发生故障时,例如进入死循环或跑飞,就不能“喂狗”,此时WDT不停计数,到达溢出后,输出信号将微控制器复位,然后微控制器重启。
WDT并不能防止系统跑飞和出现问题,只是能在短时间内(1s左右)就将出现问题的系统自动重新启动,使其恢复正常。实际应用中,WDT是作为一个能提高系统可靠性的手段在设计中使用,还有专用的WDT芯片,以便配合无WDT功能的微控制器使用。AVR已将WDT集成在芯片内。ATmega16的控制寄存器(地址$21/$0041)WDTCR的配置如图:
- |
- |
- |
WDTOE |
WDE |
WDP2 |
WDP1 |
WDP0 |
高3位保留,只读,为0。
WDTOE:对WDTCR寄存器操作允许标志位。当要关闭WDT时,该位必须置1,否则不会关闭。一旦WDTOE置1后,硬件会在4个时钟周期后自动将该位清0,以防止误操作。当重新设定WDT定时器的预置分频器参数时,WDTOE也必须先置1。
WDE:WDT允许标志位,为1时使能WDT定时器,为0时WDT功能禁止。清0WDE的操作,必须在WDTOE置1后的4个时钟周期内完成。
WDT[2:0]:WDT定时器预分频器设置位,用于设定WDT的复位时间间隔。
WDP2 |
WDP1 |
WDP0 |
WDT脉冲数 |
典型溢出时间(3V) |
典型溢出时间(5V) |
0 |
0 |
0 |
16K(16384) |
17.1ms |
16.3ms |
0 |
0 |
1 |
32K(32768) |
34.3ms |
32.5ms |
0 |
1 |
0 |
64K(65536) |
68.5ms |
65ms |
0 |
1 |
1 |
128K(131072) |
0.14s |
0.13s |
1 |
0 |
0 |
256K(262144) |
0.27s |
0.26s |
1 |
0 |
1 |
512K(524288) |
0.55s |
0.52s |
1 |
1 |
0 |
1024K(1048576) |
1.1s |
1.0s |
1 |
1 |
1 |
2048K(2097152) |
2.2s |
2.1s |
对WDTCR的操作必须按照以下的特定操作顺序:
·首先必须要将WDTOE设置为1,允许对WDTCR的写操作。
·在设置WDTOE为1后的4个时钟周期内,修改WDTCR的内容。
·在设置WDTOE为1后的4个时钟周期后,硬件自动将WDTOE清0,禁止操作。
汇编程序代码:
WDT_off:
;复位WDT
WDT
;向WDTOE和WDE写逻辑1
in r16,WDTCR
ori r16,(1<<WDTOE)|(1<<WDE)
out WDTCR,r16
;关闭WDT
ldi r16,(0<<WDE)
out WDTCR,r16
ret
C语言代码:
void WDT_off(void)
{
//复位WDT
_WDR();
//向WDCE和WDE写逻辑1
WDTCR|=(1<<WDTOE)|(1<<WDE);
//关闭WDT
WDTCR=0x00;
}
一旦系统中使用了WDT,建议将熔丝位WDTON设置在0状态,此时WDT在上电后就会始终处于工作状态,即使指令也不能将WDT禁止。一旦使用WDT,在系统设计时要特别注意“喂狗”操作,2次间隔小于所设定的WDT溢出复位时间。