搜索
bottom↓
回复: 0

avr和弦播放程序中,asm改c这样对吗?

[复制链接]

出0入0汤圆

发表于 2013-12-6 12:54:22 | 显示全部楼层 |阅读模式
一个用avr播放和弦的程序中,主程序已经改为c了,但是中断函数还是用asm写的,为了更好得理解过程,把asm改成了c,肯定有错的,请看下什么地方理解得不对。
  1. #include <avr/io.h>
  2. /*
  3. struct Note{
  4.   unsigned int k;          //相位步进
  5.   unsigned char ac;        //相位累加器0~7位
  6.   unsigned char *wp;       //指向wave_table表中元素索引,2字节(相位累加器第8~24位)
  7.   unsigned char wrap;      
  8.   unsigned char loop;
  9.   unsigned char lp;
  10.   unsigned char lvl;
  11.   }Notes[6];
  12. */
  13. #define Nk    0
  14. #define Nac   2
  15. #define Nwp   3
  16. #define Nwrap 5
  17. #define Nloop 6
  18. #define Nlp   7
  19. #define Nlvl  8

  20. #define _0                           R2
  21. #define TEMP                        R3
  22. #define INDEX                        R17
  23. #define sMUL                    R18
  24. #define usMUL                   R19
  25. #define SUML                       R20
  26. #define SUMH                       R21
  27. #define PHASEL                R22
  28. #define PHASEH                     R23
  29. #define ADDRESSL                  R24
  30. #define ADDRESSH                   R25

  31. .extern time1,time2,time3,Notes,wave_table
  32. .section .text
  33. .global TIMER2_COMP_vect
  34. TIMER2_COMP_vect:
  35.                  PUSH R0
  36.                                  PUSH R1
  37.                                  PUSH R2
  38.                                  PUSH R3
  39.                                  PUSH R4
  40.                                  PUSH R18
  41.                                  PUSH R19
  42.                                  PUSH R20
  43.                                  PUSH R21
  44.                                  PUSH R22
  45.                                  PUSH R23
  46.                                  PUSH R24
  47.                                  PUSH R25
  48.                  PUSH R28
  49.                                  PUSH R29
  50.                                  PUSH R30
  51.                                  PUSH R31
  52.                      IN R0, _SFR_IO_ADDR(SREG)
  53.                                  PUSH R0                      //保存状态寄存器

  54.                  LDI YL,lo8(Notes)                       //Y指向Notes
  55.                                  LDI YH,hi8(Notes)
  56.                                  LDI ADDRESSL,lo8(wave_table) //计算wave_table最后一个数据地址.wave_table总共数据为1024(0x400)个
  57.                                  LDI ADDRESSH,hi8(wave_table)
  58.                                  LDI INDEX,0x4
  59.                                  ADD ADDRESSH,INDEX           //相当与:ADDRESSL+0x00;ADDRESSH+0x4(addressh:addressl +=0x400)
  60.                                  LDI INDEX,6
  61.                                  CLR SUML   
  62.                                  CLR SUMH
  63.                                  CLR _0
  64. ////////////////////////////////////////////////////
  65. TONE_LP:
  66.                  LDD TEMP,Y+Nac
  67.                                  LDD ZL,Y+Nwp                //加载wave_table首地址给Z
  68.                                  LDD ZH,Y+Nwp+1
  69.                                  LPM sMUL,Z         //从wave_table 取数据  
  70.                                  LDD PHASEL,Y+Nk    //加载相位步进  
  71.                                  LDD PHASEH,Y+Nk+1
  72.                          
  73.                                  ADD TEMP,PHASEL    //相位累加
  74.                                  ADC ZL,PHASEH
  75.                                  ADC ZH,_0

  76.                                  CP ZL,ADDRESSL
  77.                                  CPC ZH,ADDRESSH
  78.                                  BRCS SAVE          //如果小于跳
  79.                  SUBI ZL,128        //大于,超过数据表的范围了,则减去128(128个正弦波波表数据)
  80.                                  SBC ZH,_0
  81.                                  STD Y+Nwrap,_0     //大于则将wrap清零,开始将音量衰减
  82. SAVE:
  83.                  STD Y+Nac,TEMP     //不管大于还是小于都将相位保存
  84.                                  STD Y+Nwp,ZL
  85.                                  STD Y+Nwp+1,ZH

  86.                                  LDD usMUL,Y+Nlvl   //获取衰减数据
  87.                  
  88.                                  MULSU sMUL,usMUL   //有符号与无符号相乘,将所得结果送到R1:R0中
  89.                  ASR R1         //将结果除以8(向右边移动3位),这样做目的是保正几个通道音量数据总和不超过两字节所容纳的数据大小
  90.                  ROR R0         //不将结果除以128,是为了不在循环里面花费过多时间。
  91.                  ASR R1         //为什么要除以128?原因将衰减数据最大值(0xff)看作2,进行比例缩小(比例是128:1)
  92.                  ROR R0         //为什么不是除以255?原因是波表数据是-128~+127之间,如果乘以衰减系数最大值(2)则得到结果在-255~255之间
  93.                  ASR R1
  94.                  ROR R0
  95.                  ADD SUML,R0    //累加各通道的值
  96.                                  ADC SUMH,R1                 

  97.                                  ADIW YL,9      //下一通道数据占用RAM的值
  98.                  DEC INDEX      //通道索引减少1
  99.                                  BRNE TONE_LP   //获取下一通的值
  100. ////////////////////////////////////////////////////
  101.                  ASR SUMH                   //SUMH:SUML=SUMH:SUML除以16        (向右边移动4位)
  102.                  ROR SUML       //配合SUM在相乘之后除以8,那么相当于每通道数据除以128
  103.                  ASR SUMH       //即:SUM是每通道数据除以128之后的总和,这样做目的是
  104.                  ROR SUML       //尽可能缩短中断程序所花费的时间
  105.                  ASR SUMH               
  106.                  ROR SUML
  107.                  ASR SUMH
  108.                  ROR SUML
  109. ////////////////////////////////////////////////////
  110.                  ASR SUMH                //SUMH:SUML=SUMH:SUML除以4,而不是除以6(虽然SUM是6通道数据的总和)       
  111.                  ROR SUML       //原因是:不是每一个通道的数据是很大的,类是弹钢琴,当前按下的是音量最大的
  112.                  ASR SUMH       //前面已经按下的声音已经衰减了,越前面的就越小声。这个程序采取6通道,
  113.                                  ROR SUML       //就是模拟这种效果(模拟6个音符混在一起的效果,SUM表示6个音符混杂一起的音量)
  114.                                                                   
  115.               
  116.                              LDI R18,253    //判断SUM是否大于253,如果大于则SUM=253
  117.                                  LDI R19,0
  118.                                  CP SUML,R18
  119.                                  CPC SUMH,R19
  120.                                  BRLT NEXT2     //寄存器SUM中带符号二进制数小于在寄存器VALUE中带符号二进制数时,将发生跳转
  121.                                  MOVW SUML,R8

  122. NEXT2:           LDI R18,1      //VALUEH:VALUEL=-255(-255的补码是0xFF01)
  123.                                  LDI R19,255
  124.                                  CP SUML,R18    //判断SUM是否小于-255,如果小于则SUM=-255
  125.                                  CPC SUMH,R19  
  126.                                  BRGE NEXT3
  127.                                  MOVW SUML,R18

  128. NEXT3:           ASR SUMH       //由于输出是差动输出的,PB1和PB2的输出是反相的
  129.                  ROR SUML
  130.                                  SUBI SUML,0x80 //由于-127<= SUML <=126,当SUML-0x80,则-255<= (SUML-0x80) <=-2,
  131.                                  MOV SUMH,SUML  //所对应的十六进制:0x01<= (SUML-0x80) <=0xfe,也就是归一化。
  132.                                  COM SUMH
  133.                                  OUT _SFR_IO_ADDR(OCR1AL),SUML  //输出相位相反的PWM
  134.                                  OUT _SFR_IO_ADDR(OCR1BL),SUMH
  135.          
  136. ////////////////////////////////////////////////////
  137.                  SEC
  138.                                  LDS TEMP,time1                //每次中断发生,time1都会增加1
  139.                                  ADC TEMP,_0
  140.                  STS time1,TEMP

  141.                                  LDS TEMP,time2                //只有time1由0xff->0时候time2才会增加1
  142.                                  ADC TEMP,_0
  143.                  STS time2,TEMP

  144.                                  LDS TEMP,time3                //只有time2由0xff->0时候time3才会增加1
  145.                                  ADC TEMP,_0
  146.                  STS time3,TEMP

  147.                                  POP R0
  148.                                  OUT _SFR_IO_ADDR(SREG),R0     //恢复状态寄存器
  149.                                  POP R31
  150.                                  POP R30
  151.                  POP R29
  152.                                  POP R28               
  153.                                  POP R25
  154.                                  POP R24
  155.                                  POP R23
  156.                                  POP R22
  157.                                  POP R21
  158.                                  POP R20
  159.                                  POP R19
  160.                                  POP R18
  161.                                  POP R17
  162.                                  POP R3
  163.                                  POP R2
  164.                                  POP R1
  165.                      POP R0
  166.                                  RETI
复制代码


  1. struct Note{
  2.   unsigned int k;          //相位步进
  3.   unsigned char ac;        //相位累加器0~7位
  4.   unsigned char *wp;       //指向wave_table表中元素索引,2字节(相位累加器第8~24位)
  5.   unsigned char wrap;      
  6.   unsigned char loop;
  7.   unsigned char lp;
  8.   unsigned char lvl;
  9.   }Notes[6];


  10. extern uchar    time1,time2,time3,Notes,wave_table;

  11. {
  12.     uchar * pY;
  13.     uchar * pZ;
  14.     uchar * ADDRESS;
  15.     uchar INDEX;

  16.     pY = Notes;
  17.     ADDRESS = wave_table;
  18.     INDEX = 4;
  19.     ADDRESS = ADDRESS + 0x400;

  20.     INDEX = 6;
  21.     SUM = 0;

  22. TONE_LP:   
  23.     uint PHASE;

  24.     TEMP = Notes.ac;
  25.     pZ = Notes.wp;
  26.     sMUL = *pZ;
  27.     PHASE = Notes.k;


  28.     tTEMP = TEMP + (0xff | PHASE);
  29.     PHASE = TEMP + PHASE;
  30.     TEMP = tTEMP;

  31.     pZ = pZ + (PHASE >> 8);

  32.     if(pZ > ADDRESS)
  33.     {
  34.         pZ = pZ -128;
  35.         Notes.wrap = 0;     //大于则将wrap清零,开始将音量衰减
  36.     }

  37. SAVE:
  38.     Notes.ac = TEMP;    //不管大于还是小于都将相位保存
  39.     Notes.wp = pZ;

  40.     usMUL = Notes.lv1;

  41.     uint tMUL;

  42.     tMUL = sMUL * usMUL;
  43.     tMUL = tMUL >> 3;   //将结果除以8(向右边移动3位),这样做目的是保正几个通道音量数据总和不超过两字节所容纳的数据大小

  44.     SUM = SUM + tMUL;

  45.     pY = pY + 9;
  46.     INDEX--;
  47.     if(INDEX == 0)
  48.     {
  49.         goto TONE_LP;
  50.     }

  51.     SUM = SUM >> 6;     //SUMH:SUML=SUMH:SUML除以
  52.     if(SUM > 253)   //判断SUM是否大于253,如果大于则SUM=253
  53.     {
  54.         SUM = 253;
  55.     }

  56.     if(SUM < -255)  //判断SUM是否小于-255,如果小于则SUM=-255  //VALUEH:VALUEL=-255(-255的补码是0xFF01)
  57.     {
  58.         SUM = -255;
  59.     }


  60. NEXT3:
  61.     char cSUM;
  62.     SUM = SUM / 2;      //由于输出是差动输出的,PB1和PB2的输出是反相的
  63.     cSUM = (uchar)SUM;
  64.     cSUM = cSUM - 0x80; //由于-127<= SUML <=126,当SUML-0x80,则-255<= (SUML-0x80) <=-2,
  65.     cSUM = 0xff - cSUM;

  66.     OUT _SFR_IO_ADDR(OCR1AL),(SUM & 0xff);  //输出相位相反的PWM
  67.     OUT _SFR_IO_ADDR(OCR1BL),cSUM;

  68.     time1++;
  69.     if(time1 == 0)
  70.     {
  71.         time2++;
  72.         if(time2 == 0)
  73.         {
  74.             time3++;
  75.         }
  76.     }
  77. }
复制代码

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-7-23 22:14

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

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