|
从MCS51 向AVR 的快速转换 ATMEL 的AVR 系列单片机是一个优秀的RISC 结构单片机系列与MCS51 相 比其有以下一些典型特点: AVR 的机器周期为1 个时钟周期,绝大多数指令为单周期指令,因此每MHZ 时钟有接近1MIPS 的性能。 程序存贮器与数据存贮器有分开的总线程序,可以高效地执行8MHZ 频率下工作的AVR 相当于224MHZ 频率下工作的MCS51 内置可重复编程的FLASH 程序存贮器和EEPROM 数据存贮器支持对单片 机的在系统编程ISP 在生产中可以先装配后编程从而缩短工艺流程和节约 购买万用编程器的费用并且可以方便地升级或修改程序 内置上电复位电路和看门狗定时器WatchDog 电路在提高产品可靠性的 同时降低了电路的成本 部分AVR 单片机与MCS51 系列单片机管脚兼容如AT90S1200/2313 对应 AT89C1051/2051 AT90S4414/8515 对应AT89C51/52 因此可以做到一套PCB 板对应两套电路增加了用户备货的可选择性和灵活性 定时/计数器的功能大大增强串口通信时波特率发生不占用定时器 注在本文中AVR 的C 语言是指ICCAVR6.0 标准版如需向其它版本的AVR C 一AVR 和MCS51 存贮器配置的对比 1 存贮器布置 MCS51 的存贮器从使用角度看分三个地址空间三个空间分别用MOV MOVX 和MOVC 指令访问 而AVR 的存贮器在物理结构上可分为五个部分AT90S8515 为例 1 程序空间000H~FFFH 访问时用LPM 指令访问 2 片内数据存贮器0060H~025FH 访问时用STS LDS 和ST LD 指令访问 3 片外数据存贮器0260H~FFFFH 访问时用STS LDS 和ST LD 指令访问 4 32 个通用寄存器R0~R31 它们之间数据传送可使用MOV 指令 5 I/O 寄存器00H~3FH 使用IN OUT 指令访问 看了以上介绍仔细的读者可能发现有一部分数据存贮器的地址0000H~005FH 是空闲的,其实这部分地址空间并不空闲其被映射为通用寄存器 R0~R31 和I/O 寄存器的数据空间地址具体为32 个通用寄存器直接映射到数据存贮器的0000H~001FH, 64 个I/O 寄存器直接映射到数据存贮器空间的0020H~005FH。这种映射关系大大增强了AVR 指令的灵活性,一方面对寄存器可以象SRAM 一样地访问,另一方面对寄存器的访问时也可以使用X Y 和Z 寄存器作为索引从而大大提高了访问寄存器的灵活性 2 堆栈工作方式 MCS51 的堆栈是一个由堆栈指针寄存器SP 单字节控制的向上生长型堆栈即将数据压入堆栈时SP 增大 在AVR系列单片机的堆栈同样是受SP寄存器控制而堆栈的生长方向与MCS51是不相同的,其向下生长即将数据压入堆栈时SP 减小另外要注意以下几点: 1 MCS51 的堆栈空间只能放置在片内的SRAM 中而AVR 的堆栈空间既可以放置的片内SRAM 中也可以放置在片外SRAM 中 2 AVR 的SP 寄存器对不支持外部SRAM 的单片机为一个字节长度对支持外部SRAM 的单片机为两个字节长度SPL SPH 3 为了提高速度一般在初始化SP 时将其定位于内部SRAM 的顶部如对8515 为025FH 4 AT90S1200 不支持软件堆栈即由SP 控制堆栈其包含了一个三级深度的硬件堆栈 5 在对AVR 编程时一定要对SP 进行初始化否则很可能出现在AVR Studio中模拟调试正常而程序下载到芯片后程序却不工作的现象 3 外部SRAM 的配置 在MCS51 中外部SRAM 是使用专用的MOVX 指令访问的而在AVR 中访问片内或片外SRAM 使用相同的指令,当访问数据空间的地址超过片内SRAM 范围时会自动选择片外的SRAM 空间,但为了正常工作还必须对寄存器MCUCR 的SRE D7 SRW D6 位进行设置 SRE SRW SE SM ISC11 ISC10 ISC01 ISC00 MCUCR 寄存器 当SRE=1 时使能外部SRAM 如汇编指令SBI MCUCR SRE SRE=0 时禁止外部SRAM 如汇编指令CBI MCUCR SRE 当SRW=1 时在访问外部SRAM 中插入一个等待周期如汇编指令SBI MCUCR SRW 当SRW=0 时在访问外部SRAM 中不插入一个等待周期如汇编指令SBI MCUCR SRW 在C语言中可以直接用MCUCR|=0xC0 或MCUCR&=0x3F来配置外部SRAM 4 程序空间的访问 MCS51 的程序存贮器是以字节为单位的地址也是按字节进行寻址的,使用 MOVC 指令访问程序ROM 和指令寄存器访问程序ROM 没有什么区别。 在AVR 中程序存贮器的总线为16 位即指令寄存器访问程序ROM时是以字双字节为单位的,即一个程序地址对应两个字节而AVR 的数据存贮器的总线为8 位。当用户使用LPM 指令访问程序ROM 时是以字节为单位进行读取的,此时Z 寄存器中的一个地址只对应一个字节,因此要注意这两个地址的换算否则很容易产生错误。具体的换算是LPM 指令使用的Z寄存器中的地址应该是程序地址的两倍。 如ldi ZH high(F_TABLE*2) ldi ZL low(F_TABLE*2) 初始化Z 指针 . lpm st Y+ R0 . F_TABLE .db 0,1 ;表的起点(20 bytes) . .db 18,19 二AVR 输入/输出端口的使用 MCS51 单片机的I/O 端口大部分是准双向口,在复位时全部输出高电平,对端口的输入和输出操作也是直接通过I/O 端口的地址进行的,而AVR 的I/O 端口为标准双向口,在复位时所有端口处于没有上拉电阻的输入状态,高阻态管脚电平完全由外部电路决定,这在强调复位状态的场合是很有用的。AVR 的每一个端口对应三个地址即DDRX、PORTX 和PINX X 针对不同的单片机,可从A~F 中分别取不同的符号。注意只有PINX 可取F ,DDRXn、PORTXn I/O 上拉。备注: 0 0 输入关闭高阻态 0 1 输入打开 提供弱上拉低电平必须由外电路位低此时输出电流 1 0 输出关闭推挽输出0 1 1 输出关闭推挽输出1 表一端口功能配置表X=A~E n=0~7 DDRX 为端口方向寄存器当DDRX 的某一位置1 时相应端口的引脚作为输出使用,当DDRX 的某一位清0 时相应端口的引脚作为输入使用 PORTX 为端口数据寄存器当引脚作为输出使用时PORTX 的数据由相应引脚输出,当引脚作为输入使用时POTRX 的数据决定相应端口的引脚是否打开弱上拉 具体可参考表一 PINX 为相应端口的输入引脚地址,如果希望读取相应引脚的逻辑电平值一定要读取PINX 而不能读取PORTX,这与MCS51 是有区别的。 注意:在使用AVR 单片机之前一定要根据引脚功能定义对相应的端口初始化,否则端口很可能在用作输出时不能正常工作如设置端口B的高四位为输出。低四位为输入 汇编语言ldi R16 $F0 out DDRB R16 在C 语言中DDRB=0xF0 三AVR 和MCS51 定时器的对比 1 功能比较 在MCS51 中定时/计数器有两种基本用法即以晶振频率的十二分频信号为输入的定时器工作方式和以外部引脚INT0 INT1 上的信号为输入的计数器工作方式 在AVR中有两个定时器T0 和T1 AT90S1200 只有一个T0 T0 的功能与MCS51相似而T1 的功能很强除了普通的定时/计数功能外,还有一些增强的功能如比较匹配A 比较匹配B 由ICP 引脚或模拟比较器触发的捕捉功能8~10 位的PWM 调制器 AVR 的定时/计数器用作定时器时其输入信号为晶振频率的某一个分频信号分频比为1 8 64 256 1024 五种作为计数器使用时既可上升沿触发也可下降沿触发 2 T0 的使用 在AVR 中T0 为八位长度其由TCCR0 寄存器控制TCCR0 组成如下图所示 X X X X X CS02 CS01 CS00 TCCR0 的作用如下表所示 CSX2 CSX1 CSX0 说明CSX2 CSX1 CSX0 说明 0 0 0 T0 停止工作1 0 0 CK/256 定时器 0 0 1 CK 定时器1 0 1 CK/1024 定时器 0 1 0 CK/8 定时器1 1 0 计数器(下降沿触发) 0 1 1 CK/64 定时器1 1 1 计数器(上升沿触发) 表二TCCR0 功能表X=0 1 例1 定时器T0 用作定时器晶振频率4M 定时时间10ms 可以这样对T0 初始化 汇编语言LDI R16 $D9 OUT TCNT0 R16 定时常数到定时寄存器TCNT0 LDI R16 $05 OUT TCRR0 R16 1024 分频比 C 语言TCNT0=0xD9 TCRR0=0x05 说明TCNT0 为定时计数寄存器 例2 定时器T0 用作计数器下降沿触发可以这样对T0 初始化 汇编语言LDI R16 00 OUT TCNT0 R16 TCNT0 清零 LDI R16 $06 OUT TCRR0 R16 计数器方式工作下降沿触发 C 语言TCNT0=0 TCRR0=0x06 3 T1 的使用 在AVR 中T1 是16 位的其控制寄存器有TCCR1A 和TCCR1B 两个TCCR1A 组成如下图所示 COM1A1 COM1A0 COM1B1 COM1B0 X X PWM 11 PWM 10 各位的功能如表三所示 COM1X1 COM1X0 说明PWM11 PWM10 说明 0 0 与输出OC1X 不连接0 0 禁止PWM 操作 0 1 OC1X 电平翻转0 1 8 位PWM 1 0 OC1X 为低电平1 0 9 位PWM 1 1 OC1X 为高电平1 1 10 位PWM 表三TCCR1A 功能表 TCCR1B 的组成如下图所示其中CS10~CS12 的用法同T0 见表二所示 ICNC1 ICES1 X X CTC1 CS12 CS11 CS10 ICNC1 置1 时使能输入捕捉噪声消除清0 时禁止输入捕捉噪声消除 ICES1 置1 时在ICP 的上升沿时发生定时器捕捉清0 时在ICP 的下降沿发生定时器捕捉 CTC1 置1 时当比较匹配A发生时将TCNT1 清0 清0 时TCNT1 继续计数 直至它被停止清除溢出为止注意只有比较匹配A有效另外在PWM方式下该位无效 例1 定时器1 用比较匹配A 方式在OC1A引脚输出一个50HZ 的方波晶振频率为4MHZ 可以这样对T1 初始化 汇编语言LDI R16 $20 OUT DDRD R16 引脚OC1A 输出 LDI R16 $00 OUT TCNT1H R16 OUT TCNT1L R16 TCNT1 清0 LDI R16 $02 OUT OCR1AH R16 LDI R16 $71 OUT OCR1AL R16 送入对应10ms 的比较常数 LDI R16 $40 OUT TCCR1A R16 T1 和OC1A 相连比较匹配时OC1A 翻转 LDI R16 $0B OUT TCCR1B R16 T1 以定时器方式工作分频比为64 比较匹配后自动清除TCNT1 C 语言DDRD=0x20 //引脚OC1A 输出 TCNT1=0x00 //TCNT1 清0 OCR1A=0x271 //送入对应10ms 的比较常数 TCCR1A=0x40 //T1 和OC1A 相连比较匹配时OC1A 翻转 TCCR1B=0x0B //T1 以定时器方式工作分频比为64 比较匹配后 // 自动清除TCNT1 注意 1 由于T1 的TCNT1 OCR1A OCR1B 和ICR1 均为16 位的定时器为了正确地写入和读出在写入数据时应先写入高位字节后写入低位字节在读取数据时应先读取低位字节后读取高位字节 2 T1 的捕捉方式可用于ICP 引脚上频率或周期的测量在使用时只需使能捕捉中断即可对T1 的设置可参考定时的用法 四AVR 和MCS51 中断系统的对比 MCS51 有六个中断源5 个中断入口地址分两个优先级并且是通过IE 寄存器控制中断的使能通过IP 控制中断的优先等级 而在AVR 中根据不同的单片机有不同数量的中断源典型的AT90S8515 有12个中断源,这12 个中断源各自有自己的中断向量入口地址如表四所示,AVR 通过寄存器GIMSK 和TIMSK 及SREG 来控制中断使能,其中SREG 的D7 位I 是全局中断使能标志在AVR 中只有全局中断控制位和某一特定中断控制位同时使能中断才会起作用GIMSK 和TIMSK 的功能见下图 INT1 INT0 X X X X X X GIMSK TOIE1 OCIE1A OCIE1B X TICIE1 X TOIE0 X TIMSK INT0 INT1 外部中断请求0 1 使能置1 时开放中断清0 时禁止中断外部中断的触发方式由MCUCR 的D0~D3 位控制如表五所示 TOIE0 TOIE1 定时器0 1 的溢出中断使能 OCIE1A B 定时器1 的比较匹配A B 中断使能 TICIE1 定时器1 的输入捕捉中断使能 向量号入口地址中断源说明 1 $000 RESET 硬件复位和看门狗复位 2 $001 INT0 外部中断请求0 3 $002 INT1 外部中断请求1 4 $003 TIMER1 CAPT 定时器1 捕捉中断 5 $004 TIMER1 COMPA 定时器1 比较匹配A 中断 6 $005 TIMER1 COMPB 定时器1 比较匹配B 中断 7 $006 TIMER1 OVF 定时器1 溢出中断 8 $007 TIMER0 OVF 定时器0 溢出中断 9 $008 SPI STC SPI 传送完成 10 $009 UART RX 串行通信接收完成 11 $00A UART UDRE 串行通信数据寄存器空 12 $00B UART TX 串行通信发送完成 13 $00C ANA_COMP 模拟比较器中断 表四中断向量名称与入口地址 ISCX1 ISCX0 说明ISCX1 ISCX0 说明 0 0 低电平触发中断1 0 下降沿触发中断 0 1 高电平触发中断1 1 上升沿触发中断 表五外部中断触发方式X=0 1 在AVR 中没有专门的中断优先级控制寄存器来区分中断的优先等级,用户可在中断服务程序中通过使能全局中断I 来使系统响应,高优先级的中断具体的做法是当AVR 单片机响应任何一个中断时硬件会禁止全局中断I 从而禁止系统响应其它中断而当从中断服务程序中退出时硬件重新使能全局中断I ,而当我们在中断服务程序中用SEI 指令打开全局中断使能时系统在没有退出中断服务程序的情况下又恢复了对中断的响应能力,从而可以响应高优先级的中断另外在同一优级中入口地址较低的中断优先级较高 例:系统使能定时器1 溢出中断和外部INT0 中断其中INT0 的优先级较高,此时可以这样对MCU 初始化 汇编语言 LDI R16 $40 OUT GIMSK R16 使能INT0 中断 LDI R16 $80 OUT TIMSK R16 使能T1 溢出中断 SEI 使能全局中断 . . timer1_ovf T1 溢出中断服务程序 SEI 在T1 溢出中断服务程序中开放全局中断 保证INT0 的优先级 RETI 注意在AVR 的子程序中硬件不保护SREG 状态寄存器应根据实际情况由软 件进行保护 C 语言#pragma interrupt_handler timer1 7 //声明timer1( )为中断处 //理函数 #pragma interrupt_handler int0 2 //声明_int0( )为中断处理 //函数 void main (void) { GIMSK=0x40 //使能INT0 中断 TIMSK=0x80 //使能T1 溢出中断 _SEI( ) //使能全局中断 . } void timer1(void)//T1 溢出中断服务程序 { _SEI( ) //在T1 溢出中断服务程序中开放全局中断 //保证INT0 的优先级 . } 在C 语言的中断服务程序中断处理函数中会自动保护中断服务程序使用过的所有寄存器 五AVR 和MCS51 位操作功能的对比 MCS51 和AVR 都有较强的位操作功能在汇编语言写的AVR 源程序中对端口的某一位置1 可用SBI 指令清0 可用CBI 指令 在C 语言程序中可用位运算或在线汇编完成上述功能如置PORTB 的D2 位 为1 清PORTB 的D6 位为0 PORTB|=(1<<2) //D2 位置1 PORTB&=~(1<<6) //D6 位清0 或 ASM( SBI 0x18 2 ) //D2 位置1 ASM( CBI 0x18 6 ) //D6 位清0 六AVR 单片机内置EEPROM 的使用 AVR是通过三个寄存器来访问MCU内置的EEPROM 的一个寄存器是EEAR存放访问EEPROM 的地址其根据片内EEPROM 的多少可能有不同的长度另一个是8 位的EEDR 用于存放访问EEPROM 的数据第三个是EECR 用于控制对EEPROM 的读写EECR 的结构如下图所示 X X X X X EEMWE EEWE EERE EEMWE EEPROM 主写使能只有在其置1 后的4 个时钟周期内将EEWE置1才能完成EEPROM 写入否则写操作无效EEMWE被置1 后在4 个周期后由硬件自动清除 EEWE EEPROM 写入使能 EERE EEPROM 读取使能 例写数据到片内EEPROM 中子程序 汇编语言 .def EEdwr =r16 写入EEPROM 的数据 .def EEawr =r17 EEPROM 的地址低位 .def EEawrh =r18 EEPROM 的地址高位 EEWrite sbic EECR EEWE rjmp EEWrite 等待EEPROM 就绪 out EEARH Eeawrh out EEARL EEawr 送入EEPROM 地址 out EEDR EEdwr 送入写入EEPROM 的地址 sbi EECR,EEMWE 设置EEPROM 主写使能 sbi EECR,EEWE 设置EEPROM 写使能 ret C 语言注意应包含头文件eeprom.h int EEPROMwrite( int location, unsigned char); int location 片内EEPROM 的地址 unsigned char 写入EEPROM 的数据 七AVR 单片机内置看门狗电路WatchDog 的使用 AVR 系列单片机内置看门狗电路其由寄存器WDTCR控制WDTCR的结构如下图所示 X X X WDTOE WDE WDP2 WDP1 WDP0 WDTOE 看门狗关闭使能 只有在该位被置1 后的4 个时钟周期内将WDE 清0 才能关闭看门狗电路,否则看门狗电路不会被关闭WDTOE在被置1 后在4 个周期后由硬件自动清0 WDE 置1 时使能看狗电路清0 时关闭看门狗电路注意关闭看门狗电路应在对WDTOE置1 后4 个时钟周期内进行 WDP0~WDP2 看门狗电路的分频系数产生复位所需要的振荡周期数其影响看门狗电路复位的时间如表六所示 WDP 2 WDP 1 WDP 0 分频系数DC3V 时 产生复位所需时间 DC5V 约1MHZ 产生复位所需时间 0 0 0 16K 47ms 15ms 0 0 1 32K 94ms 30ms 0 1 0 64K 0.19s 60ms 0 1 1 128K 0.38s 0.12s 1 0 0 256K 0.75s 0.24s 1 0 1 512K 1.5s 0.49s 1 1 0 1024K 3.0s 0.97s 1 1 1 2048K 6.0s 1.9s 注意:看门狗电路的振荡器为内部RC 振荡器其振荡频率受电压影响在DC5V 时约为1MHZ 在AVR 中有一条指令WDR 来清除看门狗定时器在C 语言中对应为_WDR( ) 或WDR( )函数 八AVR 和MCS51 中串口通信UART 功能的对比 在MCS51 中串口通信的波特率发生需要使用一个定时器而且支持的波特率也较低AVR 单片机可以有较高的波特率最高波特率可达115200 而且有专用的波特率发生器注意AT90S1200 没有UART 只能用软件模拟串口通信 在AVR 中用于UART 的寄存器主要有以下几个接收和发送数据寄存器UDR 状态寄存器USR 控制寄存器UCR 和波特率寄存器UBRR UDR 寄存器由两个物理上分开的寄存器共享同一个地址写入数据时是写到发送寄存器读出数据时是读取接收寄存器 USR 如下图所示其反映了UART 的状态 RXC TXC UDR FE OR X X X RXC UART 接收完成 TXC UART 发送完成 UDR UART 数据寄存器空标志 FE 帧出错 OR 超越出错 UCR 控制UART 的工作其组成如下图所示 RXCIE TXCIE UDRIE RXEN TXEN CHR9 RXB8 TXB8 RXCIE 接收中断使能 TXCIE 发送中断使能 UDRIE UART 数据寄存器空中断使能 RXEN 接收使能 TXEN 发送使能 CHR9 发送9 位字符 RXB8 接收到的第8 位字符 TXB8 发送的第8 位字符 UBRR 控制UART 的波特率其与波特率的计算公式为 BAUD=FCK/[16(UBRR+1)] 其中BAUD 表示波特率FCK 表示晶振频率UBRR 表示UBRR 寄存器中的常数 注意波特率的计算值与标准波特率相差不能超过2% 否则会影响串行通信 例1 在8MHZ 晶振下以19200 波特率和PC 机通信可这样对AVR初始化 汇编语言LDI R16 25 OUT UBRR R16 LDI R16 $18 OUT UCR R16 C 语言UBRR=25 UCR=0x18 例2 在8MHZ 晶振下以19200 波特率与PC 机通信每接收到一个非0 字节 发送一个OK #include #include void main(void) { unsigned char temp; UBRR = 25; UCR=0x18; puts("Hello World!"); putchar(0x0d); putchar(0x0a); while (1) { temp=getchar(); if (temp!=0) { puts("OK!"); putchar(0x0d); putchar(0x0a); temp=0; } } } 九C51 的源代码向ICCAVR 的快速转换 熟悉C51 的读者看了以上内容完全可以很快写出AVR 的C 源程序来下面再将C51 向ICCAVR 的转换进行一次总结 1 头文件 对C51 中定义寄存器的头文件如reg51.h at89x51.h等替换成相应的AVR头文件 如io8515.h io2313.h 等 2 中断处理函数 在C51 中以interrupt 关键字来说明某一个函数为中断处理函数在ICCVAR 中可采用#pragma interrupt_handler 预处理命令在程序开始处声明具体用法如下: #pragma interrupt_handler <中断处理函数名> <中断向量号> 注意对原C51 源程序中的interrupt 和using 关键字应当删除 3 对C51 中的bit 和sbit 数据类型的处理 在ICCAVR 中不支持bit 和sbit 数据类型对这两种类型可用unsigned char 来代替 对有关位运算用标准C 的位运算功能进行处理也可采取在线汇编处理 4 对中断系统定时器初始化 需重新根据相应控制寄存器的功能给其赋值方法与C51 相同具体如下 对MCS51 中TMOD TCON 的处理改为对AVR 的TCCR0 TCCR1A TCCR1B TIFR 的处理 对MCS51 中IE IP 的处理改为对AVR 中GIMSK TIMSK MCUCR SREG 的处理 5 将原C51 中有关对看门狗电路外部EEPROM 的处理改为对AVR 芯片内部 看门狗电路内部EEPROM 的处理 6 对MCS51UART 的初始化改为对UCR 和UBRR 和被始化 7 如果使用片外SRAM 应当对MCUCR 初始化如果有引脚作为输出引脚使用应当对其方向寄存器进行初始化 8 对C51 中符合ANSI 标准的C 语言原则上不需要进行修改除非为了程序结构的优化 |