AVR汇编示例
AVR汇编百例 - 脉宽调制(PWM)

;脉宽调制(PWM)输出程序;范例50 ;以定时器定时产生精确半秒信号,以PD5输出精确秒号.ORG $000 ;晶体实测频率为8000367HZSTRT40: RJMP RST40 ;USE 8535.ORG $008 ;t/C1 overflow vectorRJMP T1_OVF.ORG $011RST40: LDI R16,HIGH(ramend)OUT SPH,R16LDI R16,LOW(ramend)OUT SPL,R16SBI DDRD,5 ;PD5(OC1A)为输出CBI PORTD,5 ;初始输出为低LDI R16,2 ;8分频INT(8000367/8)=1000046) 折半500023定半秒OUT TCCR1B,R16 ;T/C1控制寄存器(I/O ADDR:$2E)LDI R16,$5E ;500023=65536*8-24265=$10000*8-$5EC9OUT TCNT1H,R16 ;TCC=$5EC9 先写高位字节LDI R16,$C9OUT TCNTIL,R16LDI R16,$04OUT TIMSK,R16 ;允许T/C1溢出中断/8535C/t1:timsk,2&t0:timsk,0LDI R17,8 ;8次中断定半秒CLR R16OUT TIFR,R16 ;清除定时/计数器中断标志SEI ;HH40: RJMP HH40 ;背景程序略T1_OVF: IN R5,SREG ;保存状态寄存器DEC R17BRNE COMP1 ;定时时间到?IN R16,PORTD ;读入PD5当前状态LDI R17,$20EOR R16,R17 ;求反PD5(OC1A)输出OUT PORTD,R16IN R17,TCNT1L ;*IN R16,TCNT1H ;*读回TCNT1计数值SUBI R17,$37 ;*SBCI R16,$A1 ;*减去$5EC9之补码$A137SUBI R17,$FF ;*补偿指令8条占一个计数单位SBCI R16,$FF ;*补偿后TCC=$5EC9+(TCNT1)+1OUT TCNT1H,R16 ;*OUT TCNT1L,R17 ;*写入TCNT1LDI R17,8 ;重新写入中断次数COMP1: OUT SREG,R5RETI;范例51 ;以比较匹配A达到时交替输出高低电平及写入其维持;时间常数之方法实现脉宽调制输出.ORG $000STRT41: RJMP RST41 ;5.008MS(高):10.000MS(低) 晶振4MHZ .ORG $006RJMP T1_CMPA ;USE 8535.ORG $011RST41: LDI R16,HIGH(RAMEND)OUT SPH,R16LDI R16,LOW(RAMEND)OUT SPL,R16LDI R16,$80 ;T/C1比较匹配A达到时,清除输出脚oc1aOUT TCCR1A,R16LDI R16,$0B ;64分频ctc1=1 比较匹配达到清tcnt1OUT TCCR1B,R16SBI DDRD,5SBI PORTD,5 ;pd5(oc1a)初始化输出为高CLR R16OUT TCNT1H,R16 ;予清除tcnt1OUT TCNT1L,R16LDI R16,1OUT OCR1AH,R16LDI R16,$39 ;写比较匹配寄存器(313*0.25*64=5.008MS)OUT OCR1AL,R16LDI R16,$10OUT TIMSK,R16 ;允许比较匹配A中断SEIHH41: RJMP HH41 ;背景程序略T1_CMPA:IN R5,SREGIN R16,TCCR1ASBRS R16,6RJMP OUTLOW ;当前输出低电平,转LDI R16,1OUT OCR1AH,R16LDI R16,$39 ;写入高电平维持时间313OUT OCR1AL,R16LDI R16,$80 ;比较匹配A达到时,OC1A输出为低OUT TCCR1A,R16OUT SREG,R5RETIOUTLOW: LDI R16,2OUT OCR1AH,R16LDI R16,$71 ;写入低电平维持时间625(=$271) (625*0.25*64=10.000MS) OUT OCR1AL,R16LDI R16,$C0 ;比较匹配A达到时,OC1A输出为高OUT TCCR1A,R16OUT SREG,R5RETI;范例52 ;以比较匹配达到时求反输出并按高低电平写入.ORG $000 ;维持时间之方法实现脉宽调制输出STRT42: RJMP RST42 ;5.008MS(高):10.000MS(低) 晶振4MHZ .ORG $006RJMP T1_CMPA.ORG $011RST42: LDI R16,HIGH(ramend)OUT SPH,R16LDI R16,LOW(RAMEND)OUT SPL,R16LDI R16,$40 ;比较匹配A达到时,对OC1A输出求反OUT TCCR1A,R16LDI R16,$0C ;256分频ctc1=1 比较匹配达到时清除cnt1 OUT TCCR1B,R16SBI DDRD,5 ;PD5(oc1a)为输出SBI PORTD,5 ;初始输出为高CLR R16OUT TCNT1H,R16 ;清除tcnt1OUT TCNT1L,R16OUT OCR1AH,R16LDI R16,78 ;高电平时间常数78OUT OCR1AL,R16LDI R16,$10OUT TIMSK,R16 ;允许比较匹配A中断SEIHH42: RJMP HH42 ;背景程序略T1_CMPA:IN R5,SREG ;IN R16,PORTDSBRC R16,5RJMP T1CM1 ;当前oc1a为高,转LDI R16,0OUT OCR1AH,R16LDI R16,156 ;低电平时间常数156OUT OCR1AL,R16OUT SREG,R5RETIT1CM1: LDI R16,0OUT OCR1AH,R16LDI R16,78 ;高电平时间常数78OUT OCR1AL,R16OUT SREG,R5RETI;模/数转换和数/模转换及脉宽调制输出应用;范例53 ;模拟量采集和3路脉宽调制输出(OCR1A/OCR1B&OCR2)综合程;序/晶振4MHZ.ORG $000STRT50: RJMP RST50 ;avr is AT90S8535.ORG $00ERJMP ADCOM ;模数转换完成中断.ORG $011RST50: LDI R16,HIGH(ramend)OUT SPH,R16LDI R16,LOW(ramend)OUT SPL,R16 ;堆栈指针初始化CLR R11 ;通道号初始化CLR R12CLR R13 ;累加和予清除OUT $07,R11 ;ADC通道初始化,指向0#通道LDI R16,$6C ;T/C2为自运行pwm输出,加法计数匹配清除OC2,减法计;数匹配置位OC2(正向PWM);对晶振64分频OUT TCCR2,R16 ;tccr2' ADDR.:$25LDI R16,$ED ;使能,启动ADC/自由运行/转换完成中断/对晶振32分频OUT ADCSR,R16 ;ADDR:$06 adc控制状态寄存器IN R16,ASSRCBR R16,8OUT ASSR,R16 ;TCNT2 用主时钟!INC R11OUT $07,R11 ;予切换到1号ADC通道SBI DDRD,4SBI PORTB,4 ;pd4:oc1bSBI DDRD,5 ;pd5:oc1a pd4,pd5 皆为输出oc1b初始输出为高SBI DDRD,7 ;oc2 输出LDI R16,$E3 ;0B11100011,自运行PWM,COM1A1/0=11,COM1B1/0=10 OUT TCCR1A,R16 ;减法计数匹配清除OC1A,加法计数匹配置位OC1A(反向PWM);加法计;数匹配清除OC1B,减法计数匹配置位OC1B(正向PWM)LDI R16,2OUT TCCR1B,R16 ;tcnt1 8分频LDI R16,0OUT TCNT1H,R16 ;wr.high B at firstOUT TCNT1L,R16 ;清除TCNT1OUT TCNT2,R16 ;清除TCNT2OUT DDRA,R16 ;A口输入OUT PORTA,R16 ;输入为高阻态SEICOMLP: CPI R11,1BREQ COMLP ;通道号初始为1,等待切换过去COML0: CPI R11,1BRNE COML0 ;通道号再次为1时,0#通道正在转换,7#通道已转换完毕,;已得到8个A/D采样累加和ASR R12ROR R13ASR R12ROR R13ASR R12ROR R13 ;累加和除以8BRCC COML1CLR R16ADC R13,R16ADC R12,R16 ;四舍五入COML1: OUT OCR1AH,R12OUT OCR1AL,R13OUT OCR1BH,R12OUT OCR1BL,R13 ;10位数据写入比较匹配寄存器ASR R12ROR R13ASR R12ROR R13BRCC COML2INC R13BRNE COML2DEC R13COML2: OUT OCR2,R13 ;8位数据写入比较匹配寄存器CLR R12CLR R13 ;累加和清除RJMP COMLPADCOM: IN R15,ADCL ;ADC完成中断IN R14,ADCHADD R13,R15 ;模拟数值加入累加和ADC R12,R14INC R11SBRC R11,3CLR R11 ;total 8 chanales!&8 CHANGED TO 0OUT $07,R11 ;$07:admux'address REGISTERRETI;范例54 ;以R-2R电阻网络和C口配合组成DAC与输入模拟量比较实现模数转换.ORG $000 ;电阻网络DAC最大输出(AIN0)只能达到3.32V(PCi输出只能达到5V)STRT51: RJMP RST51 ;输入模拟量最大为4.98V,故应将DAC输出放大1.5倍再与前者比较.ORG $011 ;也可将输入模拟量衰减为2/3再与DAC输出比较RST51: LDI R16,2 ;但应将转换结果乘以1.5以使其复原,程序取后者OUT SPH,R16 ;堆栈指针初始化LDI R16,$5FOUT SPL,R16SER R16OUT DDRC,R16 ;C口全部为输出,DAC输出为AIN0输入CLR R16OUT DDRB,R16 ;B口为输入LDI R16,$F3OUT PORTB,R16 ;PB2(AIN0),PB3(AIN1)输入为高阻状态CLR R15 ;模数转换结果予清除LDI R16,$80 ;逼近增量初始值CMPLP: ADD R15,R16 ;模数转换阶段值加逼近增量OUT PORTC,R15 ;转成模拟量NOPNOPNOP ;4MHZ/等待1微秒SBIC ACSR,ACO ;输入模拟量大于DAC模拟量,清除ACOSUB R15,R16 ;否则去掉逼近增量LSR R16 ;逼近增量折半BRNE CMPLP ;逼近增量变为0?MOV R16,R15 ;*是,转换结束LSR R15 ;*ADC R15,R16 ;*将转换结果乘以1.5HH50: RJMP HH50 ;背景程序略范例55 ;40点平均在r18r19,累加和在r5r6r7;20点平均在R14R15,累加和在R1R3R4 SLPA V: PUSH R26 ;采样在R8R9,采样数据存储区$150--$19F/工作寄存器r1--r19&r26 r27PUSH R27LDI R27,1LDS R26,$14F ;数据存储区首地址$14FADD R7,R9ADC R6,R8 ;采样加入40点平均累加和BRCC SLP1INC R5 ;有进位,高位字节增1ADC R3,R8 ;采样加入20点平均累加和BRCC SLP2INC R1 ;有进位,高位字节增1SLP2: LD R16,XST X+,R9MOV R9,R16 ;置换出最旧采样低位字节LD R16,XST X+,R8MOV R8,R16 ;置换出最旧采样高位字节CPI R26,$A0BRNE SLPA1LDI R26,$50 ;采样放满存储区后,指针初始化($1A0=$150)STS $14F,R26LDS R16,$A4SBRC R16,4RJMP SLPA2 ;40点平均时间达到,转SBR R16,$10 ;设置40点平均时间达到标志STS $A4,R16RJMP SLDIV ;转去计算40点平均SLPA1: STS $14F,R26 ;暂存指针LDS R16,$A4SBRS R16,4RJMP SLPB0 ;还未到40点平均,转SLPA2: SUB R7,R9SBC R6,R8 ;到40点平均后除加上新采样外,还要减去最旧采样BRCC SLDIVDEC R5 ;不够减,高位字节减1SLDIV: CLR R12LDI R16,40MOV R11,R16CLR R10MOV R13,R5MOV R14,R6MOV R15,R7RCALL DIV165 ;计算40点平均MOV R18,R14MOV R19,R15 ;存入r18r19SLPB0: CPI R26,$78BRNE SLPB1LDS R16,$A4SBRC R16,3RJMP SLPB2SBR R16,8 ;建20点平均时间到标志RJMP SLPDV ;SLPB1: LDS R16,$A4SBRS R16,3RJMP SLRET ;20点平均时间未到SLPB2: SUBI R26,42 ;指针退回42字节,指向20点平均最旧数据CPI R26,$50 ;不小于80,未超出采样数据存储区BRCC SLPB20SUBI R26,-80 ;否则加80调整回$150-$19FSLPB20: LD R11,X+ ;LD R10,XSUB R4,R11SBC R3,R10 ;找到20点平均最旧采样,并将其从累加和中减去!BRCC SLPDVDEC R1SLPDV: LDI R16,20MOV R11,R16CLR R10CLR R12MOV R13,R1MOV R14,R3MOV R15,R4RCALL DIV165 ;20点平均在r14r15中SLRET: POP R27POP R26RET。
AVR汇编百例 - 实用程序

;范例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。
AVR的示例

A VR的示例1、矩阵键盘扫描的应用如果按键多的话,为节省I/O口资源,我们一般采用矩阵方式接口。
矩阵键盘由行和列组成,每个按键都有行值和列值,行值和列值的组合就是识别每个按键的编码。
确定哪个按键的流程是:先在行和列的一个口中输出高电平,在另一个行和列口读取扫描码;然后在后一个行列口输出高电平,在前一个行列口,读取第二个扫描码,然后查表就可以确定哪个按键按下了。
下面为我们的编程示例:/*功能:矩阵键盘扫描的应用CPU: ATMEGA8晶振:8MHZ */#include <iom8v.h>#include "Delay.h"//按键扫描函数,返回按键的值unsigned char ScanKey(void){unsigned char temp,temp1,key;temp=PINC; //读C口temp &=0x07;switch(temp) //判断行中哪条线有低电平{case 0x06: //PC0口有低电平DDRC=0X07; //PC0~PC2设为输出,PC3~PC5设为输入PORTC=0x38; //PC0~PC2输出0,PC3~PC5为1delay_us(1;);temp1=PINC; //读C口temp1 &=0x38;switch(temp1) //判断行中哪条线有低电平{case 0x30:key=0x01; //得到键值break;case 0x28:key=0x02; //得到键值break;case 0x18;key=0x03; //得到键值break;default:key=0;break;}DDRC=0x38;PORTC=0x07;break;case 0x05: //PC1口有低电平DDRC=0X07; //PC0~PC2设为输出,PC3~PC5设为输入PORTC=0x38; //PC0~PC2输出0,PC3~PC5为1delay_us(1;);temp1=PINC; //读C口temp1 &=0x38;switch(temp1) //判断行中哪条线有低电平{case 0x30:key=0x04; //得到键值break;case 0x28:key=0x05; //得到键值break;case 0x18;key=0x06; //得到键值break;default:key=0;break;}DDRC=0x38;PORTC=0x07;break;case 0x03: //PC2口有低电平DDRC=0X07; //PC0~PC2设为输出,PC3~PC5设为输入PORTC=0x38; //PC0~PC2输出0,PC3~PC5为1delay_us(1;);temp1=PINC; //读C口temp1 &=0x38;switch(temp1) //判断行中哪条线有低电平{case 0x30:key=0x07; //得到键值break;case 0x28:key=0x08; //得到键值break;case 0x18;key=0x09; //得到键值break;default:key=0;break;}DDRC=0x38;PORTC=0x07;break;default:key=0;break;}return (key);}//主函数,扫描按键显示数据void main(){unsigned char temp,keynum;unsigned char num[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //初始化端口DDRB=0xFF; //设置B口为输出口PORTB=oxFF; //置高电平DDRC=0x38;PORTC=0x07;while(1){PORTB=0x40; //按键放开后显示“一”temp=PINC;temp &=0x07;if(temp==0x07) //检测是否有按键按下contune;delay_us(10);temp=PINC;temp &=0x07;if(temp==0x07) //再次检测是否有按键按下,按键防抖contune;keynum=ScanKey();PORTB=num[keynum]; //通过查表在PORTB口显示按键值while(temp!==0x07 ) //等待按键放开{temp=PINC;temp &=0x07;}}}2、中断触发键盘扫描按下任何一个按键就会触发一个中断,然后在中断函数中调用键盘处理函数。
嵌入式系统入门—03—AVR的指令与汇编系统

数据优化
合理使用寄存器和内存,减少数据传输开销。
并行处理
利用AVR的并行处理能力,实现多任务并发 执行。
性能评估与优化建议
性能评估
通过性能测试和基准测试,评估程序的执行效率和性能。
优化建议
根据性能评估结果,提出针对性的优化建议,如采用更高效的算法、优化数据结构等。
THANKS FOR WATCHING
来执行这组指令。
宏展开
02
在宏定义后,可以使用宏展开将宏符号替换为相应的指令序列。
宏参数
03
在宏定义中可以定义参数,并在宏展开时将参数替换为相应的
值。
汇编语言程序结构
程序入口
程序从入口点开始执行,通常在程序的开头定义入口点。
程序主体
程序主体包含程序的逻辑和算法,由一系列指令和数据组成。
程序结束
程序结束时需要返回操作系统或返回到调用程序中。
控制流类指令
用于控制程序的流程,如JMP、CALL、RET等。
02 AVR指令详解
数据传输指令
数据传输指令用于在寄存器和内存之 间、寄存器和寄存器之间传输数据。
例如:MOV, LDS, STS等指令可以实 现数据的传输。
算术指令
算术指令用于执行加、减、乘、除等 算术运算。
例如:ADD, SUB, MUL, 语言的基础,汇编语言是使用助记 符表示机器指令的符号化语言。
指令集与机器码
指令集最终被转换为机器码,由计算机硬件执行。
AVR指令集的特点
精简高效
AVR指令集设计简洁,功能强大,适用于嵌入式系统。
丰富的寻址模式
AVR指令集支持多种寻址模式,如直接寻址、间接寻 址、相对寻址等,方便编程。
AVR汇编运算

sub16: sub r16,r18 ; r17:r16-r19:r18 r17:r16
sbc r17,r19
;******************************************************************************
步的处理
4.2.1 乘法运算子程序
列出了 mpy8u 8 位*8 位无符号乘法 mpy8 s 8 位*8 位带符号乘法 mpy 16u 16 位
*16 位无符号乘法 mpy 16s 16 位*16 位带符号乘法 mpy32u 32 位*32 位无符号乘法
;******************************************************************************
32 位运算与 16 位运算相似 例 32 位加法程序和 32 位减法程序如下
是整数运算程序 另外 定点数又可分为无符号数和有符号数 无符号数是明确为正数的数
其符号省略了 带符号数可能是正数 也可能是负数 一般负数以补码表示 最高位为符号位
整数乘以 10-n 或 2-n 来表示 例 十进制数 12.56=1256*10-2
十六进制数 1A.F8=1AF8*2 - 16
这样 可以将定点数先按整数运算 最后再考虑小数点的位置 所以下面所讲的程序主要
dec r19 ;循环计数器减 1
brne m8u_1 ; 如没完成 再循环
ret
4.2.1.2 mpy8s 8 位*8 位带符号乘法
1 程序功能 r1 6 (被乘数) *r17(乘数) r18 r17( 结果)
addi16: subi r16,low(-addi2) ; r17:r16+addi2 r17:r16
AVR汇编百例 - 晋级篇 - 参考程序

; 以下提供几个补充参考程序,都带有详细说明和指令注释.它们是主从多机通讯程序,采;用中断方式写入EEPROM,直接对晶振分频产生0.1秒和秒号的精确定时程序,以及RS-232/ ;RS-485标准转换程序,A VR频率计程序,串行时锺日历芯片DS13021302具体积小,;可靠性高,与单片机连接方便等优点.; 以下程序请参看有关章节或程序中的注释。
;范例91 ;多机通讯主机程序/晶振4MHZ.ORG 0 ;以8/9位数据模式区分被选/未被选分机通讯.EQU DTPINT=$180 ;UBRR=12 波特率19200(REL.ERR.=0.16%).EQU DRPINT=$1C0 ;主机对1#,2#,3#,4#分机发送数据块在$180-18F,$190-19F,$1A0-1AF)和$1B0-1BFSTRT38: RJMP RST38 ;主机从1#,2#,3#,4#分机接收数据块在$1C0-1CF,$1D0-1DF,$1E0-1EF)和$1F0-1FF.ORG $00B ;RJMP STRT38.ORG $00CRJMP STRT38 ;主机不设串口中断,只以查询接收.ORG $011RST38: LDI R16,12OUT UBRR,R16 ;设波特率:[BAUD RATE=FCP/16(UBRR+1)]CLR R15 ;初始化分机号LDI R27,HIGH(DTPINT)LDI R26,LOW(DTPINT);发送数据指针〔首指$180〕LDI R29,HIGH(DRPINT)LDI R28,LOW(DRPINT);接收数据指针(首指$1C0)NEXTNO: LDI R16,$18OUT UCR,R16 ;允许UART接收和发送,8位数据模式INC R15 ;指向1#分机OUTLP: OUT UDR,R15 ;呼分机号,1:1#/2:2#/03:3#/04:4#...TSLOP: IN R16,USRSBRS R16,7RJMP TSLOP ;分机返回机号?IN R16,UDRCP R16,R15 ;分机号正确返回?BRNE OUTLPLDI R16,$1C ;改为9位数据模式TXB8=0OUT UCR,R16 ;TXLOP: LD R16,X+OUT UDR,R16 ;向分机发送数据块TESTL: IN R17,USRSBRS R17,5RJMP TESTL ;等待发送完成CPI R16,$0ABRNE TXLOP ;RXTST: IN R17,USRSBRS R17,7 ;RXC=1 收到数据RJMP RXTST ;等待接收分机返回数据块IN R16,UDRST Y+,R16 ;存储接收数据CPI R16,$0A ;分机数据块发完?BRNE RXTSTMOV R16,R15CPI R16,4 ;与分机轮询通讯完毕?BRNE NEXTNO ;未完转对下一分机通信HH38: RJMP HH38 ;否那么踏步〔可改为处理分机返回的数据,之后再进行下一个轮询〕.DSEG.ORG $180DTPINT:.BYTE $40;$41 $45 $65 $73 $46 $42 $40 $6F $33 $44 $66 $5C $4D $4B $0D $0A;$42 $4F $66 $78 $47 $45 $44 $63 $32 $48 $60 $7C $6D $45 $0D $0A;$43 $56 $55 $53 $4D $4F $40 $2E $31 $42 $67 $4C $47 $4A $0D $0A;$45 $54 $59 $63 $3D $4B $48 $2F $35 $48 $69 $3C $77 $43 $0D $0A.ORG $1C0DRPINT:.BYTE $40;范例92.ORG 0 ;多机通讯1#分机程序/晶振4MHZ.EQU DTPIT1=$180 ;〔UBRR〕=12 波特率为19200(REL.ERR.=0.16%).EQU DRPNT1=$1C0STRT39: RJMP RST39.ORG $00BRJMP UARXC ;8535UART接收完成中断.ORG $00CRJMP UATXC ;UART发送完成中断.ORG $011RST39: CLR R18 ;去除分机被选中〔R18,6〕和主机数据块接收完毕标志(R18,7) LDI R16,12OUT UBRR,R16 ;设波特率[BAUD RATE=4000000/16*〔12+1)=19200]LDI R16,HIGH(DRPNT1)MOV R8,R16LDI R16,LOW(DRPNT1)MOV R9,R16 ;r8,r9:接收数据指针(FIRST POINT TO $1C0)LDI R16,$98 ;允许UART中断接收,8位数据模式OUT UCR,R16SEIRXDTS: SBRS R18,6 ;主机呼号已收到〔假设收到,在R17中〕?RJMP RXDTSOUT UDR,R17 ;返还该机号TXDON: IN R16,USRSBRS R16,5RJMP TXDON ;该机号发送完成?LDI R16,$9C ; 允许UART中断接收,9位数据模式,TXB8=0OUT UCR,R16RCVBLK: SBRS R18,7RJMP RCVBLK ;主机发来数据块已接收完毕?LDI R16,HIGH(DTPIT1)MOV R6,R16LDI R16,LOW(DTPIT1)MOV R7,R16 ;设发送数据指针r6r7,首指$180LDI R16,$3C ;允许UART中断发送,9位数据模式,TXB8=0OUT UCR,R16TXDN: SBIC UCR,5RJMP TXDN ;发送完毕?RJMP RST39 ;:UART中断接收程序UARXC: SBIC USR,4RETI ;祯错误〔主机正与其它分机进行9位数据模式通信〕,不予接收IN R14,SREG ;保存当前状态TST R18BREQ NUMB ;〔R18〕=0时收到数据,只可能是机号,转去核实PUSH R16 ;否那么为主机向本分机发来数据块〔9位模式,机号已符合〕PUSH R26PUSH R27IN R17,UDR ;接收数据MOV XH,R8MOV XL,R9 ;取接收数据指针ST X+,R17 ;转入RAMMOV R8,XHMOV R9,XL ;存数据指针CPI R17,$0A ;是数据块结束符LF?BRNE RSCOM1SBR R18,$80 ;收到完整数据块标志RSCOM1: POP R27POP R26POP R16DRETI: OUT SREG,R14RETINUMB: IN R17,UDR ;取出数据CPI R17,1 ;是1#分机?2#分机与$02比拟/3#分机与$03比拟...BRNE DRETI ;机号不符合,转!SBR R18,$40 ;建机号符合标志RJMP DRETI; UART中断发送程序UA TXC: PUSH R16 ;r6 r7:发送数据指针,首指$180IN R16,SREGPUSH R16PUSH R26PUSH R27MOV XH,R6MOV XL,R7 ;取出发送指针LD R16,X+ ;取数据,调指针MOV R6,XHMOV R7,XLOUT UDR,R16 ;送入发送存放器CPI R16,$0ABRNE SDCOMCBI UCR,5 ;发送最后1个字符后,禁止发送存放器空中断(CLR UDRIE)LDI R16,HIGH(DRPINT)MOV R8,R16LDI R16,LOW(DRPINT)MOV R9,R16 ;接收数据指针初始化〔POINT TO $1C0)SDCOM: POP R27POP R26POP R16OUT SREG,R16POP R16RETI.DSEG.ORG $180DTPIT1:.BYTE $40.ORG $1C0DRPNT1:.BYTE $10;$41 $45 $65 $73 $46 $42 $40 $6F $33 $44 $66 $5C $4D $4B $0D $0A;范例93;以中断方式写入EEPROM〔仅对8535,8515无此功能〕,克服查询方式占用过多机时的缺点,;并可在线写入;运作过程特点如下:;(1)主程序初始化时设置EEPROM就绪(ready)中断使能位和中断总使能位;(2)在主程序中写入第一个字节,写入完成后引起就绪中断,其他写入在中断效劳中完成;(3)本程序为一写入特例,写入地址为$100--$1FF,可作适当修改〔如设块长计数器等〕;(4)为防止高优先级中断破坏写入过程,中断效劳中不允许中断嵌套;(5)本例为简化程序只以查询写入地址循环作为背景程序,实用时可改为具体的背景序;(6)如能确信当前系统没有EEPROM正在写入,可删除对其进行查询局部. STWEEP: LDI R16,HIGH(ramend)OUT SPH,R16LDI R16,LOW(ramend)OUT SPL,R16SBI EECR,3 ;设置EEPROM就绪(ready)中断使能位SEI ;中断总使能RJMP SRTW.ORG $00FRJMP EEPRDY ;8535 EEPROM就绪(ready)中断向量SRTW: LDI YH,1LDI YL 0 ;EEPROM 写入首地址:$100LDI XL,$60 ;欲写入数据块首地址:$60CLR XHWEEP0: SBIC EECR,1 ;当前有EEPROM写入操作,有那么等待写入完成RJMP WEEP0RCALL WREEP ;写入第一个字节,($60)->$100,写入完成后,EEWE=0时引发EEPROM就绪中断INC YL ;调整写入地址指针HHWEEP: TST YLBRNE HHWEEPCPI YH,2 ;写入地址到达$200后,写入完成BRNE HHWEEPCBI EECR,3 ;禁止EEPROM就绪(ready)中断WDON: RJMP WDON ;踏步EEPRDY: IN R6,SREGPUSH R16RCALL WREEP ;写入一个字节INC YLBRNE WRETIINC YH ;EEPROM末地址为$1FFWRETI: POP R16OUT SREG,R6RETIWREEP: OUT EEARH,YH ;OUT EEARL,YL ;写入地址送入EEARLD R16,X+ ;取数据,调指针OUT EEDR,R16 ;数据写入EEPROM数据存放器SBI EECR,2 ;设置EEPROM写入总使能位EEMWESBI EECR,1 ;设置EEPROM写入使能位EEWERET;用定时/计数器1定时,不分頻定出0.1秒信号,由PC5脚输出正脉冲。
AVR 100个汇编范例

SBC R16,R9
RCALL SUDAA
MOV R13,R16
MOV R16,R12
SBC R16,R8
RCALL SUDAA
ADLOP: LD R16,-X ;X-1指向被加数;
LD R6,-Y ;Y-1指向加数
ADC R16,R6
RCALL ADDAA ;相加后调整
ST X,R16 ;返还调整后结果
RET ;否则返回
LDI R17,255
SUB R13,R17
SBC R12,R17 ;以减去-1($FFFF)替代加1
RET
RET
;范例2
SUDAA: BRCC SBD1 ;bcd码减法调整子程序,差在R16中
BRHC SBD3
SUBI R16,$66 ;进位半进位都置位,将差减去立即数$66
DEC R7
BRNE ADLOP
RET
;范例6
SUBCD4: MOV R16,R15 ;4字节压缩bcd码减法子程序
SUB R16,R11 ;R12,R13,R14,R15内为被减数,R8,R9,R10,R11内为减数
SUBLP: LD R16,-X ;X-1指向被减数
LD R6,-Y ;Y-1指向减数
SBC R16,R6
RCALL SUDAA ;相减后调整
ST X,R16 ;返还调整后结果
;范例10 ;32位被除数/16位除数-->16位商,精确到1
DIV16: LDI R16,16 ;(r12r13r14r15)/(r10r11)-->r14r15
DLOOP: LSL R15
电子设计资料-AVR单片机汇编语言机器人控制样例-

AVR单片机汇编语言机器人控制样例SL-DIY02-9伺服电机(舵机)机器人专用控制板的应用摘要:双龙电子为高中《简易机器人制作》课程开设,提供AVR单片机汇编语言机器人控制样例。
采用双龙电子SL-DIY02-9伺服电机(舵机)机器人专用控制板,利用双轴输出伺服电机(舵机)组成各种创意机器人,伺服电机既是机器人的驱体,又是机器人的活动关节部件,采用AVR单片机ATmega16作为机器人核心控制部件。
用AVR汇编语言编写机器人程序, 程序启停采用中断触发方式,可以同时控制4只伺服电机机器人动作,伺服电机运动速度、动作幅度可修改,也可方便扩展到8只伺服电机机器人动作。
本程序采用模块式结构,流程图说明,并有详细中文注释,程序在实验中调试通过,本程序可作为机器人创新开发参考。
一、SL-DIY02-9伺服电机(舵机)机器人专用控制板简介双龙电子的SL-DIY系列积木式单片机开发实验模块板,是单片机教学实验、机器人开发制作、参加各种创新大赛及参加各种机器人大赛的通用开发实验模板,做到一机多用。
SL-DIY系列积木式单片机开发实验模块板,只需一条ISP下载电缆线就可开发所有的AVR单片机。
从而为用户节省了购买仿真器、编程器、芯片适配器的大量费用。
功能板可以是空芯片,相当于提供一张白纸,可以让你写最好的文章,画最好最美的图画。
当然该功能板还提供各种程序例子,有汇编级及高级语言源程序,供使用者学习参考、修改补充,使该功能板符合自己项目工程的需要。
另外双龙电子也提供含有监控程序的芯片(含相应操作系统软件),使你可锦上添花,提高你的项目开发水平,加快项目的开发进程,让你早出成果,快出成果。
为了让SL-DIY系列积木式单片机开发实验模块板使用者更好地参加各种创新大赛及机器人大赛,尽量减小功能板体积及减轻功能板重量,双龙电子特别推出SL-DIY02-9伺服电机(舵机)机器人专用开发板(简称开发板),电原理框图如图1。
图1 电原理框图SL-DIY02-9开发板体积小(77x53mm),重量轻,是伺服电机机器人专用控制板,可用于有手有脚机器人、仿生机器人、虚拟机器人、网络机器人等的控制。
一个avr单片机的汇编程序,注意几个宏指令

一个avr单片机的汇编程序,注意几个宏指令//晶振1MHz//LED接PB0//使用定时器1,1024分频,0.5秒中断一次,LED闪烁一次程序如下:.include "m8def.inc".equ led =0.equ flash =$60.org $0000//中断向量表rest:rjmp STARTINT0addre: ; External Interrupt0 Vector Address retiINT1addre: ; External Interrupt1 Vector Address retiOC2addre : ; Output Compare2 Interrupt Vector AddressretiOVF2addre: ; Overflow2 Interrupt Vector AddressretiICP1addre: ; Input Capture1 Interrupt Vector Address retiOC1Aaddre: ; Output Compare1A Interrupt Vector AddressretiOC1Baddre: ; Output Compare1B Interrupt Vector AddressretiOVF1addre: ; Overflow1 Interrupt Vector Address rjmp Timer1_ovfOVF0addre: ; Overflow0 Interrupt Vector Address retiSPIaddre : ; SPI Interrupt Vector AddressretiURXCaddre: ; USART Receive Complete Interrupt Vector AddressretiUDREaddre: ; USART Data Register Empty Interrupt Vector AddressretiUTXCaddre: ; USART Transmit Complete InterruptVector AddressretiADCCaddre: ; ADC Interrupt Vector AddressretiERDYaddre: ; EEPROM Interrupt Vector AddressretiACIaddre : ; Analog Comparator Interrupt Vector AddressretiTWIaddre : ; Irq. vector address for Two-Wire InterfaceretiSPMaddre : ; SPM complete Interrupt Vector Address retiSPMRaddre: ; SPM complete Interrupt Vector Address reti.org $20START:ldi r16,low(ramend)//设置堆栈指针out spl,r16ldi r16,high(ramend)out sph,r16clr r16sts flash,r16sbi ddrb,led//PB0接ledrcall Timer1_ovf_init//调用初始化函数MAIN:lds r16,flashsbrs r16,0 ;if the flag is set,jump one low rjmp mainldi r16,0x01//LED取反in r17,pinbeor r17,r16out portb,r17clr r16sts flash,r16rjmp mainTimer1_ovf_init:ldi r16,0xfeout tcnt1h,r16ldi r16,0x17out tcnt1l,r16in r16,timsksbr r16,1<<2//开溢出中断out timsk,r16ldi r16,0x05out tccr1b,r16//开定时器sei //开中断retTimer1_ovf://定时器2定时0.5S in r16,sregpush r16//保存SREG入栈ldi r16,0xfeout tcnt1h,r16ldi r16,0x17out tcnt1l,r16clr r16sbr r16,1<<0//设置标志sts flash,r16pop r16out sreg,r16reti//中断返回。
avr iic汇编控制

avr iic汇编控制AVR(Advanced Virtual RISC)是一种由Atmel公司开发的8位RISC(精简指令集计算机)微控制器架构。
它广泛应用于嵌入式系统中,因为其高性能、低功耗和易用性。
在AVR上编程,你通常可以使用C语言或汇编语言。
使用汇编语言可以给予开发者更底层的硬件控制,但编程复杂度也相对较高。
下面是一个简单的AVR IIC(In-System Programming)汇编控制的例子,用于读取一个字节的数据:asm; 假设我们使用AVR的SPI接口进行IIC通信; 初始化SPI为Master模式.equ SPI_DDR = 0x3C ; SPI数据方向寄存器地址.equ SPI_PORT = 0x3D ; SPI数据端口地址.equ SPI_CTRL = 0x3B ; SPI控制寄存器地址; SPI初始化init_spi:ldi r16,(1<<SPIE)|(1<<MSTR)|(0<<CPOL)|(0<<CPHA)|(0<<SPR1)|(0<<SPR0) ; 设置SPI为Master模式,不启用中断,时钟极性和相位为默认,时钟分频为f_osc/4 out SPI_CTRL, r16 ; 将配置写入SPI控制寄存器ret; 读取一个字节的数据read_byte:ldi r16, (1<<SPIE)|(1<<MSTR)|(1<<SPE) ; 启用SPI,其他设置与之前相同out SPI_CTRL, r16 ; 将配置写入SPI控制寄存器ldi r16, 0xFF ; 准备发送的字节,这里假设是0xFFout SPI_PORT, r16 ; 将数据写入SPI数据端口,启动传输wait_for_complete:in r16, SPI_CTRL ; 读取SPI控制寄存器状态sbrs r16, SPIF ; 检查SPIF标志位,如果为0则跳转rjmp wait_for_complete ; 如果SPIF为0,继续等待in r16, SPI_DR ; 读取SPI数据寄存器,获取接收到的数据ret ; 返回这只是一个非常基础的例子,实际的IIC通信可能涉及更复杂的协议和时序。
AVR汇编百例 - 输入输出

;时钟日历芯片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。
ICCAVR 汇编参考

ICCAVR 汇编参考一. 名称1.1所有汇编名称必须由下列字符组成( …_‟ | [a-z] ) [ [a-z] | [0-9] | …_‟ ] *1.2在ICC 中汇编名称必须由下划线或字母开始,随后跟字母数字或下划线组成.1.3在这个文档中名称和符号是同名词名称,可以是表示一个常数值的符号名称或代表某一个地址的标号名称中的任意一个.1.4一个名称的长度最多为30 个字符长而且区分大小写,汇编指令和汇编伪指令除外1.5符号可以只用在程序模块中, 也可显式地被其它模块使用,在以前的例子中符号表示局部符号,而在以后的例子中表示全局符号1.6如果在一个文件一个符号没有被定义而直接使用了,那么它是被假设为在其它文件已经定义,而且它的值由链接器决定二. 数1.如果数带有一个0x 或$前坠那么这个数是一个十六进制数例如: 100x10$100xBAD0xBEEF0xC0DE-20三. 汇编文件格式汇编文件必须是一个ASCII纯文本文件,而且要遵守一定的规则文件的每一行应该是如下的格式[label: [:]] [command] [operands] [;comments]label 表示标号一个冒号表示局部符号两个符号表示全局符号command 表示操作码指令码operands 表示操作数[ ] 表示为可选项comments 表示注释注意在C 文件中注释用/ /或/* …. */ 引导而在汇编文件中用分号或// 引导上式的每项之间必须用一个或多个空格分开系统汇编时对注释部分不进行处理四. 标号1.一个后面跟着一个或两个冒号的名称表示标号.2.标号的值是程序中某一点的PC 计数器的值3.一个标号带两个符号表示全局符号,它在其它模块中也是显式的4.操作码应该是AVR 指令5.伪指令或宏操作数是指指令所需要的参数五. 4 表达式1.在指令后的操作数可以是表达式2.例如直接地址是一个最简单的表达式lds R10,asymbolasymbol 是一个简单表达式有例子它是一个符号或标号名称通常一个表达式描述为expr: term |{ expr }unop exprexpr binop exprterm: . 当前程序计数器PC 值name |#name3.圆括号用于分组其运算优先级高于运算符表达式,不能随意使用,有一个限制是使用链接器的重定位信息表达式的基本规则,是它只能出现一个重定位符号4.例如lds R10,foo+bar如果foo 和bar 两个全都是外部符号那么表达式无效六. 运算符下面列出了各种运算符和它们的优先级,运算符的优先级是很有用的只有加号可以用于重定位符号计算, 比如外部符号其它所有运算符必须用于常数或本文件中定义的符号的运算运算符功能类型优先级乘法二进制10/ 除法二进制10% 取模二进制10<< 左移二进制5>> 右移二进制5^ 按位异或XOR 二进制4& 按位与AND 二进制4| 按位或二进制4负号一元运算符11~ 取补运算一元运算符11< 取低字节一元运算符11取高字节一元运算符111.圆点. 或程序计数器如果圆点出现在表达式中那么当前程序计数器的值被放置在圆点的位置七. 汇编伪指令1.area <name> [(attributes)]定义代码或数据装入的内存区域, 链接器将所有使用同一名称的区域集合至一起,并且根据它们的属性进行连接或覆盖2.属性有两类2.1一类为abs, 或绝对定位区域rel 重定位区域2.2另一类为con, 或连接定位ovr 覆盖定位3.绝对定位区域的起始点地址是在汇编文件中由它自己指定的,而重定位区域的起始地址是由送命令选项给链接器来指定的,对带连接属性的区域链接器连接这个区域到另一个同名区域后面,对带有覆盖属性的区域对每一个文件链接器都是从同一地址开始安排区域4.下面举例说明它们的区别4.1file1.o:.area text 10 bytes, 调用text_1.area data 10 bytes.area text 20 bytes, 调用text_24.2file2.o:.area data 20 bytes.area text 40 bytes, 调用text_34.3text_1 和text_2 在这个例子中是正确的名称,实际上它们是不会获得一个单独的名称的让,我们假设text 区域的起始地址设置为0, 如果这个text 区域有“con”属性, 那么text_1将从0 开始, text_2 从地址10 开始, 而text_3 从30 地址开始,如果这个text 区域有“ovr”属性, 那么text_1 和text_2 将分别地从0 和10 开始,但对text_3 ,由于它在另外一个文件中定义,所以它将同样从0 地址开始. 所有同名的区域必须有相同有属性即使它们用在不同的模块中.4.4下面是具有合适属性的全部例子.area foo(abs).area foo(abs,con).area foo(abs,ovr).area foo(rel).area foo(rel,con).area foo(rel,ovr).ascii strings?八. ASC 字符串1..ASCIZ 字符串2.这个伪指令用于定义字符串,无论哪一个都要附上一对分界符在两个分界符之内任意可打印字符都是有效的下面是C 语言中的类型转义字符转义字符都是从反斜线\ 开始的\e ESC\b 退格\f 换页\n 换行\r 回车\t TAB3.\<最多三个八进制数> 字符是等于这个八进制数的值4.A SCIZ 定义在字符串的结尾增加了NUL 字符(\0) 它使\0 正确地嵌入字符串的内部例如: asciz “Hello World\n”asciz “23\0456”3 .byte <expr> [,<expr>]*.word <expr> [,<expr>]*.long<expr> [,<expr>]*5.这些伪指令是定义常数它们分别表示字节常数(byte) 字常数(2byte) 和双字长数6.(4byte) 字和双字常数是以高低字节倒置的格式输出这个格式用于AVR 微控制器(MCU)7.注意双字常数只能用作操作数而另外两个可以用于重定位表达式8.例如: .byte1, 2, 39..word label,foo10.4 .blkb <value>11..blkw <value>12..blkl <value>13.这些伪指令是保留空间而没有给它们赋值指令后面的数分别是指保留的字节字或14.双字的数目九.d efine <symbol> <value>1.定义一个文本替代符无论何时"symbol"可用在表达式中如寄存器符号或标号它2.是用"value."定义的例如3..define quot R154.mov quot,R16十.i f <symbol name>1..else2..endif3.上述三个伪指令定义了一个条件汇编语句如果条件<symbol name>为真非0 则执4.行.if 和.else 之间的指令如果条件<symbol name>为假等于0 则执行.else 和.endif 之间5.的指令.else 可以省略条件语句最多可以嵌套10 层如6..if cond7.lds R10,a8..else9.lds R10,b10..endif11.如果cond 不等于0 则将a 装入R10 如果cond 等于0 则将b 装入R10十一.macro <macroname>1.定义一个宏由一直到.endmacro 之间的所有声明组成宏除了另外一个宏声明外任意汇编声明可以是宏的组成部分在宏内部表达式@digit(digit 由0~9 的数字代替)是宏被调用时相应的宏参数定义的宏名称不能与汇编指令及汇编伪指令名称相冲突例如定义宏名“foo”.macro foolds @0,amov @1,@0ImageCraft ICCAVR 的中文使用说明.endmacro2.调用宏foo 需要两参数如foo R10,R11等同于lds R10,amov R11,R103.e ndmacro 结束一个宏定义4.<macro> [<arg0> [,<args>]*]调用宏是在操作码的位置放置宏名后面跟上相应的参数汇编器使用组成宏的声明来替换宏同时用相应的宏参数来扩展@digit 你可以指定多个参数例如:foo bar,x调用宏foo 而且带两个参数bar 和x.<symbol> = <value>定义一个符号等于常数值如:foo = 5十二.include “<filename>”1.处理指定的由文件名称指定的文件,如果当前目录该文件不存在汇编器将试图按文件名称指定的路径打开指定的文件2.如: .include “registers.h”十三.org <value>1.设定程序计数器PC 的值为"value." 这个伪指令中在带有"abs"属性的区域内有效,注意"value"是字节地址2.例如:.area interrupt_vectors(abs) 0xFFD04.dc.wreset十四.全局符号,1.将一个符号定义为全局符号使其在当前或其它模块中都是显式的这也和跟着两个冒号的标号相同否则符号只能在当前模块中使用。
AVR汇编百例 - 浮点程序库

;范例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。
[AVR汇编例程]AVR单片机用定时器1产生PWM波形实验
![[AVR汇编例程]AVR单片机用定时器1产生PWM波形实验](https://img.taocdn.com/s3/m/4b83133da9114431b90d6c85ec3a87c240288ae6.png)
[AVR汇编例程]AVR单片机用定时器1产生PWM波形实验AVR单片机的定时器功能非常强大,除了一般的定时、计数功能外,还具有PWM波形发生,捕获和比较等功能。
本实验演示AVR单片机的定时器产生PWM波形的方法。
我们配置定时器1(Timer1)工作在10位相位修正PWM波形产生模式。
该程序用AVR- Studio-4 开发,在AVR单片机Atmega48上调试通过。
本实验的详细说明和硬件搭建请参考>>;--------------------------------------------------------------------------------------------------;--------单片机入门实验用定时器1产生PWM波形实验 AVR 汇编程序-----------;--------------------------------------------------------------------------------------------------;作者: 超简单工作室;Email:********************;软件版本: AVR Studio 4.13.571 Service Pack 2;创建日期: 2008.5;版本 V1.00;; Target : M48; Crystal: 8.0000Mhz;*****************************************************.include "m48def.inc".org $0000rjmp _main.org $0020_port_init:; PORTB = 0x00;clr R2out 0x5,R2; DDRB = 0x06;ldi R24,6out 0x4,R24; PORTC = 0x00;out 0x8,R2; DDRC = 0x00;out 0x7,R2; PORTD = 0x00;out 0xb,R2; DDRD = 0x00;out 0xa,R2ret_timer1_init:; TCCR1B = 0x00; //stopclr R2sts 129,R2; TCNT1H = 0xFC; //setupldi R24,252sts 133,R24; TCNT1L = 0x01;ldi R24,1sts 132,R24; TCCR1A = 0xE3;ldi R24,227sts 128,R24; TCCR1B = 0x03; //start Timer ldi R24,3sts 129,R24ret_adc_init:; 设置前,先关闭ADCclr R2sts 122,R2; 选择内部AVCC为基准ldi R24,64sts 124,R24; 关闭模拟比较器ldi R24,128out 0x30,R24; 使能ADC,启动ADC单次转换,选64分频ldi R24,198sts 122,R24ret_adc_get:; 启动ADC转换lds R24,122ori R24,64sts 122,R24L5:lds R2,122sbrc R2,6rjmp L5lds R16,120lds R17,120+1ret_main:rcall _port_initrcall _timer1_initrcall _adc_initL9:; adc_v = adc_get(); //ADC转换rcall _adc_get; lt = 1023 - adc_v;ldi R24,0xffldi R25,3movw R12,R24sub R12,R16sbc R13,R17; rt = 1023 - adc_v;sub R24,R16sbc R25,R17movw R10,R24;; OCR1A = lt;sts 136+1,R13sts 136,R12; OCR1B = rt;sts 138+1,R11sts 138,R10rjmp L9ret。
AVR汇编百例 - 串行通讯

;范例40.ORG 0 ;8535UART串行通讯程序,晶振4MHZ.EQU DTPINT=$180 ;UBRR=12 波特率19200(REL.ERR.=0.16%).EQU DRPINT=$1D0STRT30: RJMP RST30.ORG $00BRJMP U_RXC ;UART接收完成中断.ORG $00CRJMP U_TXC ;UART发送寄存器空中断.ORG $011RST30: LDS R16,$A3 ;CBR R16,3STS $A3,R16 ;清完整ASCII数据块接收到标志($A3,1),错误标志(FE/OR)($A3,0) LDI R16,12OUT UBRR,R16 ;BAUD RA TE=FCP/16(UBRR+1)=19200LDI R27,HIGH(DIPINT)MOV R6,R27LDI R26,LOW(DTPINT)MOV R7,R26 ;发送数据指针在r6r7(dtpint)CLR R11INC R11LDI R16,$30 ;发送数据块长度为$30MOV R12,R16RCALL CRC0 ;得到CRC检测之余式(冲掉$0D&$0A)INC XLINC XLLDI R16,$0DST X+,R16LDI R16,$0AST X,R16 ;在数据块末尾加$0D&$0A,实际发送数据块长度为$32LDI R16,$B8 ;允许UART发送和接收,接收中断,发送寄存器空中断,8位数据OUT UCR,R16LDI R16,HIGH(DRPINT)MOV R8,R16LDI R16,LOW(DRPINT)MOV R9,R16 ;r8,r9:接收缓存区指针(FIRST POINT TO $1D0)CLR R10 ;接收数据块长预先清除SEI ;HH30: LDS R16,$A3SBRC R16,0 ;错误接收?RJMP RCVER ;错误处理SBRS R16,1 ;接收数据完成?RJMP HH30 ;否,转再查询RCVEF: CLR R11 ;块长予处理INC R11DEC R10DEC R10 ;$0D&$0A不算块长度之内(故将块长减2)MOV R12,R10 ;(R11,R12):块长LDI XH,HIGH(DRPINT)MOV R8,XHLDI XL,LOW(DRPINT)MOV R9,XLRCALL CRC0 ;恢复出CRC余式LDI R16,$0DCP R16,R14BRNE CRCERLDI R16,$0ACP R16,R15 ;恢复出$0D$0A为正确接收BREQ HH30CRCER: ;. ;循环冗余检测错误处理;.;.RJMP STRT30RCVER: CBI UCR,RXCIE;. ;接收错误(FE/OR)处理;. ;(过程略);.RJMP STRT30:UART接收数据块程序U_RXC: PUSH R16IN R16,SREGPUSH R16PUSH R26PUSH R27RSC1: IN R16,USR ;UART状态寄存器ANDI R16,$18 ;FE/OR ERROR?BRNE RVERR ;错误转INC R10 ;块长加1MOV XH,R8MOV XL,R9 ;r8r9:接收数据指针,首指$1D0IN R16,UDRST X+,r16 ;MOV R8,XHMOV R9,XLCPI R16,$0A ;收到最末字符(回车命令LF)?BRNE RSCOMLDS R16,$A3SBR R16,2 ;建立数据块接收完毕标志STS $A3,R16CBI UCR,RXCIE ;禁止接收中断RJMP RSCOMRVERR: LDS R16,$A3SBR R16,1STS $A3,R16 ;$A3,0:FE/OR错误接收标志RSCOM: POP R27POP R26POP R16OUT SREG,R16POP R16RETI; UART发送数据块程序U_TXC: PUSH R16IN R16,SREGPUSH R16PUSH R26PUSH R27SPSV1: MOV XH,R6MOV XL,R7 ;发送数据指针,首指$180LD R16,X+ ;取发送数据,调指针MOV R6,XHMOV R7,XLSPS11: OUT UDR,R16 ;送入数据寄存器,移入发送移位寄存器后即引起数据寄存器空中断CPI R16,$0ABRNE SPCOMCBI UCR,UDRIE ;发送最末字符后禁止发送寄存器空中断LDI R16,HIGH(DRPINT)MOV R8,R16LDI R16,LOW(DRPINT)MOV R9,R16 ;接收数据指针初始化,指向$1D0;CBI USR,6 ;SPCOM: POP R27POP R26POP R16OUT SREG,R16POP R16RETI.DSEG.ORG $180DTPINT:.BYTE $32;$41,$45,$65,$73,$46,$42,$40,$6F,$33,$44,$66,$8C,$4D,$4B,$2F,$67;$42,$4F,$66,$78,$47,$45,$44,$63,$32,$48,$60,$7C,$6D,$45,$2A,$63;$43,$56,$55,$53,$4D,$4F,$40,$2E,$31,$42,$67,$4C,$47,$4A,$38,$39;$0D,$0A.EQU DRPINT=$1D0.ORG $1D0DRPINT: .BYTE $34 ;(内容略);范例41 ;外部中断int0接收ASCII码数据块.ORG 0 ;8515/8535/晶振4MHZSTRT31: RJMP RST31RJMP EX_INT0.ORG $00D ;8535外部中断0RST31: LDI R17,HIGH(ramend)OUT SPH,R17LDI R17,LOW(ramend)OUT SPL R17LDI R17,2OUT TCCR1B,R17 ;4mhz/8分频,计数单位为2微秒,TCCR1B:$2e LDI R17,$40OUT GIMSK,R17 ;gimsk,6(允许int0中断)LDI R17,2OUT MCUCR,R17 ;设INT0为下降沿中断(mcucr'b1&b0=10)CBI DDRD,2 ;int0 为输入;.;. ;其他初始化略SEI ;CLRBUF: LDI R27,1CLR R26 ;接收数据缓存区首址$100LDI R17,$40OUT GIMSK,R17 ;gimsk,6CLR R17CLRLOP: ST X+,R17CPI R26,$48BRNE CLRLOP ;清接收缓存区($100--$147)LDS R16,$A3CBR R16,$60STS $A3,R16 ;接收错误($A3,6)和接收完成($A3,5)标志清除CLR5: ;.;. ;背景程序略RJMP CLR5 ;RCVST: CBI DDRD,2 ;int0 为输入SER R16 ;接收开始OUT PORTC,R16 ;关显LDI R27,1CLR R26 ;接收数据指针,首指$100LDI R17,18 ;接收18个字符,其末尾为$0D$0AMOV R14,R17RCALL RVBYT1 ;接收第一个字符RJMP RVBYTRVBLOP: RCALL RVBYT2 ;接收第二个字符及其后字符RVBYT: LDS R17,$A3SBRC R17,6RJMP CLRBUF ;接收出错,转去清除$100--$14FSBRC R17,5RJMP DTCOM ;接收完整数据块,转去处理ST X+,R16DEC R14BRNE RVBLOP ;未收完18个字符,继续CPI R26,$42 ;指针达到$142?BREQ DTCOM ;接收完整数据块,转去处理DEC R26DEC R26 ;$0D$0A(CR&LF)丢掉RCVLP: LDI R17,18MOV R14,R17RJMP RVBLOPDTCOM: LDI R27,1CLR R26 ;接收数据首地址:$100DLLOP: CLR R29LDI R28,$90 ;处理ASCII码程序acum要求将数据放在$90--$9f LD R16,XCPI R16,$50 ;第一个字符约定为‘P’才有效BRNE RVCOM1 ;也是判断处理结束符DLLOP1: LD R16,X+ST Y+,R16CPI R28,$A0BRNE DLLOP1 ;传16个字符PUSH R26PUSH R27RCALL ACUM ;ASCII变BCD再变为二进制数,累加POP R27POP R26BRTS RVCOM1 ;ASCII码无效,转出!RJMP DLLOPRVCOM1:CLTRJMP CLRBUF ;转去清缓存区,重新接收;晶振采用4MHZ,指令(DEC+BRNE)耗时0.75微秒)! EX_INT0:POP R16 ;int0中断服务子程序POP R16 ;废弃返回地址LDI R16,HIGH(RCVST)PUSH R16LDI R16,LOW(RCVST)PUSH R16 ;设置返回地址IN R16,GIMSK ;禁止int0中断CBR R16,$40OUT GIMSK,R16RETIRVBYT1: LDI R17,2 ;查到0接收时,再做一次接收MOV R15,R17LDI R17,50 ;第一个起始位半位延时(50*0.75=38微秒)MOV R12,R17RJMP RVBCMRVBYT2: LDI R17,2MOV R15,R17RVBY2: LDI R17,147 ;110微秒>1位宽/9600baud,110/0.75=147 MOV R12,R17TEST3: SBI PORTD,2SBIS PIND,2 ;停止位超宽测试RJMP RVSTDEC R12BRNE TEST3LDS R16,$A3 ;110微秒内查到低电平为起始位ORI R16,$20STS $A3,R16 ;否则为接收结束,令$A3,5=1RETRVST: LDI R17,60 ;60*0.75=45微秒(半位延时)MOV R12,R17RVBCM: DEC R12BRNE RVBCMLDI R17,9 ;1位起始+8位数据MOV R13,R17SBI PORTD,2SBIC PIND,2RJMP RVER1 ;无效起始位(半位测试)RVLOP: LDI R17,130 ;may be 128-132/位延时常数MOV R12,R17RVLP1: DEC R12 ;0.25微秒BRNE RVLP1 ;0.5微秒/if condition is trueSECSBI PORTD,2SBIS PIND,2CLCDEC R13BRNE OVRRC ;不是停止位,转数据位接收BRCC RVER1 ;无效停止位,出错TST R16 ;BRNE RBYRT ;不为0,收到一个有效字符DEC R15BRNE RVBY2 ;2次接收到$00,出错RVER1: LDS R16,$A3ORI R16,$40 ;接收出错标志CBR R16,$20STS $A3,R16RBYRT: RETOVRRC: ROR R16 ;组织数据RJMP RVLOP ;100.7微秒/程序实设位宽;范例42 ;8535'T0中断发送ASCII码程序,晶振4MHZ .EQU DATA2=$150.ORG $000STRT32: RJMP RST32.ORG 009RJMP T0_OVF.ORG $011RST32: SER R17OUT DDRB,R17 ;B口为输出OUT PORTB,R17 ;输出高电平LDI R16,2 ;0B00000010/8 DIVIDED(4fc/8:2微秒)OUT $33,R17 ;写入tccr0LDI R16,204 ;(256-204)*2=104微秒/9600baud 104微秒/位!OUT TCNT0,R17 ;LDI R17,HIGH(ramend)OUT SPH,R17LDI R17,LOW(ramend)OUT SPL,R17LDI R25,HIGH(DA TA2)LDI R24,LOW(DATA2);发送数据指针LDS R17,$A3CBR R17,$14 ;发送出错标志($A3,4)/发送完毕标志位($A3,2)清除!STS $A3,R17SEILDI R17,1OUT TIMSK,R17 ;允许T/C0溢出中断CLR R17 ;位计数器请除HH32: LDS R16,$A3SBRC R16,4RJMP HHER32 ;出错SBRS R16,2 ;RJMP HH32 ;查询等待数据块发送完成;. ;其他程序略;. ;可安排接收对方发来数据程序,见STRT33 RJMP RST32HHER32:;.;. ;错误处理略RJMP RST32T0_OVF: PUSH R16IN R16,SREGPUSH R16PUSH R26PUSH R27IN R16,TCNT0INC R16SUBI R16,52 ;重写入一位定时常数(带修正)OUT TCNT0,R16MOV R26,R24 ;数据指针MOV R27,R25CPI R17,10BREQ SND10TST R17BRNE SND9SND0: CBI PORTB,0 ;发起始位(0)RJMP SVCOMSND9: CPI R17,9BRNE SND18 ;1-8为数据位SBI PORTB,0 ;9为停止位(1)CLR R17 ;停止位发完后,位计数器清除ADIW R24,1 ;指针增1,指下一位数据LD R16,XCPI R16,$0A ;本次发送的是$0A?BRNE SVCOM1LDI R17,10 ;停止位标志RJMP SVCOM1SND10: LDS R16,$A3SBR R16,4 ;发送完成标志STS $A3,R16 ;SND11: CLR R16OUT TCCR0,R16 ;关闭T/C0CLR R17 ;清位计数器LDI R24,LOW(DATA2);发送指针初始化LDI R25,HIGH(DA TA2)RJMP SVCOM1SENDER: LDS R16,$A3SBR R16,$10STS $A3,R16 ;建出错标志RJMP SND11SND18: BRCC SENDER ;大于10为错误LD R16,XROR R16 ;发送位传到进位CBRCC S182SBI PORTB,0 ;C(=1)-->PB0($18,0)BRCS S183S182: CBI PORTB,0 ;C(=0)-->PB0($18,0)S183: LD R16,XROR R16 ;ST X,R16 ;保存剩余位MOV R24,R26 ;存数据指针MOV R25,R27SVCOM: INC R17 ;位计数器增1SVCOM1: POP R27POP R26POP R16OUT SREG,R16POP R16 ;恢复现场RETI;范例43 ;8515/8535/晶振4MHZ RECEIVING ASCII CHAR. BY TCNT0&PB0 .EQU DATA3=$100 ;UES R11 SA VE SREG, R12 R13:数据指针DATA3;R14: 块长(BLOCK LENGTH),R15:接收字符暂存寄存器.ORG 0 ;R16:(THE BIT SEQUENCE COUNTER)位序列计数器;R17:WORKING REG.R18:FLAG UNIT,BAUD RATE:9600 STRT33: RJMP RST33 ;X&Y:POINTER/接收数据缓存区首地址:$100 .ORG $009 ;$007(8515)RJMP T0_OVF1.ORG $011 ;$00D(8515)RST33: LDI R17,HIGH(ramend)OUT SPH,R17LDI R17,LOW(ramend)OUT SPL,R17LDI R17,HIGH(DA TA3)MOV R12,R17LDI R17,LOW(DATA3)MOV R13,R17 ;R12R13:接收数据指针CLRBF1: CLR R16CLRLP: ST X+,R16CPI R26,$48BRNE CLRLP ;接收数据缓存区请除CLR R18 ;标志寄存器请除/R18,2:完整数据块收到,R18,1;第一字符(块长)收到:R18,0:出错LDI R17,$02 ;8535:$01OUT TIMSK,R17 ;允许T/C0溢出中断LDI R17,6 ;外部脉冲下降沿计数OUT TCCR0,R17CBI DDRB,0 ;PB0为输入LDI R17,$FFOUT TCNT0,R17 ;计一个数即中断;SEI ;TEST1: RCALL DSPL Y3 ;调串行移位显示子程序SBRC R18,0 ;RJMP DLERR ;出错,转错误处理SBRS R18,2 ;数据块接收完成?RJMP TEST1LDI R16,128DECLP: DEC R16BRNE DECLPRJMP DTCOM0 ;先延时,再转处理数据块DLERR: ;. ;出错处理;.;.RCALL DL50 ;延时50毫秒后RJMP RST33 ;重新接收DTCOM0: LDI R27,1CLR R26 ;数据存储区首地址$100DLLOP0: CLR R29LDI R28,$90 ;ASCII码处理区为$90--$9fLD R16,XCPI R16,$50 ;字母P打头才有效BRNE RVCOM0 ;否则为无效字串或ASCII码处理结束DLLO1: LD R16,X+ST Y+,R16CPI R28,$A0BRNE DLLO1 ;传送16个字符PUSH R26PUSH R27RCALL ACUM ;处理一组ASCII码数据POP R27POP R26BRTC DLLOP0 ;T=1,ASCII码数据无效CLT;. ;错误处理RJMP STRT33RVCOM0:;. ;错误处理;.RJMP STRT33T0_OVF1:IN R11,SREG ;T/C0中断服务PUSH R17CPI R16,0 ;起始位下降沿中断?BRNE T0SV10LDI R17,2 ;YESOUT TCCR0,R17 ;改为内定时(4MHZ/8分频)LDI R17,232 ;半位时间常数24 定48微秒(<52)OUT TCNT0,R17RJMP T0SV6T0SV10: CPI R16,1 ;1,半位定时到BRNE T0SV2SBI PORTB,0SBIC PINB,0RJMP T0ERR ;高电平,错误RJMP T0SV60 ;低电平,有效起始位T0SV2: CPI R16,10 ;BRNE T0SV3SBI PORTB0 ;10,接收停止位SBIS PINB,0RJMP T0ERR ;低电平,错误LDI R17,6OUT TCCR0,R17 ;改为外部脉冲下降沿计数,为接受下一位字符准备LDI R17,$FF ;计一个数即中断OUT TCNT0,R17CLR R16 ;位计数器请除SBRC R18,1 ;是第一个字符(r18,1=0)?RJMP T0SV21 ;否,为块内数据MOV R14,R15 ;块长转入r14SBR R18,2 ;块长已收到RJMP T0SV61T0SV21: PUSH XLPUSH XHMOV XH,R12MOV XL,R13 ;取缓存区指针ST X+,R15 ;字符送入缓存区MOV R12,XHMOV R13,XLPOP XHPOP XLDEC R14BRNE T0SV61SBR R18,4 ;块长减为0,完整数据块收到CLR R16OUT TCCR0,R16 ;停止TCNT0RJMP T0SV61T0SV3: BRCC T0ERR ;出错(大于10)CLC ;2--9:数据位SBI PORTB,0 ;接收一位数据SBIC PINB,0SECROR R15 ;数据组织到R15T0SV60: IN R17,TCNT0 ;读TCNT0计数值INC R17 ;SUBI R17,52OUT TCNT0,R17 ;写入补偿后的时间常数T0SV6: INC R16 ;位序列计数器增1T0SV61: POP R17OUT SREG,R11RETIT0ERR: CLR R16T0ERL: SBR R18,1 ;错误接收标志OUT TCCR0,R16 ;停止TCNT0RJMP T0SV61;范例44.ORG 0 ;8535多机通讯主机程序/振4MHZ.EQU DTPINT=$180 ;UBRR=12,波特率19200(REL.ERR.=0.16%).EQU DRPINT=$1C0 ;主机发往#1,#2,#3,#分机数据在;$180-18F,$190-19F,$1A0-1AF和$1B0-1BFSTRT34: RJMP RST34 ;主机接收#1,#2,#3,#4分机之数据块分别在;$1C0-1CF,$1D0-1DF,$1E0-1EF和$1F0-1FF.ORG $00BRJMP U_RXC ;UART接收完成中断.ORG $00CRJMP U_TXC ;UART 发送完成中断.ORG $011RST34: LDI R16,12OUT UBRR,R16 ;BAUD RA TE=FCP/16(UBRR+1)=4000000/(16*13)=19200 CLR R15 ;分机号初始化LDI R27,HIGH(DTPINT)LDI R26,LOW(DTPINT);发送数据指针,首指$180LDI R29,HIGH(DRPINT)LDI R28,LOW(DRPINT);接收数据指针(POINT TO $1C0) NEXTNO: LDI R16,$18OUT UCR,R16 ;允许UART接收和发送,8位数据模式INC R15 ;指向分机OUTLP: OUT UDR,R15 ;呼分机号TSLOP: IN R16,USRSBRS R16,7RJMP TSLOP ;分机返回机号?IN R16,UDRCP R16,R15 ;与发送分机号符合?BRNE OUTLP ;不符再发TXLOP: LD R16,X+OUT UDR,R16 ;向分机发送数据块TESTL: IN R17,USRSBRS R17,5 ;发送寄存器空?RJMP TESTLCPI R16,$0ABRNE TXLOP ;发完整个数据块?RXTST: IN R17,USRSBRS R17,7 ;RXC=1 分机发来数据RJMP RXTSTIN R16,UDRST Y+,R16 ;接收数据转入内存CPI R16,$0ABRNE RXTST ;接收完整数据块后MOV R16,R15CPI R16,4 ;转与下一分机通讯(只有4台分机)BRNE NEXTNO ;直到轮询完毕HH34: RJMP HH34 ;可改为处理分机发来数据,再转入下一周轮询.DSEG.ORG $180DTPINT:.BYTE $40$41 $45 $65 $73 $46 $42 $40 $6F $33 $44 $66 $5C $4D $4B $0D $0A$42 $4F $66 $78 $47 $45 $44 $63 $32 $48 $60 $7C $6D $45 $0D $0A$43 $56 $55 $53 $4D $4F $40 $2E $31 $42 $67 $4C $47 $4A $0D $0A$45 $54 $59 $63 $3D $4B $48 $2F $35 $48 $69 $3C $77 $43 $0D $0A.ORG $1C0DRPINT: .BYTE $40;范例45.ORG 0 ;8535多机通讯1#分机程序,晶振4MHZ.EQU DTPIT1=$180 ;UBRR=12 波特率19200(REL.ERR.=0.16%).EQU DRPNT1=$1C0STRT35: RJMP RST35.ORG $00BRJMP UARXC ;UART接收完成中断.ORG $00CRJMP UATXC ;UART发送寄存器空中断.ORG $011RST35:CLR R18 ;请除主机发来完整数据块标志(R18,7)/主机呼号选中分机;标志(R18,6)LDI R16,12OUT UBRR,R16 ;[BAUD RATE=FCP/16(UBRR+1)]LDI R16,HIGH(DRPNT1)MOV R8,R16LDI R16,LOW(DRPNT1)mov R9,R16 ;r8,r9:接收数据指针(FIRST POINT TO $1C0)LDI R16,$98 ;允许UART发送,接收,接收完成中断OUT UCR,R16SEICLR R15INC R15 ;1#分机设为1/2#分机设为2/3#分机设为3/4#分机设为4 RXDTS: SBRS R18,6 ;收到主机发来呼号?RJMP RXDTSOUT UDR,R15 ;将分机号反还主机TXDON: IN R16,USRSBRS R16,5RJMP TXDON ;发送寄存器空?RCVBLK: SBRS R18,7RJMP RCVBLK ;等待接收主机发来数据块LDI R16,HIGH(DTPIT1)MOV R6,R16LDI R16,LOW(DTPIT1)MOV R7,R16 ;设置发送数据指针r6r7,首指$180SBI UCR,5 ;UDRIE=1 ,引起发送寄存器空中断TXDN: SBIC UCR,5RJMP TXDNRJMP RST35 ;等待UDRIE=0 ,向主机发送数据块完毕后,转下一轮通讯:UART中断接收程序UARXC: IN R14,SREGTST R18BREQ NUMB ;无主机呼号选中标志,查机号PUSH R26PUSH R27IN R17,UDR ;读入接收数据MOV XH,R8MOV XL,R9 ;r8r9:接收数据缓存区指针,首指$1C0ST X+,R17MOV R8,XHMOV R9,XLCPI R17,$0A ;收到换行符?BRNE RSCOM1SBR R18,$80 ;建立数据块接收完毕标志RSCOM1: POP R27POP R26DRETI: OUT SREG,R14RETINUMB: IN R17,UDRCP R17,R15 ;主机呼号与本分机号符合?BRNE DRETI ;不符,转SBR R18,$40 ;建选中标志RJMP DRETI; UART中断发送数据程序UA TXC: IN R16,SREG ;r6 r7:the sendDATA pointer(FIRST POINT TO $180) PUSH R16PUSH R26PUSH R27MOV XH,R6MOV XL,R7 ;发送数据指针LD R16,X+MOV R6,XHMOV R7,XLOUT UDR,R16 ;发送数据写入数据寄存器CPI R16,$0A ;发送LF?BRNE SDCOMCBI UCR,5 ;禁止数据寄存器空中断(清UDRIE)LDI R16,HIGH(DRPINT)MOV R8,R16LDI R16,LOW(DRPINT)MOV R9,R16 ;为接收作准备(FIRST POINT TO $1C0)SDCOM: POP R27POP R26POP R16OUT SREG,R16POP R16RETI.DSEG.ORG $180DTPIT1: .BYTE $10;$41 $45 $65 $73 $46 $42 $40 $6F $33 $44 $66 $5C $4D $4B $0D $0A.ORG $1C0DRPNT1: .BYTE $10;$41 $45 $65 $73 $46 $42 $40 $6F $33 $44 $66 $5C $4D $4B $0D $0A;范例46.ORG $000 ;RS232<->RS485通讯标准转换/晶振4MHZSTRT36: RJMP RST485 ;使用8515!.ORG $009RJMP U_RXC ;UART 接收中断.ORG $00DRST485: LDI R16,2OUT SPH,R16LDI R16,$5f ;OUT SPL,R16LDI R16,$98 ;允许UART接收和发送,允许接收中断OUT UCR,R16LDI R16,12OUT UBRR,R16 ;波特率19200SBI DDRB,7SBI DDRB,6 ;PB7,PB6为输出CBI PORTB,7CBI PORTB,6 ;PB7控制485发送(高有效)PB6控制485接收(低有效) SEIHERE0: CPI R16,3 ;收到停止符?BRNE HERE0 ;未收到循环等待HERE1: SBIS USR,6 ;RJMP HERE1 ;等待停止符发送完毕CBI PORTB,7 ;禁止485发送CBI PORTB,6 ;允许485接收SBI USR,6 ;写‘1’清除发送完成标志!CLR R16RJMP HERE0 ;转等待下一轮中转U_RXC: SBI PORTB,7 ;允许485发送SBI PORTB,6 ;禁止485接收,IN R16,UDR ;读出接收数据,同时清除接收中断标志TSAGN: SBIS USR,6 ;上一数据发送完毕?RJMP TSAGNSBI USR,6 ;清除发送完成标志OUT UDR,R16 ;转发本次接收数据RETI;范例47.EQU DATA4=$220.ORG $000 ;同步串口通讯主机程序,晶振4MHZSTRT37: RJMP RST37.ORG $00A ;8535 SPI中断矢量(8515为$008)RJMP SPINT.ORG $011 ;$00D(8515)RST37: LDI R16,2OUT SPH,R16LDI R16,$5fOUT SPL,R16 ;堆栈指针初始化LDI R16,$A0OUT DDRB,R16 ;SCK,MOSI为输出LDI R16,$DCOUT SPCR,R16 ;允许SPI中断,先发送高位,主控方式,时钟为主频4分;频,后沿有效LDI XH,HIGH(DATA4)LDI XL,LOW(DA TA4);数据指针LDI R16,$30MOV R15,R16 ;数据块长LDI R16,12 ;0.25微秒SPI0: DEC R16 ;0.25微秒BRNE SPI0 ;0.5微秒总延时9微秒LD R16,XOUT SPDR,R16 ;写发送数据寄存器,启动发送SEIHH37: RJMP HH37 ;背景程序略SPINT: IN R14,SREGIN R16,SPDR ;读出接收数据ST X+,R16DEC R15BRNE SPI1 ;数据收发完毕?OUT SPCR,R15 ;是,停止收发OUT SREG,R14RETISPI1: LDI R16,6 ;0.25微秒SPI1A: DEC R16 ;0.25微秒BRNE SPI1A ;0.5微秒总共4.5微秒LD R16,XOUT SPDR,R16 ;发下一个数据OUT SREG,R14RETI;范例48.ORG $000STRT37S:RJMP RST37S ;同步串口通讯从机程序(8515) 晶振4MHZ .ORG $008 ;$00A(8535)RJMP SPINTS ;同步串口中断矢量.ORG $00D ;$011(8535)RST37S: LDI R16,2OUT SPH,R16LDI R16,$5fOUT SPL,R16LDI R16,$40OUT DDRB,R16 ;MISO为输出LDI R16,$CCOUT SPCR,R16 ;允许SPI中断,先发送高位,从控方式,时钟为主频4分频,后沿有效LDI YH,HIGH(DATA4)LDI YL,LOW(DA TA4);数据指针LDI R16,$30 ;数据长度LD R15,YOUT SPDR,R15 ;写入数据寄存器SEIHH37S: RJMP HH37S ;背景程序从略SPINTS: IN R14,SREGIN R15,SPDR ;读接收数据ST Y+,R15DEC R16BRNE SPI2 ;数据块收发完毕OUT SPCR,R16 ;停止中断收发RJMP SPI3SPI2: LD R15,YOUT SPDR,R15 ;发下一数据SPI3: OUT SREG,R14RETI;范例49 以模拟串口与串行移位寄存器74165通讯,以74165驱动LED显示子程序DSPL Y3: SBI DDRC,1 ;PC1,串行数据输出SBI DDRC,0 ;PC0,移位时钟CBI PORTC,0 ;LDI R17,8 ;8字节显示缓存区$60(高)--$67(低))MOV R8,R17CLR XHLDI XL,$60 ;指针,首指最高位($60)SRDLOP: LDI R17,8 ;8位/字节MOV R9,R17LD R10,X+LDI ZH,HIGH(TABLE*2)LDI ZL,LOW(TABLE*2);使用DSPY子程序段选表ADD ZL,R10 ;加代码寻址BRCC DSPL1INC ZHDSPL1: LPM ;取段选码COM R0 ;取为反码SENDLP: ROR R0 ;段选码右移一位C<--R0最低位CBI PORTC,1BRCC SNDL1 ;进位C传给PC1SBI PORTC,1SNDL1: SBI PORTC,0 ;移位时钟,上升沿有效CBI PORTC,0 ;移位时钟变低DEC R9BRNE SENDLP ;8位段选码循环右移DEC R8BRNE SRDLOP ;8位LED显示数据都更新一遍?RET ;是,结束。
AVR汇编指令

AVR指令算术指令:加法(4)ADD Rd,Rr (Rd)<- (Rd)+(Rr);d,r =【0-31】ADC Rd,Rr (Rd)<- (Rd)+ (Rr)+ C ;d,r =【0-31】ADIW Rdl,K (Rdh:Rdl)<- (Rdh:Rdl)+K ;d =【24,26,28,30】 K =【0-63】INC Rd (Rd)<- (Rr)+ 1 ;d =【0-31】减法(6)SUB Rd,Rr (Rd)<- (Rd)- (Rr);d,r =【0-31】SUBI Rd,K (Rd)<- (Rd)- K ;d =【16-31】K =【0-255】SBC Rd,Rr (Rd)<- (Rd)- (Rr)- C ;d,r =【0-31】SBCI Rd,K (Rd)<- (Rd)- K - C ;d =【16-31】K =【0-255】 SBIW Rdl,K (Rdh:Rdl)<- (Rdh:Rdl)- K ;d =【24,26,28,30】 K =【0-63】DEC Rd (Rd)<- (Rr)- 1 ;d =【0-31】乘法(1)MUL Rd,Rr (R1)<-H(Rd*Rr)(R0)<-L(Rd*Rr);d,r =【2-31】逻辑运算与(4)AND Rd,Rr (Rd)<- (Rd)&(Rr);d,r =【0-31】ANDI Rd,K (Rd)<- (Rd)& K ;d =【16-31】K =【0-255】CBR Rd,K (Rd)<- (Rd)& (FF- K);d =【16-31】K =【0-255】 TST Rd (Rd)<- (Rd)&(Rr);d =【16-31】Z标记位或(4)OR Rd,Rr (Rd)<- (Rd)|(Rr);d,r =【0-31】ORI Rd,K (Rd)<- (Rd)| K ;d =【16-31】K =【0-255】SBR Rd,K (Rd)<- (Rd)| K ;d =【16-31】K =【0-255】 SER Rd (Rd)<- FF ;d =【16-31】异或(2)EOR Rd,Rr (Rd)<- (Rd)⊕(Rr);d,r =【0-31】CLR Rd (Rd)<- 00 ;d =【0-31】比较(3)CP Rd,Rr (Rd)- (Rr);d,r =【0-31】CPI Rd,K (Rd)- K ;d =【16-31】K =【0-255】CPC Rd,Rr (Rd)- (Rr)- C ;d,r =【0-31】取反(1)COM Rd (Rd)<- FF -(Rd);d =【0-31】取补(1)NEG Rd (Rd)<- 00 -(Rd);d =【0-31】无条件跳转(3)RJMP K (PC)<- (PC)+1+K ;K =【-2k - 2k】IJMP (PC)<- (Z);Z : 16BITJMP K (PC)<- K ;K =【0-4M】条件跳转(20)BRBS S , K BRBC S , K 状态寄存器判断位;S =【0-7】K =【-64,63】BREQ K BRNE K 为零标记不为零BRIE K BRID K 全局中断开关BRTS K BRTC K 标记位为零BRHS K BRHC K 半进位置位为零BRGM K BRLT K 带符号大于等于小于BRSH K BRLO K 无符号大于等于小于BRCS K BRCC K 进位置位为零BRVS K BRVC K 补码溢出置位为零BRMI K BRPL K 负数正数条件跳行(5)CPSE Rd,Rr 相等时跳行;d,r =【0-31】SBRS Rd,b 该为置位时跳行;d =【0-31】S =【0-7】 SBRC Rd,b 该为零时跳行;d =【0-31】S =【0-7】SBIC P,b 该为零时跳行;P =【0-31】S =【0-7】 SBIS P,b 该为置位时跳行;P =【0-31】 S =【0-7】调用(5)RCALL K (PC)<- (PC)+1+K ;K =【-2k - 2k】ICALL 跳转到Z指向地址;16 bitCALL K 0-4MRET 子程序返回RETI 中断返回栈(2)PUSH Rd 进入堆栈;d =【0-31】POP Rd 出栈;d =【0-31】直接数据传送(4)MOV Rd,Rr (Rd)<-(Rr);d,r =【0-31】LDS Rd,K (Rd)<-(K);d =【0-31】STS K,Rd (K)<-(Rd);d =【0-31】LDI Rd,K (Rd)<- K ;d =【16-31】K =【0-255】间接数据传送(22)X寄存器:LD Rd,X (Rd)<-((X));d =【0-31】LD Rd,X+ (Rd)<-((X)),(X)+=1 ;d =【0-31】LD Rd,-X (X)- =1,(Rd)<-((X));d =【0-31】ST X,Rd ((X))<-(Rd);d =【0-31】ST X+,Rd ((X))<-(Rd),(X)+=1 ;d =【0-31】ST -X,Rd (X)- =1,((X))<-(Rd);d =【0-31】Y寄存器:LD Rd,YLD Rd,Y+LD Rd,-YLDD Rd,Y+Q (Rd)<-((Y+Q));d =【0-31】Q =【0-63】 ST Y,RdST Y+,RdST -Y,RdSTD Y+Q,RdZ寄存器:LD Rd,ZLD Rd,Z+LD Rd,-ZLDD Rd,Z+QST Z,RdST Z+,RdST -Z,RdSTD Z+Q,Rd寻址(1)LMP 利用Z寄存的地址寻址(注意lsb位要为0读低8位数1读高8位数)I/O口(2)IN Rd,P (Rd)<- (P);d =【0-31】 P =【0-63】 OUT P,Rd (P)<- (Rd);d =【0-31】 P =【0-63】移位(6)LSL Rd (Rd)<<1, C<-MSB ,LSB<-0 ;d =【0-31】LSR Rd (Rd)>>1, C<-LSB ,MSB<-0 ;d =【0-31】ROL Rd (Rd)<<1 ,LSB<-C , C<-MSB ;d =【0-31】ROR Rd (Rd)>>1 ,MSB<-C , C<-LSB ;d =【0-31】SWAP Rd 半字节交换;d =【0-31】ASR Rd 7位不变,其余右移 , C<-LSB ;d =【0-31】T标记位(2)BLD Rd,b 将位读入T标记;d =【0-31】 b =【0-7】BST Rd,b 将T标记写入位;d =【0-31】 b =【0-7】状态位设置(20)BSET S BCLR S 设置状态寄存器指定位; S =【0-7】SEI CLI 状态标记设置或清除SEH CLHSET CLTSES CLSSEN CLNSEV CLVSEZ CLZSEC CLCSBI P,b CBI P,b 32IO口指定位设置清楚;P =【0-31】 b =【0-7】其他WDR 看门狗复位SLEEP 休眠NOP 空指令。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
系统使用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 ;时单元该程序实例采用规范标准的设计理念和风格,程序中已给出比较详细的注解。