1、DSP 汇编DSP 2010-04-12 17:39:36 阅读 155 评论 0 字号:大中小 订阅 实验一 新手上路 初学者编写的第一个程序通常是控制 XF 引脚的变化,然后用示波器测量 XF 脚波形或观察与相接的 LED。这个程序也常常用来测度一下 DSP 能否正常工作。实验 1.1 最简单的程序:控制 XF 引脚周期性变化实验目的:通过简单的程序了解 DSP 程序的结构,熟悉 CCS 开发环境。*最简单的程序:TestXF1.asm*循环对 XF 位置 1 和清 0,用示波器可以在 XF 脚检测到电平高低周期性变化*常用于检测 DSP 是否工作。*.mmregs ;预定义的寄存器.de
2、f CodeStart ;定义程序入口标记.text ;程序区CodeStart: ;程序入口SSBX XF ;XF 置 1RPT #999 ;重复执行 1000 次空指令产生延时NOPRSBX XF ;XF 清 0RPT #999 ;重复执行 1000 次空指令产生延时NOP B CodeStart ;跳转到程序开头循环执行.end NOP 指令执行时间为一个时钟周期,设 DSP 工作频率是 50MHz,可以估算出 XF引脚电平的变化频率约为:50M/2000=25kHz在没有示波器的情况下,就要将程序 1.1 稍作改进,增加延时,用一个延时子程序将 XF 脚电平变化频率降到肉眼可分辨的程度
3、,就可以用 LED 来显示电平的变化,程序如下:实验 1.2 子程序调用实验目的:学习子程序的调用*TestXF2.asm*对 TestXF1.asm 稍作改进,用延时子程序设置较长的延时,*可以用试验板上的 LED 看到 XF 引脚电平的变化*.mmregs ;预定义的寄存器.def CodeStart ;定义程序入口标记.text ;程序区CodeStart: ;程序入口SSBX XF ;XF 置 1CALL Delay ;调用延时程序RSBX XF ;XF 清 0CALL Delay ;调用延时程序B CodeStart ;跳转到程序开头循环执行*延时子程序:Delay*用两级减一计数器
4、来延时。调整 AR1 和 AR2 的大小 LED 闪烁的频率不同*Delay: STM #999,AR1 ;循环次数 1000LOOP1: STM #4999, AR2 ;循环次数 5000LOOP2: BANZ LOOP2,*AR2- ;如果 AR2 不等于 0,AR2 减 1,再判断BANZ LOOP1,*AR1- ;如果 AR1 不等于 0,AR1 减 1,跳转到 LOOP1RET.end*注意这种延时方法并不精确,需要精确定时必须用定时器。*按此法延时的近似公式为:4*(AR2+1)*(AR1+1)*时钟周期*当 DSP 工作在 50MHz(时钟周期 20ns),AR1=999, AR
5、2=4999 时*延时约为 400ms,则 LED 闪烁的周期为 800ms,频率 1.25Hz*设计指导:1源代码书写格式源代码的书写有一定的格式,初学者往往容易忽视。简单归纳如下:1每一行代码分为三个区:标号区、指令区和注释区。标号区必须顶格写,主要是定义变量、常量、程序标签时的名称。指令区位于标号区之后,以空格或TAB 格开。如果没有标号,也必须在指令前面加上空格或 TAB,不能顶格。注释区在标号区、程序区之后,以分号开始。注释区前面可以没有标号区或程序区。另外还有专门的注释行,以*打头,必须顶格开始。2一般区分大小写,除非加编译参数忽略大小写。3标点符号有时不注意会打成中文全角字符导致
6、错误。书写格式的要求在很多 DSP 书里都没有提,初学者往往只把书上的代码输入进去,编译时得到错误的提示,而不知所措。其中最容易犯的错误指令顶格写,不过一般经提示后不会犯第二次。有些格式 CCS 并没有做要求,但注意养成良好的代码书写风格,增加代码的可读性。以上两个例子的书写风格可作参考,但不是硬性规定:1标号区占 3 个 TAB 的间隔,即 12 个字符2指令中的指令码占两个 TAB 间隔,然后是操作数。3每一行的尾注能对齐的尽量对齐4标明一段程序功能的注释以*号打头顶格写,如果功能说明的注释较多,用分格线框起来。此外其它编程语言的编程风格也可以借用过来,比如标示符命名规则、程序说明的要求等
7、。如果项目组有规定,则按规定执行。本书的代码尽量保持一定的风格,不过读者可以发现前面的代码注释较多,后面随着学习的深入,一般不会对每一条指令加注释,只注明程序段的功能。另外代码贴到 word 里后,格式有些错位,无法一一纠正。2链接配置文件一个完整的 DSP 程序至少包含三个部分:程序代码、中断向量表、链接配置文件(*.cmd)。这里介绍一下链接配置文件文件,对本次试验影响不大的中断向量表将在后文介绍。连接配置文件的确定了程序链接成最终可执行代码时的选项,其中有很多条目,实现不同方面的选项,其中最常用的也是必须的有两条:1.存贮器的分配 2.标明程序入口。以本次实验为例,下面的简单的链接配置文
8、件就够用了:/* TestXF.cmd */-e CodeStart /*程序入口,必须在程序中定义相应的标号*/MEMORY page 0:PRAM: org=0100h len=0F00h /*定义程序存贮区,起始 0100H,长度 0F00H*/SECTIONS.text:PRAM page 0 /*将.text 段映射到 page0 的 param 区*/由于每个程序都需要一个链接配置文件,可以编写一个满足通常需要的链接配置文件。作为本手册通用的链接配置文件如下,可以满足本书大部分程序的需要。在未特别指明的情况下使用这个通用的链接配置文件:/* 5402.cmd */-e CodeSt
9、art /*程序入口,必须在程序中定义相应的标号*/-m map.map /*生成存储器映射报告文件 */MEMORY PAGE 0:VECT: org=0080h len=0080h /*中断向量表*/PARAM: org=100h len=0F00h /*代码区*/PAGE 1:DARAM: org=1000h len=1000h /*数据区*/SECTIONS .text : PARAM PAGE 0 /*代码段*/.vectors : VECT PAGE 0 /*中断向量表*/STACK : DARAM PAGE 1 /*堆栈*/.bss : DARAM PAGE 1 /*未命名段*/
10、.data : DARAM PAGE 1 /*数据段*/更多参考:1关于代码书写格式:SPRU102: TMS320C54x Assembly Language Tools Users Guide,3.5 Source Statement Format2关于链接配置文件:SPRU102: TMS320C54x Assembly Language Tools Users Guide,7.5 Linker Command Files,7.7 The MEMORY Directive,7.8 The SECTIONS Directive练习:1、试一下不按规定格式书写代码会产生什么样的编译错误。2、
11、试一下将链接配置文件中的 MEMORY,SECTIONS 改成小写会出现什么样的编译错误。3修改程序 1.2 中 AR1,AR2 的值,观察 LED 闪烁频率实验二 基本运算本节选自为 HK-DSP 实验箱写的实验指导书,有待整理DSP 指令数量最多的是:算术指令、逻辑指令和数据加载与传送指令。数据加载与传送指令由于处处要用,所以不单独列为实验。算术与逻辑指令也是数量繁多,无法一一举例,这里简单举一个加法和除法的例子,乘法和乘加指令在FIR 用得比较多,稍后一并介绍。其它指令有兴趣可以对照指令表的说明,试验一下各指令运行的结果。实验 2.1 加减法计算 *计算 z=x+y-w。*.mmregs
12、.def CodeStartData_DP: ;数据段指针x: .word 10 ;初始化变量y: .word 26w: .word 23z: .word 0 .textCodeStart:LD #Data_DP,DP ;装载数据指针 DPSTM #STACK+10H,SPSUMB: LD x,A ;A=xADD y,A ;A=A+ySUB w,A ;A=A-wSTL A,z ;z=AEND: B END计算结果数据存储器地址存储内容十进制x1010H000aH10y1011H001aH26w1012H0017H23z1013H000dH13技巧提示:试验算术指令由于不需要外部资源,可以不需要
13、仿真器和实验箱。同学们可以平时自己用软件仿真,多多实验。但是复杂的算法最好还是在线仿真,因为程序是流水线执行,软件仿真有时与实际硬件执行结果有所不同。实验 2.2 除法计算 DSP 并没有除法指令,回想一下我们用在稿纸上演算除法列的竖式,实际是一种移位减法,DSP 中也是通过做多次减法的办法来做除法。下面例子是把用除以 10 的办法二进制数转成 BCD 码例子:*16 进制转 BCD 码*.mmregs.global CodeStart.datax: .word 1234 ;待转换的数字y: .word 10 ;除数z: .word 0Fh,0Fh,0Fh,0Fh,0Fh;结果区,每位 BCD
14、 存一个字,;初始化为 F 因为实验板的数码管不显示 F.textCodeStart:LD #x,DP ;设置 DPLD x,A ;被除数STM #z,AR1 ;结果区指针loop: RPT #15 ;执行完 16 次减法后,A 的高 16 位是余数SUBC y,A ;低 16 位是商STH A,*AR1+ ;余数保存到 ZAND #0FFFFH,A ;掩盖掉高 16 位,保留商值BC loop,ANEQ ;继续做除法直到商为 0 end: B end练习:练习其他算术指令其它参考:spru172c:TMS320C54x DSP Reference Set Volume 2: Mnemonic
15、 InstructionSet,2.1 Arithmetic Operations这个资料对每个指令都有详细说明。也可以在 Help 中的TMS320C54x DSP Mnemonic Instruction Set 中查询或搜索相关指令。实验三 中断中断的概念应该不陌生,指的是当某个事件发生时,暂停当前的操作,转向中断服务程序,执行完后再返回继续原来的操作。这使得 DSP 能够处理多个任务。DSP 有许多中断源,可以设置中断控制寄存器来确定响应哪些中断而不理会哪些中断。本实验介绍最常用的定时器中断和外部中断的使用方法,并介绍中断向量表和中断向量指针。 实验 3.1 定时器中断:方波发生器实验
16、目的:学习定时器中断的设计方法回顾一下实验一控制 LED 的闪烁实际就是一个简单的方波发生器。但不足的是延时的方法定时不精确,另外还有一个缺点是在执行延时的过程中 DSP 就无法执行其它指令,这时就可以用定时器来改进。使用定时器首先要对它初始化,基本步骤如下:1关掉中断2停止定时器运行。3设定时器的定时长度4允许定时器中断5运行定时器6打开中断现以简单的方波程序为例:;=; fangbo1.asm; 利用定时器 Timer0 在 XF 脚产生周期 2ms 的的方波;=.title “fangbo1.asm“.mmregs.def codestart ;程序入口.def TINT0_ISR ;T
17、imer0 中断服务程序STACK .usect “STACK“,10H ;分配堆栈空间 ;设定定时器 0 控制寄存器的内容K_TCR_SOFT .set 0B技巧提示:只有第一个中断(Reset 中断)是每个程序都应该有的,在不需要其它中断的情况下,可以只用这一部分,后面可以省略。如果只需要部分中断也可以按需设置,但必须保证所用中断在中断向量表的位置不变。不熟悉中断向量表的情况下最好还是用这个完整中断向量表样例。另外 C5400 系列中不同型号 DSP 的中断向量数量和在中断向量表中的位置有所不同,程序移植时需要查相应 datasheet 确认。2中断向量指针中断向量表的位置并没有强制的位置
18、,可以在内部存贮器,也可以在外部存贮器。但有一个要求:中断量表必须放在 80H 字长存贮块的起始处,即中断向量表的首地址的低 7 位必须全为 0。DSP 的寄存器 PMST 的高 9 位是中断向量表的指针 IPTR。其上电时默认是在 FF80H处,这是为了运行固化在内部 ROM 的上电加载程序(见实验八的程序加载部分)。由于 FF80H 是只读的,加载用户自定义的中断向量表时会报错。这样需要重新设置 IPTR 的值,本书一般把它重定义到 0080H(也可以用自定义的地址),并在程序开头重新设置一下 IPTR 的值:;改变中断向量表位置K_IPTR .set 0080h ;指向 0080H,默认
19、是 FF80LDM PMST,AAND #7FH,A ;保留低 7 位,清掉高位OR #K_IPTR,A ;将新值传到高 9 位STLM A,PMST ;修改 PMST 寄存器技巧指示:由于这段代码几乎每个程序都需要,可以单独存成一个文件:IPTR0080H.asm,然后在程序需要的地方用.copy 或.include 指令:.copy “IPTR0080H.asm”或: .include “IPTR0080H.asm”编译时就会自动把这段代码嵌到相应位置。稍微要注意的是由于这一小段代码要用到累加器 A,所以最好保证执行这段代码之前不要使用累加器 A。其它还有一些经常重复的代码,如初始化 SP
20、、DP、IPTR 的代码都可以写在一个文件里 include/copy 进来。注 1:.copy 和.inlucde 指令效果是一样的,只是在生成程序列表时,.copy 会把代码复制过来,而.include 不会。注 2:文件名可以用路径,如果不用,则编译器会按下面的循序搜索:当前目录、编译选项指定的目录、环境变量指定的目录。更多参考:1关于中断:SPRU131 TMS320C54x DSP Reference Set, Volume 1: CPU and Peripherals,6.10 Interrupts2关于定时器:SPRU131 TMS320C54x DSP Reference Se
21、t, Volume 1: CPU and Peripherals,8.4 Timer实验 3.2 外部中断:频率计DSP 有 4 个外部中断 INT0-INT3,下降沿触发,实验箱的频率计使用的是INT3。频率计的设计原理是:在设定时间下计外部中断 INT3 的次数,除以定时器的定时周期(也就是乘以定时器中断的触发频率),就得到外部脉冲频率。实验箱上配有 1.024k-262.144k 共 8 档频率源,也可以外接频率源。用跳线冒选择频率源,并接到 INT3 上。下面的例程是定时器定时 1s,在 INT3 中断服务子程序中计脉冲个数,到时则关闭中断。脉冲计数结果显示到数码管上,即为以单位为Hz
22、 的频率值*频率计*.mmregs.global CodeStart.global TINT1_ISR.global INT3_ISR.include “/DefineIO.asm“ .dataDATA_DP:PulseCounter: .word 0 ;脉冲计数器Display: .word 0FH,0FH,0FH,0FH,0FH,0FH;存放数据管显示值,值 F 在数码管上不显示DotData: .word 000000B ;数码管的 dot pointNumber10: .word 10 ;十六进制转 BCD 所除的 10.textCodeStart:.copy “/SP_DP_IPTR
23、.asm“ ;初始化 SP、DP 和 IPTR 的代码段STM #99,AR1 ;10ms 计数后再 100 分频STM #Display,AR3 ;定义数据管显示存贮区指针LD #0,A ;A 用来计脉冲数SSBX INTM ;关中断CALL Timer1Init ;初始化 Timer1 STM #110000000B,IMR ;允许 Timer1 和 INT3 中断STM #0FFH,IFR ;清除挂起的中断RSBX INTM ;开中断wait: B wait;*外部中断子程序*INT3_ISR:ADD #1,A ;计中断次数RETE*定时器中断子程序*TINT1_ISR:BANZ GoO
24、nCount,*AR1- ;测量次数计数器减 1,次数为 0 就中止计数数,;结束计数STM #0,IMR ;取消所有中断HEX2BCD: ;把计数结果转成 BCD 码RPT #15SUBC Number10,ASTH A,*AR3+AND #0FFFFH,ABC HEX2BCD,ANEQ ;在数码管上显示结果STM #Display,AR3PORTW *AR3+,Digital0PORTW *AR3+,Digital1PORTW *AR3+,Digital2PORTW *AR3+,Digital3PORTW *AR3+,Digital4PORTW *AR3+,Digital5PORTW Do
25、tData,DotPoint RETEGoOnCount: ;继续计数STM #1100001B,IFR ;清除挂起的中断RETE*定时器初始化*Timer1Init: ;定时器 1 的寄存器地址TIM1 .set 0030h ;减计数器PRD1 .set 0031h ;存放定时时间常数TCR1 .set 0032h ;定时器状态及控制寄存器;F=50MHz, T=20ns*(1+15)*(1+3124)=20ns*16*31250=10msSTM #010,TCR1 ;TSS 置位停止 TimerSTM #31249,PRD1STM #2FH,TCR1RET.end 简单起见本例只能测一次,
26、可以做一些改进,比如每隔 1-2S 自动重新测量,或者用按键来触发测量。实验 4.1 数码管及 LED 显示接口实验实验箱说明部分已经介绍了数码管的控制原理,下面的程序 DigitalLED.asm 简单的演示了对数码管和 LED 控制的指令,可以在显示预设的数字和 LED 状态。复杂的程序可以见附盘的流水灯程序,DigitalLED2.asm;=;DigitalLED.asm;实验用 DSP 控制实验板数码管;DSP 用 I/O 指令对 CPLD 地址 1000-10005 写数据,分别对应 Digtal0-5;=.mmregs.def main ;主程序入口.ref Timer0Init
27、;Timer0 初始化子程序 ;数据管地址Digital0 .set 1000H ;数据管 1Digital1 .set 1001H ;数据管 2Digital2 .set 1002H ;数据管 3Digital3 .set 1003H ;数据管 4Digital4 .set 1004H ;数据管 5Digital5 .set 1005H ;数据管 6 DotPoint .set 1006H ;小数点LED .set 1007H ;LEDSTACK .usect “STACK“,10H ;分配堆栈空间.dataDATA: .word 1,2,3,4,5,6 ;测试数据Dot_DATA: .wo
28、rd 010101b;LED_DATA: .word 0101010b.textmain:STM #STACK+10H,SP ;设堆栈指针 SPSTM #K_SWWSR,SWWSRSSBX INTM ;关中断LD #DATA,DP ;设数据地址 DPSTM #DATA,AR1*写数据PORTW *AR1+,Digital0PORTW *AR1+,Digital1PORTW *AR1+,Digital2PORTW *AR1+,Digital3PORTW *AR1+,Digital4PORTW *AR1+,Digital5PORTW Dot_DATA,DotPointPORTW LED_DATA,
29、LEDEND: B END .end 技巧提示:数码管、LED 的 IO 地址的定义也可以单独存到一个文件中,在需要它的程序中用.include/.copy 指令。练习:修改预设值重新运行观察结果。实验 4.2 键盘接口实验实验板上有四个按键,当有键按下时,会触发 DSP 的 INT1 中断,在 INT1 的中断服务程序中读入键码,判断哪一个键被按下,然后执行相应的操作。各键对应的二进制和十六进制键码分别为:按键 1: 0001B 1H按键 2: 0010B 2H按键 3: 0100B 4H按键 4: 1000B 8H 下面有一个小例子:*keyboardTest.asm*测试按键的功能,响应
30、按键中断,读取键值,*并对不同键按键次数计数*.mmregs.global CodeStart.global INT1_ISR.include “/DefineIO.asm“.dataDATA_DP:Counter1: .word 0 ;按键 1 计数器Counter2: .word 0 ;按键 2 计数器Counter3: .word 0 ;按键 3 计数器Counter4: .word 0 ;按键 4 计数器 Keyvalue: .space 30H*16 ;按键历史缓冲区.textCodeStart:.copy “/SP_DP_IPTR.asm“ ;初始化 SP、DP 和 IPTR 代码
31、段;初始化变量STM #Keyvalue,AR2ST #0,Counter1ST #0,Counter2ST #0,Counter3ST #0,Counter4SSBX INTM ;关中断STM #00000010B,IMR ;允许 INT1 中断STM #0FFH,IFR ;清除挂起的中断RSBX INTM ;开中断wait: B wait;*键盘中断子程序* INT1_ISR: PORTR #Keyboard,*AR2 ;读取键码ANDM #0FH,*AR2 ;Keyvalue 只有低四位有效BITF *AR2,#01H ;如果键码为 1,跳转到 FuncKey1 BC FuncKey1,
32、TC BITF *AR2,#02H ;如果键码为 2,跳转到 FuncKey2BC FuncKey2,TCBITF *AR2,#04H ;如果键码为 3,跳转到 FuncKey3BC FuncKey3,TCBITF *AR2,#08H ;如果键码为 4,跳转到 FuncKey4BC FuncKey4,TCB FuncKeyEnd ;FuncKey1: ADDM #1,Counter1 ;按键 1 计数器+1B FuncKeyEndFuncKey2: ADDM #1,Counter2 ;按键 2 计数器+1B FuncKeyEndFuncKey3: ADDM #1,Counter3 ;按键 3
33、计数器+1B FuncKeyEndFuncKey4: ADDM #1,Counter4 ;按键 4 计数器+1B FuncKeyEnd FuncKeyEnd: PORTW *AR2+,Digital0 ;当前键码显示到数码管上STM #0FFH,IFR ;清除挂起的中断RETE实验六 DMA 实验实验目的:学习 DMA 的原理的使用方法实验内容:用 DMA 方法接收 McBSP 接口语音芯片的数据 DMA 是直接存储器存取,是一种传送不占用 CPU 处理时间的大批量数据传送的有效方式。我们用以下实例来说明它的应用:如果我们要做一个音频处理系统,需要连续用 McBSP 接口的语音芯片采集若干个样
34、本进行处理,比如频谱分析、音频压缩等。本例假设要每采集 256 个样本进行一次处理。上例用的是查询方式,占用了所有 CPU 资源。可以用中断方式,结合前面的实验不难做到,请同学们自行完成。在这个实验中我们将介绍一个更有效的 DMA 传送方式。我们比较一下用中断方式和 DMA 方式的效率有何不同:一、中断方式:每当中缓冲串口接收一个 16bit 样本的数据,触发一次串口接收中断,将数据转移到一个 256 word 的数据接收缓冲区并计数。当计数达到 256 个,即缓冲区满时,将 256 个数据转移到数据处理存储区,并通知主程序进行处理。二、DMA 方式:我们使用一个通道自动接收 McBSP 传来
35、的数据并存入接收缓冲区,当缓冲区满时触发 DMA 中断,将 256 个数据传送到数据处理存储区,传送完毕触发通知主程序进行处理。由上比较可见,每接收一批样本,用中断方式将触发 256 次中断,也就是主程被打断 256 次去接收数据。而用 DMA 方式,只在全部 256 个样本全部接收完毕时发生一次中断,这时主程序应该已经处理完上一批的数据。进一步考虑,当数据处理完毕后还需要将数据送走,这时又可以采用另一个DMA 通道完成这个任务,将 CPU 释放出来等待进行下一批样本的处理。事实上 DMA 传送并非比用 CPU 直接处理快,例如在内部存贮器之间传送时,用CPU 需要 2cycle/word,而
36、用 DMA 要 4cycle/word。DMA 的优势在是把 CPU 解放出来做其它的事。以下是两个 DMA 通道与 CPU 协调工作的情况(阴影部分表示空闲)。DMA0CPU DMA1 从 McBSP 接收数据DMA 中断,将数据从接收缓冲区转移到数据处理存储区对对数据进行处理将处理完的数据送走估计一下各步的时间,设采样频率是 8kHz,CPU 时钟频率 100MHz。因此一个处理周期为 1/8kHz*256=32ms。传送 256 个点至少需要 256word*2cycle/word=512cycle=5.12us。假设处理完后数据量不变,需要256word*4cycle/word=102
37、4 cycle=10.24us。所需要的时钟周期取决于算法的复杂度了。计算好各步所需要的时钟周期,就可以根据情况灵活选择如何使用 DMA,例如如果 CPU 有足够的空闲时间送走数据就不必要;如果 CPU 仍然不足,就需要再增加个一个 DMA 来做的任务。如果数据的输出也是从 McBSP 输出,还要用一个 DMA 通道进行 McBSP 的发送。总之要合适地使用 DMA 通道,使用不当也会使程序变得更加复杂,例如多个DMA 通道优先级的问题等等。C54x 系列有 6 个 DMA 通道,但不同型号 C54x 系列 DSP DMA 通道的使用不全相同,如 C5402 只能将 DMA 通道用于内部数据存
38、贮器之间传送、McBSP 和 HPI 接口,而 C5410 可用于内部、外部数据、程序存贮器之间传送。详细介绍请参阅 SPRU302 TMS320C54x DSP Reference Set, Volume 5: Enhanced Peripherals 和各 DSP 的数据手册。实验 7.1 FIR;=; fir4.asm;用用循环缓冲区和双操作数寻址方法实现 FIR 滤波器;先用 matlab,选择 80 点汉明窗设计一个截止频率为 0.2 的低通滤波器; 本例与前不同的是系数直接引用程序存储器的系数表;N=5 y(n)=h0*x(n)+h1*x(n-1)+h2*x(n-2)+h3*x(n
39、-3)+h4*x(n-4);=.title “fir4.asm“.mmregs .def start;分配数据存储区.bss y,1 ;yxn .usect “xn“,80 ;xnh .usect “h“,80 ;hPA0 .set 0000H ;数据输出端口PA1 .set 0001H ;数据输入端口;参数表.datatable: .word -7,-18,-24,-22,-9,11,33,48 ;已在 Matlab 中转成十六进制的小数.word 46,20,-24,-73,-104,-97,-43,49.word 146,204,187,81,-91,-268,-371,-337.wor
40、d -144,162,476,661,603,261,-297,-894.word -1283,-1222,-562,697,2373,4142,5618,6456.word 6456,5618,4142,2373,697,-562,-1222,-1283.word -894,-297,261,603,661,476,162,-144.word -337,-371,-268,-91,81,187,204,146.word 49,-43,-97,-104,-73,-24,20,46.word 48,33,11,-9,-22,-24,-18,-7 start: SSBX FRCT ;小数乘法;把参
41、数表复制到数据存储区STM #h,AR1 RPT #79MVPD #table,*AR1+;把 x(n)-x(n-79)赋始值 0STM #xn,AR1RPT #79ST #0,*AR1+STM #xn+79,AR3 ;x(n-79)-AR3STM #h+79,AR4 ;h(n-79)-AR4STM #80,BK ;循环缓冲区大小 80 STM #-1,AR0 ;指针调整值-1LD #xn,DP ;DP 指向 xn 所在页PORTR PA1,xn ;输入数据LD #y,DP ;DP 指向 y 所在页FIR: RPTZ A,#79 ;进行一次 FIR 运算MAC *AR3+0%,*AR4+0%,
42、A;A=(AR3)*(AR4)+A, AR3=AR3+AR0,AR4=AR4+AR0 STH A,y ;保存计算结果PORTW y,PA0 ;输出结果BD FIR ;读入下一个数据并进行下一次计算PORTR PA1,*AR3+0% ;新数据覆盖了最旧的数据.end实验 7.2 IIR.mmregs.global codestart K_DATA_SIZE .set 256 ;输入数据个数K_BUFFER_SIZE .set 8 ;缓冲大小,需是 2 的整数次幂,并大于 a、b 的个数K_STACK_SIZE .set 256 ;堆栈大小K_A .set 3 ;a 向量个数K_B .set 4
43、;b 向量的个数K_CIR .set 4 ;=a、b 的长度,也可以设为 K_BUFFER_SIZE-1 STACK .usect “stack“,K_STACK_SIZESYSTEM_STACK .set K_STACK_SIZE+STACK.dataDATA_DP: .align K_BUFFER_SIZEbufferdatax: .space K_BUFFER_SIZE*16 ;size in bitsbufferdatay: .space K_BUFFER_SIZE*16 ;size in bits inputdata: .word 0filterdata: .word 0 .text
44、.asg AR2, ORIGIN.asg AR3, INPUT.asg AR4, FILTER.asg AR5, OUTPUTcodestart:SSBX FRCTSSBX INTMLD #DATA_DP,DPSTM #SYSTEM_STACK, SPCALL filter_startNOPNOPNOPLOOP:B LOOP.def b0,b1,b2,b3,a1,a2,a3;.def filter_startb0 .set 1456H ;b1=0.1589 *215b1 .set 3D07H ;b2=0.4768b2 .set 3D07H ;b3=0.4768b3 .set 1456H ;b4=0.1589a1 .set -103AH ;a1=-0.1268a2 .set 430FH ;a2=0.5239a3 .set -1016H ;a3=-0.1257;=;滤波子程序:filter_start;=