avr和弦播放程序中,asm改c这样对吗?
一个用avr播放和弦的程序中,主程序已经改为c了,但是中断函数还是用asm写的,为了更好得理解过程,把asm改成了c,肯定有错的,请看下什么地方理解得不对。#include <avr/io.h>
/*
struct Note{
unsigned int k; //相位步进
unsigned char ac; //相位累加器0~7位
unsigned char *wp; //指向wave_table表中元素索引,2字节(相位累加器第8~24位)
unsigned char wrap;
unsigned char loop;
unsigned char lp;
unsigned char lvl;
}Notes;
*/
#define Nk 0
#define Nac 2
#define Nwp 3
#define Nwrap 5
#define Nloop 6
#define Nlp 7
#define Nlvl8
#define _0 R2
#define TEMP R3
#define INDEX R17
#define sMUL R18
#define usMUL R19
#define SUML R20
#define SUMH R21
#define PHASEL R22
#define PHASEH R23
#define ADDRESSL R24
#define ADDRESSH R25
.extern time1,time2,time3,Notes,wave_table
.section .text
.global TIMER2_COMP_vect
TIMER2_COMP_vect:
PUSH R0
PUSH R1
PUSH R2
PUSH R3
PUSH R4
PUSH R18
PUSH R19
PUSH R20
PUSH R21
PUSH R22
PUSH R23
PUSH R24
PUSH R25
PUSH R28
PUSH R29
PUSH R30
PUSH R31
IN R0, _SFR_IO_ADDR(SREG)
PUSH R0 //保存状态寄存器
LDI YL,lo8(Notes) //Y指向Notes
LDI YH,hi8(Notes)
LDI ADDRESSL,lo8(wave_table) //计算wave_table最后一个数据地址.wave_table总共数据为1024(0x400)个
LDI ADDRESSH,hi8(wave_table)
LDI INDEX,0x4
ADD ADDRESSH,INDEX //相当与:ADDRESSL+0x00;ADDRESSH+0x4(addressh:addressl +=0x400)
LDI INDEX,6
CLR SUML
CLR SUMH
CLR _0
////////////////////////////////////////////////////
TONE_LP:
LDD TEMP,Y+Nac
LDD ZL,Y+Nwp //加载wave_table首地址给Z
LDD ZH,Y+Nwp+1
LPM sMUL,Z //从wave_table 取数据
LDD PHASEL,Y+Nk //加载相位步进
LDD PHASEH,Y+Nk+1
ADD TEMP,PHASEL //相位累加
ADC ZL,PHASEH
ADC ZH,_0
CP ZL,ADDRESSL
CPC ZH,ADDRESSH
BRCS SAVE //如果小于跳
SUBI ZL,128 //大于,超过数据表的范围了,则减去128(128个正弦波波表数据)
SBC ZH,_0
STD Y+Nwrap,_0 //大于则将wrap清零,开始将音量衰减
SAVE:
STD Y+Nac,TEMP //不管大于还是小于都将相位保存
STD Y+Nwp,ZL
STD Y+Nwp+1,ZH
LDD usMUL,Y+Nlvl //获取衰减数据
MULSU sMUL,usMUL //有符号与无符号相乘,将所得结果送到R1:R0中
ASR R1 //将结果除以8(向右边移动3位),这样做目的是保正几个通道音量数据总和不超过两字节所容纳的数据大小
ROR R0 //不将结果除以128,是为了不在循环里面花费过多时间。
ASR R1 //为什么要除以128?原因将衰减数据最大值(0xff)看作2,进行比例缩小(比例是128:1)
ROR R0 //为什么不是除以255?原因是波表数据是-128~+127之间,如果乘以衰减系数最大值(2)则得到结果在-255~255之间
ASR R1
ROR R0
ADD SUML,R0 //累加各通道的值
ADC SUMH,R1
ADIW YL,9 //下一通道数据占用RAM的值
DEC INDEX //通道索引减少1
BRNE TONE_LP //获取下一通的值
////////////////////////////////////////////////////
ASR SUMH //SUMH:SUML=SUMH:SUML除以16 (向右边移动4位)
ROR SUML //配合SUM在相乘之后除以8,那么相当于每通道数据除以128
ASR SUMH //即:SUM是每通道数据除以128之后的总和,这样做目的是
ROR SUML //尽可能缩短中断程序所花费的时间
ASR SUMH
ROR SUML
ASR SUMH
ROR SUML
////////////////////////////////////////////////////
ASR SUMH //SUMH:SUML=SUMH:SUML除以4,而不是除以6(虽然SUM是6通道数据的总和)
ROR SUML //原因是:不是每一个通道的数据是很大的,类是弹钢琴,当前按下的是音量最大的
ASR SUMH //前面已经按下的声音已经衰减了,越前面的就越小声。这个程序采取6通道,
ROR SUML //就是模拟这种效果(模拟6个音符混在一起的效果,SUM表示6个音符混杂一起的音量)
LDI R18,253 //判断SUM是否大于253,如果大于则SUM=253
LDI R19,0
CP SUML,R18
CPC SUMH,R19
BRLT NEXT2 //寄存器SUM中带符号二进制数小于在寄存器VALUE中带符号二进制数时,将发生跳转
MOVW SUML,R8
NEXT2: LDI R18,1 //VALUEH:VALUEL=-255(-255的补码是0xFF01)
LDI R19,255
CP SUML,R18 //判断SUM是否小于-255,如果小于则SUM=-255
CPC SUMH,R19
BRGE NEXT3
MOVW SUML,R18
NEXT3: ASR SUMH //由于输出是差动输出的,PB1和PB2的输出是反相的
ROR SUML
SUBI SUML,0x80 //由于-127<= SUML <=126,当SUML-0x80,则-255<= (SUML-0x80) <=-2,
MOV SUMH,SUML//所对应的十六进制:0x01<= (SUML-0x80) <=0xfe,也就是归一化。
COM SUMH
OUT _SFR_IO_ADDR(OCR1AL),SUML//输出相位相反的PWM
OUT _SFR_IO_ADDR(OCR1BL),SUMH
////////////////////////////////////////////////////
SEC
LDS TEMP,time1 //每次中断发生,time1都会增加1
ADC TEMP,_0
STS time1,TEMP
LDS TEMP,time2 //只有time1由0xff->0时候time2才会增加1
ADC TEMP,_0
STS time2,TEMP
LDS TEMP,time3 //只有time2由0xff->0时候time3才会增加1
ADC TEMP,_0
STS time3,TEMP
POP R0
OUT _SFR_IO_ADDR(SREG),R0 //恢复状态寄存器
POP R31
POP R30
POP R29
POP R28
POP R25
POP R24
POP R23
POP R22
POP R21
POP R20
POP R19
POP R18
POP R17
POP R3
POP R2
POP R1
POP R0
RETI
struct Note{
unsigned int k; //相位步进
unsigned char ac; //相位累加器0~7位
unsigned char *wp; //指向wave_table表中元素索引,2字节(相位累加器第8~24位)
unsigned char wrap;
unsigned char loop;
unsigned char lp;
unsigned char lvl;
}Notes;
extern uchar time1,time2,time3,Notes,wave_table;
{
uchar * pY;
uchar * pZ;
uchar * ADDRESS;
uchar INDEX;
pY = Notes;
ADDRESS = wave_table;
INDEX = 4;
ADDRESS = ADDRESS + 0x400;
INDEX = 6;
SUM = 0;
TONE_LP:
uint PHASE;
TEMP = Notes.ac;
pZ = Notes.wp;
sMUL = *pZ;
PHASE = Notes.k;
tTEMP = TEMP + (0xff | PHASE);
PHASE = TEMP + PHASE;
TEMP = tTEMP;
pZ = pZ + (PHASE >> 8);
if(pZ > ADDRESS)
{
pZ = pZ -128;
Notes.wrap = 0; //大于则将wrap清零,开始将音量衰减
}
SAVE:
Notes.ac = TEMP; //不管大于还是小于都将相位保存
Notes.wp = pZ;
usMUL = Notes.lv1;
uint tMUL;
tMUL = sMUL * usMUL;
tMUL = tMUL >> 3; //将结果除以8(向右边移动3位),这样做目的是保正几个通道音量数据总和不超过两字节所容纳的数据大小
SUM = SUM + tMUL;
pY = pY + 9;
INDEX--;
if(INDEX == 0)
{
goto TONE_LP;
}
SUM = SUM >> 6; //SUMH:SUML=SUMH:SUML除以
if(SUM > 253) //判断SUM是否大于253,如果大于则SUM=253
{
SUM = 253;
}
if(SUM < -255)//判断SUM是否小于-255,如果小于则SUM=-255//VALUEH:VALUEL=-255(-255的补码是0xFF01)
{
SUM = -255;
}
NEXT3:
char cSUM;
SUM = SUM / 2; //由于输出是差动输出的,PB1和PB2的输出是反相的
cSUM = (uchar)SUM;
cSUM = cSUM - 0x80; //由于-127<= SUML <=126,当SUML-0x80,则-255<= (SUML-0x80) <=-2,
cSUM = 0xff - cSUM;
OUT _SFR_IO_ADDR(OCR1AL),(SUM & 0xff);//输出相位相反的PWM
OUT _SFR_IO_ADDR(OCR1BL),cSUM;
time1++;
if(time1 == 0)
{
time2++;
if(time2 == 0)
{
time3++;
}
}
}
页:
[1]