|
一个用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[6];
- */
- #define Nk 0
- #define Nac 2
- #define Nwp 3
- #define Nwrap 5
- #define Nloop 6
- #define Nlp 7
- #define Nlvl 8
- #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[6];
- 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++;
- }
- }
- }
复制代码 |
阿莫论坛20周年了!感谢大家的支持与爱护!!
你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。
|