搜索
bottom↓
回复: 29

AVR汇编程序参考

[复制链接]

出0入0汤圆

发表于 2005-2-17 23:51:37 | 显示全部楼层 |阅读模式
该AVR的汇编程序选自《M128》,程序中体现了AVR汇编的基本特点,仅供大家参考。







   该应用系统为一个带1/100秒的简易24小时制时钟,它在上电后能够自动从11时59分55秒00开始计时和显示时间。下图为简易时钟系统硬件电路图。



                           图  简易24小时时钟硬件原理图



   系统使用8个LED数码管显示时、分、秒、1/100秒4个时段的数字,每个时段占用2个LED。显示方式采用动态扫描方式,ATmega128的PA口输出显示数字的7段码(注意:图中省缺了PA口连接到LED各段的8个限流电阻,阻值800欧左右),PC口用于控制8个LED的位选。ATmega128使用外部16MHz晶振(图中未画出)。

  系统还使用ATmega128片内的计数/定时器T1,设计T1工作在定时溢出中断方式,定时间隔为2ms,即T1每2ms产生一次中断。5次中断得到10ms的时间间隔,此时时钟的1/100秒加1,并相应进行时、分、秒的调整。

  LED动态扫描方式的设计如下:在每2ms的时间中,点亮8个LED中的一个,显示其相应的数字(PC口的输出只有一位为低电平,选通一个LED,保持2ms)。因此PC口的输出值为0b11111110,每隔2ms循环右移,到0b01111111时8个LED各点亮一次,时间为16ms。在1秒钟内,循环8个LED的次数为62.5(1000/16),是人眼的滞留时间(25次/秒)的2.5倍,保证了LED显示亮度均匀,无闪烁。在程序设计中,在各个LED转换和7段码输出时,关闭位选信号(PC输出0b11111111),消除了显示的拖尾现象(消影功能)。

  T1的设计:T1为16位定时器,系统时钟为16M,采用其64分频后的时钟作为T1的计数信号(寄存器TCCR1B = 0x03),一个计数周期为4us,2ms需要计500个(0x01F4)。由于T1溢出中断发生在0xFFFF后下一个T1计数脉冲的到来(参见第二章关于定时器原理部分),因此T1的计数初始值为0xFE0C = 0xFFFF – 0x01F3(65535-499),即寄存器TCNT1的初值为0xFE0C。



3.8.2  AVR汇编源代码

  该系统的汇编源代码如下,开发软件平台使用AVR Studio 4.08。



;********************************************************

;AVR汇编程序实例

;简易带1/100秒的24小时制时钟

;********************************************************

.include "m128def.inc"                ;引用器件I/O配置文件



;定义程序中使用的变量名(在寄存器空间)

.def count                =        r18        ;循环计数单元

.def position                =        r19        ;LED显示位指针,取值为0-7

.def p_temp                 =        r20        ;LED显示位选,其值取反由PC口输出

.def count_10ms        =        r21                ;10ms计数单元

.def flag_2ms                =        r22        ;2ms到标志

.def temp                        =        r23        ;临时变量

.def temp1                =        r24                ;临时变量

.def temp_int                =        r25        ;临时变量(中断中使用)



;中断向量区定义,flash空间$0000-$0045

.org $0000

        jmp reset                ;复位处理

        reti                        ;IRQ0 Handler

        nop

        reti                        ;IRQ1 Handler

        nop

        reti                        ;IRQ2 Handler

        nop

        reti                        ;IRQ3 Handler

        nop

        reti                        ;IRQ4 Handler

        nop

        reti                        ;IRQ5 Handler

        nop

        reti                        ;IRQ6 Handler

        nop

        reti                        ;IRQ7 Handler

        nop

        reti                        ;Timer2 Compare Handler

        nop

        reti                        ;Timer2 Overflow Handler

        nop

        reti                        ;Timer1 Capture Handler

        nop

        reti                        ;Timer1 CompareA Handler

        nop

        reti                        ;Timer1 CompareB Handler

        nop

        jmp time1_ovf ;Timer1 Overflow Handler

        reti                        ;Timer0 Compare Handler

        nop

        reti                        ;Timer0 Overflow Handler

        nop

        reti                        ;SPI Transfer Complete Handler

        nop

        reti                        ;USART0 RX Complete Handler

        nop

        reti                        ;USART0 UDR Empty Handler

        nop

        reti                        ;USART0 TX Complete Handler

        nop

        reti                        ;ADC Conversion Complete Handler

        nop

        reti                        ;E2PROM Ready Handler

        nop

        reti                        ;Analog Comparator Handler

        nop

        reti                        ;Timer1 CompareC Handler

        nop

        reti                        ;Timer3 Capture Handler

        nop

        reti                        ;Timer3 CompareA Handler

        nop

        reti                        ;Timer3 CompareB Handler

        nop

        reti                        ;Timer3 CompareC Handler

        nop

        reti                        ;Timer Overflow Handler

        nop

        reti                        ;USART1 RX Complete Handler

        nop

        reti                          ;USART1 UDR Empty Handler

        nop

        reti                        ;USART1 TX Complete Handler

        nop

        reti                        ;Two-wire Serial Interface Handler

        nop

        reti                        ;SPM Ready Handler

        nop               



;程序开始

.org $0046

reset:

        ldi r16,high(RAMEND)                ;设置堆栈指针高位

        out sph,r16

        ldi r16,low(RAMEND)                ;设置堆栈指针低位

        out spl,r16

       

        ser temp                       

        out ddra,temp                                ;设置PORTA为输出,段码输出

        out ddrc,temp                                ;设置PORTC为输出,位码控制

        out portc,temp                        ;PORTC输出$FF, 无显示



        ldi position,0x00                        ;段位初始化为1/100秒低位

        ldi p_temp,0x01                        ;LED第1位亮



;初始化时钟时间为11:59:55:00

        ldi xl,low(time_buff)                ;

        ldi xh,high(time_buff)                ;X寄存器取得时钟单元 首指针

        ldi temp,0x00

        st  x+,temp                                ;1/100秒 = 00

        ldi temp,0x55

        st  x+,temp                                ;秒 = 55

        ldi temp,0x59

        st  x+,temp                                ;分 = 59

        ldi temp,0x11

        st  x,temp                                ;时 = 11



        ldi temp,0xfe                                ;T1初始化,每隔2ms中断一次

        out tcnt1h,temp

        ldi temp,0x0c

        out tcnt1l,temp

        clr temp

        out tccr1a,temp

        ldi temp,0x03                                ;16M,64分频 2ms

        out tccr1b,temp

        ldi temp,0x04

        out timsk,temp                        ;允许T1溢出中断

        sei                                                ;全局中断允许



;主程序

main:

        cpi flag_2ms,0x01                        ;判2ms到否

        brne main                                        ;No,转main循环

        clr flag_2ms                                ;到,请2ms标志

        rcall display                                ;调用LED显示时间(动态扫描显示一位)

d_10ms_ok:

        cpi count_10ms,0x05                ;判10ms到否

        brne main                                        ;No,转main循环

        clr count_10ms                        ;10ms到,清零10ms计数器

        rcall time_add                        ;调用时间加10ms调整

        rcall put_t2d                                ;将新时间值放入显示缓冲单元

        rjmp main                                        ;转main循环



;LED动态扫描显示子程序,2ms执行一次,一次点亮一位,8位循环

display:

        clr r0

        ser temp                                        ;temp = 0x11111111

        out portc,temp                        ;关显示,去消影和拖尾作用

        ldi yl,low(display_buff)

        ldi yh,high(display_buff)        ;Y寄存器取得显示缓冲单元首指针

        add yl,position                        ;加上要显示的位值

        adc yh,r0                                        ;加上低位进位

        ld temp,y                                        ;temp中为要显示的数字

       

        clr r0

        ldi zl,low(led_7 * 2)

        ldi zh,high(led_7 * 2)                ;Z寄存器取得7段码组的首指针

        add zl,temp                                ;加上要显示的数字

        adc zh,r0                                        ;加上低位进位       

        lpm                                        ;读对应七段码到R0中

        out porta,r0                                ;LED段码输出



        mov r0,p_temp

        com r0,

        out portc,r0                        ;输出位控制字,完成LED一位的显示

       

        inc position                        ;调整到下一次显示位

        lsl p_temp

        cpi position,0x08

        brne display_ret

        ldi position,0x00

        ldi p_temp,0x01

display_ret:

        ret



;时钟时间调整,加0.01秒

time_add:

        ldi xl,low(time_buff)        ;

                ldi xh,high(time_buff)        ;X寄存器为时钟单元首指针

                rcall dhm3                        ;ms单元加1调整

                cpi temp,0x99                ;

                brne        time_add_ret        ;未到99ms返回

                rcall dhm                        ;秒单元加1调整

                cpi temp,0x60

                brne        time_add_ret        ;未到60秒返回

                rcall dhm                        ;分单元加1调整

                cpi temp,0x60

                brne time_add_ret                ;未到60分返回

                rcall dhm                        ;时单元加1调整

cpi temp,0x24

     brne time_add_ret                        ;未到24时返回

        clr temp

        st x,temp                                ;到24时,时单元清另

time_add_ret:

        ret



;低段时间清零,高段时间加1,BCD调整

dhm:  clr temp                        ;当前时段清零

dhm1: st  x+,temp                        ;当前时段清零,X寄存器指针加一

dhm3: ld  temp,x                        ;取出新时段数据

      inc temp                  ;加一

      cpi temp,0x0A                ;若个位数码未到$0A(10)

      brhs dhm2                        ;例如$58+1=$59,不须调整;

      subi temp,0xFA                ;否则做减$FA调整:例如$49+1-$FA=$50

dhm2: st x,temp                        ;并将调整结果送回

      ret



;将时钟单元数据送LED显示缓冲单元中

put_t2d:

        ldi xl,low(time_buff)                ;

        ldi xh,high(time_buff)                ;X寄存器时钟单元首指针

        ldi yl,low(display_buff)

        ldi yh,high(display_buff)        ;Y寄存器显示缓冲单元首指针

        ldi count,4                                ;循环次数 = 4

loop:

        ld        temp,x+                                ;读一个时间单元

        mov        temp1,temp

        swap        temp1

        andi        temp1,0x0f                        ;高位BCD码

        andi        temp,0x0f                                ;低位BCD码

        st y+,temp                                ;写入2个显示单元

        st y+,temp1                        ;低位BCD码在前,高位在后

        dec        count

        brne        loop                        ;4个时间单元->8个显示单元

        ret



;T1时钟溢出中断服务

time1_ovf:

        in temp_int,sreg

        push temp_int                                ;保护状态寄存器

       

        ldi temp_int,0xfe                        ;T1初始值设定,2ms中断一次

        out tcnt1h,temp_int

        ldi temp_int,0x0c

        out tcnt1l,temp_int

       

        inc count_10ms                        ;10ms计数器加一

        ldi flag_2ms,0x01                        ;置2ms标志到

       

pop temp_int

        out sreg,        temp_int                        ;恢复状态寄存器

        reti                                                ;中断返回               

       

.CSEG                                        ;LED七段码表,定义在Flash程序空间

led_7:                                        ;7段码表

.db 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07

.db 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71       



;字 PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0 共阴极 共阳极

;        h        g        f        E        d        c        b        a               

;0        0        0        1        1        1        1        1        1        3FH                C0H

;1        0        0        0        0        0        1        1        0        06H                F9H

;2        0        1        0        1        1        0        1        1        5BH                A4H

;3        0        1        0        0        1        1        1        1        4FH                B0H

;4        0        1        1        0        0        1        1        0        66H                99H

;5        0        1        1        0        1        1        0        1        6DH                92H

;6        0        1        1        1        1        1        0        1        7DH                82H

;7        0        0        0        0        0        1        1        1        07H                F8H

;8        0        1        1        1        1        1        1        1        7FH                80H

;9        0        1        1        0        1        1        1        1        6FH                90H

;A        0        1        1        1        0        1        1        1        77H                88H

;b        0        1        1        1        1        1        0        0        7CH                83H

;C        0        0        1        1        1        0        0        1        39H                C6H

;d        0        1        0        1        1        1        1        0        5EH                A1H

;E        0        1        1        1        1        0        0        1        79H                86H

;F        0        1        1        1        0        0        0        1        71H                8EH



.DSEG                                ;定义程序中使用的变量位置(在RAM空间)

.ORG     $0100

display_buff:                        ;LED显示缓冲区,8个字节

.BYTE        0x00                        ;LED 1 位显示内容

.BYTE        0x00                        ;LED 2 位显示内容

.BYTE        0x00                        ;LED 3 位显示内容

.BYTE        0x00                        ;LED 4 位显示内容

.BYTE        0x00                        ;LED 5 位显示内容

.BYTE        0x00                        ;LED 6 位显示内容

.BYTE        0x00                        ;LED 7 位显示内容

.BYTE        0x00                        ;LED 8 位显示内容



.org        $0108

time_buff:                        ;时钟数据缓冲区,4个字节

.BYTE        0x00                        ;1/100s单元

.BYTE        0x00                        ;秒单元

.BYTE        0x00                        ;分单元

.BYTE        0x00                        ;时单元



  该程序实例采用规范标准的设计理念和风格,程序中已给出比较详细的注解。关于程序如何具体完成和实现系统的功能请读者仔细阅读程序,用心体会。下面仅对编写ATmega128汇编程序时,在结构和语句使用上一些需要注意的方面加以介绍。

1.将程序中操作最频繁以及需要特殊位处理的变量定义在AVR的32个工作寄存器空间,因为MCU对R0-R31的操作仅需要一个时钟周期,而且功能强大。由于R0-R31的功能有不同,而且也仅有32个,所以程序员应认真考虑和规划这32个工作寄存器的使用。如尽量不要将变量放置在R26-R31中,因为这6个寄存器构成3个16位的X、Y、Z地址指针寄存器,应保留用于各种寻址使用。

2.ATmega128有35个中断源,Flash程序存储器的低段空间为这35个中断向量地址。由于ATmega128的程序存储器空间为64K字,所以与其它AVR不同的是,ATmega128的一个向量地址空间为2个字长度,在中断向量处应使用长转移指令jmp转移到中断服务程序,而一般的AVR的一个向量地址空间为1个字长度,使用rjmp转移指令。出于提高系统可靠性的设计,对于系统不使用的中断向量,应填充2个中断返回指令reti(每个reti占一个字)。在本程序中,为了程序的理解和阅读方便,使用了reti和nop指令填充一个2个字长度的向量地址空间。

3.程序中使用X、Y、Z三个16位的地址指针寄存器,基于他们的一些指令有自动加(减)一的功能,以及先加(减)、后使用,和先使用、后加(减)的区别,在使用中应注意正确和灵活的使用。

4.由于LED的七段码对照表是固定不变的,程序中将LED的七段码表放置在Flash存储器中。对于Flash存储器的间址取数只能使用Z寄存器。由于程序存储器的地址是以字(双字节)为单位的,因此,16位地址指针寄存器Z的高15位为程序存储器的字地址,最低位LSB为“0”时,指字的低字节;为“1”时,指字的高字节。程序中使用伪指令db定义的七段码为一个字节,他保存在一个字的低字节处。如果定义字,应使用伪指令dw。

本例使用指令lpm读取Flash中的一个字节,因此在取七段码表的首地址时乘2(ldi zl,low(led_7 * 2)),将地址左移一位,Z寄存器的LSB为“0”,表示取该字的低位字节。

指令lpm能寻址的程序存储器空间为低64K字节的页(32k字),因此如果常量表的位置处在高64字节的页中,请使用指令elpm。详细的指令功能见3.4.3的内容。

5.中断服务程序中,必须对MCU的标志寄存器SREG进行保护。在T1的溢出中断服务程序中,还需要对TCNT1的初值进行设置,以保证下一次中断仍为2ms。中断服务程序应尽量短小,因此在中断服务中,只将2ms标志置位和10ms加一计数,其它处理应尽量放在主程序中。

6.程序中定义了8个字节的显示缓冲区和4个字节的时钟数据缓冲区,分别存放8个LED所对应的显示数字和4个时间段的时间值(BCD码),这12个单元定义放置在ATmega128的RAM中。ATmega128的RAM单元应从0x0100开始,前面的地址分别对应的是32个工作寄存器、I/O寄存器、扩展I/O寄存器,因此不要把一般的数据单元定义在小于0x0100的空间(参见2.2.2,RAM空间分配)。

7.与使用db或dw伪指令在Flash空间定义常量不同的是,在RAM空间予留变量空间的定义应使用byte伪指令。byte伪指令的功能是定义变量的位置(予留空间),不能定义(填充)变量的值,变量具体的值是需要由程序在运行中写入的。而伪指令db、dw具有数据位置和值定义(填充)的功能。

出0入0汤圆

发表于 2005-2-18 01:09:25 | 显示全部楼层
从当AVR菜鸟的那一天起就没想编AVR汇编,但学学没坏处,至少调试时需要,或看别人的范例后再移植到C。

出0入0汤圆

 楼主| 发表于 2005-2-18 02:11:36 | 显示全部楼层
知道PIC的张XX吧?他是21IC中PIC的版主(现已离开PIC了),可称的上高手了。他曾经有一句话,“我坚持认为,如果你对单片机的汇编语言和内部结构根本不了解,请先不要用C语言编程”

   对此我深有同感,而且还要再加一句:如果你对单片机的汇编语言和内部结构根本不了解,根本就写不出好的单片机的C程序。
头像被屏蔽

出0入0汤圆

发表于 2005-2-18 08:39:32 | 显示全部楼层
谢谢。迟点整理入网站中。

出0入0汤圆

发表于 2005-2-18 08:58:10 | 显示全部楼层
哈哈,张教主是我的好网友。



本人也三十生有幸得到张工赠本人亲笔签名新书一本

出0入0汤圆

发表于 2005-2-18 14:01:35 | 显示全部楼层
先睹为快,太谢谢啦

出0入0汤圆

发表于 2005-2-23 17:34:30 | 显示全部楼层
马老师,有几个问题:

1、在AVR汇编中诸如 RAMEND、SRAM_SIZE 这样的特殊保留字是否有什么书或者文档有过总结性的统一说明,因为实在太多了,好象应该存在一个总结列表的吧。

2、还有关于AVR的汇编语言,伪指令有没有什么资料详细的说明了用法,感觉现在的书似乎都不是很全。

3、宏汇编我从来没用过,有什么地方可以学习的吗,是不是需要编译器的特殊支持呢。

出0入0汤圆

发表于 2005-4-11 10:55:10 | 显示全部楼层
"如果你对单片机的汇编语言和内部结构根本不了解,根本就写不出好的单片机的C程序。"

當然,要成為高手就必要!

但對時序要求不高的程序, 用c寫並沒什麼問題!

出0入0汤圆

发表于 2005-4-11 12:16:26 | 显示全部楼层
在中断程序中给T1送定时数,那在中断程序发生到送数可是要损失几个us,这样看来,24小时的误差可不小啊!

出0入0汤圆

 楼主| 发表于 2005-4-11 14:50:51 | 显示全部楼层
这仅仅是一个用于学习和使用汇编的例子,如果要精度高一些的话,T1可工作于自动重装的模式。



    如果在实际的产品中需要精度高的时钟,我一般采用外扩专用的时钟芯片,如DS1302等。就是这样,你实际看到的时间也是比真正的时间晚,因为读到时间到显示也需要时间的。

出0入0汤圆

发表于 2005-4-11 15:19:29 | 显示全部楼层
DFSDAF

出0入0汤圆

发表于 2005-4-11 15:26:48 | 显示全部楼层
说的有理,不过以前见到PIC的张斑竹有一个好办法:对t0分频后让它自由的从0x00到0xff运行,比如这样每次中断时间为512us,设一个计数器counter,每次中断counter+=512;然后判断counter是否大于50ms,如果是则counter-=500000,然后对50ms计数,这样虽然50ms有误差,但误差被保存在counter中,所以长时间跨度的计时很精确,因为理论上没有任何损失。这个方法对pic适合,对avr是一样的。

再问一个问题,在pic中对t0赋值会让t0在接下来的2个时钟周期内停止运行,avr呢?在M16的手册中没有发现,请马老师确认一下,谢谢!

出0入0汤圆

 楼主| 发表于 2005-4-11 22:55:57 | 显示全部楼层
不要钻这些“牛角”。实际上你的系统时钟就有误差,4M的误差是多少?

出0入0汤圆

发表于 2005-4-13 22:50:18 | 显示全部楼层
这可不是钻“牛角”哦,事实上你的写法作为程序的钟摆tick是没有问题的,但有些应用需要停机后过5到6小时开机(这是我在实际应用中碰到的),这样的误差可是要考虑的,不然用户不一定会满意地。就像你不一定会在程序中用到((void(code *)(void))0x0000)();这样地写法,但是要知道这是怎么一回事,千万不要看到头晕。

一点意见,仅供参考。出差刚回,回帖稍晚见谅。

出0入0汤圆

发表于 2005-4-14 06:38:08 | 显示全部楼层
请问马老师:

在T1初始化时,一般先有个CLI,然后初始化结束后才用SEI。本例中只有初始化结束后用SEI。是不是默认是CLI,所以省略。

出0入0汤圆

 楼主| 发表于 2005-4-15 02:01:46 | 显示全部楼层
复位上电时,I初始化为0,手册中清请楚楚的写着。你应该先看手册,养成好的习惯。

出0入0汤圆

发表于 2005-4-21 10:31:32 | 显示全部楼层
马老师,发布一些C语言的例子吧

出0入0汤圆

 楼主| 发表于 2005-4-21 13:21:34 | 显示全部楼层
在我贴上的讲稿中有一些基本的C的例子,专栏里也有,如关于USART、I2C的等。



   如:一个AVR USART(RS232)低层驱动+中间层软件示例, 使用AVR定时/计数器的PWM功能设计要点,自引导IAP(boot load)的应用设计--armok转贴,AVR 串行接口SPI接口应用设计(主机方式)--(修改重发) 。
-----此内容被machao于2005-04-21,13:25:56编辑过

出0入0汤圆

发表于 2008-6-14 00:41:04 | 显示全部楼层
深有同感,只可惜本论坛汇编相关内容太少了,现代人更应该踏实。

出0入0汤圆

发表于 2008-6-14 00:56:22 | 显示全部楼层
以下程序,我仅使用TIMER0溢出中断,来作为系统时钟节拍。PORTB5接LED用于闪烁,软件仿真是通过了,而写入芯片48时,LED总是灭的,请教一下,什么原因。程序稍长,不过比较简单。还有子程序TIMER_PRESCALE_SYN_PROC(GTCCR设置)时钟同步不知用得对不对。


;===============================================
;文件: temperature
;微控: atmel atmega48
;日期: 2008-02-17
;===============================================

#include "m48def.inc"
#include "test_avr.inc"
.device atmega48
;.EQU        TEST_UNIT                =        0                                ;单元测试
;.EQU        TEST_LED_ALL_DISP        =        1                                ;测试LED显示
;.EQU        TEST_NUM_DISP                =        2                                ;测试LED数字显示
;.EQU        TEST_TIMER0_OVF0        =        3                                ;测试TIMER0溢出中断
;.EQU        TEST_TIMER1_OVF1        =        4                                ;测试TIMER1溢出中断
;.EQU        TEST_TIMER2_OVF2        =        5                                ;测试TIMER2溢出中断
;.EQU        TEST_ADC                =        6                                ;测试ADC转换值


.EQU        TEST_DELAY_CONST        =        0xff




.dseg

.cseg
    .org        RSTaddr
    rjmp        START
    .org        INT0addr
        rjmp        NO_USE_INT_PROC  
    .org        INT1addr
    rjmp        NO_USE_INT_PROC  
    .org        PCI0addr
    rjmp        NO_USE_INT_PROC         
    .org        PCI1addr       
    rjmp        NO_USE_INT_PROC
    .org        PCI2addr       
    rjmp        NO_USE_INT_PROC
    .org        WDTaddr               
    rjmp        NO_USE_INT_PROC
    .org        OC2Aaddr
        rjmp        NO_USE_INT_PROC       
    .org        OC2Baddr
        rjmp        NO_USE_INT_PROC       
    .org        OVF2addr       
        rjmp        NO_USE_INT_PROC
    .org        ICP1addr       
        rjmp        NO_USE_INT_PROC
    .org        OC1Aaddr       
        rjmp        NO_USE_INT_PROC
    .org        OC1Baddr       
        rjmp        NO_USE_INT_PROC
    .org        OVF1addr       
        rjmp        NO_USE_INT_PROC
    .org        OC0Aaddr       
        rjmp        NO_USE_INT_PROC
    .org        OC0Baddr
        rjmp        NO_USE_INT_PROC       
    .org        OVF0addr       
        rjmp        TIMER0_OVF0_PROC
    .org        SPIaddr               
    rjmp        NO_USE_INT_PROC
    .org        URXCaddr       
    rjmp        NO_USE_INT_PROC
    .org        UDREaddr       
    rjmp        NO_USE_INT_PROC
    .org        UTXCaddr       
    rjmp        NO_USE_INT_PROC
    .org        ADCCaddr       
        rjmp        NO_USE_INT_PROC
    .org        ERDYaddr       
    rjmp        NO_USE_INT_PROC
    .org        ACIaddr               
    rjmp        NO_USE_INT_PROC
    .org        TWIaddr               
    rjmp        NO_USE_INT_PROC
    .org        SPMRaddr                                                ;0x0019
    rjmp        NO_USE_INT_PROC
   
;================================
;未使用中断统一处理
;================================
NO_USE_INT_PROC:
        nop
        nop
        nop
    reti

;================================
;TIMER0 溢出中断
;================================
TIMER0_OVF0_PROC:
        push r31                                                ;push Z REG
        push r30
        push r29            ;push Y REG
        push r28
        push r27            ;push X REG
        push r26
        push r18            ;SREG TMP
        push r17
        push r16
       
        in   r18,SREG
       
        clr  XH
        ldi  XL,TIMER_INT_FLAG ;设置TIMER0中断发生标志寄存器
        ori  r16,0xc0
        st   X,r16

        out  SREG,r18
       
        pop  r16
        pop  r17
        pop  r18
        pop  r26
        pop  r27
        pop  r28
        pop  r29
        pop  r30
        pop  r31         
    reti





        .org PROGaddr                                                 ;0x0030

START:
        cli                                                                        ;禁止全局中断
        ldi          r16,0xff                                        ;设置系统堆栈
        out          SPL,r16        

        sbi                DDRB,0x2

        rcall        CLK_CHG_DLY                             ;系统延时
    rcall        SYS_CLK_INIT                ;系统时钟初始化
        rcall        SYS_SET_INIT                                ;系统设置初始化
        rcall        LED_IO_CTRL_INIT                        ;LED控制IO初始化
        rcall        LED_DISP_LIGHT                                ;显示全点亮
        rcall        START_LED_DISP_DLY                        ;保持LED全亮0.5秒
        rcall        LED_SR_CTRL_INIT                        ;LED控制寄存器初始化
        rcall        TIMER_PRESCALE_SYN_PROC                ;时钟分频同步   
        rcall        TIMER0_INIT_PROC                        ;系统时钟.8.2ms
;        rcall        TIMER_PRESCALE_SYN_PROC                ;时钟分频同步
        sei                                                                        ;开全局中断

        ldi  XL,TEMPERATURE_TIME_SRL
        ldi  r16,0x0F
        st   X,r16
        ldi  XL,TEMPERATURE_TIME_SRH
        ldi  r17,0x01
        st         X,r17

        clr  r19
        clr  r20

        sbi  DDRB,5
        cbi  PORTB,5


MAINLOOP:
        rcall DELAY_COMMON

        ldi  XL,TEMPERATURE_TIME_SRL
        ld   r16,X
        ldi  XL,TEMPERATURE_TIME_SRH
        ld   r17,X
        or   r16,r17
        cpi  r16,0x00
        breq MLOOP1

        rjmp MAINLOOP

MLOOP1:
        ldi  XL,TEMPERATURE_TIME_SRL
        ldi  r16,0x0F
        st   X,r16
        ldi  XL,TEMPERATURE_TIME_SRH
        ldi  r17,0x01
        st         X,r17

        cpi         r19,0x00
        breq  MLOOP2

        clr  r19

        sbi  DDRB,5
        sbi  PORTB,5

        rjmp  MAINLOOP

MLOOP2:
        ldi  r19,0x08

        cbi  PORTB,5
        nop
        nop
        nop
        rjmp  MAINLOOP

       
;=======================================
;    定时器分频同步
;
;=======================================
TIMER_PRESCALE_SYN_PROC:
        ldi   r16,0x00                                        ;
        sts   GTCCR,r16
        ret



;=======================================
;公用延时程序
;产生一次TIMER0中断,TEMPERATURE_TIME_SR减1
;=======================================
DELAY_COMMON:
        clr  XH
        ldi  XL,TIMER_INT_FLAG
        ld   r16,X
        andi r16,0x80                                                ;高两位为TIMER0中断置位标志
        cpi  r16,0x00
        brne DELAY_COMMON_GO
DELAY_COMMON_END:
        ret

DELAY_COMMON_GO:
        andi  r16,0x7f
        st          X,r16


DELAY_COMMON_B:
        ldi  XL,TEMPERATURE_TIME_SRL
        ld   r16,X
        ldi  XL,TEMPERATURE_TIME_SRH
        ld   r17,X
        or   r16,r17
        cpi  r16,0x00
        breq DELAY_COMMON_C
        ldi  XL,TEMPERATURE_TIME_SRL
        ld   r16,X
        subi r16,0x01
        brcs DELAY_COMMON_B_1
        st   X,r16
        rjmp DELAY_COMMON_C
       
DELAY_COMMON_B_1:
        st   X,r16
        dec  r17
        ldi  XL,TEMPERATURE_TIME_SRH
        st   X,r17
       
DELAY_COMMON_C:
        nop
        nop
        ret





   





               
;========================================
;           系统初始化程序
;
;说明: 系统功能初始化,INT,WDT,IO,SRAM,
;      EEPROM,SLEEP...
;========================================
SYS_SET_INIT:
        rcall SYS_INT_INIT
        rcall SYS_WDT_INIT
        rcall SYS_IO_INIT
        rcall SYS_SRAM_INIT
        rcall SYS_EEPROM_INIT
        rcall SYS_OTHER_CSR_INIT
        rcall SYS_SLEEP_INIT
        ret
;---------------------------------
;系统其它部分初始化看门狗,无看门狗
SYS_WDT_INIT:
        ldi  r16,0x00
        sts  WDTCSR,r16
        ret

;---------------------------------
;系统睡眠初始化
SYS_SLEEP_INIT:
        ret

;---------------------------------
;选用内部时钟,下载时设置,8MHz;
SYS_CLK_INIT:
        ldi  r16,SYS_CLK_CALIBRATE
        sts  OSCCAL,r16
        ldi  r16,0x80
        sts  CLKPR,r16                                ;EXCLK 8M,Prescale = 0
        ret




;=============================================
;          【定时器0初始化子程序】
;
;说明: TIMER0使用溢出中断,作为系统时钟,时钟
;      为8毫秒,不与OCR0A,OCR0B连接,分频256,
;      初始值:0x00,递加.
;=============================================
TIMER0_INIT_PROC:
        ldi  r16,0x00                       ;不与OCR0A,OCR0B相接
        out  TCCR0A,r16                    
    ldi  r16,0x05                                ;0x04:256分频        0x05:1024分频                 
        out  TCCR0B,r16                    
                                       
        ldi  r16,0x00                       ;清零计数器
        out  TCNT0,r16                     
                                       
        lds  r16,TIMSK0                                ;使能TIMER0溢出中断
        andi r16,0xf8                      
        ori  r16,0x01                      
        sts  TIMSK0,r16                    
                                           
        ldi  r16,0x00                                ;清零TIMER0中断标志位
        out  TIFR0,r16                     
                                       
        ldi  r16,0xff                      
        out  OCR0A,r16                      ;初始化比较计存器A
        out  OCR0B,r16                                ;初始化比较计存器B       

        ret



;======================================
;      系统其它控制寄存器初始化
;
;说明: 未使用功能,全部禁止
;======================================
SYS_OTHER_CSR_INIT:
        ldi  r16,0xc0                        ;不使用睡眠模式
        sts  SMCR,r16
       
        lds  r16,EICRA                        ;INT0,INT1中断触发方式
        andi r16,0x0f
        sts  EICRA,r16
       
        in  r16,EIMSK               ;屏蔽INT0,INT1
        andi r16,0x03
        out  EIMSK,r16
       
        in  r16,EIFR                        ;清除INT0,INT1中断标志寄存器
        andi r16,0x03
        out  EIFR,r16
       
        lds  r16,PCICR              ;禁止引脚电平变化中断
        andi r16,0x03              
        sts  PCICR,r16             
                                   
        in  r16,PCIFR               ;清除引脚电平变化中断
        andi r16,0x03
        out  PCIFR,r16
       
        lds  r16,PCMSK2             ;禁止PCINT16~PCINT23电平变化中断
        andi r16,0x00              
        sts  PCMSK2,r16            
                                   
        lds  r16,PCMSK1             ;禁止PCINT8~PCINT14电平变化中断
        andi r16,0x80              
        sts  PCMSK1,r16            
                                   
        lds  r16,PCMSK0             ;禁止PCINT0~PCINT7电平变化中断
        andi r16,0x00
        sts  PCMSK0,r16
       
        in   r16,SPCR                        ;禁止SPI中断
        andi r16,0x7f
        out  SPCR,r16
       
        in   r16,SPCR                        ;禁止SPI功能
        andi r16,0xbf
        out  SPCR,r16
       
        in   r16,SPCR                        ;使用MSB首发
        andi r16,0xdf
        out  SPCR,r16
       
        in   r16,SPCR                        ;先定主机
        ori  r16,0x10
        out  SPCR,r16
       
        in   r16,SPCR                        ;上升沿
        andi r16,0xf7
        out  SPCR,r16
       
        in   r16,SPCR                        ;起始沿采样
        andi r16,0xfb
        out  SPCR,r16
       
        in   r16,SPCR                        ;fosc/4
        andi r16,0xf8
        out  SPCR,r16
       
        in   r16,SPSR                        ;清除中断标志,碰撞位,倍速位
        andi r16,0x00
        out  SPSR,r16
       
        in   r16,SPDR                        ;清零SPI发送数据
        andi r16,0x00
        out  SPDR,r16
;--------------------
        lds  r16,UCSR0B                        ;禁止发送,接收,空,中断
        andi r16,0x00
        sts  UCSR0B,r16
       
        lds  r16,UCSR0C                        ;使用异步,禁止校验,1字节停止位,5位长度
        andi r16,0x0
        sts  UCSR0C,r16
       
        lds  r17,UBRR0H                        ;设置波特率
        andi r17,0x00
        lds  r16,UBRR0L
        andi r16,0x00
        sts  UBRR0H,r17
        sts  UBRR0L,r16
       
        lds  r16,UCSR0A                        ;
        andi r16,0x00
        sts  UCSR0A,r16
       
;---------------------
        lds  r16,TWCR                        ;
        andi r16,0x00
        sts  TWCR,r16
       
        lds  r16,TWSR
        andi r16,0x00
        sts  TWSR,r16
       
        lds  r16,TWDR
        andi r16,0x00
        sts  TWDR,r16
       
        lds  r16,TWAR
        andi r16,0x00
        sts  TWDR,r16
       
        lds  r16,TWAMR
        andi r16,0x00
        sts  TWAMR,r16
       
        ret
       
;======================================
;系统其它部分初始化
;======================================
SYS_OTHER_INIT:
        ldi  r16,0x00
        sts  MCUSR,r16
        ret
       
;======================================
;           系统SRAM初始化
;======================================
SYS_SRAM_INIT:
        ret

;====================================
;           EEPROM初始化
;====================================
SYS_EEPROM_INIT:
        ret

;====================================
;          系统中断初始化
;====================================
SYS_INT_INIT:
        ret

;====================================
;          系统端口初始化
;说明: 设置所有GPIO全部为输入口
;====================================
SYS_IO_INIT:
        lds  r16,MCUCR                                ;使能上拉功能
        ori  r16,0x10
        sts  MCUCR,r16
       
        ldi  r16,0x00
        out  DDRB,r16
        out  PORTB,r16
        out  PINB,r16
        out  DDRC,r16
        out  PORTC,r16
        out  PINC,r16
        out  DDRD,r16
        out  PORTD,r16
        out  PIND,r16
       
        ret       
       

;----------------------------------
;改变系统时钟,加入延时以待其工作稳定

CLK_CHG_DLY:
        ldi  r16,0x80

DLY_XX:
        ldi  r17,0xff
       
DLY_XX1:
        mov         r17,r17
        brcc DLY_XX2
        dec  r17
        rjmp  DLY_XX1
DLY_XX2:
        mov         r16,r16
        brcc DLY_XX3
        dec  r16
        rjmp  DLY_XX

DLY_XX3:
        ret



        .eseg       
        .exit

出0入0汤圆

 楼主| 发表于 2008-6-14 12:47:08 | 显示全部楼层
建议楼上的先写小的程序,一口一口的吃饭.比如,怀疑TIMER0有问题,就专门写个测试TIMER0的代码.然后逐步把要的东西加上去,这样容易发现问题出在什么地方.

出0入0汤圆

发表于 2008-6-15 01:09:32 | 显示全部楼层
实质上更怀疑的是端口设置有问题.

出0入0汤圆

发表于 2009-6-4 18:53:15 | 显示全部楼层
菜鸟想知道《M128》是什么书啊 谢谢啊

出0入0汤圆

发表于 2009-10-7 13:41:08 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-10-9 00:53:37 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-12-25 13:44:40 | 显示全部楼层
ji

出0入0汤圆

发表于 2010-2-20 23:02:09 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-6-13 15:53:51 | 显示全部楼层
ldi zl,low(led_7 * 2)
  ldi zh,high(led_7 * 2)
跪求!这句的怎样实现ed_7数组的各个数取出的?还有程序中X Z代表什么意思呀?又是那些值呢?

出0入0汤圆

发表于 2012-10-26 09:03:19 | 显示全部楼层
学习了……………………

出0入0汤圆

发表于 2013-11-20 14:21:30 | 显示全部楼层
路过的
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-18 09:34

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表