AVR汇编百例 - 实用程序
- 格式:doc
- 大小:74.00 KB
- 文档页数:10
系统使用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 $0000jmp reset ;复位处理reti ;IRQ0 Handlernopreti ;IRQ1 Handlernopreti ;IRQ2 Handlernopreti ;IRQ3 Handlernopreti ;IRQ4 Handlernopreti ;IRQ5 Handlernopreti ;IRQ6 Handlernopreti ;IRQ7 Handlernopreti ;Timer2 Compare Handlernopreti ;Timer2 Overflow Handlernopreti ;Timer1 Capture Handlernopreti ;Timer1 CompareA Handlernopreti ;Timer1 CompareB Handlernopjmp time1_ovf ;Timer1 Overflow Handlerreti ;Timer0 Compare Handlernopreti ;Timer0 Overflow Handlernopreti ;SPI Transfer Complete Handlernopreti ;USART0 RX Complete Handlernopreti ;USART0 UDR Empty Handlernopreti ;USART0 TX Complete Handlernopreti ;ADC Conversion Complete Handler nopreti ;E2PROM Ready Handlernopreti ;Analog Comparator Handlernopreti ;Timer1 CompareC Handlernopreti ;Timer3 Capture Handlernopreti ;Timer3 CompareA Handlernopreti ;Timer3 CompareB Handlernopreti ;Timer3 CompareC Handlernopreti ;Timer Overflow Handlernopreti ;USART1 RX Complete Handlernopreti ;USART1 UDR Empty Handlernopreti ;USART1 TX Complete Handlernopreti ;Two-wire Serial Interface Handlernopreti ;SPM Ready Handlernop;程序开始.org $0046reset:ldi r16,high(RAMEND) ;设置堆栈指针高位out sph,r16ldi r16,low(RAMEND) ;设置堆栈指针低位out spl,r16ser tempout 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:00ldi xl,low(time_buff) ;ldi xh,high(time_buff) ;X寄存器取得时钟单元首指针ldi temp,0x00st x+,temp ;1/100秒 = 00ldi temp,0x55st x+,temp ;秒 = 55ldi temp,0x59st x+,temp ;分 = 59ldi temp,0x11st x,temp ;时 = 11ldi temp,0xfe ;T1初始化,每隔2ms中断一次out tcnt1h,templdi temp,0x0cout tcnt1l,tempclr tempout tccr1a,templdi temp,0x03 ;16M,64分频 2msout tccr1b,templdi temp,0x04out 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 r0ser temp ;temp = 0x11111111out portc,temp ;关显示,去消影和拖尾作用ldi yl,low(display_buff)ldi yh,high(display_buff) ;Y寄存器取得显示缓冲单元首指针add yl,position ;加上要显示的位值adc yh,r0 ;加上低位进位ld temp,y ;temp中为要显示的数字clr r0ldi 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_tempcom r0,out portc,r0 ;输出位控制字,完成LED一位的显示 inc position ;调整到下一次显示位lsl p_tempcpi position,0x08brne display_retldi position,0x00ldi p_temp,0x01display_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,0x60brne time_add_ret ;未到60秒返回rcall dhm ;分单元加1调整cpi temp,0x60brne time_add_ret ;未到60分返回rcall dhm ;时单元加1调整cpi temp,0x24brne time_add_ret ;未到24时返回clr tempst 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 ;循环次数 = 4loop:ld temp,x+ ;读一个时间单元mov temp1,tempswap temp1andi temp1,0x0f ;高位BCD码andi temp,0x0f ;低位BCD码st y+,temp ;写入2个显示单元st y+,temp1 ;低位BCD码在前,高位在后dec countbrne loop ;4个时间单元->8个显示单元ret;T1时钟溢出中断服务time1_ovf:in temp_int,sregpush temp_int ;保护状态寄存器ldi temp_int,0xfe ;T1初始值设定,2ms中断一次out tcnt1h,temp_intldi temp_int,0x0cout tcnt1l,temp_intinc count_10ms ;10ms计数器加一ldi flag_2ms,0x01 ;置2ms标志到pop temp_intout 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 $0100display_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 $0108time_buff: ;时钟数据缓冲区,4个字节.BYTE 0x00 ;1/100s单元.BYTE 0x00 ;秒单元.BYTE 0x00 ;分单元.BYTE 0x00 ;时单元该程序实例采用规范标准的设计理念和风格,程序中已给出比较详细的注解。
;范例62.ORG $A00EXCH: MOV R5,R8 ;两浮点数交换子程序MOV R8,R12MOV R12,R5EXCH1: MOV R5,R9 ;尾数交换MOV R9,R13MOV R13,R5MOV R5,R10 ;双字节交换MOV R10,R14MOV R14,R5MOV R5,R11MOV R11,R15MOV R15,R5RETDP: ANDI R16,$7F ;处理积/商数符,计算积/商阶码子程序SBRC R9,7SUBI R16,$80SBRC R13,7SUBI R16,$80 ;积/商符号放在r16,7ADD R12,R8 ;移码相加(除数阶码已求补)LDI R17,$80BRCC DP1ADD R12,R17 ;移码求和有进位,将和再加上$80,再有进位为溢出RETDP1: SUB R12,R17 ;移码求和无进位,将和减去$80,有借位RET ;或差为0也为溢出NEG3: COM R15 ;3字节数据求补COM R14 ;先求反后加1COM R13INC3: LDI R17,255SUB R15,R17 ;以减去-1代替加1SBC R14,R17SBC R13,R17RET;范例63 ;浮点数比较大小子程序X1为被减数X2为减数FPCP: SBRC R9,7 ;X1为正,跳行RJMP CP1SBRC R13,7 ;X2为正,跳行RJMP CP2 ;X1,X2异号FPCP1: CP R11,R15 ;X1,X2皆为正,以尾数低位字节,中位字节,高位字节和CPC R10,R14 ;阶码的顺序(按无符号数)进行比较CPC R9,R13 ;不等,阶码大者浮点数值也大;只有阶码和尾数对应相等,CPC R8,R12 ;两浮点数才相等RET ;比较结果:Z=1时X1=X2,否则C=0时X1>X2,C=1时X1<X2 CP1: SBRC R13,7RJMP CP3 ;两负数比较,转CP2: CP R13,R9 ;正数与负数比较,只比较尾数高位字节即可RETCP3: CP R15,R11 ;X1,X2皆为负,以尾数低位字节,中位字节,高位字节和CPC R14,R10 ;阶码的顺序(按无符号数)进行比较CPC R13,R9 ;但要将X1、X2交换位置后按正数比较过程进行CPC R12,R8CP4: RET ;比较结果:Z=1时X1=X2,否则C=0时X1>X2,C=1时X1<X2;范例64FPSU: LDI R17,$80 ;浮点减法子程序SUB R13,R17 ;减数数符求反后作为加数FPAD: TST R8 ;浮点加法子程序BREQ DON1 ;被加数为0,加数为和TST R12BRNE FPLAD ;加数为0,取被加数为和SA V0: MOV R12,R8 ;传送被加数取代加数MOV R13,R9MOV R14,R10MOV R15,R11DON1: RETFPLAD: ANDI R16,$3f ;清除被加数,加数数符SBRC R9,7ORI R16,$80 ;被加数数符取到(R16,7)SBRC R13,7ORI R16,$40 ;加数数符取到(R16,6)LDI R17,$80OR R9,R17OR R13,R17 ;恢复尾数最高位MOV R17,R12SUB R17,R8 ;计算阶差BREQ GOON ;两阶相等,转BRCC NX3NEG R17 ;不够减求补CPI R17,24BRCC EXAD ;|阶差|>24,取被加数为和NX2A: LSR R13ROR R14ROR R15BRNE NX2A ;加数阶小,右移加数对阶MOV R12,R8 ;取被加数阶为和之阶BRCC GOONRCALL INC3 ;舍入移出位RJMP GOONNX3: CPI R17,24BRCC COM1 ;阶差>24,取加数为和LOOP: LSR R9ROR R10ROR R11DEC R17BRNE LOOP ;加数阶大,右移被加数对阶BRCC GOONRCALL INC3A ;舍入移出位GOON: SBRC R16,6SUBI R16,$80SBRS R16,7 ;判别两数是否同号RJMP SAMS ;同号转SUB R15,R11 ;异号,执行减法,加数为被减数SBC R14,R10SBC R13,R9BRCC NOM ;够减转SUBI R16,$40 ;否则被减数数符求反为和之数符RCALL NEG3 ;并将差求补NOM: MOV R17,R13OR R17,R14OR R17,R15BREQ DON0 ;差为0转NMLOP: SBRC R13,7RJMP COM1LSL R15ROL R14ROL R13DEC R12BRNE NMLOP ;规格化OV1: SEV ;阶码变为0,下溢(可取为0,不算溢出)RETSAMS: ADD R15,R11ADC R14,R10ADC R13,R9 ;两数同号,执行加法BRCC COM1ROR R13ROR R14INC R12 ;有进位时右规1次($7F+1=$80溢出)BREQ OV1 ;阶码增1后变为0为上溢BRNC COM1RCALL INC3COM1: CLVSBRC R16,6RETCOMA: LDI R17,$7FAND R13,R17 ;正数数符为0DON: RETEXAD: RCALL SA V0 ;取被加数为和SBRS R16,7RJMP COMA ;配置数符RETDON0: CLR R12 ;浮点数为0RET;范例65 ;浮点乘法子程序FPMU: TST R8BREQ M0 ;被乘数为0,积为0TST R12BRNE M1 ;乘数为0,积也为0M0: RJMP G0M1: RCALL DP ;处理积符号,计算积之阶码BRCS OV2BREQ OV2 ;判断溢出LDI R17,$80OR R9,R17OR R13,R17 ;恢复尾数最高位MOV R5,R13MOV R6,R14MOV R7,R15 ;乘数转入R5,R6,R7LDI R17,25 ;设右移部分积次数CLR R13CLR R14CLR R15 ;r13r14r15清除,存放积CLCLOOP1: BRCC M2ADD R15,R11ADC R14,R10ADC R13,R9 ;乘数右移移出位为1,被乘数加入部分积1次M2: ROR R13ROR R15ROR R5ROR R6ROR R7 ;部分积连同乘数右移1位DEC R17BRNE LOOP1 ;尾数相乘计算完成?SBRC R13,7RJMP M3 ;乘积最高位为1 转ROL R5ROL R15ROL R14ROL R13 ;乘积最高位为0,高4位字节左移1位SBRS R5,7RJMP M5RCALL INC3 ;末位字节舍入BRNE M5SEC ;舍入后R13变为0ROR R13 ;将其改为$80(即0.5)RJMP COM2M5: DEC R12 ;舍入后R13不为0BRNE COM2 ;阶码减1OV2: SEV ;变为0为溢出RETM3: SBRC R5,7RCALL INC3 ;乘积低3位字节舍入COM2: LDI R17,$7FSBRS R16,7AND R13,R17 ;正数将符号位请除DON2: CLVRET;范例66FPDI: TST R12 ;浮点除法子程序BREQ OV3 ;除数为0,溢出TST R8BRNE D1RJMP G0 ;被除数为0,商为0D1: NEG R12 ;除数阶码求补,以加补码代替减原码RCALL DP ;处理商符号,计算商之阶码BRCS OV3BREQ OV3 ;判断溢出LDI R17,$80OR R9,R17OR R13,R17 ;恢复尾数最高位FPD3: LDI R17,25 ;左移相减试商25次,最后1次舍入SUB R11,R15SBC R10,R14SBC R9,R13BRCS D2 ;第一次尾数相减试商INC R12 ;够减,商阶增1SECBRNE D3 ;商阶增1后不为0,转计商;否则为溢出OV3: SEVRETD2: ADD R11,R15ADC R10,R14ADC R9,R13 ;不够减则恢复被除数LOOP2: LSL R11ROL R10ROL R9 ;被除数算术左移BRCS D4 ;进位位为1,够减,本位商1SUB R11,R15SBC R10,R14SBC R9,R13 ;否则相减试商BRCS D2ASECRJMP D3 ;够减,本位商1D2A: ADD R11,R15 ;不够减,恢复被除数ADC R10,R14ADC R9,R13CLC ;本位商0RJMP D3D4: SUB R11,R15SBC R10,R14SBC R9,R13 ;被除数减去除数D3: DEC R17BRNE D5 ;除法未完成,循环(1-1=0,不溢出)MOV R13,R5MOV R14,R6MOV R15,R7 ;取回商BRCC COM3RCALL INC3 ;第25位商舍入($800000-$FFFFFF不溢出,故INC3不会溢出!)COM3: LDI R17,$7FSBRS R16,7AND R13,R17 ;配置商数符DON3: RETD5: ROL R7 ;在R5,R6,R7中记商(不必预先清除)ROL R6ROL R5 ;商数左移1位并记商RJMP LOOP2;范例67FPSQ: ANDI R16,$7F ;模拟手算开平方子程序SBRC R13,7ORI R16,$80 ;负数建虚根标志FPS0: TST R12BREQ DON4 ;0的平方根为0LDI R17,$80OR R13,R17 ;恢复尾数最高位LSR R12 ;阶码算术右移1位BRCC FSQ2INC R12 ;移出位舍入RCALL INC3 ;先将位数增1(提前舍入)BRCS FSQ1 ;C=1,不够减SECROR R13 ;若尾数变为0将其改为0.5($80-->r13)RJMP FSQ2FSQ1: LSR R13ROR R14ROR R15 ;否则将为数算术右移FSQ2: LDI R17,25 ;开出25位根,末位舍入MOV R8,R17LDI R17,$40ADD R12,R17 ;根恢复为移码CLR R5CLR R6CLR R7 ;根扩展区清除CLR R9CLR R10CLR R11 ;根存储区清除FSQ3: SUB R13,R17SBC R7,R11SBC R6,R10SBC R5,R9 ;试根BRCS FSQ3ASECRJMP FSQ4 ;够减,本位根1FSQ3A: ADD R13,R17ADC R7,R11ADC R5,R9 ;否则恢复开平方数之尾数CLC ;本位商0FSQ4: DEC R8BRNE FSQ5 ;开出第25位根?FQDON: MOV R13,R9MOV R14,R10MOV R15,R11 ;回送根尾数BRCC COM4RCALL INC3 ;第25位根舍入COM4: LDI R17,$7FAND R13,R17 ;根尾数为正数DON4: RETFSQ5: ROL R11ROL R10ROL R9 ;根尾数带进位左移,记根LSL R15ROL R14ROL R13ROL R7ROL R6ROL R5LSL R15ROL R14ROL R13ROL R7ROL R6ROL R5 ;开平方数之尾数连同扩展区左移2位BRCC FSQ3 ;未产生进位,循环RJMP FQDON ;否则进位为第25位根(不须试,并结束子程序)!;范例68 ;牛顿迭代开平方子程序FSQR: TST R12BREQ SQRT ;0的平方根为0ANDI R16,$7ESBRC R13,7ORI R16,$80 ;虚根标志SBRC R12,0INC R16 ;阶码为奇数LDI R17,$7FAND R13,R17 ;尾数变为正数LSR R12ADC R12,R17 ;得到根之移码PUSH R12 ;暂存LDI R17,$80MOV R12,R17SBRC R16,0INC R12 ;得到X1的阶码(0.5≤X1<2)RCALL LD1 ;存X1LSR R13ROR R14ROR R15LDI R17,$40SBRS R16,0 ;阶码为奇数时算术右移尾数即得到X1之尾数;否则将其最;高位字节加上$40OR R13,R17 ;得到首次根r0=(1+x1)/2LDI R17,3MOV R0,R17 ;迭代3次FSQLP: RCALL LD2RCALL GET1RCALL FPDIRCALL GET2RCALL FPADDEC R12 ;计算r(i+1)=(x1/ri+ri)/2DEC R0BRNE FSQLP ;r3的尾数为根之尾数POP R12 ;取回根之阶码SQRT: RET ;r16,7=1 为虚数根;范例69 ;基本运算程序的演示程序DMST1: .EQU SPL=$3D.EQU SPH=$3ELDI R16,2 ;high(ramend)OUT SPH,R16LDI R16,$5F ;low(ramend)OUT SPL,R16LDS R11,$60 ;r11,7:数符r11,6 :阶符r11,5--0:阶(最大为38)LDS R12,$61 ;r12-r15:尾数LDS R13,$62LDS R14,$63LDS R15,$64 ;尾数共8位BCD码RCALL DTOB ;转为二进制浮点数RCALL LD2 ;暂存LDS R11,$65 ;r11,7:数符r11,阶符r11,5--0:阶(最大为38)LDS R12,$66 ;r12-r15:尾数LDS R13,$67LDS R14,$68LDS R15,$69RCALL DTOB ;转为二进制浮点数RCALL GET2 ;取第一操作数RCALL FPAD ;调基本运算子程序之一(FPSU/FPMU/FPDI) RCALL BTOD ;转回十进制浮点数DMRET: RJMP DMRET;范例70 ;辅助子程序KP2: MOV R8,R12 ;复制第二操作数MOV R9,R13MOV R10,R14MOV R11,R15RETLD1: STS $70,R12 ;存浮点数STS $71,R13STS $72,R14SYS $73,R15RETLD2: STS $74,R12 ;存浮点数STS $75,R13STS $76,R14STS $77,R15RETLD3: STS $78,R12 ;存浮点数STS $79,R13STS $7A,R14STS $7B,R15RETGET1: LDS R8,$70 ;取浮点数LDS R9,$71LDS R10,$72LDS R11,$73RETGET2: LDS R8,$74 ;取浮点数LDS R9,$75LDS R10,$76LDS R11,$77RETGET3: LDS R8,$78 ;取浮点数LDS R9,$79LDS R10,$7ALDS R11,$7BRETINVPI: LDI R17,$86 ;取浮点数180/лMOV R8,R17LDI R17,$65MOV R9,R17LDI R17,$2EMOV R10,R17LDI R17,$E1MOV R11,R17RETG90: LDI R17,$87 ;取浮点数90 MOV R8,R17LDI R17,$34MOV R9,R17CLR R10CLR R11RETDTOR: RCALL PI18 ;角度化为弧度RJMP FPMURTOD: RCALL INVPI ;弧度化为角度RJMP FPMUGHPI: LDI R17,$81 ;取浮点数л/2 MOV R8,R17LDI R17,$49MOV R9,R17LDI R17,$0fMOV R10,R17LDI R17,$DBMOV R11,R17RETG01: LDI R17,$7D ;取浮点数0.1 MOV R8,R17LDI R17,$4CMOV R9,R17LDI R17,$CCMOV R10,R17LDI R17,$CDMOV R11,R17RETG1: LDI R17,$81 ;取浮点数1MOV R8,R17CLR R9CLR R10CLR R11RETPI18: LDI R17,$7B ;取浮点数л/180MOV R8,R17LDI R17,$0EMOV R9,R17LDI R17,$FAMOV R10,R17LDI R17,$35MOV R11,R17RETGINT: LDI R17,R12 ;浮点数取整CPI R17,$81BRCC GINT1RCALL G0 ;阶码<$81,结果为0RJMP KP2GINT1: ANDI R16,$DDSBRC R13,7ORI R16,2 ;记数符CPI R17,$98BRCC GOVER ;阶码>$97,溢出RCALL BRK ;分解出整数部分(在R9 R10 R11)SBRS R16,1RET ;正数返回NEG3A: COM R11 ;负数求(r9 r10 r11)之补COM R10COM R9INC3A: LDI R17,255SUBI R11,R17SBCI R10,R17SBCI R9,R17 ;求反后加1RETGOVER: ORI R16,$20 ;设整数部分超过23位标志RETBRK: ANDI R16,$DF ;将正浮点数分解为整数/小数两部分LDI R17,$80OR R13,R17 ;恢复尾数最高位CLR R9CLR R10CLR R11MOV R17,R12SUBI R17,$80BREQ BRKRTBRCS LOOPTCPI R17,$19 ;整数部分超过24位BRCC GOVER ;为溢出LOOP4: LSL R15ROL R14ROL R13ROL R11ROL R10ROL R9DEC R17BRNE LOOPT ;左移位数为阶码-$80,整数部分进入r9-r11中BRKRT: RETLOOPT: LSR R13 ;只有小数部分右移尾数($80-阶码)位ROR R14ROR R15INC R17BRNE LOOPTRETNRML: ANDI R16,$BF ;1字节正整数(在R13中)规格化为浮点数CLR R14CLR R15LDI R12,$88 ;设阶码RJMP NMLOPG10: LDI R17,$84 ;取浮点数10MOV R8,R17LDI R17,$20MOV R9,R17CLR R10CLR R11RETGLN2: LDI R17,$80 ;取浮点数ln2(=0.6931471806)MOV R8,R17LDI R17,$31MOV R9,R17LDI R17,$72MOV R10,R17LDI R17,$18MOV R11,R17RETGLN10: LDI R17,$82 ;取浮点数ln10(=2.302585093)MOV R8,R17LDI R17,$13MOV R9,R17LDI R17,$5DLDI R17,$8EMOV R11,R17RETINVX: TST R12 ;计算1/X, X=0时溢出BRNE INVOV4: SEVRETINV: RCALL G1 ;取1RJMP FPDI;范例71 ;用荷纳法计算多项式值子程序FPLN1: ORI R16,$10 ;设计算奇函数(lnx,sinx,arcsinx 等)标志RCALL LD3 ;存XRCALL KP2RCALL FPMU ;计算X2RJMP FLN0 ;FPLN2: ANDI R16,$EF ;设计算偶函数(EXP,COSX等)标志FLN0: RCALL LD1 ;存T,T=X 或T=X2POP R30POP R31 ;系数表数据地址进入ZLSL R30ROL R31 ;由按字取数变为按字节取数LPM ;r0<--(z)取阶码MOV R8,R0ADIW R30,1 ;指针增1LPM ;取尾数高位字节MOV R9,R0ADIW R30,1 ;z+1LPM ;取尾数中位字节MOV R10,R0ADIW R30,1 ;z+1LPM ;取尾数低位字节MOV R11,R0 ;取浮点数到r8 r9 r10&r11ADIW R30,1 ;z+1PLN: RCALL M1 ;计算(....((An*T+A(n-1))*T+A(n-2))*T+....+Ai)*T LPMMOV R8,R0ADIW R30,1LPMMOV R9,R0ADIW R30,1LPMADIW R30,1LPMMOV R11,R0 ;取A(i-1)ADIW R30,1RCALL FPLAD ;计算(....((An*T+A(n-1))*T+A(n-2))*T+....+Ai)*T+A(i-1)LPMRCALL GET1DEC R0BRNE PLN ;1为停止符号;否则继续计算PEND: SBRS R16,4RJMP RENDRCALL GET3 ;奇函数取出自变量RCALL M1 ;自变量乘以计算结果才是函数值REND: LSR R31ROR R30 ;Z指针折半后ADIW R30,1 ;增1为后继指令地址IJMP ;转到该地址去执行;范例72LNX: TST R12 ;对数函数子程序BREQ OV5SBRS R13,7RJMP LN1OV5: SEV ;求负数或0的对数为错误RETLN1: ANDI R16,$7E ;R16,7:(T-1)/(T+1)或(2T-1)/(2T+1)之符号R16,0:p之符号; mMOV R0,R12 ;设X=2 *T, 则LnX=m*Ln2+LnT,存入p=mLDI R17,$F3CP R15,R17LDI R17,$04CPC R14,R17LDI R17,$35CPC R13,R17 ; _BRCC LN5 ;T>√2/2时跳转DEC R0 ;取p=m-1 LnX=(m-1)*Ln2+LN(2T)MOV R17,R15OR R17,R14OR R17,R13MOV R12,R17BREQ LN5A ;2T-1=0 只须计算(m-1)Ln2RCALL KP2 ;R12 NOUSED!LSL R9ROL R10ROL R11 ;(2T-1)LSR R13ROR R14ROR R15LDI R17,$80OR R13,R17 ;2T+1LDI R17,$7EMOV R12,R17 ;取1/(2T+1)的阶码RJMP LNTLPLN5: ORI R16,$80 ;(T-1)为负,数符位改为1RCALL KP2RCALL NEG3ALDI R17,$80ADD R9,R17 ;计算(T-1)LSR R13ROR R14ROR R15LDI R17,$C0OR R13,R17LDI R17,$7FMOV R12,R17 ;取1/(T+1)的阶码LNTLP: LSL R11ROL R10ROL R9 ;(2T-1)或(T-1)规格化DEC R12 ;调整(2T-1)/(2T+1))或(T-1)/(T+1)的阶码SBRS R9,7RJMP LNTLPRCALL FPD3 ;计算(2T-1)/(2T+1)或(T-1)/(T+1) 位r16,7为商之数符PUSH R0RCALL FPLN1 ;计算LnT或Ln(2T).DB $7E,$12,$49,$25 ;0.14285714 ;er.total<0.000000029!.DB $7E,$4C,$CC,$CD ;0.2.DB $7F,$2A,$AA,$AB ;0.33333333.DB $81,$00,$00,$00 ;1.DB $01,$00 ;结束符INC R12POP R0LN5A: LDI R17,$80ADD R0,R17BREQ LN53 ;p=$80结束BRCS LN51NEG R0INC R16 ;p为负数LN51: RCALL LD1 ;存LnT或Ln(2T)MOV R13,R0RCALL NRML ;|P|规格化RCALL GLN2 ;取ln2RCALL FPMU ;计算|p|*ln2RCALL GET1 ;取LnT或Ln(2T)SBRS R16,0RJMP LN52RCALL FPSU ;p<0 计算lnT-|p|*ln2或Ln(2T)-|p|*ln2RETLN52: RCALL FPAD ;p>0 计算lnT+|p|*ln2或Ln(2T)+|p|*ln2 LN53: RET;范例73 ;对数衍生函数子程序LGX: RCALL LNX ;计算lnxRCALL GLN10 ;取ln10RCALL EXCHRJMP FPDI ;转计算lgx=lnx/ln10LGAX: RCALL LD2 ;存aRCALL EXCHRCALL LNX ;计算lnxRCALL GET2 ;取aRCALL LD2 ;存lnxRCALL EXCHRCALL LNX ;计算lnaRCALL GET2 ;转计算logax=lnx/lnaRJMP FPDI;范例74EXP: MOV R17,R12 ;指数函数子程序CPI R17,$68 ;X之阶<$68E1: BRCC E2RCALL G0ROR R12 ;(R12)=$80INC R12 ;取exp=1RETE2: ANDI R16,$3F ;r16,6:数符SBRC R13,7ORI R16,$40 ;负数LDI R17,$7FAND R13,R17 ;取正(取|X|)LDI R17,$33CP R15,R17LDI R17,$0FCPC R14,R17LDI R17,$30CPC R13,R17LDI R17,$87CPC R12,R17 ;|X|与88.02969 比较BRCS E3 ;|X|<88.02969 转SBRS R16,6RJMP OV6G0: CLR R12 ;若x<-88.02969CLR R13CLR R14 ;Exp=0CLR R15RETOV6: SEV ;x>88.02969,Exp溢出RETE3: CLR R0 ;X整数部分予清除LDI R17,$81MOV R8,R17LDI R17,$38MOV R9,R17LDI R17,$AAMOV R10,R17LDI R17,$3BMOV R11,R17 ;取log2e(=1/ln2)RCALL FPMU ;计算X/ln2LDI R17,$80SBRC R16,6OR R13,R17MOV R17,R12CPI R17,$81BRCS E6 ;X/ln2整数部分为0 转RCALL BRK ;否则分解该数为整数I(在R11),小数F两部分LDI R17,$80MOV R12,R17RCALL NOM ;小数部分规格化为浮点数SBRC R16,6NEG R11 ;整数部分求补MOV R0,R11 ;E6: PUSH R0RCALL FPLN2 ;计算EXP(F*ln2).DB $69,$5A,$92,$9F ;0.10178086 E-6 ;er.total<0.000000024.DB $6D,$31,$60,$11 ;0.13215487 E-5.DB $70,$7F,$E5,$FE ;0.15252734 E-4.DB $74,$21,$84,$89 ;0.15403530 E-3.DB $77,$2E,$C3,$FF ;0.13333558 E-2.DB $7A,$1D,$95,$5B ;0.96181291 E-2.DB $7C,$63,$58,$47 ;0.55504109 E-1.DB $7E,$75,$FD,$F0 ;0.24022651.DB $80,$31,$72,$18 ;0.69314718.DB $81,$00,$00,$00 ;1.DB $01,$00 ;结束符POP R0ADD R12,R0 ;整数部分I 加入阶码中RET;范例75 ;指数衍生函数子程序DXP: RCALL GLN10 ;取ln10RJMP EXP0 ;转计算EXP(X*ln10) AXP: RCALL LD2 ;存XRCALL EXCHRCALL LNX ;计算lnaRCALL GET2 ;取出xEXP0: RCALL FPMURJMP EXP ;转计算EXP(X*lna);范例76 ;双曲函数和反双曲函数子程序SHX: RCALL SUB11 ;计算双曲正弦RCALL FPSUBRNE NX48RETCHX: RCALL SUB11 ;计算双曲余弦RCALL FPADNX48: DEC R12RETSUB11: RCALL EXPRCALL LD2RCALL INVXRJMP GET2ASHX: RCALL SUB2 ;计算反双曲正弦RCALL FPADASH: RCALL FPSQRCALL GET2RCALL FPADRJMP LNXACHX: RCALL SUB2 ;计算反双曲余弦RCALL EXCHRCALL FPSURJMP ASHSUB2: RCALL LD2 ;存XRCALL KP2RCALL FPMU ;得到X2RJMP G1 ;取浮点数1; 范例77 ;正弦函数子程序SINX: RCALL RTOD ;弧度化为角度SINX1: CLR R16 ;X1为角度SBRC R13,7INC R16 ;存数符LDI R17,$7F ;X1-->|X1|AND R13,R17NX30: RCALL G90INC R8INC R8 ;取360°RCALL FPCP1 ;|X1|与360°比较BREQ GE0 ;相等,转出BRCC NX31 ;|X1|<360°转出RCALL EXCHRCALL FPSU ;否则|X1|-360°-->|X1|RJMP NX30 ;循环NX31: DEC R8RCALL FPCP1 ;|X1|与180°比较BREQ GE0 ;相等,转出BRCC NX32 ;|X1|<180°,转RCALL EXCHRCALL FPSU ;否则|X1|-180°-->|X1|INC R16 ;将数符求反NX32: RCALL G90RCALL FPCP1 ;|X1|与90°比较BRCC NX36INC R8RCALL FPSU ;|X1|>90°,取180°-|x1|-->|x1| RJMP NX36GE0: RJMP G0 ;|X1|=0 则sinX=0NX36: RCALL DTOR ;变回弧度XMOV R17,R12CPI R17,$79 ;阶码<$79,sinX=XBRCS PP2RCALL FPLN1 ;计算sin|X|.DB $60,$30,$92,$32 ; 0.16059044 E-9 er.total<0.0000000071.DB $67,$D7,$32,$2A ;-0.25052108 E-7.DB $6E,$38,$EF,$1C ; 0.27557319 E-5.DB $74,$D0,$0D,$01 ;-0.19841270 E-3.DB $7A,$08,$88,$88 ; 0.83333333 E-2.DB $7E,$AA,$AA,$AA ;-0.16666667.DB $81,$00,$00,$00 ;1.DB $01,$00 ;结束符PP2: LDI R17,$80SBRC R16,0PP3: OR R13,R17 ;配置数符DON6: RET;范例78 ;衍生三角函数子程序CTNX: RCALL RTOD ;弧度化为角度CTNX1: RCALL TANX1 ;计算tgXRJMP INVX ;取倒数为ctgXTANX: RCALL RTOD ;弧度化为角度TANX1: RCALL LD2 ;存XRCALL SINX1 ;计算sinXRCALL GET2 ;取XRCALL LD2 ;存sinXRCALL EXCHRCALL COSX1 ;计算cosXBRNE NX39OV7: SEVRET ;cosX=0,溢出NX39: RCALL GET2 ;取sinXRJMP FPDI ;tgX=sinX/cosXCOSX: RCALL RTOD ;弧度化为角度COSX1: RCALL G90 ;取浮点数90°RCALL FPSURJMP SINX1 ;cosX=sin(90-X);范例79 ;反正弦函数子程序ASINX: MOV R17,R12CPI R17,$78BRCS DON6 ;X阶码<$78,acrsinX=XANDI R16,8 ;清除数符和|X|>0.5标志,保留计算acosx标志(R16,3)SBRC R13,7INC R16 ;记数符LDI R17,$7FAND R13,R17 ;取绝对值X-->|X|RCALL G1RCALL FPCP1BREQ AABRCC AA1OV8: SEV ;|X>1,溢出RETAA: RCALL GHPIRCALL EXCHRJMP PP2 ;|X|=1,arcsinX=±л/2AA1: MOV R17,R12CPI R17,$80BRNE AS1 ;|X|<0.5,y=|x|MOV R17,R13OR R17,R14OR R17,R15BREQ AS1 ;X=0.5,y=|x|ORI R16,$20 ;X>0.5,建标RCALL NEG3LDI R17,$80ADD R13,R17LDI R17,$7FMOV R12,R17 ;((1-|x|)/2)方根之阶最大为$7FNRMLP: LSL R15ROL R14ROL R13DEC R12SBRS R13,7RJMP NRMLP ; __________RCALL FPS0 ;√(1-|X|)/2-->yAS1: RCALL FPLN1 ;计算arcsiny.DB $7A,$3D,$43,$C4 ;0.11551801 E-1 er. total<0.0000000245 .DB $7A,$64,$CC,$CD ;0.13964844 E-1.DB $7B,$0E,$27,$62 ;0.17352764 E-1.DB $7B,$37,$45,$D1 ;0.22372159 E-1.DB $7B,$78,$E3,$8E ;0.30381944 E-1.DB $7C,$36,$DB,$6E ;0.44642857 E-1.DB $7D,$19,$99,$9A ;0.075.DB $7E,$2A,$AA,$AA ;0.16666667.DB $81,$00,$00,$00 ;1.DB $01,$00 ;结束符SBRS R16,5RJMP PP2 ;|x|≤0.5 转配置数符,有acsin|x|=acsinyINC R12 ;否则取2arcsiny(=arccosx)SBRC R16,3 ;测试计算ARCCOSX的标志RJMP ACSRT ;有计算ARCCOSX标志,转清除该标志(其余计算在ACOSX子程序中完成)RCALL GHPI ;否则取л/2AS2: RCALL FPSU ;|X|>0.5时,arcsin|X|=л/2 -2arcsinyPP20: RJMP PP2 ;转去配置数符;范例80 ;函数值为弧度的反三角函数子程序ACOSX: ORI R16,8 ;设计算arccosx标志RCALL ASINX ;调反正弦函数子程序RCALL GHPI ;取л/2SBRC R16,3 ;计算ARCCOS|X|标志未被清除?RJMP AS3 ;是,转计算arccosx=л/2-arcsinxSBRS R16,0 ;x>0且x>0.5RJMP ACSRT ;有arccosx=2arcsiny!INC R8 ;否则取л;即当x<0且|X|>0.5时,有arccosX=л-2arcsinyAS3: RCALL FPSUACSRT: ANDI R16,$F7 ;清除计算arccosx标志RETATANX: MOV R17,R12 ;反正切函数子程序CPI R17,$98BRCS AT1RCALL GHPI ;X阶码大于$98,取л/2RCALL EXCHROL R9BRCC AT2LDI R17,$80OR R13,R17 ;arctgx=л/2AT2: RETAT1: MOV R17,R12CPI R17,$74 ;X阶码小于$74,arctgX=XBRCS AT2RCALL KP2RCALL LD1 ;存XRCALL FPMURCALL G1RCALL FPAD ; _______RCALL FPSQ ;计算√(1+X2)RCALL GET1RCALL FPDIRJMP ASINX ;转计算arctgx=arcsin(X/√<(1+X2)ACTNX: RCALL ATANX ;反余切函数子程序RCALL GHPIRJMP FPSU ;arcctgX=л/2-arctgx;范例81 ;函数值为角度的反三角函数子程序ASNX: RCALL ASINX ;反正弦函数子程序,结果以角度表示RJMP RTODACSX: RCALL ACOSX ;反余弦函数子程序,结果以角度表示RJMP RTODATNX: RCALL ATANX ;反正切函数子程序,结果以角度表示RJMP RTODACNX: RCALL ACTNX ;反余切函数子程序,结果以角度表示RJMP RTOD;范例82 ;函数计算子程序演示程序DMST2: LDI R16,2OUT SPH,R16LDI R16,$5F ;堆栈指针初始化OUT SPL,R16LDS R11,$65 ;取操作数(自变量X)LDS R12,$66 ;r11,7:数符r11,6:阶符LDS R13,$67 ;r11,5--0:阶(最大为38)LDS R14,$68LDS R15,$69 ;r12-r15:十进制尾数(8位BCD码)RCALL DTOB ;翻为二进制浮点数RCALL LNX ;调函数子程序之一RCALL BTOD ;将函数值转为十进制浮点数DMHER: RJMP DMHER;范例83 ;阶乘子程序NP: RCALL G1 ;取浮点数1MOV R17,R12 ;二进制整数N在R12中CPI R17,2 ;N<2,N!=1BRCS GGCPI R17,34BRCS NX59OV9: SEV ;N>33,溢出RETGG: RJMP SA V0 ;取N!=1NX59: MOV R0,R12 ;存NDEC R0 ;N-1PUSH R17 ;取T=1 并存入LDI R17,$81STS $70,R17CLR R17STS $71,R17STS $72,R17STS $73,R17 ;存储浮点数1L43: POP R13 ;取TINC R13 ;T+1-->TPUSH R13 ;存TRCALL NRML ;T规格化RCALL GET1 ;取阶段阶乘结果RCALL FPMU ;得到当前T!RCALL LD1DEC R0BRNE L43 ;T=N时得到N!POP R0RET;范例84 ;长整数(r9,r10,r11,r12)规格化为浮点数LINOM: BST R9,7 ;数符存于TBRTC LI10CLR R16 ;负数求补SUB R16,R12MOV R12,R16CLR R16SBC R16,R11MOV R11,R16CLR R16SBC R16,R10MOV R10,R16CLR R16SUB R16,R9MOV R9,R16LI10: LDI R16,$A0 ;取阶32(长整数共32位)LP10: SBRC R9,7RJMP NX63 ;最高位为1,已规格化LSL R12ROL R11ROL R10ROL R9 ;否则左规1位DEC R16 ;阶码减1BRNE LP10RJMP G0 ;左规达32次,浮点数为0;范例85 ;定点十进制数翻为二进制浮点数DTOB1: RCALL LD1 ;存入十进制小数RCALL CONV2 ;定点整数十翻二RCALL GET1 ;取出十进制小数RCALL LD1RCALL SA V0RCALL CONV4 ;定点小数十翻二RCALL GET1 ;取出二进制定点整数LDI R16,$98 ;予设阶码LP11: SBRC R9,7RJMP NX63 ;最高位为1,已规格化LSL R15ROL R14ROL R13ROL R12ROL R11ROL R10ROL R9 ;整数和小数部分左移一位DEC R16 ;阶码减1CPI R16,$60BRNE LP11RET ;得到浮点数0NX63: MOV R13,R9MOV R14,R10MOV R15,R11 ;尾数取到r13-r15SBRS R12,7RJMP PP6RCALL INC3 ;尾数截去部分舍入BRNE PP6INC R16 ;尾数变为0将阶码增1SECROR R13 ;$80-->r13,即将尾数变为0.5PP6: MOV R12,R16 ;取回阶码BLD R13,7 ;装入数符(T-->R13,7)RET;范例86 ;浮点数十翻二DTOB: ANDI R16,$FC ;r11,7:数符r11,6:阶符r11,5--0:阶(最大为38)SBRC R11,6 ;R12---R15;8BCD码尾数INC R16 ;阶符存于R16,0SBRC R11,7ORI R16,2 ;数符存于R16,1MOV R17,R11ANDI R17,$3F ;取阶MOV R0,R17 ;存于R0MOV R8,R12OR R8,R13OR R8,R14OR R8,R15BREQ PP8 ;十进制浮点数尾数为0,取二进制浮点数0 PUSH R16RCALL CONV4 ;十进制浮点数尾数翻为二进制定点小数MOV R16,R15MOV R15,R14MOV R14,R13MOV R13,R12 ;二进制定点小数转入r13r14r15r16LDI R17,$80 ;予设阶码MOV R12,R17LP14: SBRC R13,7RJMP NX67LSL R16ROL R15ROL R14ROL R13DEC R12RJMP LP14 ;二进制定点小数规格化为浮点数NX67: SBRS R16,7RJMP NX66RCALL INC3 ;调整BRNE NX66INC R12SEC ;调整后结果为0将其改为0.5ROR R13 ;即$80-->r13NX66: LDI R17,$7FPOP R16SBRS R16,1AND R13,R17 ;配置数符SBRS R16,0RJMP DBL4 ;正阶转DBL1: LDI R17,$10SUB R0,R17BRCS DBL2RCALL INVDP ;RCALL FPMU ;阶码减10, X*10ˉ1o -->X RJMP DBL1DBL2: ADD R0,R17 ;不够减则恢复阶BREQ PP8DBL3: RCALL G01 ;取0.1RCALL FPMUDEC R0 ;X*0.1-->X,阶减1BRNE DBl3RETDBL4: LDI R17,$10SUB R0,R17 ;阶减10BRCS DBL5RCALL DDP ;X*101o -->XRCALL FPMURJMP DBL4DBL5: ADD R0,R17 ;不够减则恢复阶BREQ PP8DBL6: RCALL G10RCALL FPMUDEC R0 ;X*10-->X,阶减1BRNE BDL6PP8: RETINVDP: LDI R17,$5F ;取浮点数10ˉ1oMOV R8,R17LDI R17,$5BMOV R9,R17LDI R17,$E6MOV R10,R17LDI R17,$FFMOV R11,R17RET ;DDP: LDI R17,$A2 ;取浮点数101oMOV R8,R17LDI R17,$15MOV R9,R17LDI R17,$02MOV R10,R17LDI R17,$F9MOV R11,R17RET;范例87 ;浮点数二翻十BTOD: TST R12BREQ PP4 ;转取十进制浮点数0ANDI R16,$FC ;予清十进制浮点数数符及阶符(r16,1&0) CLR R0 ;予清十进制浮点数之阶SBRC R13,7ORI R16,2 ;取数符LDI R17,$7FAND R13,R17 ;取绝对值BTA: RCALL DDPRCALL FPCP1 ;|X|与101o 比较BREQ BTBBRCC BTC ;|X|<101o 转BTB: RCALL INVDPRCALL FPMU ;|X|*10ˉ1o-->|X|LDI R17,$10ADD R0,R17 ;十进制浮点数阶加10RJMP BTABTC: RCALL INVDP ;RCALL FPCP1 ;|X|与10ˉ1o 比较BREQ BTC1 ;BRCS BT0 ;|X|>10ˉ1o 转BTE: RCALL DDP ;RCALL FPMU ;|X|*101o -->|X|LDI R17,$10ADD R0,R17 ;十进制浮点数阶加10ORI R16,1 ;置负阶RJMP BTCBTC1: LDI R17,9 ;|X|=10ˉ1o 特别处理ADD R0,R17 ; -9ORI R16,1 ;取0.1*10SJMP BT4BT0: RCALL G1RCALL FPCP1 ;|X|与1比较BREQ BT1BRCC BT2 ;|X|<1转BT1: RCALL G01RCALL FPMU ;|X|*0.1-->|X|INC R0 ;十进制浮点数阶加1RJMP BT0BT2: RCALL G01RCALL FPCP1 ;|X|与0.1比较BREQ BT4BRCS BDS ;|X|≤0.1转出BT3: RCALL G10RCALL FPMU ;|X|*10--->|X|INC R0 ;十进制浮点数阶加1ORI R16,1 ;置负阶RJMP BT2PP4: RJMP KP2 ;十进制浮点数取为0BT4: LDI R17,$10MOV R9,R17CLR R10CLR R11CLR R12 ;十进制浮点数尾数取为0.10000000BT6: MOV R8,R0 ;取十进制浮点数阶SBRS R8,3RJMP BT7SBRC R8,1SUBI R8,$FA ;对产生非法BCD调整(加6)BT7: LDI R17,$40SBRC R16,0OR R8,R17 ;配置阶符(r8,6)LSL R17SBRC R16,1OR R8,R17 ;配置阶浮(r8,7)RETBDS: RCALL BT6 ;BT6将十进制浮点数阶,阶符和数符配置到R8 LDI R17,$80OR R13,R17 ;恢复尾数最高位LDI R17,$98SUB R17,R12 ;右移次数为($98-阶码)RJMP CONV31 ;调CONV31子程序完成尾数二翻十,结果在(r9r10r11r12);范例88 ;二进制浮点数快速翻为定点十进制数,整数在r9,r10,r11中,小数在r13,r14,r15中FBTOD: RCALL BRK ;二进制浮点数分解为整数和小数两部分SBRC R16,5RET ;整数部分多于24位,溢出MOV R0,R13MOV R5,R14MOV R8,R15 ;小数部分转入R0R5R8RCALL CONV1 ;定点整数二翻十,结果在R12,R13,R14,R15RCALL LD1 ;十进制整数-->RAMMOV R15,R8MOV R14,R5MOV R13,R0 ;取回二进制小数RCALL CONV3 ;定点小数二翻十,结果在r9,r10,r11,r12RCALL EXCH1 ;十进制定点小数转入r13,r14,r15,r12RCALL GET1 ;取出十进制定点整数r8,r9,r10,r11)/小数在r13,r14,r15,r12CLR R16 ;清除无用的标志!RET;范例89.ORG $E80 ;最小二乘法拟和直线子程序.EQU NUMB=10 ;取10点,即十对浮点数,按增地址存放Y1,X1,Y2,X2,..Yn,Xn .EQU TABLA=$9000 ;数据表,第一个浮点数为Y1STRT: LDI R28,$70CLR R29 ;POINT TO $0070LP51: ST Y+,R29 ;累加和或暂存区清除(LD1,LD2,LD3,LD4和LD5子程序工作区)CPI R28,$84BRNE LP51LDI R16,NUMB ;取拟合点数MOV R0,R16LDI R29,$90CLR R28 ;参加拟合数据首地址$9000IN R16,MCUCR,7SBR R16,$C0 ;片外RAM,选一个读写等待周期OUT MCUCR,R16LOOP3: RCALL GETA ;取浮点数Yi 占4字节即Yi0,Yi1,Yi2,Yi3 RCALL INVX ;计算1/YiRCALL LD6 ;暂存RCALL GET1 ;取累加和nRCALL FPAD ;1/Yi加入累加和(∑1/Yi是∑1/Yi 简写形式,下同)RCALL LD1 ; i=1RCALL GET6 ;取1/YiPUSH R28PUSH R29 ;保护堆栈指针RCALL GETA ;取浮点数Xi(Xi0,Xi1,Xi2,Xi3)占4字节POP R29POP R28 ;恢复堆栈指针,仍指向XiRCALL FPMU ;计算Xi/YiRCALL LD7 ;暂存RCALL GET2RCALL FPAD ;Xi/Yi加入累加和∑(Xi/Yi)RCALL LD2RCALL GET7 ;取出Xi/YiRCALL SA V0 ;RCALL FPMU ;计算(Xi/Yi)2RCALL GET3RCALL FPAD ;(Xi/Yi)2加入累加和∑(Xi/Yi)2RCALL LD3RCALL GET6 ;取1/YiRCALL SA V0 ;RCALL FPMU ;计算1/Yi2RCALL LD6 ;暂存RCALL GET4RCALL FPAD ;1/Yi2 加入累加和∑1/Yi2RCALL LD4RCALL GET6 ;取出1/Yi2RCALL GETA ;再取XiRCALL FPMU ;计算Xi/Yi2RCALL GET5RCALL FPAD ;Xi/Yi2加入累加和∑Xi/Yi2RCALL LD5DEC R0 ;点数减1BRNE LOOP3 ;未到总点数n,循环RCALL GET4RCALL SA V0RCALL GET3RCALL FPMU ;计算(∑1/Yi2)*(∑(Xi/Yi)2) 并存入RCALL LD6RCALL GET5 ;取出∑Xi/Yi2RCALL SA V0RCALL FPMU ;计算(∑Xi/Yi2)2RCALL GET6RCALL FPSU ;计算c=(∑1/Yi2)*(∑(Xi/Yi)2-(∑Xi/Yi2)2 RCALL LD6 ;存入RCALL GET2RCALL SA V0RCALL GET4RCALL FPMU ;计算(∑(Xi/Yi)*(∑1/Yi2)并存入RCALL LD7RCALL GET1RCALL SA V0RCALL GET5RCALL FPMU ;计算(∑1/Yi)*(∑(Xi/Yi2) 并存入RCALL GET7RCALL FPSU ;计算d=(∑Xi/Yi)*(∑1/Yi2)-(∑1/Yi)*(∑Xi/Yi2)) RCALL GET6 ;取cRCALL EXCHRCALL FPDI ;计算b=d/c并存入RCALL LD7RCALL GET5 ;取∑Xi/Yi2RCALL FPMU ;计算(∑Xi/Yi2)*bRCALL GET1RCALL FPSU ;计算(∑1/Yi)-(∑Xi/Yi2)*bRCALL GET4 ;取∑1/Yi2RCALL EXCHRCALL FPDI ;计算a=(∑1/Yi-(∑Xi/Yi2)*b)/∑1/Yi2 RCALL LD6 ;结果a在$84-$87中,b在$88-$8b中RERGETA: LD R12,Y+LD R13,Y+LD R14,Y+LD R15,Y+ ;从外部SRAM中取浮点数到R12-R15 RETLD4: STS $7C,R12 ;存浮点数STS $7D,R13STS $7E,R14STS $7F,R15RETLD5: STS $80,R12 ;计算∑Xi/Yi2的存储单元STS $81,R13STS $82,R14STS $83,R15RETLD6: STS $84,R12 ;暂存1/Yi,1/Yi2等浮点数STS $85,R13STS $86,R14STS $87,R15RETLD7: STS $88,R12 ;暂存Xi/Yi等浮点数STS $89,R13STS $8A,R14STS $8B,R15RETGET4: LDS R8,$7C ;取浮点数LDS R9,$7DLDS R10,$7ELDS R11,$7FRET ;GET5: LDS R8,$80 ;取∑Xi/Yi2或中间结果LDS R9,$81LDS R10,$82LDS R11,$83RETGET6: LDS R8,$84 ;取浮点数1/Yi,1/Yi2等LDS R9,$85LDS R10,$86LDS R11,$87RETGET7: LDS R8,$88 ;取浮点数Xi/Yi等LDS R9,$89LDS R10,$8ALDS R11,$8BRET;范例90GETAD: LDI R17,0Bxxx01110;PC0&PC4输入/PC1-PC3输出&PC3(CAL) OUT DDRC,R17 ;CBI PORTC,1GAD1: SBI PORTC,4SBIB PINC,4 ;查DRDYRJMP GAD1 ;低为数据准备好GAD2: SBI PORTC,4SBIC PINC,4 ;PINC:$13/PORTB:$15RJMP GAD2 ;DRDY低有效CBI PORTC,2 ;置片选有效LDI R16,16 ;16位数据GETL0: CLC ;予清除CSBI PORTC,0SBIC PINC,0 ;接收一位数据SECROL R14 ;数据高位在前ROL R13 ;在R13R14里带进位左移SBI PORTC,1CBI PORTC,1 ;发出时钟,下降沿读出数据DEC R16BRNE GETL0SBI PORTC,2 ;置片选无效MOV R4,R14 ;MOV R3,R13 ;保存GADCOM: CLR R15 ;3字节小数r13r14r15(0)规格化为浮点数LDI R16,$80MOV R12,R16 ;阶码为$80GAD: SBRC R13,7RJMP GETL2LSL R14。
;范例19 ;等步距线性内插计算子程序.EQU TBLGTH=10CHETA: LDI R16,TBLGTH-1 ;r16<--表长(即字数)-1LDI R31,HIGH(chtbl*2);y0(函数初值)在r14r15,STEP(步长)在r10r11,自变量X 在r12r13LDI R30,LOW(chtbl*2+1);查表指针,首指数据表第1字之高位字节!RCALL CPMR1 ;X与表中第一个字型数据(X0)比较BRCC CHRET ;X<X0 查表结束,Y=Y0CHET1: RCALL CMPR1 ;X与表中下一个数据比较BRCC NX33 ;X<X(i+1) 找到插值区间ADD R15,R11 ;否则Y0中加入一个STEP:Yk=Y0+k*step(步距为负时则;减去|STEP|)ADC R14,R10DEC R16BRNE CHET1 ;未查到表格终值,循环;否则结束,Y取得最大值Yn CHRET: RETNX33: SBIW R30,5 ;指针退回(-5),指向XiMOV R8,R14MOV R9,R15 ;保存Y0+i*STEPRCALL SUBS ;(X-Xi)-->r16r17MOV R15,R17MOV R14,R16 ;转入r14r15RCALL MUL16 ;(X-Xi)*STEP-->r12r13r14r15MOV R10,R12MOV R11,R13 ;保存乘积高位字LPM ;X(i+1)低位字节MOV R13,R0ADIW R30,1LPM ;X(i+1)高位字节MOV R12,R0SBIW R30,3 ;指针指向XiRCALL SUBS ;X(i+1)-Xi-->r16r17MOV R12,R10MOV R13,R11 ;取回乘积高位字MOV R10,R16MOV R11,R17 ;X(i+1)-Xi-->r10r11RCALL DIV165 ;(X-Xi)*STEP/[X(i+1)-Xi]-->r14r15ADD R15,R9ADC R14,R8 ;Y0+i*STEP+(X-Xi)*STEP/[X(i+1)-Xi]-->r14r15RET ;若STEP为负值则改为计算(r8r9)减去(r14r15)之值CMPR1: LPM ;取数据高位字节ADIW R30,2 ;指向下一数据的高位字节CP R0,R12 ;与X高位字节相比较BRNE CPRT1 ;不相等即转出SBIW R30,3 ;否则调整指针LPM ;取数据低位字节ADIW R30,3 ;指向下一数据的高位字节CP R0,R13 ;与X低位字节相比较CPRT1: RET ;以进位C带回比较结果SUBS: LPM ;计算(X-Xi)或[X(i+1)-Xi]并送入r16r17MOV R5,R0 ;取Xi低位字节ADIW R30,1LPM ;取Xi高位字节SBIW R30,1 ;仍指向Xi低位字节SUB R13,R5MOV R17,R13SBC R12,R0MOV R16,R12 ;计算差并将其转入R16R17RET;自变量x表长为12字CHTBL:DW 19214,23404,27600,32799,37009,40211,45414,48618,51821,55029,57787,60070 ;步距表长为11字STEPT: DW 356,366,379,395,415,440,471,509,555,603,657;不等步距线性内插计算子程序,步距表首址在R6R7中;自变量X在R12R13之中,函数初值Y0在R14R15中;范例20 ;表长(字个数)-1在R16中CHTSTP: LDI R31,HIGH(chtbl*2)LDI R30,LOW(chtbl*2+1);查表指针LDI R16,LOW(stept*2)MOV R7,R16LDI R16,HIGH(stept*2)MOV R6,R16 ;步距表指针LDI R16,TBLGTH-1 ;r16<--表长(字个数)-1RCALL CMPR1 ;X与表首数据比较BRCC CHSTPT ;X<X0 查表结束,有Y=Y0CHSTP1: RCALL CMPR1 ;否则与表中下一数据比较BRCC CHSTP3 ;X<X(i+1),找到插值区间!RCALL GTSTP ;查表取STEP字型变量ADD R15,R11 ;Y0<--Y0+STEPkADC R14,R10DEC R16BRNE CHSTP1 ;未查到表格终值循环;否则结束,Y取得最大值Yn CHSTPT: RETCHSTP3: SBIW R30,5 ;指针退回,指向Xi低位字节MOV R8,R14MOV R9,R15 ;Y0+∑STEPk送入r14 r15RCALL SUBS ;(X-Xi)->r16r17MOV R14,R16 ;(X-Xi)转入R14R15RCALL GTSTP ;查表取STEPi-->R10R11RCALL MUL16 ;(X-Xi)*STEPi-->R12R13R14R15MOV R10,R12MOV R11,R13 ;保存积高位字LPMMOV R13,R0ADIW R30,1LPMMOV R12,R0SBIW R30,3RCALL SUBS ;(X(i+1)-Xi)-->r16 r17MOV R12,R10MOV R13,R11MOV R10,R16MOV R11,R17 ;取回积高位字&(X(i+1)-Xi)-->r10r11RCALL DIV165 ;(X-Xi)*STEPi/[X(i+1)-Xi]-->r14r15ADD R15,R9 ;ADC R14,R8 ;Y0+∑STEPk+(X-Xi)*STEPi/[X(i+1)-Xi]-->r14r15 RETGTSTP: MOV R5,R6 ;查取STEP字型变量/POINTER in r6r7!MOV R6,R30MOV R30,R5MOV R5,R7MOV R7,R31MOV R31,R5 ;(r6r7)<-->ZLPMMOV R11,R0ADIW R30,1LPMMOV R10,R0 ;STEPk取到r10r11ADIW R30,1MOV R5,R6MOV R6,R30MOV R30,R5MOV R5,R7MOV R7,R31MOV R31,R5 ;指针增2后送回r6r7RET;范例21 ;功能表程序FUNC2: LDS R16,$A3 ;use r0,r8,r9,r10,r11,r16&r17/& subprogram dspa SBR R16,$80 ;功能表程序标志LDI YH,2LDI YL,0 ;功能内容表SRAM地址RCALL FLFUNC ;CLR r27!LDI R16,2ST X,R16 ;显示'FUNC.2'RCALL DL2SCLR R9 ;功能内容寻址偏移量R9!CLR R8 ;功能名称寻址偏移量(R8)=(r9)*3FFUNC0: RCALL DSF_ ;显示'F- 'FF0: RCALL DSPA ;in subprogram dspy clr. r27!CPI R16,11 ;回车键按下?BRNE FF2PFF0C: RCALL COMBNO ;合成功能名称送入r16 CPI R16,20 ;是最后一个功能名称?BRNE FF1CLR R9 ;是,两偏移量初始化!CLR R8FF1: LDI ZH,HIGH(FTABL*2)LDI ZL,LOW(FTABL*2);功能名称表指针ADD ZL,R8ADC ZH,R27 ;(r27)=0 ALWAYSLPMMOV R16,R0RCALL BRA3A ;分解新功能名称到$6E/$6FFF0G: LDI R28,0ADD R28,R9 ;功能内容指针加偏移量LD R16,YLDI R26,$72RCALL BRAX ;将新功能内容分解到$72/$73FF0A: RCALL DSPA ;显示新功能名称/内容CPI R16,11BRNE FF0B ;回车键按下?INC R8INC R8INC R8 ;是,功能名称寻址偏移量加3INC R9 ;功能内容寻址偏移量加1RJMP FF0C ;转回FF2P: RJMP FF2FF0B: CPI R16,10BRNE FF0DRCALL DSF_ ;清除键按下,清除显示区后,显示‘F-’FF1B: RCALL DSPACPI R16,11BREQ FF1 ;转恢复当前显示CPI R16,10BRCC FF1BRJMP FF2D ;只有数字键按下才转出去处理FF0D: CPI R16,10BRCC FF0AFF1D: LDI R17,$24 ;STS $73,R17 ;数字键处理,先在缓存区内放一空白FF0E: LDS R17,$73STS $72,R17 ;键入数字左移STS $73,R16 ;存入新数字FF0F: RCALL DSPACPI R16,10BREQ FF0G ;清除键按下,恢复显示旧功能内容BRCS FF0E ;键入数字左移更新CPI R16,11BRNE FF0FLDS R26,$72 ;回车键按下RCALL COMBA ;合成新功能内容(combin $72&$73 into binary(r16)) MOV R17,R8INC R17LDI ZH,HIGH(FTABL*2)LDI ZL,LOW(FTABL*2)ADD ZL,R17 ;取当前功能内容下限ADC ZH,R27FF1F: LPMCP R16,R0BRCS DSER2 ;新功能内容小于下限,错误INC R17LDI ZH,HIGH(FTABL*2)LDI ZL,LOW(FTABL*2)ADD ZL,R17 ;取当前功能内容上限ADC ZH,R27LPMCP R0,R16BRCS DSER3 ;新功能内容大于上限,错误FF7: LDI R28,0ADD R28,R9 ;功能内容表首地址为$200!ST Y,R16 ;合法的新功能内容进入功能内容表INC R9INC R8INC R8INC R8 ;调整偏移量,进入下一个功能显示RJMP FF0CFF1P: RJMP FF1DSER2: RCALL FERR2 ;显示'F Err.2'2秒RCALL EXCH0RJMP FF0G ;恢复原数据显示DSER3: RCALL FERR3 ;显示'F Err.3'2秒RCALL EXCH0RJMP FF0G ;恢复原数据显示FF2: CPI R16,10BRCS FF2D ;功能键按下,转初始RJMP FF0FF2D: LDI R17,$24 ;数字键按下,在显示缓存区内左移STS $6F,R17 ;FF3: LDS R17,$6FSTS $6E,R17STS $6F,R16FF4: RCALL DSPACPI R16,10BRNE FF41RCALL DSF_ ;清除数字,显示‘F-’FF40: RCALL DSPACPI R16,11BREQ FF1P ;转回显示当前功能名称及内容CPI R16,10BRCC FF40 ;无效键按下,转回RJMP FF2D ;否则转数字处理FF41: BRCS FF3CPI R16,11BRNE FF4RCALL COMBNO ;合成新功能名称CLR R10 ;功能名称偏移量计数器清除CLR R11 ;功能内容偏移量计数器清除SFFLP: LDI ZH,HIGH(FTABL*2)LDI ZL,LOW(FTABL*2)ADD ZL,R10ADC ZH,R27LPMCP R0,R16 ;BREQ SFFND ;在功能名称表中找到新名称INC R11 ;INC R10INC R10INC R10 ;调整偏移量LDI R17,60CP R10,R17 ;功能名称指针偏移量超过59?BRCS SFFLP ;否,继续查功能名称表RCALL FERR1 ;查完功能名称表未查到键入功能名称!RJMP FFUNC0 ;转回恢复原显示SFFND: MOV R9,R11 ;得到功能内容指针偏移量MOV R8,R10 ;得到功能名称指针偏移量RJMP FF0G ;转显示新功能名称及内容FTABL: .DB 1,0,1,2,1,8,3,0,2,4,0,1 5,1,2,6,0,4,7,1,4,8,1,2,9,2,7,10,1,5,11,1 .DB 5,12,0,5,13,1,2,14,1,7,15,1,10,16,1,4,17,2,4,18,2,5,19,1,2,20,1,3 COMBNO: LDI XL,$6E ;取$6E$6F中的BCD码,合成新功能名称子程序COMBA: LD R16,X+CPI R16,$24BRNE CMBACLR R16CMBA: MOV R0,R16LSL R16LSL R16ADD R16,R0LSL R16 ;高位BCD乘10LD R0,XADD R16,R0 ;加低位BCDRETDSF_: RCALL FIL8 ;准备显示'F- 'LDI R16,$0FSTS $6C,R16LDI R16,$14STS $6D,R16RETBRA3A: LDI XL,$6E ;二进制数转换为两位BCD码并显示BRAX: LDI R17,$24 ;十位为0时显示空白ST X,R17BRHOUR: CLR R0 ;BRX0: SUBI R16,10 ;减10BRCS BRX2INC R0RJMP BRX0BRX2: SUBI R16,-10 ;不够减恢复出十位BCDTST R0BREQ BRX1ST X,R0 ;放入显示区BRX1: INC R26ST X,R16BRART: RETFERR1: LDI XL,$71 ;显示'F Err.1'LDI R16,1ST X,R16RJMP FER123FERR2: RCALL MOVE1 ;显示'F Err.2' LDI R16,2STS $71,R16RJMP FER123FERR3: RCALL MOVE1 ;显示'F Err.3' LDI R16,3STS $71,R16FER123: LDI XL,$6CLDI R16,$0FST X+,R16LDI R16,$24ST X+,R16LDI R16,$0EST X+,R16LDI R16,$1BST X+,R16LDI R16,$3BST X+,R16 ;显示'F Err.1/2/3'LDI R16,$24 ;2秒STS $72,R16STS $73,R16RCALL DL2SRETFIL8: LDI R26,8 ;将显示缓存区充空白MOV R10,R26LDI R26,$6CCLR R27LDI R16,$24FILP: ST X+,R16DEC R10BRNE FILPRETFLFUNC: RCALL FIL8 ;准备显示'Func.' LDS R26,$6CLDI R16,$0F ;'F'ST X+,R16LDI R16,$1E ;'u'ST X+,R16LDI R16,$17 ;'n'ST X+,R16LDI R16,$40 ;'c.'ST X+,R16RETEXCH0: LDI ZL,$14 ;将显示缓存区内容转移$6C-$73<-->$214-$21B LDI ZH,2LDI XL,$6CEXL: LD R16,XLD R17,ZST X+,R17ST Z+,R16CPI R26,$74BRNE EXLRETMOVE1: LDI ZL,$14 ;将显示缓存区内容传送到$214-$21BLDI ZH,2LDI XL,$6CMV1: LD R16,X+ST Z+,R16CPI R26,$74BRNE MV1RET;范例22 ;读出EEPROM子程序REEP: LDI YH,1LDI YL 0 ;EEPROM 读出首地址:$100LDI XL,$60 ;读出数据存放首地址:$60CLR XHREEP1: SBIC $1C,1 ;查EEWE位,EEWE=1为当前尚有写入操作未结束RJMP REEP1 ;等待EEWE=0OUT $1F,YHOUT $1E,YL ;读出地址写入EEPRO地址寄存器SBI $1C,0 ;设置读出使能位(EERE)IN R16,$1D ;从EEPROM数据寄存器中读出数据ST X+R16 ;存入缓存区INC YLBRNE REEP1 ;INC YHCPI YH,2 ;EEPROM最末数据(地址为$1FF)读完?BRNE REEP1RET;范例23 ;写入EEPROM子程序WEEP: LDI YH,1LDI YL 0 ;EEPROM 写入之首地址:$100LDI XL,$60 ;写入数据存储区首地址:$60CLR XHWEEP1: SBIC $1C,1 ;查EEWE位,EEWE=1为当前尚有写入操作未结束RJMP WEEP1 ;等待EEWE=0OUT $1F,YHOUT $1E,YL ;送写入地址到EEPRO地址寄存器LD R16,X+ ;取写入数据并调整数据指针OUT $1D,R16 ;送到EEPROM数据寄存器SBI $1C,2 ;设置EEPROM写入总使能位EEMWESBI $1C,1 ;设置EEPROM写入使能位EEWEINC YLBRNE WEEP1INC YHCPI YH,2 ;EEPROM最末写入单元地址为$1FFBRNE WEEP1RET。
算术和逻辑指令•ADD 加法•ADC 带进位加•ADIW 加立即数•SUB 减法•SUBI 减立即数•SBC 带进位减•SBCI 带C 减立即数•SBIW 减立即数•AND 与•ANDI 与立即数•OR 或•ORI 或立即数•EOR 异或•COM 取反•NEG 取补•SBR 寄存器位置位•CBR 寄存器位清零•INC 加1•DEC 减1•TST 测试零或负•CLR 寄存器清零•SER 寄存器置FF•MUL 乘法•MULS 有符号数乘法•MULSU 有(无)符号数乘法•FMUL 小数乘法•FMULS 有符号数乘法•FMULSU 有(无)符号小数乘法条件转移指令•RJMP 相对转移•IJMP 间接转移•JMP 长转移•RCALL 相对调用•ICALL 间接调用•CALL 长调用•RET 子程序返回•RETI 中断返回•CPSE 比较相等跳行•CP 比较•CPC 带进位比较•CPI 带立即数比较•SBRC 位清零跳行•SBRS 位置位跳行•SBIC I/O 位清零跳行•SBIS I/O 位置位跳行•BRBS SREG 位置位转•BRBC SREG 位清零转•BREQ 相等转移•BRNE 不相等转移•BRCS C 置位转•ELPM 扩展装载程序存储器•EIJMP 扩展间接跳转•ESPM 扩展存储程序存储器•EICALL延长间接调用子程序•BRCC C 清零转•BRSH 转•BRLO 小于转(无符号)•BRMI 负数转移•BRPL 正数转移•BRGE 转(带符号)•BRLT 小于转(带符号)•BRHS H 置位转移•BRHC H 清零转移•BRTS T 置位转移•BRTC T 清零转移•BRVS V 置位转移•BRVC V 清零转移•BRIE 中断位置位转移•BRID 中断位清零转移数据传送指令•MOV 寄存器传送•MOVW 拷贝寄存器字•LDI 装入立即数•LD X X 间接取数•LD X+ X 间接取数后•LD -X X 间接取数先•LD Y Y 间接取数•LD Y+ Y 间接取数后+•LD –Y Y 间接取数先•LDD Yq Y 间接取数 q•LD Z Z 间接取数•LD Z+ Z 间接取数后•LD –Z Z 间接取数先•LDD Zq Z 间接取数 q•LDS 从SRAM 装入•ST X X 间接存数•ST X+ X 间接存数后•ST –X X 间接存数先•ST Y Y 间接存数•ST Y+ Y 间接存数后•ST –Y Y 间接存数先•STD Yq Y 间接存数 q•ST Z Z 间接存数•ST Z+ Z 间接存数后•ST –Z Z 间接存数先•STD Zq Z 间接存数 q•STS 数据送SRAM•LPM 装程序存储器•LPM Z Z•LPM Z+ Z+•SPM 存储程序存储器•IN I/O 口输入•OUT 送I/O 口•PUSH 压栈•POP 出栈位指令和位测试指令•SBI 置位I/O 位•CBI 清零I/O 位•LSL 左移•LSR 右移•ROL 带进位左循环•ROR 带进位右循环•ASR 算术右移•SWAP 半字节交换•BSET 置位SREG•BCLR 清零SREG•BST Rr 的b 位送T•BLD T 送Rr 的b 位•SEC 置位C•CLC 清零C•SEN 置位N•CLN 清零N•SEZ 置位Z•CLZ 清零Z•SEI 置位I•CLI 清零I•SES 置位S•CLS 清零S•SEV 置位V•CLV 清零V•SET 置位T•CLT 清零T•SEH 置位H•CLH 清零H•NOP 空操作•SLEEP 休眠•WDR 看门狗复位90 条指令器件:Attiny11/12/15/2289 条指令器件:AT90S1200118 条指令器件:AT90S2313/2323/2343/2333 AT90S4414/4433/4434/8515 AT90S8534/8535 121 条指令器件:ATmega603/103130 条指令器件:ATmega161。
;范例56 ;断电保护芯片MAX704,/RESET脚接8515同名脚;/PFO接INT0,由VOUT脚给UT6264(或UT62256)/62x42x供电,;本程序不涉及休眠!.ORG $000 ;AT90S8515/时钟4MHZSTRT60: RJMP RST60RJMP EX_INT0 ;外部中断0RJMP EX_INT1 :外部中断1.ORG $009 ;uart_rxc interruptRJMP RCVSV.ORG $010RST60: LDI R16,2OUT SPH,R16LDI R16,$5fOUT SPL,R16 ;堆栈指针初始化,指向$25fCLR XHLDI XL,$60CLR R16CLRX: ST X+,R16CPI XL,$5EBRNE CLRXCPI XH,2BRNE CLRX ;清除$60--$25dLDI R16,$F0OUT DDRB,R16 ;PB3-PB0输入PB7-PB4输出OUT PORTB,R16 ;上拉PB7-PB4SBI PORTB,0SBIS PINB,0RJMP BG1A ;若将PB0接地,不做断电启动LDI R16,70CLR R12CLR R11DLOPX: DEC R11BRNE DLOPXDEC R12BRNE DLOPXDEC R16BRNE DLOPX ;延时3.4秒(clk 4mhz)CLR R27LDI R26,$60CLR R16LOPX1: ST X+,R16CPI R26,$5EBRNE LOPX1CPI R27,2 ;清除$60--$25dBRNE LOPX1CLILDI R16,$80OUT GIMSK,R16 ;int1中断使能LDI R16,$DA ;激活外部RAM,加1等待周期,不休眠,int0/int1下降沿有效OUT MCUCR,R16;.;.;. ;LDS R16,$9FFE ;片外sram $8000-$9fff)CPI R16,$55BRNE BG1A ;查断电标志LDS R16,$9FFFCPI R16,$AABREQ BG2B ;查到BG1A: LDI R27,$80LDI R26,0CLR R16CLOPX: ST X+,R16CPI R27,$A0BRNE CLOPX ;清除$8000--$9FFFLDI R16,$AAST -X,R16 ;$AA-->($9fff)COM R16ST -X,R16 ;$55-->($9ffe)BG1A0: IN R16,GIMSKSBR R16,$40OUT GIMSK,R16 ;允许int0中断RJMP NRMSTBG2B: LDS R16,$9FFD ;$9FFD:最高位为生产标志SBRS R16,7RJMP NRMST ;无生产标志转平常启动BG5C: CBI PORTB,7 ;指示断电启动LDI R27,$80LDI R26,2 ;SRAM 8002-825F传回片内LDI R29,0LDI R28,2CLR R0 ;检查和清除APX0: LD R1,X+ST Y+,R1 ;传送数据块ADD R0,R1CPI R28,26 ;指向r26?BRNE APX0LD R1,X+ ;取r26ADD R0,R1LD R1,X+ ;取r27ADD R0,R1LD R1,X+ ;取r28ADD R0,R1LD R1,X+ ;取r29/ r26--r29为数据指针,不能当作数据传送ADD R0,R1LDI R28,30APX2: LD R1,X+ADD R0,R1ST Y+,R1CPI R28,$5FBRNE APX2INC XLINC YL ;SREG不断变化,不能加入累加和!APX3: LD R1,X+ADD R0,R1ST Y+,R1CPI R28,$60BRNE APX3CPI R29,2BRNE APX3 ;到$25f?LDS R1,$9FFC ;取检查和ADD R0,R1 ;检查和(CHECKSUM)正确?BREQ BG5DRJMP BG1A ;错,转总清BG5D: WDRLDI R16,$0D ;看门狗初始化,溢出时间0.49"OUT WDTCR,R16CLR R2 ;调DSPA次数计数器清除IN R16,GIMSKSBR R16,$40OUT GIMSK,R16 ;允许int0中断LDS R26,$235OUT SPH,R26LDS R26,$234OUT SPL,R26POP R26POP R27POP R28POP R29 ;数据指针出栈POP R1OUT SREG,R1 ;POP R1POP R0RETI ;弹出断点,开放中断NRMST: WDRLDI R16,$0D ;看门狗初始化,溢出时间0.49"OUT WDTCR,R16CLR R2;.......SEI;(略)RCVSV: ;.;.;.EX_INT0:PUSH R0 ;断电中断服务I BE CLEARED!PUSH R1IN R1,SREGPUSH R1PUSH R29PUSH R28PUSH R27PUSH R26 ;保护X,Y指针LDI R26,$1DOUT WDTCR,R26LDI R26,$15OUT WDTCR,R26 ;禁止看门狗IN R26,SPLSTS $234,R26IN R26,SPHSTS $235,R26 ;保护堆栈指针LDI R27,0LDI R26,2LDI R29,$80LDI R28,2 ;SRAM $002-25F 转片外$8002-$825fCLR R0 ;检查和予清除ALPX1: LD R1,X+ST Y+,R1ADD R0,R1 ;加入累加和CPI R26,26 ;BRNE ALPX1 ;POP R1 ;R26~R29从堆栈中取!ADD R0,R1ST Y+,R1POP R1 ;取R27ST Y+,R1POP R1 ;取R28ADD R0,R1ST Y+,R1POP R1 ;取R29ADD R0,R1ST Y+,R1IN R26,SPLSUBI R26,4 ;恢复堆栈指针,抵消4个POPOUT SPL,R26LDI R26,30 ;越过R26-R29,指向R30APX10: LD R1,X+ST Y+,R1ADD R0,R1CPI R26,$5FBRNE APX10INC XL ;SREG 越过!INC YLAPX20: LD R1,X+ST Y+,R1ADD R0,R1CPI R26,$60BRNE APX20CPI R27,2BRNE APX20 ;完成到$8002-825F之转移NEG R0STS $9FFC,R0 ;SAVE THE CHECKSUM TO $9FFC LDI R26,62CLR R27CLR R28DLPX5: DEC R28BRNE DLPX5DEC R27BRNE DLPX5DEC R26BRNE DLPX5 ;延时3秒(49.16ms*62=3")LDI R27,$80LDI R26,2 ;$8002-$825FLDI R29,0LDI R28,2 ;$002-25FCLR R0APX1A: LD R1,X+ST Y+,R1 ;将片外SRAM数据传回片内CPI R28,26BRNE APX1ALD R1,X+ ;R26ADD R0,R1LD R1,X+ ;R27ADD R0,R1LD R1,X+ ;R28ADD R0,R1LD R1,X+ ;R29ADD R0,R1LDI R28,30APX1B: LD R1,X+ST Y+,R1ADD R0,R1CPI R26,$5FBRNE APX1BINC XL ;越过SREG!INC YLAPX2A: LD R1,X+ADD R0,R1ST Y+,R1CPI R28,$60BRNE APX2ACPI R29,2BRNE APX2A ;到$25f?LDS R1,$9FFCADD R0,R1BRNE ERRDLRJMP BG5D ;检查和正确ERRDL: (略) ;错误处理;范例57;使用干电池便携系统断电保护程序MAX704 RESET引脚接8535同名脚;/PFO接8535INT0 断电时由电池给AT90LS8535供电;晶振4MHZ.ORG $000 ;AT90LS8535只使用片内sram;在片内RAM中保护数据STRT61: RJMP RST61RJMP EX_INT0RJMP EX_INT1.ORG $00BRJMP RVCMPLT ;串行数据接收完成.ORG $011OUT DDRA,R16 ;PA7-PA0为输入LDI R16,21CLR R12CLR R13DLPX: DEC R13BRNE DLOPXDEC R12BRNE DLPXDEC R16BRNE DLOPX ;延时1秒(clk 4mhz)LDI R16,2OUT SPH,R16LDI R16,$5fOUT SPL,R16 ;堆栈指针$25fCLR R2 ;调DSPB次数预清除WDRLDI R16,$0D ;设置看门狗溢出时间0.49"OUT WDTCR,R16LDI R16,$0FOUT PORTA,R16IN R16,PINACBR R16,$F0 ;清除无用的高4位CPI R16,15BRNE BG3A ;K0-K3有键按下,转LDS R16,$23E ;CPI R16,$55BRNE BG3ALDS R16,$23FCPI R16,$AABRNE BG3A ;无断电标志,转CLR R16STS $23E,R16 ;清除断电标志CLILDI R16,$C0OUT GIMSK,R16 ;LDI R16,$60 ;掉电休眠,OUT MCUCR,R16 ;int0 INT0 电平中断;.;. ;其他初始化程序略;. ;RJMP REST2 ;转断电启动! RVCMPLT:;(MISSING)BG3A: CLR R27CLR R16LOPX1: ST X+,R16CPI R26,$60BRNE LOPX1CPI R27,2BRNE LOPX1 ;清除$60--$25fLDI R16,2OUT SPH,R16LDI R16,$5FHOUT SPL,R16CLILDI R16,$C0OUT GIMSK,R16 ;允许int0/int1中断LDI R16,$60 ;掉电休眠OUT MCUCR,R16 ;INT0/INT1 电平中断;.;. ;其他初始化程序略;.SEIHH61: RCALL DSPB ;液晶显示子程序略LDI R16,$0F ;激活上拉电阻OUT PORTA,R16 ;IN R16,PINA ;读入键状态CBR R16,$F0CPI R16,$0F ;有键按下?BRNE HH61 ;等待释放IN R16,TIMSKSBR R16,$C0OUT TIMSK,R16 ;重新允许INT1中断SLEEP ;进入掉电休眠RJMP HH61 ;唤醒后显示新采集的数据EX_INT1:SEI ;允许INT0中断PUSH R16 ;K0/K1/K2/K3有按下者,产生电平中断唤醒MCU,采集数据IN R16,SREGPUSH R16SBI PORTA,3SBIS PINA,3RJMP DLK63 ;K3按下采集数据SBI PORTA,2SBIS PINA,2RJMP DLK62 ;K2按下采集数据SBI PORTA,1SBIS PINA,1RJMP DLK61 ;K1按下采集数据RJMP DLK60 ;K0按下采集数据DLKRT: IN R16,TIMSKCBR R16,$80OUT TIMSK,R16 ;禁止INT1中断(键未释放或抖动时不引起中断) POP R16OUT SREG,R16POP R16RETIDLK60: ;. ;采集、处理数据,数据处理后送入显示缓存区;.;.RJMP DLKRTDLK61: ;. ;采集、处理数据,数据处理后送入显示缓存区, ;.;.RJMP DLKRTDLK62: ;. ;采集、处理数据,数据处理后送入显示缓存区;.;.RJMP DLKRTDLK63: ;. ;采集、处理数据,数据处理后送入显示缓存区;.;.RJMP DLKRTEX_INT0:PUSH R0 ;掉电中断服务子程序PUSH R2PUSH R12PUSH R13 ;CLI ALREADY!PUSH R14PUSH R15PUSH R16PUSH R17PUSH R26PUSH R27PUSH R30PUSH R31IN R16,SREGPUSH R16 ;保护状态寄存器LDI R16,$1DOUT WDTCR,R16LDI R16,$15OUT WDTCR,R16 ;停止看门狗IN R16,SPLSTS $23C,R16IN R16,SPHSTS $23D,R16 ;保护堆栈指针LDI R16,$55STS $23E,R16COM R16STS $23F,R16 ;写断电标志SER R16OUT PORTC,R16 ;关显示CLR R16OUT GIMSK,R16 ;禁止外部中断(INT0&INT1)SLEEP ;进入掉电休眠REST2: LDS R16,$23DOUT SPH,R16LDS R16,$23COUT SPL,R16 ;取出堆栈指针POP R16OUT SREG,R16 ;恢复状态寄存器POP R31POP R30POP R27POP R26POP R17POP R16POP R15POP R14POP R13POP R12POP R2POP R0 ;恢复工作寄存器,主程序初始化时只能使用这些寄存器!RETI ;弹出断点,开放中断。
单片机汇编语言经典一百例汇编语言是一种底层的程序设计语言,是一种将汇编指令直接翻译成机器指令的语言。
在单片机编程中,掌握汇编语言是非常重要的,因为它可以充分发挥单片机的性能,并且提高程序的运行效率。
本文将介绍一百个经典的单片机汇编语言例子,帮助读者更好地理解汇编语言的使用。
1. 点亮LED灯```ORG 0x0000 ; 程序起始地址MOV P1, #0xAA ; P1口输出高电平,LED灯点亮END ; 程序结束```2. LED流水灯效果```ORG 0x0000 ; 程序起始地址MOV P1, #0x01 ; P1口输出低电平,第一个LED点亮CALL DELAY ; 调用延时函数MOV P1, #0x02 ; P1口输出低电平,第二个LED点亮CALL DELAY ; 调用延时函数MOV P1, #0x04 ; P1口输出低电平,第三个LED点亮CALL DELAY ; 调用延时函数MOV P1, #0x08 ; P1口输出低电平,第四个LED点亮CALL DELAY ; 调用延时函数…DELAY: ; 延时函数MOV R0, #100 ; 设置延时时间DELAY_LOOP:DJNZ R0, DELAY_LOOP ; 循环减一RET ; 返回END ; 程序结束```3. 数码管动态扫描显示```ORG 0x0000 ; 程序起始地址CLR P0.0 ; P0.0口输出低电平,选择第一个数码管MOV P2, #0x7E ; 将数码管对应的值存放到P2口CALL DELAY ; 调用延时函数CLR P0.1 ; P0.1口输出低电平,选择第二个数码管MOV P2, #0x30 ; 将数码管对应的值存放到P2口CALL DELAY ; 调用延时函数CLR P0.2 ; P0.2口输出低电平,选择第三个数码管MOV P2, #0x6D ; 将数码管对应的值存放到P2口CALL DELAY ; 调用延时函数CLR P0.3 ; P0.3口输出低电平,选择第四个数码管MOV P2, #0x79 ; 将数码管对应的值存放到P2口CALL DELAY ; 调用延时函数…DELAY: ; 延时函数MOV R0, #100 ; 设置延时时间DELAY_LOOP:DJNZ R0, DELAY_LOOP ; 循环减一RET ; 返回END ; 程序结束```...通过以上例子,我们可以看到单片机汇编语言的应用非常广泛,可以实现各种各样的功能。
;时钟日历芯片62×42×读写程序,时钟日历数据读入到显示缓存区$6C--$73 ;范例24 ;USE 8515!使用DSPA子程序.EQU RTCH=$40 ;rtc地址高八位RDATE: RCALL BSYT ;初始化,兼冻结RTCLDI XL,$6D ;数据缓存区首地址LDI YL,$06 ;首指日单元RDLP: LD R16,Y+ ;$6b 6c 6d 6e 6f 70 71 72 73ANDI R16,15 ; 2 9(D) - 1 0(M) - 0 2(Y)CPI R16,10BRCS RDL1ANDI R16,$7F ;容错处理RDL1: ST X,R16$DEC R26CPI R26,$6BBRNE RDLP1LDI XL,$70RDLP1: CPI R26,$6EBRNE RDLP2LDI R16,$14 ;送‘-’到$6E单元ST X,R16LDI XL,$73RDLP2: CPI R26,$71BRNE RDLPLDI R16,$14ST X,R16 ;送‘-’到$71单元并结束子程序RDINVL: RJMP WCRTRTIME: RCALL FIL2 ;请除缓存区RCALL BSYTLDI XL,$73LDI YL,$02 ;指向分单元(只读时分)RCL: LD R16,Y+ANDI R16,15CPI R16,10BRCS RCL0ANDI R16,$7F ;容错处理RCL0: ST X,R16DEC R26CPI R26,$71BRNE RCL1LDI R16,$14 ;写入‘-’ST X,R16DEC R26RCL1: CPI R26,$6E ;$6c 6d 6e 6f 70 71 72 73BRNE RCL ; 1 6 - 3 5CLR R16ST Y,R16LDS R17,$9FFB ;时制存储单元LDS R16,$6fSW AP R16LDS R15,$70ADD R16,R15 ;合成小时SUBI R16,$24 ;模24RCALL SUDAA ;BCD码减法调整BRCC RCL2 ;够减,转SUBI R16,-36 ;否则恢复被减数RCL2: CPI R17,2BRNE PRTD1 ;24小时制,转SUBI R16,$12RCALL SUDAABRCC PRTD1 ;12小时制处理SUBI R16,-18PRTD1: MOV R17,R16SW AP R16ANDI R16,$0FANDI R17,$0FSTS $6F,R16STS $70,R17 ;小时数据送入显示区RJMP WCRTWDATE: RCALL WRTC ;将显示缓存区中日期数据写入RTC LDI XL,$6FLD R16,XCPI R16,10BRCC WDRT ;非法数据,退出LDI YL,6WDLP: LD R16,XDEC R26CPI R16,$24 ;SPC?BRNE WD0CLR R16 ;变为0WD0: ST Y+,R16CPI R26,$6DBRNE WD1 ;$6d 6e 6f 70 71 72 73LDI XL,$71 ; 2 9(日) 1 1(月) 0 2 (年)RJMP WDLPWD1: CPI R26,$6fBRNE WD2WD2: CPI R26,$71BRNE WDLPLWDRT: RJMP WCRTWTIME: RCALL WRTC ;将显示缓存区中时间数据写入RTC LDI R26,$73LD R16,XCPI R16,10BRCC WCRT ;非法数据,退出LDI YL,2WLOP: LD R16,XCPI R16,$24BRNE WT1CLR R16 ;容错处理WT1: ST Y+,R16DEC R26WLP: CPI R26,$6FBRNE WLOP ;$6E 6f 70 71 72 73WCRT: CLR R16 ; 1 5 3 8LDI YL,$0DST Y,R16 ;解除对RTC之冻结IN R16,MCUCRCBR R16,$C0OUT MCUCR,R16 ;禁止读写外部RAMRET;对rtc初始化/冻结时钟BSYT: LDI YH,RTCH ;rtc地址高八位LDI YL,$0D ;指向D寄存器IN R16,MCUCRSBR r16,$C0 ;允许读写外部RAM并选一个时钟周期等待时间OUT MCUCR,R16LDI R16,5 ;设置冻结位和中断申请位ST Y,R16CLR XHBSRT: RET;写RTC初始化子程序WRTC: RCALL BSYTLDI YL,$0E ;指向寄存器ELDI R16,6ST Y+,R16 ;指向寄存器FLDI R16,1 ;设置时制位ST Y,R16LDI R16,4 ;选24小时制CLR R16 ;请除时制位ST Y,R16RJMP BSYT;范例25 ;显示保护子程序/晶振4MHZDSPRV: LDI R16,HIGH(ramend)OUT SPH,R16LDI R16,LOW(ramend)OUT SPL,R16CLR R2 ;调DSPY次数寄存器清除WDRLDI R16,$0D ;启动看门狗,溢出时间为0.49sOUT WDTCR,R16 ;写入看门狗控制寄存器CLR XHLDI XL,$6CDSPVL: ST X+,XH ;清显示缓存区($6c-$73)CPI XL,$74BRNE DSPVLDSPV0: LDI R16,$66MOV R9,R16LDI R16,$82 ;$6582=25986,高位字节增1为$66MOV R10,R16 ;调25986次DSPA耗时120sDSNEX: LDI XL,$74 ;将显示区十进制数据增1以演示数据变化DSLOP: LD R16,-X ;实用时可以采样数据更新显示(参考范例96)INC R16ST X,R16CPI R16,$0ABRNE DSPRV1CLR R16ST X,R16CPI R26,$6CBRNE DSLOP ;增1后如有进位则调整DSPRV1: DEC R10BRNE DSPGNDEC R9BRNE DSPGN ;2分钟定时到?DSCLOS: RCALL FIL2 ;将显示缓存区充入空白($24)RCALL DSPA ;其效果相当于关显SBRC R16,7RJMP DSCLOSRJMP DLFUNC ;有键按下,转出;否则继续关显DSPGN: RCALL DSPA ;未到,显示数据RJMP DSNEX ;无键按下,继续显示DLFUNC: CPI R16,12 ;关显键键值为12BEEQ DSCLOS ;关显键按下,转关闭显示;.;.;.;.;(其他键值处理,参考范例26 DEALKY程序)RJMP DSPV0 ;执行功能后转入二分钟定时;范例26 ;键值处理程序DEALKY: LDI R16,HIGH(ramend)OUT SPH,R16LDI R16,LOW(ramend)OUT SPL,R16CLR R2 ;调DSPY次数寄存器清除WDRLDI R16,$0D ;启动看门狗,溢出时间为0.49”OUT WDTCR,R16 ;写入看门狗控制寄存器DEALK0: RCALL DSPASBRC R16,7RJMP DEALK0 ;无键按下,反复查询CPI R16,10BRCC FNCKY ;功能键按下,跳转RCALL FIL2 ;键值<10为数字键,先清除显示缓存区NUMKY: RCALL LSDD8 ;8位数字左移,新键值加入序列尾DSLP: RCALL DSPASBRC R16,7RJMP DSLP ;无键按下,继续显示CPI R16,11BRCS NUMKY ;键入数字形成左移序列/按清除键则清除所有键入数据BRNE DSLP ;键值大于11无效;11为回车键,对键入数字进行处理(如将其两两合并为BCD;码,再转为二进制数等)RJMP DEALK0 ;转回FNCKY: SUBI R16,10 ;功能键散转处理,先计算键值偏移量LDI R31,HIGH(FKYTB)LDI R30,LOW(FKYTB);散转表表首ADD R30,R16CLR R16ADC R31,R16 ;偏移量加入指针IJMP ;散转FKYTB: RJMP CLTTL ;10:清除累加和RJMP DSTTL ;11:显示累加和RJMP DSCLS ;12:关显示RJMP SLFTS ;13:自检RJMP FDPAP ;14:打印机走纸RJMP PRSMP ;15:打印采样RJMP PRTTL ;16:打印累加和RJMP DSCLK ;17:显示系统时钟;............. ;.........;............. ;.........CLTTL: ;............. ;程序内容略;.............RJMP DEALK0 ;程序执行完毕,转回DSTTL: RCALL BRTTL ;分解累加和送显示缓存区RCALL DSPA ;显示累加和SBRC R16,7RJMP DSTTL ;任一键按下,结束显示累加和RJMP DEALK0 ;程序执行完毕,转回DSCLS: RJMP DSCLOS ;转去关显示SLFTS: ;.............;.............RJMP DEALK0 ; 自检程序执行完毕,转回FDPAP: ;.............;.............RJMP DEALK0 ; 走纸程序执行完毕,转回PRSMP: ;.............;.............RJMP DEALK0 ; 打印采样程序执行完毕,转回PRTTL: ;.............;.............RJMP DEALK0 ;打印累加和程序执行完毕,转回DSCLK: RCALL BRCLK ;分解系统时钟送入显示缓存区RCALL DL1S ;延时1秒RCALL DSPA ;显示时钟SBRC R16,7 ;任一键按下,结束显示时钟RJMP DSCLKRJMP DEALK0 ;程序执行完毕,转回;.............;............. ;其他功能键处理略;.............;范例27 ;主显子程序DSPA: SBRC R16,7 ;USE R0,R2,R11,R12,r13,r14,r15,r16,r17&Z,X POINTERS RJMP DSA2 ;无键按下,跳转DSA0: CLR R12INC R12 ;有键按下,将计数器置1DSA1: RCALL DSPYDEC R12BRNE DSA1 ;等待键释放DSA2: RCALL DSPYLDS R16,$A3SBRS R16,7 ;有进入功能表程序标志?RET ;没有返回SBI PORTA,0 ;SBIS PINA,0 ;退出功能表程序吗?RETCBR R16,$80 ;是,清除进入功能表程序标志($A3,7)STS $A3,R16RCALL FIL2LDI R16,$0F ;'F'STS $6C,R16LDI R16,$0E ;'E'STS $6E,R16LDI R16,$17 ;'n'STS $6F,R16LDI R16,$0D ;'d'STS $70,R16 ;显示‘F End'RCALL DL2S ;2秒后RJMP DIPA1 ;转到主程序(包括对堆栈)初始化DL2S: RCALL DL1S ;延时2秒子程序DL1S: LDI R16,217 ;延时1秒子程序/4MHz clkMOV R11,R16 ;4.618×217=1000msDLCOM: RCALL DSPADEC R11BRNE DLCOMRET;范例28 ;基显子程序,显示缓存区:$6C--$73,执行时间4.618ms/晶振4MHZ ;主程序应对看门狗初始化,设置溢出时间为0.49秒!DSPY: LDI R17,$0F ;使用R0,R2,R12,R13,R14,R15,R16&R17/z&x pointer!OUT DDRA,R15 ;PA7--PA4为键列值输入CLR R15COM R15OUT DDRB,R15OUT DDRC,R15 ;口B:段选输出,口C:位选输出OUT PORTC,R15 ;关显DPY1: LDI R26,$6C ;指向显示缓存区首址:$6C CLR R27LDI R17,$7FMOV R13,R17 ;位选初始化(首显最高位)L0D: LD R17,X+LDI R31,HIGH(table*2)LDI R30,LOW(table*2)ADD R30,R17ADC R31,R27L0C: LPM ;取段选码OUT PORTB,R0 ;送段选口OUT PORTC,R13 ;位选口SEC ;ROR R13 ;指下一位位选LDI R17,3 ;4MHz(6 if 8MHz)CLR R14DLOP: DEC R14BRNE DLOPDEC R17BRNE DLOP ;延时0.5762毫秒IN R16,PORTAORI R16,$F0 ;保护PA3--PA0输出OUT PORTA,R16 ;提拉PA7-PA4IN R14,PINA ;读入列值NEX: ROL R14 ;use high 4bits!BRCC L1 ;有键按下,跳转NEX1: INC R17 ;指向下一列CPI R17,4BRNE NEX ;各列都查完?NEX2: SER R17OUT PORTC,R17 ;将$FF写入位选口(关显)CPI R26,$74BRNE L0D ;每位LED都显示一遍??MOV R16,R15 ;YESINC R2 ;增一调DSPY次数寄存器MOV R17,R2CPI R17,100 ;到100次?BRNE NEX3CLR R2 ;清除看门狗定时器时间到计数器/4.618ms×100=0.462s(<0.49s) WDR ;看门狗定时器复位NEX3: RETL1: LDS R16,$73 ;计算键值代码/查键值SUB R16,R26 ;$73-(r26)-->r16LSL R16LSL R16 ;行值*4ADD R16,R17 ;键值代码=行值*4+列值LDI R30,LOW(TABL0*2)ADD R30,R16LDI R31,HIGH(TABL0*2)ADC R31,R27LA00: LPM ;查出键值MOV R15,R0 ;放在R15LA10: INC R12 ;计数器增1以备判断键释放RJMP NEX1 ;转回查下一列TABL0: .DB 10,0,11,20,1,2,3,16,4,5,6,22,7,8,9,18,12,15,19,23,14,17,21,13TABLE: .DB $3F,$06,$5B,$4F,$66,$6D,$7D,$07,$7F,$67,$77,$7C,$39 ;0--C .DB $5E,$79,$71,$6F,$74,$04,$1F,$40,$38,$37,$54,$5C ;'d'---'o'.DB $73,$67,$50,$6D,$78,$1C,$3E,$7E,$F8,$6E,$49,$00.DB $48,$52,$D3,$76 ;$25(=),$26(/)$27(?) END AT $28(H).DB $BF,$86,$DB,$CF,$E6,$ED,$FD,$87,$FF,$E7;THE 0.($29)--9.($32).DB $D7,$C9,$80 ;THE 'X.' 'Z.' &'.'($33--$35).DB $DE,$EF,$B8,$F3,$E7,$D0,$DC,$ED,$86,$F9,$B9H,$F7,$F1,$B7,$D4 ;the d.,g.,L.,p.,q.,r.,o.,s.,l.,E.,C.,A.,F.,M.,n.(36--44h);范例29 ;键入数字序列左移处理子程序LSDD8: LDI R26,$6C ;8bcd码($6C--$73H)LDS R27,$A3CBR R27,8 ;清$A3,3STS $A3,R27CLR R27CPI R16,10 ;10为清除键BRNE DDLRCALL FIL2 ;清除显示缓存区($6c-$73)!LDS R16,$A3SBR R16,8STS $A3,R16 ;建清除显示缓存区标志$A3,3=1RETDDL: INC R26 ;数字键按下,序列左移LD R16,X ;SUBI R16,$29 ;数字带小数点?BRCC DD4 ;若带则将其复原(参考DSPY子程序段码表)SUBI R16,$D7 ;恢复DD4: ST -X,R16 ;移入左邻单元DD5: INC R26CPI R26,$73BRNE DDL ;各数字都左移了一位?ST X,R15 ;新键入数字进入数字序列末位LDI R26,$6CDEL: LD R16,XCPI R16,10 ;是BCD码?BRCS DEL2CPI R16,$29BRCC DELRT ;大于$29为错误!DELA: INC R26 ;0--9/$24/$14为有效!CPI R26,$73BRNE DEL ;缓存区检查完毕?RJMP DELRTDEL2: CPI R16,0BRNE DELRTLDI R16,$24 ;0改为空白ST X,R16RJMP DELA ;DELRT: LDS R16,$A0 ;小数点位置单元TST R16BREQ DDRET ;($a0)=0,无小数点NEG R16ADD R16,$73MOV R26,R16 ;找到缓存区内带小数点的数据位LD R16,XSUBI R16,$D7 ;加上小数点ST X,R16CPI R16,$4D ;在空白码加了小数点($24(空白)+$29=$4d)?BRNE STLR1LDI R16,$29ST X,R16 ;是,将其改为'0.'STLR1: CPI R26,$73BREQ DDRET ;并将其后所有空白都改为0INC R26LD R16,XCPI R16,$24BRNE DDRETCLR R16ST X,R16RJMP STLR1DDRET: RETFIL2: LDI R26,8 ;在显示缓存区内填充空白MOV R14,R26FIL2A: LDI R26,$6CFIL: CLR R27LDI R16,$24FILP: ST X+,R16DEC R14BRNE FILPRET;范例30 ;双键输入检查数据子程序,Ky1数据键/Ky2回车键KYIN2: LDI R26,$60 ;寄存器地址:portb:$18/ddrb:$17/pinb:$16 CLR R27 ;指向数据区首地址CBI DDRB,7CBI DDRB,6 ;pb7和pb6皆为输入口SER R17OUT DDRC,R17 ;c口为数据显示口LA0: LD R17,X ;取数据CPI R17,$0ABRCS LA1CLR R17LA1: LDI R31,HIGH(table*2)LDI R30,LOW(table*2);DSPY段选码表ADD R30,R17ADC R31,R27LPMCOM R0 ;段选码取出并取反OUT PORTC,R0 ;送C口SBI PORTB,7SBIC $16,7RJMP NXA1 ;数字键未按下,转RCALL DL50 ;否则延时XA2: SBI PORTB,6SBIC $16,6RJMP XA0 ;只有数字键按下,转XA20: RCALL DL50 ;两键都按下,先延时50mS SBI PORTB,6SBIS $16,6RJMP XA20SBI PORTB,7SBIS $16,7RJMP XA20 ;等两键都释放RCALL DL50XA21: SBI PORTB,6SBIS $16,6RJMP XA21 ;等待释放SBI PORTB,7SBIS $16,7RJMP XA21 ;再次等待释放RJMP NXA6 ;先按数字键,再按回车键,待2都键释放后退出子程序XA0: SBI PORTB,7SBIS $16,7RJMP XA2 ;等待数字键释放XA1: RCALL DL50 ;延时SBI PORTB,7SBIS $16,7RJMP XA1 ;再次等待释放INC R17 ;数字增1CPI R17,10BRCS NXA1CLR R17 ;超过10,将键值归为0NXA1: SBI PORTB,6SBIC $16,6RJMP LA1 ;回车键也未按下,重新查键RCALL DL50 ;延时NXA3: SBI PORTB,6SBIS $16,6RJMP NXA3 ;再次等待回车键释放RCALL DL50SBI PORTB,6SBIS $16,6RJMP NXA3ST X+,R17 ;数字转入缓存区SER R17OUT PORTB,R17 ;关显RCALL DL50 ;CPI R26,$70 ;到规定数字个数?BRNE LA0 ;LDI R17,$86 ;显示'E'ndOUT PORTC,R17 ;NXA4: SBI PORTB,6SBIS $16,6RJMP NXA5 ;回车键按下,转SBI PORTB,7SBIC $16,7 ;数字键按下,转RJMP NXA4 ;否则反复查键NXA40: RCALL DL50SBI PORTB,7SBIS $16,7RJMP NXA40SBI PORTB,7SBIS $16,7RJMP NXA40 ;等待键释放RJMP KYIN2 ;转检查键入数据NXA5: RCALL DL50SBI PORTB,6SBIS $16,6RJMP NXA5SBI PORTB,6SBIS $16,6RJMP NXA5 ;等回车键释放NXA6: SER R17OUT PORTB,R17 ;关显,结束子程序RETDL50: ;RCALL DL25 ;延时50毫秒子程序/8Mhz(去掉指令前“;”号)DL25: CLR R14 ;延时50毫秒子程序/4MhzCLR R15DL50L: DEC R15NOPBRNE DL50LDEC R14BRNE DL50LRET;范例31LPRNT: SER R17 ;宽行打印机检测及控打程序OUT DDRC,R17 ;C口为打印机输出口!SBI DDRD,7CBI DDRD,3 ;pd7为选通输出口,pd3(INT1)查忙输入口SBI PORTD,3SBIC PIND,3 ;查打印机忙信号RJMP ERR5 ;打印机尚未工作忙信号即已为高,打印机不能打印LDI R17,$0D ;写回车命令给打印机OUT PORTC,R17CBI PORTD,7 ;发出选通信号NOPNOPNOPSBI PORTD,7 ;strobeLDI R16,50TSPRT: SBI PORTD,3SBIc PIND,3RJMP LPRT2 ;50次内忙信号高起来为正常DEC R16 ;否则为非正常状态BRNE TSPRTERR5: LDI R16,5RCALL ERRX ;显示5号错误RJMP DIPA1 ;转主程序初始化LPRT2: LDI R25,1CLR R24 ;point to $100LDI R17,$80OUT GIMSK,R17 ;允许int1中断LDI R17,$0AOUT MCUCR,R17 ;INT1下降沿中断SEI ;general interrupt enableRETEX_INT1:PUSH R26PUSH R27IN R27,SREGPUSH R27PUSH R17 ;保护现场MOV R27,R25 ;取数据指针MOV R26,R24LD R17,X+ ;MOV R25,R27MOV R24,R26 ;增1后将指针送回CPI R17,3 ;是停止符?BRNE INT1SDCLR R17OUT GIMSK,R17 ;禁止INT1中断RJMP INT1EDINT1SD: OUT PORTC,R17 ;打印数据输出到打印口CBI PORTD,7 ;clr ($12,7)NOPNOPNOPSBI PORTD,7 ;向打印机发出选通INT1ED: POP R17POP R27OUT SREG,R27POP R27POP R26 ;恢复现场RETI。
51单片机实用程序库4.1 流水灯程序介绍:利用P1 口通过一定延时轮流产生低电平输出,以达到发光二极管轮流亮的效果。
实际应用中例如:广告灯箱彩灯、霓虹灯闪烁。
程序实例(LAMP.ASM)ORG 0000HAJMP MAINORG 0030HMAIN:9MOV A,#00HMOV P1,A ;灭所有的灯MOV A,#11111110BMAIN1:MOV P1,A ;开最左边的灯ACALL DELAY ;延时RL A ;将开的灯向右边移AJMP MAIN ;循环DELAY:MOV 30H,#0FFHD1: MOV 31H,#0FFHD2: DJNZ 31H,D2DJNZ 30H,D1RETEND4.2 方波输出程序介绍:P1.0 口输出高电平,延时后再输出低电平,循环输出产生方波。
实际应用中例如:波形发生器。
程序实例(FAN.ASM):ORG 0000HMAIN:;直接利用P1.0口产生高低电平地形成方波////////////// ACALL DELAYSETB P1.0ACALL DELAY10CLR P1.0AJMP MAIN;////////////////////////////////////////////////// DELAY:MOV R1,#0FFHDJNZ R1,$RETEND五、定时器功能实例5.1 定时1秒报警程序介绍:定时器1每隔1秒钟将p1.o的输出状态改变1 次,以达到定时报警的目的。
实际应用例如:定时报警器。
程序实例(DIN1.ASM):ORG 0000HAJMP MAINORG 000BHAJMP DIN0 ;定时器0入口MAIN:TFLA G EQU 34H ;时间秒标志,判是否到50个0.2秒,即50*0.2=1秒MOV TMOD,#00000001B;定时器0工作于方式1MOV TL0,#0AFHMOV TH0,#3CH ;设定时时间为0.05秒,定时20次则一秒11SETB EA ;开总中断SETB ET0 ;开定时器0中断允许SETB TR0 ;开定时0运行SETB P1.0LOOP: AJMP LOOPDIN0:;是否到一秒//////////////////////////////////////// INCC: INC TFLAGMOV A,TFLAGCJNE A,#20,REMOV TFLAG,#00HCPL P1.0;////////////////////////////////////////////////// RE:MOV TL0,#0AFHMOV TH0,#3CH ;设定时时间为0.05秒,定时20次则一秒RETIEND5.2 频率输出公式介绍:f=1/ts51 使用12M晶振,一个周期是1微秒使用定时器1工作于方式0,最大值为65535,以产生200HZ的频率为例:200=1/t:推出t=0.005 秒,即5000 微秒,即一个高电12平或低电平的时间为2500 微秒。
;范例19 ;等步距线性内插计算子程序.EQU TBLGTH=10CHETA: LDI R16,TBLGTH-1 ;r16<--表长(即字数)-1LDI R31,HIGH(chtbl*2);y0(函数初值)在r14r15,STEP(步长)在r10r11,自变量X 在r12r13LDI R30,LOW(chtbl*2+1);查表指针,首指数据表第1字之高位字节!RCALL CPMR1 ;X与表中第一个字型数据(X0)比较BRCC CHRET ;X<X0 查表结束,Y=Y0CHET1: RCALL CMPR1 ;X与表中下一个数据比较BRCC NX33 ;X<X(i+1) 找到插值区间ADD R15,R11 ;否则Y0中加入一个STEP:Yk=Y0+k*step(步距为负时则;减去|STEP|)ADC R14,R10DEC R16BRNE CHET1 ;未查到表格终值,循环;否则结束,Y取得最大值Yn CHRET: RETNX33: SBIW R30,5 ;指针退回(-5),指向XiMOV R8,R14MOV R9,R15 ;保存Y0+i*STEPRCALL SUBS ;(X-Xi)-->r16r17MOV R15,R17MOV R14,R16 ;转入r14r15RCALL MUL16 ;(X-Xi)*STEP-->r12r13r14r15MOV R10,R12MOV R11,R13 ;保存乘积高位字LPM ;X(i+1)低位字节MOV R13,R0ADIW R30,1LPM ;X(i+1)高位字节MOV R12,R0SBIW R30,3 ;指针指向XiRCALL SUBS ;X(i+1)-Xi-->r16r17MOV R12,R10MOV R13,R11 ;取回乘积高位字MOV R10,R16MOV R11,R17 ;X(i+1)-Xi-->r10r11RCALL DIV165 ;(X-Xi)*STEP/[X(i+1)-Xi]-->r14r15ADD R15,R9ADC R14,R8 ;Y0+i*STEP+(X-Xi)*STEP/[X(i+1)-Xi]-->r14r15RET ;若STEP为负值则改为计算(r8r9)减去(r14r15)之值CMPR1: LPM ;取数据高位字节ADIW R30,2 ;指向下一数据的高位字节CP R0,R12 ;与X高位字节相比较BRNE CPRT1 ;不相等即转出SBIW R30,3 ;否则调整指针LPM ;取数据低位字节ADIW R30,3 ;指向下一数据的高位字节CP R0,R13 ;与X低位字节相比较CPRT1: RET ;以进位C带回比较结果SUBS: LPM ;计算(X-Xi)或[X(i+1)-Xi]并送入r16r17MOV R5,R0 ;取Xi低位字节ADIW R30,1LPM ;取Xi高位字节SBIW R30,1 ;仍指向Xi低位字节SUB R13,R5MOV R17,R13SBC R12,R0MOV R16,R12 ;计算差并将其转入R16R17RET;自变量x表长为12字CHTBL:DW 19214,23404,27600,32799,37009,40211,45414,48618,51821,55029,57787,60070 ;步距表长为11字STEPT: DW 356,366,379,395,415,440,471,509,555,603,657;不等步距线性内插计算子程序,步距表首址在R6R7中;自变量X在R12R13之中,函数初值Y0在R14R15中;范例20 ;表长(字个数)-1在R16中CHTSTP: LDI R31,HIGH(chtbl*2)LDI R30,LOW(chtbl*2+1);查表指针LDI R16,LOW(stept*2)MOV R7,R16LDI R16,HIGH(stept*2)MOV R6,R16 ;步距表指针LDI R16,TBLGTH-1 ;r16<--表长(字个数)-1RCALL CMPR1 ;X与表首数据比较BRCC CHSTPT ;X<X0 查表结束,有Y=Y0CHSTP1: RCALL CMPR1 ;否则与表中下一数据比较BRCC CHSTP3 ;X<X(i+1),找到插值区间!RCALL GTSTP ;查表取STEP字型变量ADD R15,R11 ;Y0<--Y0+STEPkADC R14,R10DEC R16BRNE CHSTP1 ;未查到表格终值循环;否则结束,Y取得最大值Yn CHSTPT: RETCHSTP3: SBIW R30,5 ;指针退回,指向Xi低位字节MOV R8,R14MOV R9,R15 ;Y0+∑STEPk送入r14 r15RCALL SUBS ;(X-Xi)->r16r17MOV R14,R16 ;(X-Xi)转入R14R15RCALL GTSTP ;查表取STEPi-->R10R11RCALL MUL16 ;(X-Xi)*STEPi-->R12R13R14R15MOV R10,R12MOV R11,R13 ;保存积高位字LPMMOV R13,R0ADIW R30,1LPMMOV R12,R0SBIW R30,3RCALL SUBS ;(X(i+1)-Xi)-->r16 r17MOV R12,R10MOV R13,R11MOV R10,R16MOV R11,R17 ;取回积高位字&(X(i+1)-Xi)-->r10r11RCALL DIV165 ;(X-Xi)*STEPi/[X(i+1)-Xi]-->r14r15ADD R15,R9 ;ADC R14,R8 ;Y0+∑STEPk+(X-Xi)*STEPi/[X(i+1)-Xi]-->r14r15 RETGTSTP: MOV R5,R6 ;查取STEP字型变量/POINTER in r6r7!MOV R6,R30MOV R30,R5MOV R5,R7MOV R7,R31MOV R31,R5 ;(r6r7)<-->ZLPMMOV R11,R0ADIW R30,1LPMMOV R10,R0 ;STEPk取到r10r11ADIW R30,1MOV R5,R6MOV R6,R30MOV R30,R5MOV R5,R7MOV R7,R31MOV R31,R5 ;指针增2后送回r6r7RET;范例21 ;功能表程序FUNC2: LDS R16,$A3 ;use r0,r8,r9,r10,r11,r16&r17/& subprogram dspa SBR R16,$80 ;功能表程序标志LDI YH,2LDI YL,0 ;功能内容表SRAM地址RCALL FLFUNC ;CLR r27!LDI R16,2ST X,R16 ;显示'FUNC.2'RCALL DL2SCLR R9 ;功能内容寻址偏移量R9!CLR R8 ;功能名称寻址偏移量(R8)=(r9)*3FFUNC0: RCALL DSF_ ;显示'F- 'FF0: RCALL DSPA ;in subprogram dspy clr. r27!CPI R16,11 ;回车键按下?BRNE FF2PFF0C: RCALL COMBNO ;合成功能名称送入r16 CPI R16,20 ;是最后一个功能名称?BRNE FF1CLR R9 ;是,两偏移量初始化!CLR R8FF1: LDI ZH,HIGH(FTABL*2)LDI ZL,LOW(FTABL*2);功能名称表指针ADD ZL,R8ADC ZH,R27 ;(r27)=0 ALWAYSLPMMOV R16,R0RCALL BRA3A ;分解新功能名称到$6E/$6FFF0G: LDI R28,0ADD R28,R9 ;功能内容指针加偏移量LD R16,YLDI R26,$72RCALL BRAX ;将新功能内容分解到$72/$73FF0A: RCALL DSPA ;显示新功能名称/内容CPI R16,11BRNE FF0B ;回车键按下?INC R8INC R8INC R8 ;是,功能名称寻址偏移量加3INC R9 ;功能内容寻址偏移量加1RJMP FF0C ;转回FF2P: RJMP FF2FF0B: CPI R16,10BRNE FF0DRCALL DSF_ ;清除键按下,清除显示区后,显示‘F-’FF1B: RCALL DSPACPI R16,11BREQ FF1 ;转恢复当前显示CPI R16,10BRCC FF1BRJMP FF2D ;只有数字键按下才转出去处理FF0D: CPI R16,10BRCC FF0AFF1D: LDI R17,$24 ;STS $73,R17 ;数字键处理,先在缓存区内放一空白FF0E: LDS R17,$73STS $72,R17 ;键入数字左移STS $73,R16 ;存入新数字FF0F: RCALL DSPACPI R16,10BREQ FF0G ;清除键按下,恢复显示旧功能内容BRCS FF0E ;键入数字左移更新CPI R16,11BRNE FF0FLDS R26,$72 ;回车键按下RCALL COMBA ;合成新功能内容(combin $72&$73 into binary(r16)) MOV R17,R8INC R17LDI ZH,HIGH(FTABL*2)LDI ZL,LOW(FTABL*2)ADD ZL,R17 ;取当前功能内容下限ADC ZH,R27FF1F: LPMCP R16,R0BRCS DSER2 ;新功能内容小于下限,错误INC R17LDI ZH,HIGH(FTABL*2)LDI ZL,LOW(FTABL*2)ADD ZL,R17 ;取当前功能内容上限ADC ZH,R27LPMCP R0,R16BRCS DSER3 ;新功能内容大于上限,错误FF7: LDI R28,0ADD R28,R9 ;功能内容表首地址为$200!ST Y,R16 ;合法的新功能内容进入功能内容表INC R9INC R8INC R8INC R8 ;调整偏移量,进入下一个功能显示RJMP FF0CFF1P: RJMP FF1DSER2: RCALL FERR2 ;显示'F Err.2'2秒RCALL EXCH0RJMP FF0G ;恢复原数据显示DSER3: RCALL FERR3 ;显示'F Err.3'2秒RCALL EXCH0RJMP FF0G ;恢复原数据显示FF2: CPI R16,10BRCS FF2D ;功能键按下,转初始RJMP FF0FF2D: LDI R17,$24 ;数字键按下,在显示缓存区内左移STS $6F,R17 ;FF3: LDS R17,$6FSTS $6E,R17STS $6F,R16FF4: RCALL DSPACPI R16,10BRNE FF41RCALL DSF_ ;清除数字,显示‘F-’FF40: RCALL DSPACPI R16,11BREQ FF1P ;转回显示当前功能名称及内容CPI R16,10BRCC FF40 ;无效键按下,转回RJMP FF2D ;否则转数字处理FF41: BRCS FF3CPI R16,11BRNE FF4RCALL COMBNO ;合成新功能名称CLR R10 ;功能名称偏移量计数器清除CLR R11 ;功能内容偏移量计数器清除SFFLP: LDI ZH,HIGH(FTABL*2)LDI ZL,LOW(FTABL*2)ADD ZL,R10ADC ZH,R27LPMCP R0,R16 ;BREQ SFFND ;在功能名称表中找到新名称INC R11 ;INC R10INC R10INC R10 ;调整偏移量LDI R17,60CP R10,R17 ;功能名称指针偏移量超过59?BRCS SFFLP ;否,继续查功能名称表RCALL FERR1 ;查完功能名称表未查到键入功能名称!RJMP FFUNC0 ;转回恢复原显示SFFND: MOV R9,R11 ;得到功能内容指针偏移量MOV R8,R10 ;得到功能名称指针偏移量RJMP FF0G ;转显示新功能名称及内容FTABL: .DB 1,0,1,2,1,8,3,0,2,4,0,1 5,1,2,6,0,4,7,1,4,8,1,2,9,2,7,10,1,5,11,1 .DB 5,12,0,5,13,1,2,14,1,7,15,1,10,16,1,4,17,2,4,18,2,5,19,1,2,20,1,3 COMBNO: LDI XL,$6E ;取$6E$6F中的BCD码,合成新功能名称子程序COMBA: LD R16,X+CPI R16,$24BRNE CMBACLR R16CMBA: MOV R0,R16LSL R16LSL R16ADD R16,R0LSL R16 ;高位BCD乘10LD R0,XADD R16,R0 ;加低位BCDRETDSF_: RCALL FIL8 ;准备显示'F- 'LDI R16,$0FSTS $6C,R16LDI R16,$14STS $6D,R16RETBRA3A: LDI XL,$6E ;二进制数转换为两位BCD码并显示BRAX: LDI R17,$24 ;十位为0时显示空白ST X,R17BRHOUR: CLR R0 ;BRX0: SUBI R16,10 ;减10BRCS BRX2INC R0RJMP BRX0BRX2: SUBI R16,-10 ;不够减恢复出十位BCDTST R0BREQ BRX1ST X,R0 ;放入显示区BRX1: INC R26ST X,R16BRART: RETFERR1: LDI XL,$71 ;显示'F Err.1'LDI R16,1ST X,R16RJMP FER123FERR2: RCALL MOVE1 ;显示'F Err.2' LDI R16,2STS $71,R16RJMP FER123FERR3: RCALL MOVE1 ;显示'F Err.3' LDI R16,3STS $71,R16FER123: LDI XL,$6CLDI R16,$0FST X+,R16LDI R16,$24ST X+,R16LDI R16,$0EST X+,R16LDI R16,$1BST X+,R16LDI R16,$3BST X+,R16 ;显示'F Err.1/2/3'LDI R16,$24 ;2秒STS $72,R16STS $73,R16RCALL DL2SRETFIL8: LDI R26,8 ;将显示缓存区充空白MOV R10,R26LDI R26,$6CCLR R27LDI R16,$24FILP: ST X+,R16DEC R10BRNE FILPRETFLFUNC: RCALL FIL8 ;准备显示'Func.' LDS R26,$6CLDI R16,$0F ;'F'ST X+,R16LDI R16,$1E ;'u'ST X+,R16LDI R16,$17 ;'n'ST X+,R16LDI R16,$40 ;'c.'ST X+,R16RETEXCH0: LDI ZL,$14 ;将显示缓存区内容转移$6C-$73<-->$214-$21B LDI ZH,2LDI XL,$6CEXL: LD R16,XLD R17,ZST X+,R17ST Z+,R16CPI R26,$74BRNE EXLRETMOVE1: LDI ZL,$14 ;将显示缓存区内容传送到$214-$21BLDI ZH,2LDI XL,$6CMV1: LD R16,X+ST Z+,R16CPI R26,$74BRNE MV1RET;范例22 ;读出EEPROM子程序REEP: LDI YH,1LDI YL 0 ;EEPROM 读出首地址:$100LDI XL,$60 ;读出数据存放首地址:$60CLR XHREEP1: SBIC $1C,1 ;查EEWE位,EEWE=1为当前尚有写入操作未结束RJMP REEP1 ;等待EEWE=0OUT $1F,YHOUT $1E,YL ;读出地址写入EEPRO地址寄存器SBI $1C,0 ;设置读出使能位(EERE)IN R16,$1D ;从EEPROM数据寄存器中读出数据ST X+R16 ;存入缓存区INC YLBRNE REEP1 ;INC YHCPI YH,2 ;EEPROM最末数据(地址为$1FF)读完?BRNE REEP1RET;范例23 ;写入EEPROM子程序WEEP: LDI YH,1LDI YL 0 ;EEPROM 写入之首地址:$100LDI XL,$60 ;写入数据存储区首地址:$60CLR XHWEEP1: SBIC $1C,1 ;查EEWE位,EEWE=1为当前尚有写入操作未结束RJMP WEEP1 ;等待EEWE=0OUT $1F,YHOUT $1E,YL ;送写入地址到EEPRO地址寄存器LD R16,X+ ;取写入数据并调整数据指针OUT $1D,R16 ;送到EEPROM数据寄存器SBI $1C,2 ;设置EEPROM写入总使能位EEMWESBI $1C,1 ;设置EEPROM写入使能位EEWEINC YLBRNE WEEP1INC YHCPI YH,2 ;EEPROM最末写入单元地址为$1FFBRNE WEEP1RET。