1
信息工程学通信工程系
DSP技术 及应用
Digital Signal Processor
数字信号处理器
陈金鹰 副教授
2
第五章 汇编语言编程举例
第一节 汇编语言编程的基本方法
第二节 DSP的浮点运算方法
第三节 DSP在信号发生器上的应用
第四节 用 DSP实现 FIR滤波器
3
第一节 汇编语言编程的基本方法
1,堆栈的使用
1.压入数据时,堆栈从高地址向低地
址增长。
2.压栈时指针先减,SP-1,再压入数
据;
3.出栈时,先弹出数据后,再 SP+1。
4.如要用堆栈,必须先设置,后使用。


4
例 5-1 设计一存储空间为 100个单元的堆栈 。
size,set 100 ;设置堆栈空间的;大小为 100
stack,usect,STK”,size ;设置堆栈段的首地址;和堆栈空间
STM #stack+size,SP ;将栈底地址指针送; SP,对其初始化
5
例 5-2 编写求解加, 减法的程序, 计算 z=x+y-w。
SUM1,LD @x,A ;将 x地址的内容送 A
ADD @y,A ;将 y地址的内容与 A中 x值相加
SUB @w,A ;将 A中的内容与 w 相减, 得 z
STL A,@z ;将 A的的计算值存入 z 地址中
例 5-3 写求解直线方程的程序, 计算 y=mx+b。
SUM2,LD @m,T ;将 m 地址的内容送 T
MPY @x,A ;将 x 地址的内容与 T中的 m相乘,;结果送 A
ADD @b,A ;将 A中的 mx与 b 地址的内容相加,;结果送 A
STL A,@y ;将 A的的计算结果存入 y 地址中
2,加, 减法和乘法运算
6
传送速度比加载和存储指令要快;
传送数据不需要通过累加器;
可以寻址程序存储器;
与 RPT指令相结合 ( 重复时, 这些指
令都变成单周期指令 ), 可以实现
数据块传送 。
3,数据块传送


7
( 1) 数据存储器 ←→ 数据存储器 这类指令有:
MVDK Smem,dmad 指令的字数 /执行周期 2/2
MVKD dmad,Smem ; Smem=dmad
2/2
MVDD Xmem,Ymem ; Ymem=Xmem
1/1
( 2) 程序存储器 ←→ 数据存储器 这类指令有:
MVPD pmad,Smem ; Smem=pmad
2/3
MVDP Smem,pmad ; pmad=Smem
2/4
pmad为 16位立即数程序存储器地址;
dmad为 16位立即数数据存储器地址;
8
( 3)数据存储器 ←→ MMR 这类指令有:
MVDM dmad,MMR ;指令的字数 /执行周期 2/2
MVMD MMR,dmad ; dmad=MMR 2/2
MVMM mmrx,mmry ; mmry=mmrx 1/1
( 4)程序存储器( Acc) ←→ 数据存储器 包括:
READA Smem ; Smem=prog(A) 1/5
WRITA Smem ; prog(A)= Smem 1/5
mmrx,mmry为 AR0~ AR7或 SP;
MMR为任何一个存储器映象寄存器;
9
例 5-6 将数组 x[5] 初始化为 {1,2,3,4,5}。
.data ;定义初始化数据段起始地址
TBL,.word 1,2,3,4,5 ;为标号地址 TBL;开始的 5个单元赋初值
.sect,.vectors” ;定义自定义段, 并获;得该段起始地址
B START;无条件转移到标号为 START的地址
.bss x,5 ;为数组 x分配 5个存储单元
.text ;定义代码段起始地址
START:STM #x,AR5 ;将 x的首地址存入 AR5
RPT #4 ;设置重复执行 5次下条指令
MVPD TBL,*AR5+ ;将 TBL开始的 5个值传给 x
( 1)程序存储器 → 数据存储器
10
例 5-7 将数据存储器中的数组 x[10]复制到数组 y[10]。
.title,cjy1.asm” ;为汇编源程序取名
.mmregs ;定义存储器映象寄存器
STACK,usect,STACK”,30H;设置堆栈
.bss x,10 ;为数组 x分配 10个存储单元
.bss y,10 ;为数组 y分配 10个存储单元
.data
table:.word 1,2,3,4,5,6,7,8,9,10
.def start ;定义标号 start
.text
( 2)数据存储器 → 数据存储器
11
start:STM #0,SWWSR ;复位 SWWSR
STM #STACK+30H,SP;初始化堆指针
STM #x,AR1 ;将目的地首地址赋给 AR1
RPT #19 ;设定重复传送的次数为 20次
MVPD table,*AR1+ ;程序存储器传送到数;据存储器
STM #x,AR2 ;将 x的首地址存入 AR2
STM #y,AR3 ;将 y的首地址存入 AR3
RPT #19 ;设置重复执行 20次下条指令
MVDD *AR2+,*AR3+;将地址 x开始的 20个值;复制到地址 y开始的 20个单元
end,B end
.end
12
用间接寻址方式获得操作数, 且
辅助寄存器只用 AR2~ AR5;
占用程序空间小;
运行速度快 。
4,双操作数乘法


例 5-8 编制求解 的程序 。
利用双操作数指令可以节省机器周期 。 迭代次数
越多, 节省的机器周期数也越多 。 本例中, 在每次
循环中, 双操作数指令都比单操作数指令少用一个
周期, 节省的总机器周期数 =1T*N( 迭代次数 ) =NT。
?
?
?
20
1i
ii xay
13
单操作数指令方案 双操作数指令方案
LD #0,B LD #0,B
STM #a,AR2 STM #a,AR2
STM #x,AR3 STM #x,AR3
STM #19,BRC STM #19,BRC
RPTB done-1 RPTB done-1
LD *AR2+,T; 1T MPY *AR2+,*AR3+,A; 1T
MPY *AR3+,A; 1T ADD A,B ; 1T
ADD A,B ; 1T
done:STH B,@y done:STH B,@y
STL B,@y+1 STL B,@y+1
14
在单个周期内同时利用 C总线和 D
总线, 得到 32位操作数 。
5,长字运算


使用长操作数指令时, 按指令中给出的地址存取的总
是高 16位操作数 。 这样, 有两种数据排列方法:
( 1) 偶地址排列法 指令中给出的地址为偶地址, 存
储器中低地址存放高 16位操作数 。
如,DLD *AR3+,A
执行前,A=00 0000 0000 执行后,A=00 6CAC BD90
AR3=0100 AR3=0102
( 0100h) =6CAC( 高字 ) ( 0100h) =6CAC
( 0101h) =BD90( 低字 ) ( 0101h) =BD90
15
( 2) 奇地址排列法 指令中给出的地址为奇地址, 存储器中
低地址存放低 16位操作数 。
如,DLD *AR3+,A
执行前,A=00 0000 0000 执行后,A=00 BD90 6CAC
AR3=0101 AR3=0103
( 0100h) =6CAC( 低字 ) ( 0100h) =6CAC
( 0101h) =BD90( 高字 ) ( 0101h) =BD90
推荐采用偶地址排列法, 将高 16位操作数放在偶地址存储单元
中 。 如,程序存储器
.long 12345678 h ;偶地址,1234;奇地址,5678
数据存储器
.bss xhi,2,1,1 ;偶地址,xhi
↓ ↓ ↓ ↓ ;奇地址,xlo
变量名称 字长 页邻接 偶地址排列法
16
例 5-9 计算 Z32=X32+Y32。
标准运算 长字运算
LD @xhi,16,A DLD @xhi,A
ADDS @xlo,A DADD @yhi,A
ADD @yhi,16,A DST A,@zhi
ADDS @ylo,A ( 3个字, 3个 T)
STH A,@Zhi
STL A,@Zlo
( 6个字, 6个 T)
17
(1)并行运算指同时利用 D总线和 E总线 。
其中, D总线用来执行加载或算术运算, E总
线用来存放先前的结果 。
(2)并行指令都是单字单周期指令 。
(3)并行运算时所存储的是前面的运算结
果, 存储之后再进行加载或算术运算 。
(4)并行指令都工作在累加器的高位 。
(5)大多数并行运算指令都受累加器移位
方式 ASM位影响 。
6,并行运算


18
表 5-1 并行指令举例
指 令 指 令 举 例 操作说明
并行加载和乘法指令 LD‖MAC[R]LD‖MAS[R] LD Xmem,dst‖MAC[R] Ymem[,dst] dst=Xmem<<16dst2=dst2+T*Ymem
并行加载和存储指令 ST‖LD ST src,Yme‖LD Xmem,dst Ymem=src>>( 16-ASM)dst=Xmem<<16
并行存储和乘法指令
ST‖MAY
ST‖MAC[R]
ST‖MAS[R]
ST src,Ymem
‖MAC[R] Xmem,dst
Ymem=src>>( 16-ASM)
dst=dst+T*Xmem
并行存储和加 /减法
指令
ST‖ADD
ST‖SUB
ST src,Ymem
‖ADD Xmem,dst
Ymem=src>>( 16-ASM)
dst=dst+Xmem
19
例 5-10 编写计算 z=x+y和 f=d+e的程序段 。
在此程序段中用到了并行存储 /加载指令, 即在同一机器周期
内利用 E 总 线 存 储 和 D 总 线 加 载 。
数据存储器分配如图 5-4所示 。
.title,cjy3.asm”
.mmregs
STACK,usect,STACK”,10H
.bss x,3 ;为第一组变量;分配 3个存储单元
.bss d,3 ;为第二组变量;分配 3个存储单元
.def start
.data
table,.word 0123H,1027H,0,1020H,0345H,0
20
.text
start:STM #0,SWWSR
STM #STACK+10H,SP
STM #x,AR1
RPT #5
MVPD table,*AR1+
STM #x,AR5 ;将第一组变量的首地址传给 AR5
STM #d,AR2 ;将第二组变量的首地址传给 AR2
LD #0,ASM ;设置 ASM=0
LD *AR5+,16,A ;将 x的值左移 16位放入 A的高端字
ADD *AR5+,16,A ;将 y值左移 16位与 A的高端字 x相加
ST A,*AR5 ;将 A中的和值右移 16位存入 z中
‖LD *AR2+,B ;将 d的值左移 16位放入 B的高端字
ADD *AR2+,16,B ;将 e值左移 16位与 B的高端字 d相加
STH B,*AR2 ;将 B的高端字中的和值存入 f中
end,B end
.end
21
7,64位加法和减法运算
例 5-11 编写计算 Z64=W64+X64-Y64的程序段 。
这里的 W,X,Y和结果 Z都是 64位数, 它们都由两个 32位的
长字组成 。 利用长字指令可以完成 64位数的加 /减法 。
w3 w2 w1 w0 ( W64)
+ x3 x2 C x1 x0 ( X64) 低 32位相加产生进位 C
- y3 y2 C’ y1 y0 ( Y64) 低 32位相减产生借位 C’
__________________________________
z3 z2 z1 z0 ( Z64)
22
DLD @w1,A ; A=w1w0
DADD @x1,A ; A=w1w0+x1x0,产生进位 C
DLD @w3,B ; B=w3w2
ADDC @x2,B ; B=w3w2+x2+C
ADD @x3,16,B ; B=w3w2+x3x2+C
DSUB @y1,A ; A=w1w0+x1x0-y1y0,产生借位 C’
DST A,@z1 ; z1z0=w1w0+x1x0-y1y0
SUBB @y2,B ; B=w3w2+x3x2+C-y2-C’
SUB @y3,16,B ; B=w3w2+x3x2+C-y3y2-C’
DST B,@z3 ; z3z2=w3w2+x3x2+C-y3y2-C’
由于没有长字带进(借)位加 /减法指令,所以上述程序
中只能用 16位带进(借)位指令 ADDC和 SUBB。
23
8,32位乘法运算
x1 x0 S U
× y1 y0 S U
__________________ _____________
x0 * y0 U * U
y1 * x0 S * U
x1 * y0 S * U
y1 * x1 S * S
________________ _______________
w3 w2 w1 w0 S U U U
例 5-12 编写计算 W64=X32*Y32的程序段。
32位乘法算式如下:
图 5-5
24
其中, S为带符号数, U为无符号数 。 数据存储器分配如
图 5-5所示 。 在 32位乘法运算中, 实际上包括了三种乘法运算:
U*U,S*U和 S*S。 一般的乘法运算指令都是两个带符号数相乘,
即 S*S。
所以, 在编程时, 要用到以下三条乘法指令:
MACSU Xmem,Ymem,src ;无符号数与带符号数相乘并累
加; src=U( Xmem) * S( Ymem)
+src
MPYU Smem,dst ;无符号数相乘; dst=U( T ) * U( Smem)
MAC Xmem,Ymem,src ;两个符号数数相乘并累加; src=S( Xmem) * S( Ymem) +src
32位乘法的程序段如下:
25
STM #x0,AR2 ;将 x的首地址放入 AR2
STM #y0,AR3 ;将 y的首地址存入 AR3
LD *AR2,T ; T=x0
MPYU *AR3+,A ; A=ux0*uy0
STL A,@w0 ; w0=ux0*uy0
LD A,-16,A ; A=A>>16
MACSU *AR2+,*AR3-,A ; A+=y1*ux0
MACSU *AR3+,*AR2,A ; A+=x1*uy0
STL A,@w1 ; w1=A
LD A,-16,A ; A=A>>16
MAC *AR2,*AR3,A ; A+=x1*y1
STL A,@w2 ; w2=A的低 16位
STH A,@W3 ; w3=A的高 16位
26
9,小数运算
整数运算的问题
( 1) 两个 16位整数相乘, 乘积总是, 向左增
长, 。 这意味着多次相乘后, 乘积将会很快超出
定点器件的数据范围 。
( 2) 保存 32位乘积到存储器, 要开销 2个机
器周期以及 2个字的存储器单元 。
( 3) 由于乘法器都是 16位相乘, 因此很难在
后续的递推运算中, 将 32位乘积作为乘法器的输
入 。
小数运算的优点
( 1) 乘积总是, 向右增长, 。 这就味着超出
定点器件数据范围的将是不太感兴趣的部分 。
( 2) 既可以存储 32位乘积, 也可以存储高 16
位乘积, 这就允许用较少的资源保存结果 。
( 3) 可以用于递推运算 。
小数
运算
与整
数运
算的
比较
27
C54x采用 2的补码表示小数, 其最高位为符号位, 数值范围
从 -1~ 1。 一个 16位 2的补码小数 ( Q15格式 ) 的每一位的权值
为:
MSB( 最高位 ) … LSB( 最低位 )
-1,1/2 1/4 1/8 … 2-15
一个十进制小数乘以 32768之后再将其十进制整数部分转换
成十六进制数, 就能得到这个十进制小数的 2的补码表示了 。
≈ 1 → 7FFFh
0.5 正数:乘以 32768 4000h
0 → 0000h
-0.5 负数:其绝对值部分乘以 32768,再取反加 1 C000h
-1 8000h
( 1)小数的表示方法
28
在汇编语言中,是不能直接写入十进制
小数的,可写为整数运算式。
如果要定义一个系数 0.707,可以写成:
.word 32768*707/1000
不能写成 32768*0.707。
注意
Q格式表示法
在 Q格式中,Q之后的数字(如 Q15格式中的 15)决
定小数点右边有多少位二进制位,故 Q15表示在小数
点后有 15位小数。当用一个 16位的字来表示 Q15格式
时,在 MSB(最高位)的右边有一个小数点,而 MSB表
示符号位。所以 Q15的表示数字可表示范围从 +1(以
+0.999997表示)到 -1的值。
29
通过合适的 Q格式, 可以把数值根据所需的精确度做
适当地转换, 以便定点数的 DSP也可以处理高精度的
浮点数 。 下面以 Q15为例, 说明转换的过程 。
1) 先确定准备转换的十进制数值 N,是在 Q15格式
的数值范围之间, 即 -1.000000≤N≤+ 0.999997。
2) 数值 N乘以 215,即 N'=N× 215=N× 32768
3) 把步骤 2) 的结果加 216,即 N''=N'+216=N'+65536

4) 步骤 3) 的结果转换成十六进制, 并把第 17位舍
弃掉, 得到的结果就是 N的 Q15转换值 。
30
下面通过把 -0.2345及 +0.2345转换成 Q15格式来说
明转换方法 。
-0.2345的转换为:
-0.2345× 32768=-7684.1≈ -7684
-7684+65536=57852
57852转换成十六进制数值为 0E1FCh,所以结果为
E1FCh。
+0.2345的转换为:
0.2345× 32768=7684.1≈ 7684
7684+65536=73320
73320转换成十六进制数值为 11E04h,并把第 17位
舍弃掉,结果为 1E04h。
31
以字长为 4位和 8位累加器为例, 先看一个小数乘法的例子 。
0 1 0 0( 0.5→ 23× 0.5=( 4) 10=( 0100) 2)
× 1 1 0 1( -0.375→ 23× ( -0.375) =( -3) 10
0 1 0 0 =( 1101) 补 )
0 0 0 0
0 1 0 0
1 1 0 0 ( -0100)
1 1 1 0 1 0 0 ( -0.1875=-12/26← -12=( 1110100) 补 )
( 2)小数乘法与冗余符号位
32
上述乘积是 7位, 当将其送到 8位累加器时, 为保
持乘积的符号, 必须进行符号位扩展, 这样, 累加
器中的值为 11110100( -0.09375=-12/27), 出现了
冗余符号位 。 原因是:
S x x x ( Q3)
× S y y y ( Q3)
S S z z z z z z ( Q6格式 )
即两个带符号数相乘, 得到的乘积带有 2个符号位
,造成错误的结果 。
同样, 对于两个十六位数相乘, 乘积只有 30位,
在最高的两位也是符号位, 同样会造成错误的结果

33
解决冗余符号的办法是:在程序中设定状态寄存器
ST1中的 FRCT( 小数方式 ) 位 1,在乘法器将结果传送
至累加器时就能自动地左移 1位, 累加器中的结果为:
S zzzzzz0 ( Q7 格式 ), 即 11101000 ( -0.1875=-
24/27← -24=( 11101000) 补 ), 自动地消去了两个带
符号数相乘时产生的冗余符号位 。 所以在小数乘法编
程时, 应当事先设置 FRCT位:
SSBX FRCT

MPY *AR2,*AR3,A
STH A,@Z
这样, C54x就完成了 Q15*Q15=Q15的小数乘法 。
34
例 5-13 编制计算 的程序段, 其中数据均为
小数,a1=0.1,a2=0.2,a3=-0.3,a4=0.4,x1=0.8,
x2=0.6,x3=-0.4,x4=-0.2。
.title,cjy4.asm”
.mmregs
STACK,usect,STACK”,10H
.bss a,4 ;为 a分配 4个存储单元
.bss x,4 ;为 x分配 4个存储单元
.bss y,1 ;为结果 y分配 1个存储单元
.def start
.data ;定义数据代码段
?
?
? 4
1i
ii xay
35
table,.word 1*32768/10 ;在 table开始的 8个
.word 2*32768/10 ;地址放数据
.word -3*32768/10
.word 4*32768/10
.word 8*32768/10
.word 6*32768/10
.word -4*32768/10
.word -2*32768/10
36
.text ;定义可执行程序代码段
start:SSBX FRCT ;设置 FRCT位, 表示进行小数乘
STM #x,AR1 ;将 x的首地址传给 AR1
RPT #7 ;重复 8次下条指令
MVPD table,*AR1+ ;将程序空间 8个数传给数据存储器
STM #x,AR2 ;将数据存储器第一个数 x1的地址传给 AR2
STM #a,AR3 ;将数据存储器第五个数 a1的地址传给 AR3
RPTZ A,#3 ;将 A清零, 重复 4次下条指令
MAC *AR2+,*AR3+,A ;执行乘法累加和, 结果放在 A中
STH A,@y ;将 A的高端字存入结果 y,低端字省去
end,B end ;原处循环等待
.end
结果 y=0x1EB7 。 转 换 为 十 进 制 数, y= (
1× 163+14× 162+11× 161+7× 160) /32768=0.24
37
10,除法运算
条件减法指令的功能如下:
SUBC Smem,src ; ( src) - ( Smem) <<15
→ALU;输出端, 如果 ALU输出端 ≥ 0,;则 ( ALU输出端 ) <<1+1→src,;否则 ( src) <<1→src 。
方法:减法指令加重复指令实现无符号运算
( 1) 当|被除数|<|除数| 此时商为小数 。
38
例 5-14 编写 0.4÷ ( -0.8) 的程序段 。
.title,cjy5.asm”
.mmregs
STACK,usect,STACK”,10H
.bss num,1 ;为分子分配单元
.bss den,1 ;为分母分配单元
.bss quot,1 ;为商分配单元
.data ;定义数据段起始地址
table:.word 4*32768/10 ;在以 table为地址的;单元放入 0.4
.word -8*32768/10 ;在以 table为地址的;下一单元放入 -0.8
.def start
39
.text ;定义数据段起始地址
start,STM #num,AR1 ;将分子所在单元的地址传给 AR1
RPT #1 ;重复执行下一指令 2次
MVPD table,*AR1+;传送程序空间的 2个数据 ( 分子,;分母 ) 至地址为 num开始的数据存储器单元
LD @den,16,A ;将分母移到累加器 A( 31~ 16)
MPYA @num ; ( num) *( A( 31~ 16)) → B,;获取商的符号 ( 在累加器 B中 )
ABS A ;分母取绝对值
STH A,@den ;分母绝对值存回原处
LD @num,16,A ;分子加载到 A( 31~ 16)
ABS A ;分子取绝对值
RPT #14 ; 15次减法循环, 完成除法
SUBC @den,A ;
XC 1,BLT ;如果 B<0( 商是负数 ), 则需要变号NEG A ;如果 B<0执行求反, 否则跳过此指令
STL A,@quot ;保存商
end,B end
.end
40
a) |被除数|<|除数|商为小数 b=|被除数| ≥ |除数|商为整数
41
10,除法运算
( 2) 当|被除数| ≥ |除数|时 商为整数 。
例 5-15 编写 16384÷ 512的程序段 。
将上例程序段仅作两处修改, 其它不变, 就得本
例的程序段:
LD @num,16,A 改成 LD @num,A
RPT #14 改成 RPT #15
本例的程序段为:
.title,cjy6.asm”
.mmregs
STACK,usect,STACK”,10H
42
.bss num,1 ;为分子分配单元
.bss den,1 ;为分母分配单元
.bss quot,1 ;为商分配单元
.data ;定义数据段起始地址
table,.word 66*32768/100 ;在以 table为地址;的单元放入 16384
.word -33*32768/100 ;在以 table为地址;的下一单元放入 512
.def start
.text ;定义数据段起始地址
start,STM #num,AR1;将分子所在单元地址传给 AR1
RPT #1 ;重复执行下一指令 2次
MVPD table,*AR1+;传送程序空间的 2; 数据 ( 分子, 分母 ) 至 地址为; num开始的数据存储器单元
43
LD @den,16,A ;将分母移到累加器 A( 31~ 16)
MPYA @num ; ( num) *( A( 31~ 16)) → B,;获取商的符号 ( 在累加器 B中 )
ABS A ;分母取绝对值
STH A,@den ;分母绝对值存回原处
LD @num,A ;分子加载到 A( 15~ 0)
ABS A ;分子取绝对值
RPT #15 ; 16次减法循环, 完成除法
SUBC @den,A ;
XC 1,BLT ;如果 B<0( 商是负数 ), 则需要变号
NEG A ;如果 B<0执行求反, 否则跳过此指令
STL A,@quot ;保存商
end:B end
.end ; 结果为 quot=0x0020=32。
44
第二节 DSP的浮点运算方法
1,浮点数的表示方法
(1) C54x本身是定点 DSP芯片;
(2)用定点 DSP芯片进行浮点数运算,
必须先将定点数转换为浮点数。


浮点数表示定点数,采用
尾数和指数两部分来表示
定点数 =尾数 × 2-(指数) 或 x=m× 2e
45
2,定点数转换成浮点数
这是一条提取指数的指令, 所提取的指数保存
在 T寄存器中 。 如果累加器 A=0,则 0→T ;否则,
累加器 A的冗余符号位数减 8→T 。 累加器 A中的
内容不变 。




( 1)先将定点数放在累加器 A或 B中
,然后用指令,EXP A 或 EXP B。
注意 由于 C54x DSP用 16位表示数字, 其对浮点数的表
示与 IEEE 754-1985标准的 32位表示法略有不同 。
采用一个单元保存指数和一个单元保存尾数的两
个 16位表示法 。
46
例 5-16 提取 A=FF FFFF FFCB中的指数值 。
执行指令,EXP A
执行前 执行后
A=FF FFFF FFCB A=FF FFFF FFCB
T= 0000 T= 0019 ( 25)
本例中, 由于 A≠ 0,需要先求出 A的冗余符号位并
减去 8。
A=F F F F F F F F C B
1111 1111 1111 1111 1111 1111 1111 1111 1100 1011
33位冗余符号位 1,33-8=25=0x0019
47
例 5-17 提取 B=07 8543 2105中的指数值 。
执行指令,EXP B
执行前 执行后
B=07 8543 2105 B=07 8543 2105
T= 0007 T= FFFC ( -4)
本例中, 由于 B≠ 0,需要先求出 B的冗余符号位并
减去 8。
A= 0 7 8 5 4 3 2 1 0 5
0000 0111 1000 0101 0100 0011 0010 0001 0000 0101
4位冗余符号位 0,4-8=-4=0xFFFC
-4=-( 0x0004) =( 1111 1111 1111 1011+1) 补 =(
0xFFFC) 补
48
( 2) 使用指令 ST T,EXPONENT
将保存在 T寄存器中的指数存放到数据存储
器的指定单元 EXPONENT中。
如 EXP A
ST T,@e1 ;将指数存入数据存储器; e1所指定的单元中 。




( 3)使用指令 NORM A 。
按T寄存器中的内容对累加器 A进行归一化处理。这里
的将定点数转换成浮点数所进行的归一化处理,指通
过左移或右移,使一个二进制数变为一个小数,且小
数点后的第一个数不为零,移动的位数用指数表示。
49
例如,
0.3=(0.010011)2× 2-0=(0.10011)2× 2-1,
-0.8=-0.8× 2-0=-(0.110011) 2× 2-0,
-0.24=-(0.001111)× 2-0=-(0.1111)2× 2-2。
3=(11)2× 2-0=(0.11)2× 22
-8=-(1000)2× 2-0=-(0.1)2× 24
-24=-(11000)2× 2-0=-(0.11)2× 25
上例中,对于小数,当转换成小数点后第一位为 1的归
一化数时,通过将小数点右移实现,指数为负数。对于
整数,则将小数点左移实现,指数搂正数。
50
例 5-18 对累加器 A进行归一化处理 。
执行指令,NORM A
执行前 执行后
A=FF FFFF F001 A=FF 8008 0000
T= 0013 T= 0013( 19)
执行时, 按 T中的十进制数值, 这里为正 19,对累加
器 A中的值左移 19位, 即将在 A=FF FFFF F001中的值左
移 19位, 低位添零, 高位溢出丢弃 。
A=(1111 1111 1111 1111 1111 1111 1111 0000 0000 0001 )2
← 1111 1111 1111 1111 1111 1111 1111 0000 0000 0001 0000 0000 0000 0000 000
左移出去掉的 19位 左移进 19位添 0
← (1111 1111 1000 0000 0000 1000 0000 0000 0000 0000)2=( FF 8008 0000) 16
51
例 5-19 对累加器 B中的值进行归一化处理后存入 A。
执行指令,NORM B,A
执行前 执行后
A=FF FFFF F001 A=00 4214 1414
B=21 0A0A 0A0A B=21 0A0A 0A0A
T= FFF9 T= FFF9( -7)
将 B移 -7位, 即右移 7位:
B=( 0010 0001 0000 1010 0000 1010 0000 1010 0000 1010) 2
→ 0000 000 0010 0001 0000 1010 0000 1010 0000 1010 0000 1010
右移进 7位添 0 去掉移出的 7位
→ ( 0000 0000 0100 0010 0001 0100 0001 0100 0001 0100)
2=( 00 4214 1414)
16
52
3,浮点数转换成定点数




在将浮点数转换成定点数时,按指数
值将尾数右移(指数为负时左移)即
可。其操作与定点数转换为浮点数相
反。这种相反方向的移位是通过对指
数取反实现的。
使 用指令 NEG A
NORM A
53
如指数在 A中, 尾数在 x中, 则将浮点数转换成定点
数的指令为:
NEG A ;指数反号
STL A,@temp ;将指数暂存在数据存储单元中
LD @temp,T ;将指数装入 T寄存器
LD @x,16,A ;将尾数装入 A的高 16位
NORM A ;将尾数按 T移位,由于 T中的指数;是已经取反了的, 所进行的移;位为反向移位 。 转换后的定点;数在 A中 。
54
例 5-20 编写浮点乘法程序, 完成 x1× x2=0.3× ( -
0.8) 运算 。 程序清单为:
.title,float.asm” ;程序名
.def start ;定义标号
STACK,.usect,STACK”,100 ;设置堆栈
.bss x1,1 ;为被乘数 x1预留 1个单元的空间
.bss x2,1 ;为乘数 x2预留 1个单元的空间
.bss e1,1 ;为被乘数的指数 e1预留 1个单元空间
.bss m1,1 ;为被乘数的尾数 m1预留 1个单元空间
.bss e2,1 ;为乘数的指数 e2预留 1个单元的空间
.bss m2,1 ;为乘数的尾数 m2预留 1个单元的空间
.bss ep,1 ;为乘积的指数 ep预留 1个单元的空间
.bss mp,1 ;为乘积的尾数 mp预留 1个单元的空间
.bss product,1 ;为乘积留空间
.bss temp,1 ;为暂存留空间
55
.data ;定义数据段
table,.word 3*32768/10 ;设初值 0.3
.word -8*32768/10 ;设初值 -0.8
.text ;定义代码段
start,STM #STACK+100,SP ;设置堆栈指针初值
MVPD table,@x1 ;送 0.3,-0.8
MVPD table+1,@x2 ;至数据存储器
LD @x1,16,A ;将 x1送到 A
EXP A ;取 A中指数
ST T,@e1 ;存指数到 e1
NORM A ;对 A归一化
STH A,@m1 ;存尾数到 m1
LD @x2,16,A ;将 x2送到 A
EXP A ;提取 A中指数, 放入 T
ST T,@e2 ;保存 x2的指数到 e2
NORM A ;对累加器 A归一化
STH A,@m2 ;保存 x2的尾数到 m2
CALL MULT ;调用浮点乘法子程序
end,B end ;循环等待

0.3
的浮
点数
-0.8
的浮
点数
56
MULT,SSBX FRCT ;设置小数乘法运算
SSBX SXM ;数据进入 ALU之前进行符号位扩

LD @e1,A ; x1指数送 A
ADD @e2,A ; x2与 x1指数相加
STL A,@ep ;乘积指数存入 ep
LD @m1,T ; x1尾数送 T
MPY @m2,A ; x1与 x1尾数相乘, 结果在 A中
EXP A ;提取 A中指数, 放入 T
ST T,@temp ;尾数乘积中提取的指数存入 temp
NORM A ;对累加器 A进行归一化处理
STH A,@mp ;保存提取指数后的尾数在 mp中
LD @temp,A ;修正乘积指数, 尾数乘积指数送 A
ADD @ep,A ; ( ep) +( temp)
STL A,@ep ;保存乘积指数在 ep中
NEG A ;将浮点数乘积转换成定点数
STL A,@temp ;乘积指数反号后存入 temp
LD @temp,T ;并加载到 T寄存器
对积
求指
数并
归一

57
LD @mp,16,A ;将乘积的尾数装入 A的高 16位
NORM A ;将尾数按 T中的指数移位
STH A,@product ;保存定点乘积到 product中
RET ;返回
.end
程序执行结果为:
0.3× ( -0.8) 乘积的浮
点数尾数 0x8520,指数为
0x0002。 乘积的定点数为
0xE148,对应的十进制数
为 -0.23999。 程序执行后
数据存储器中的数据值如
图 5-8所示 。
58
第三节 DSP在信号发生器上的应用
1,一个角度正弦值的计算

点 ) ) ) )98 x1(76 x1(54 x1(32 x1(x!9x!7x!5x!3xxs i n 22229753 ???????????????
按 C54x系列采用的 Q15格式,将 θ 转换为
十进制小数的 2的补码形式为:
θ =0.7854× 32768=6487h弧度。
再将要计算的值 θ 放在 d_x单元中,计算
结果放在 d_sinx单元中。
59
60
.title,sinx.asm” ;为程序取名
.mmregs ;定义存储器映象寄存器
.def start ;定义标号 start
.ref sin_start,d_x,d_sinx ;引用别处定义的; sin_start,d_x,d_sinx
STACK:.usect,STACK”,10 ;设置堆栈空间的大小和起始位置
start,STM #STACK+10,SP; 设置堆栈指针初始指向的栈底位置
LD #d_x,DP ; 设置数据存储器页指针的起始位置
ST #6487h,d_x ;将 θ值送入地址为 d_x的单元中
CALL sin_start ;调用计算正弦值的子程序
end,B end ;循环等待
sin_start:
.def sin_start ;定义标号 sin_start的起始位置
d_coeff,usect,coeff”,4 ;定义 4个单元的未初始化段 coeff
61
.data
table,.word 01c7h ; 在程序空间定义 4个系数,c1=1/( 8*9)
.word 030bh ; c2=1/( 6*7)
.word 0666h ; c3=1/( 4*5)
.word 1556h ; c4=1/( 2*3)
d_x,usect,sin_vars”,1 ; 在自定义的未初始化段 sin_vars中
d_squr_x,usect,sin_vars”,1 ; 保留 5个单元的的空间,它们通常
d_temp,usect,sin_vars”,1 ; 被安排在 RAM中,用于暂存变量
d_sinx,usect,sin_vars”,1
c_1,usect,sin_vars”,1
.text ;完成正弦计算的可执行代码段
SSBX FRCT ; 设置进行小数乘法,以便自动左移一位
STM #d_coeff,AR5;将 4个系数的首地址 d_coeff送 AR5
62
RPT #3 ; 重复执行下一指令 4次,以便将程序空
MVPD #table,*AR5+ ;间的 4个系数传送到数据空间 d_coeff
STM #d_coeff,AR3 ;将系数所在空间 d_coeff首地址送 AR3
STM #d_x,AR2 ;将 θ所在地址送 AR2
STM #c_1,AR4 ;将小数的最大值 7fff地址 c_1送 AR4
ST #7FFFh,c_1 ;将 #7FFFh(即整数 1)送 c_1
SQUR *AR2+,A ; A=x2, AR2指向 d_squr_x
ST A,*AR2 ; d_squr_x=x2( A右移 16位,即存高字节)
‖ LD *AR4,B ; B=1( 7FFFh左移 16位放在 B的高字节)
MASR *AR2+,*AR3+,B,A ; A=1-x2/72,T=x2,AR2指向 d_temp,; AR3指向 c2 (凑整运算为结果加 215再对 15-0位清 0 )
MPYA A ; A=T*A=x2( 1-x2/72)
STH A,*AR2 ;( d_temp) =x2( 1-x2/72)
MASR *AR2-,*AR3+,B,A ; A=1-x2/42( 1-x2/72); T=x2( 1-x2/72)
63
MPYA *AR2+ ; B=x2( 1-x2/42( 1-x2/72))
ST B,*AR2 ;( d_temp) =x2( 1-x2/42( 1-x2/72))
‖ LD *AR4,B ; B=1
MASR *AR2-,*AR3+,B,A ; A=1-x2/20( 1-x2/42( 1-x2/72))
MPYA *AR2+ ; B=x2( 1-x2/20( 1-x2/42( 1-x2/72)))
ST B,*AR2 ; ( d_temp) =B=x2( 1-x2/20( 1-x2/42( 1-x2/72)))
‖ LD *AR4,B ; B=1
MASR *AR2-,*AR3+,B,A; A=1-x2/6( 1-x2/20( 1-x2/42( 1-x2/72)))
MPYA d_x ; B=x( 1-x2/6( 1-x2/20( 1-x2/42( 1-x2/72))))
STH B,d_sinx ; sin( theta)
RET
.end
64
2,用 z变换计算余弦值
下面采用 z变换和反 z变换来求 cos( x ),
其的方法为:
根据 z变换定义, 序列 x(n) 的变换公式为:
反 z变换为 x(n)=£-1[X(z)]可用留数法, 部分分式
展开法和长除法求得 。
则 cos(ω0n)u(n)的 z变换为:
H( z) =£[cos(n)u(n)]= £[ejω0n+e-jω0nu(n)]21
65
其中 C= -cosω0,A=2cosω0T,B=-1。 ω0为余
弦输出信号的频率, T为离散余弦序列的采样频
率 。
如果以该函数设计一离散时间系统, 为则其单
位冲击响应就是余弦输出信号 。 此时的输出序列
Y( k) 为 H( z) 的反 z变换 。
66
Y( k) =£-1[H( z) ]=AY[k-1]+BY[k-2]+X[k]+CX[k-1]
当 k=-1时 Y( k) =Y( -1) =AY[-2]+BY[-3]+X[-1]+CX[-2]=0
当 k=0时 Y( k) =Y( 0) =AY[-1]+BY[-2]+X[0]+CX[-1]=0+0+1+0=1
当 k=1时 Y( k) =Y( 1) =AY[0]+BY[-1]+X[1]+CX[0]=1+0+0+C=A+C
当 k=2时 Y( k) =Y( 2) =AY[1]+BY[0]+X[2]+CX[1]=AY[1]+BY[0]
当 k=3时 Y( k) =Y( 3) =AY[2]+BY[1]+X[3]+CX[2]=AY[2]+BY[1]
当 k=n时 Y( k) =Y( n) =AY[n-1]+BY[n-2]
在 k> 2以后, Y( k) 能用 Y[k-1]和 Y[k-2]算出, 这是一个
递归的差分方程 。 如果按第七章实验二的方式产生余弦信号,
对应的初始化程序为:
初始化 y[1]和 y[2]:
SSBX FRCT ;置 FRCT=1,准备进行小数乘法运算
ST #INIT_A,AA ;将常数 A装入变量 AA
ST #INIT_B,BB ;将常数 B装入变量 BB
ST #INIT_C,CC ;将常数 C装入变量 CC
67
PSHD CC ;将变量 CC压入堆栈
POPD Y2 ;初始化 Y2=CC
LD AA,A ;装 AA到 A累加器
ADD CC,A ; A累加器 =AA+CC
STH A,Y2 ; Y2=Y[1]=AA+CC
LD AA,T ;装 AA到 T寄存器
MPY Y2,A ; Y2乘系数 A,结果 Y[1]*AA放入 A累加器
ADD BB,A ; A累加器 =Y[2]=Y[1]*AA+BB*Y[0]
STH A,Y1 ;将 A累加器中 Y[2]的高 16位存入变量 Y1=Y[2]
68
以后的递推过程由中断服务程序完成 Y[3]到 Y[n]运算, 相应
的程序片段为:
LD BB,T ;将系数 B装入 T寄存器
MPY Y2,A ; Y2乘系数 B,结果 BB*Y[1]放入 A累加器
LTD Y1 ; 将 Y1=Y[2]装入 T,同时复制到 Y2,Y[2]退化为 Y[1]
MAC AA,A ;完成新余弦数据的计算, A累加器中为; Y1*AA+Y2*BB或 Y[3]= AA*Y[2]+BB*Y[1]
STH A,1,Y1 ;将新数据存入 Y1,因所有系数都除过 2,;所以在保存结果时左移一位, 恢复数据正常大小 。
STH A,1,Y0 ;将新正弦数据存入 Y0
69
第四节 用 DSP实现 FIR滤波器
1,FIR滤波器基本概念
1,FIR滤波器没有
反馈回路,因此它
是无条件稳定系统,
其单位冲激响应 h
( n)是一个有限
长序列。
2,FIR滤波算法实
际上是一种乘法累
加运算。


70
2,FIR滤波器中 z-1的实现
对于 N级的 FIR滤波器, 在数据存储器中
开辟一个称之为滑窗的 N个单元的缓冲
区, 存放最新的 N个输入样本;从最老
的样本开始, 每读一个样本后, 将此样
本向下移位, 读完最后一个样本后, 输
入最新样本至缓冲区的顶部 。
用线性缓冲区实现 z-1的优点是, 新老数
据在存储器中存放的位置直接明了 。


(1)用线性缓冲区法实现 z-1
71
C54x片内没有 I/O资源, CPU通过外部译码可以
寻址 64K的 I/O单元 。
有两条实现输入和输出的指令:
PORTR PA,Smem ;将为 PA的端口内容送;数据存储器 Smem
PORTW Smem,PA ;将地址为 Smem的数据;存储器内容送端口 PA
数据的输入 /输出
72N=6的线性缓冲区存储器图
?
?
??
5
0i
i )in(xa)n(y
73
使用存储器延时指令 DELAY,可以将数据存储单元
中的内容向较高地址的下一单元传送 。
实现 z-1的运算指令为:
DELAY Smem ; ( Smem) → Seme+1,即数据存储;器单元的内容送下一高地址单元
DELAY *AR2 ; AR2指向源地址, 即将 AR2所指单;元内容复制到下一高地址单元中
存储器的延时操作
延时指令与其它指令 的 结合
LT+DELAY→LTD 指令 ;单数据存储器的值装入; T寄存器并送下一单元延时
MAC+DELAY→MACD 指令 ;操作数与程序存储器值相乘;后累加并送下一单元延时
74
在数据存储器中开辟一个称之为滑窗的 N个单元
的缓冲区, 滑窗中存放最新的 N个输入样本;每
次输入新样本时, 以新样本改写滑窗中的最老的
数据, 而滑窗中的其它数据不作移动;利用片内
BK( 循环缓冲区长度 ) 寄存器对滑窗进行间接寻
址, 循环缓冲区地址首尾相邻 。
利用循环缓冲区实现 Z-1的优点是不需要移动数据,
不存在一个机器周期中要求能一次读和一次写的
数据存储器, 因而可以将循环缓冲区定位在数据
存储器的任何位置 ( 线性缓冲区要求定位在
DARAM) 。


( 2)用循环缓冲区法实现 z-1
75N=6的循环缓冲区存储器图
?
?
??
5
0i
i )in(xa)n(y
76
3,FIR滤波器的实现方法
例 5-25 编写 N=5,y( n)
=a0*x( n) +a1*x( n-1)
+a2*x( n-2) +a3*x( n-3)
+a4*x( n-4) 的计算程序 。
先将系数 a0~ a4存放在数
据存储器中, 然后设置线
性缓冲区, 用以存放输入
和输出数据 。
(1)用线性缓冲区和直接寻址方法实现 FIR
线性缓冲区安排
77
.title,FIR1.ASM” ;定义源程序名
.mmregs ;定义存储器映象寄存器
.def start ;定义语句标号 start
.bss y,1 ;为结果 y预留 1个单元的空间
XN,usect,XN”,1 ;在自定义的未初始化段, XN”
XNM1,usect,XN”,1 ;中保留 5个单元的空间
XNM2,usect,XN”,1
XNM3,usect,XN”,1
XNM4,usect,XN”,1
A0,usect,A0”,1 ;在自定义的未初始化段, A0”
A1,usect,A0”,1 ;中保留 5个单元的空间
A2,usect,A0”,1
A3,usect,A0”,1
A4,usect,A0”,1
PA0,set 0 ;定义 PA0为输出端口
PA1,set 1 ;定义 PA1为输入端口
78
.data
table,.word 1*32768/10 ;假定程序空间有五个参数
.word -3*32768/10
.word 5*32768/10
.word -3*32768/10
.word 1*32768/10
.text
start,.SSBX FRCT ;设置进行小数相乘
STM #A0,AR1 ; 将数据空间用于放参数的首地址送 AR1
RPT #4 ;重复下条指令 5次传送
MVPD table,*AR1+ ;传送程序空间的参数到数据空间
LD #XN,DP ;设置数据存储器页指针的起始位置
PORTR PA1,@XN ; 从数据输入端口 I/O输入最新数据 x( n)
FIR1,LD @XNM4,T ; x( n-4) → T
79
MPY @A4,A ; a4*x( n-4) → A
LTD @XNM3 ; x( n-3) → T,x( n-3) → x( n-4)
MAC @A3,A ; A+a3*x( n-3) → A
LTD @XNM2 ; x( n-2) → T,x( n-2) → x( n-3)
MAC @A2,A ; A+a2*x( n-2) → A
LTD @XNM1 ; x( n-1) → T,x( n-1) → x( n-2)
MAC @A1,A ; A+a1*x( n-1) → A
LTD @XN ; x( n) → T,x( n) → x( n-1)
MAC @A0,A ; A+a0*x( n) → A
STH A,@y ;保存 y( n) 的高字节
PORTW @y,PA0 ;输出 y( n)
BD FIR1 ;执行完下条指令后循环
PORTR PA1,@XN ;输入 x( n)
.end
80
vectors.obj
fir1.obj
-o fir1.out
-m fir1.map
-e start
MEMORY {
PAGE 0, EPROM,org=01OOOH len=01000H
VECS,org=03F80H len=00080H
PAGE 1, SPRAM,org=00060H len=00020H
DARAM,org=00080H len=01380H }
SECTIONS {
.vectors:> VECS PAGE 0
.text:> EPROM PAGE 0
.data:> EPROM PAGE 0
.bss:> SPRAM PAGE 1
.XN:> DARAM align(8){ } PAGE 1
.A0:> DARAM align(8){ } PAGE
1 }
81
(2)用线性缓冲区和间接寻址方法实现 FIR
例 5-26 编写 y( n) =a0*x( n) + a1*x( n-1) + a2*x
( n-2) + a3*x( n-3) + a4*x( n-4)的计算程序,其中
N=5。
将系数 a0~ a4存放在数据存储器中,并设置线性缓
冲区存放输入数据。利用 AR1和 AR2分别作为间接寻址
线性缓冲区和系数区的辅助寄存器。
82
.title,FIR2.ASM” ;定义源程序名
.mmregs ;定义存储器映象寄存器
.def start ;定义语句标号 start
.bss y,1 ;为结果 y预留 1个单元的空间
x,usect,x”,5 ; 在自定义的未初始化段, x”中保留 5个单元的空

a,usect,a”,5 ; 在自定义的未初始化段, a”中保留 5个单元的空

PA0,set 0 ;定义 PA0为输出端口
PA1,set 1 ;定义 PA1为输入端口
.data
table,.word 2*32768/10 ;假定程序空间有五个参数
.word -3*32768/10
.word 4*32768/10
.word -3*32768/10
.word 2*32768/10
83
.text
start,STM #a,AR2 ;将数据空间用于放参数;的首地址送 AR2
RPT #4 ;重复下条指令 5次传送
MVPD table,*AR2+ ; 传送程序空间的参数到数据空间
STM #x+4,AR1 ; AR1指向 x( n-4)
STM #a+4,AR2 ; AR2指向 a4
STM #4,AR0 ;指针复位值 4→AR 0
SSBX FRCT ;小数相乘
LD #x,DP ;设置数据存储器页指针;的起始位置
PORTR PA1,@x ; 从端口 PA1输入最新值 x( n)
84
FIR2,LD *AR1-,T ; x( n-4) → T
MPY *AR2-,A ; a4*x( n-4) → A
LTD *AR1- ; x( n-3) → T,x( n-3) → x( n-4)
MAC *AR2-,A ; A+a3*x( n-3) → A
LTD *AR1- ; x( n-2) → T,x( n-2) → x( n-3)
MAC *AR2-,A ; A+a2*x( n-2) → A
LTD *AR1- ; x( n-1) → T,x( n-1) → x( n-2)
MAC *AR2-,A ; A+a1*x( n-1) → A
LTD *AR1 ; x( n) → T,x( n) → x( n-1)
MAC *AR2+0,A ; A+a0*x( n) → A,AR2复原, 指向 a4
STH A,@y ;保存运算结果的高位字到 y( n)
PORTW @y( n),PA0 ;将结果 y( n) 输出到端口 PA0
BD FIR2 ;执行完下条指令后, 从 FIR2开始循环
PORTR PA1,*AR1+0;输入新值 x( n),AR1复原指向 x+4
.end
85
(3) 用线性缓冲区和带移位双
操作数寻址方法实现 FIR
例 5-27 编写 y( n) =a0*x( n) + a1*x( n-1) + a2*x( n-2) +
a3*x( n-3) + a4*x( n-4)的计算程序,其中 N=5。
与前面的编程不同,本例中,系数 a0~ a4存放在程
序存储器中,输入数据存放在数据存储器的线性缓冲
区中。乘法累加利用 MACD指令,该指令完成数据存储
器单元与程序存储器单元相乘,并累加、移位的功能。
86
.title,FIR3.ASM” ;定义源程序名
.mmregs ;定义存储器映象寄存器
.def start ;定义语句标号 start
.bss y,1 ;为结果 y预留 1个单元的空间
x,usect,x”,6 ;在自定义的未初始化;段, x”中保留 6个单元 PA0
.set 0 ;定义 PA0为输出端口
PA1,set 1 ;定义 PA1为输入端口
.data
COEF,.word 1*32768/10 ;假定程序空间有五个参数,a4
.word -4*32768/10 ; a3
.word 3*32768/10 ; a2
.word -4*32768/10 ; a1
.word 1*32768/10 ; a0
87
.text
start,SSBX FRCT ;小数乘法
STM #x+5,AR1 ; AR1指向 x( n-4)
STM #4,AR0 ;设置 AR1复位值
LD #x+1,DP ; 设置数据存储器页指针的起始位置
PORTR PA1,@x+1 ;输入最新值 x( n)
FIR3,RPTZ A,#4 ; 累加器 A清 0,设置重复下条指令 5次
MACD *AR1-,COEF,A ; x( n-4) → T,A= x( n-4) *a4 +A; ( PAR) +1→PAR,x ( n-4) → x( n-5)
STH A,*AR1 ;暂存结果到 y( n)
PORTW *AR1+,PA0; 输出 y( n) 到 PA0,AR1指向 x( n)
BD FIR3 ;执行下条指令后循环
PORTR PA1,*AR1+0; 输入新数据到 x( n),AR1指向 x( n-4)
88
(4) 用循环缓冲区和双操
作数寻址方法实现 FIR
例 5-28 编写 y( n) =a0*x( n) + a1*x( n-1) + a2*x( n-2) +
a3*x( n-3) + a4*x( n-4)的计算程序,其中 N=5。
本例中,存放 a0~ a4的系数表以及存
放数据的循环缓冲区均设在 DARAM中。
89
.title,FIR4.ASM” ;给汇编程序取名
.mmregs ;定义存储器映象寄存器
.def start ;定义标号 start的起始位置
.bss y,1 ;为未初始化变量 y保留空间
xn,usect,xn”,5 ;自定义 5个单元空间的数据段 xn
a0,usect,a0”,5 ;自定义 5个单元空间的数据段 a0
PA0,set 0 ;设置数据输出端口 I/O,PA0=0
PA1,set 1 ;设置数据输入端口 I/O,PA1=1
.data
table,.word 1*32768/10 ; a0=0.1=0x0CCC
.word 2*32768/10 ; a1=0.2=0x1999
.word 3*32768/10 ; a2=0.3=0x2666
.word 4*32768/10 ; a3=0.4=0x3333
.word 5*32768/10 ; a4=0.5=0x4000
.text
90
start,SSBX FRCT ;小数乘法
STM #a0,AR1 ; AR1指向 a0
RPT #4 ;从程序存储器 table开始的地址传送
MVPD table,*AR1+ ; 5个系数至数据空间 a0开始的数据段
STM #xn+4,AR3 ; AR3指向 x( n-4)
STM #a0+4,AR4 ; AR4指向 a4
STM #5,BK ;设循环缓冲区长度 BK=5
STM #-1,AR0 ; AR0=-1,双操作数减量
LD #xn,DP ; 设置数据存储器页指针的起始位置
PORTR PA1,@xn ;输入新数据到 x( n)
FIR4,RPTZ A,#4 ; A清 0,重复执行下条指令 5次
MAC *AR3+0%,*AR4+0%,A ;系数与输入数据双;操作数相乘并累加
STH A,@y ;保存结果的高字节到 y( n)
PORTW @y,PA0 ;输出 y( n) 到端口 PA0
BD FIR4 ;执行完下条指令后循环
PORTR PA1,*AR3+0% ; 从端口 PA1输入新数据到 x( n)
.end
91
4.系数对称 FIR滤波器设计
系数对称的 FIR滤波器具有线性相位特性, 这种滤
波器是用得最多的 FIR滤波器, 特别是对相位失真要
求很高的场合 。
如果 FIR滤波器的 h( n) 是实数, 且满足偶对称 h
( n) =h( N-1-n) 或奇对称 h( n) =-h( N-1-n) 的条
件, 则滤波器具有线性相位特性 。
?
??
?
??????
12/
0i
i )]i1Nn(x)in(x[h)n(y
一个对称 FIR滤波器满足 h( n) =h( N-1-n)。
92
例如, N=8的 FIR滤波器, 其输出方程为:
y( n) =h0x( n) +h1x( n-1) +h2x( n-2) +h3x( n-3
) +h3x( n-4) +h2x( n-5) +h1x( n-6) +h0x( n-7)
总共有 8次乘法和 7次加法 。 如果利用对称性, 可将
其改写成:
y( n) =h0[x( n) +x( n-7) ]+h1[x( n-1) +x( n-6
) ]+h2[x( n-2) +x( n-5) ]+h3[x( n-3) +x( n-4) ]
变成 4次乘法和 7次加法。可见乘法运算的次数少了
一半。这是对称 FIR的以一个优点。
93
对称 FIR滤波器的实现可按如下步骤进行:
(1) 将数据存储器分为新旧两个循环缓冲区,
New循环缓冲区中存放 N/2=4个新数据; Old循环缓
冲区中存放 N/2=4个老数据 。 每个循环缓冲区的长
度为 N/2。
94
(2) 设置循环缓冲区指针, 以 AR2指向 New循环缓冲
区中最新的数据;以 AR3指向 Old循环缓冲区中最老的
数据 。
(3) 在程序存储器中设置系数表 。
(4)( AR2) +( AR3) → AH( 累加器 A的高位 ), AR2-
1→AR 2,AR3-1→AR 3。
(5) 将累加器 B清 0,重复执行 4次 ( i=0,1,2,3)
下面的运算:
( AH) *系数 hi+( B) → B,系数指针 ( PAR) 加 1,
( AR2) +( AR3) → AH,AR2和 AR3减1 。
95
(6) 保存和输出结果 ( 结果在 BH中 ) 。
(7) 修正数据指针, 让 AR2和 AR3分别指向 New循环缓
冲区最新的数据和 Old循环缓冲区中最老的数据 。
(8) 用 New循环缓冲区中最老的数据替代 Old循环缓
冲区中最老的数据 。 Old循环缓冲区指针减 1。
(9) 输入一个新数据替代 New循环缓冲区中最老的数
据 。
重复执行 (4)~ (9)步 。
96
在编程中要用到系数对称有限冲激响应滤波器指令
FIRS,其操作为:
FIRS Xmem,Ymem,Pmad
该指令执行 Pmad→PAR ( 程序存储器地址寄存器 )
当 ( RC) ≠ 0
( B) +( A( 32~ 16)) × ( 由 PAR寻址 Pmem) → B
(( Xmem) +( Ymem)) <<16→A
( PAR) +1→PAR
( RC) -1→RC
FIRS指令在同一个机器周期内, 通过 C和 D总线读 2次
数据存储器, 同时通过 P总线读一个系数 。
97
例 5-29 设计对称 FIR滤波器 ( N=8) 。
.title,FIR5.ASM” ;给汇编程序取名
.mmregs ;定义存储器映象寄存器
.def start ;定义标号 start的起始位置
.bss y,1 ;为未初始化变量 y保留空间
x_new,usect,DATA1”,4 ;自定义 4个单元的未初始化段 DTAT1
x_old,usect,DATA2”,4 ; 自定义 4个单元的未初始化段
DATA2
Size,set 4 ;定义符号 size=4
PA0,set 0 ;设置数据输出端口 I/O,PA0=0
PA1,set 1 ;设置数据输入端口 I/O,PA1=1
.data
COEF,word 1*32768/10,2*32768/10; 系数对称,只需
.word 3*32768/10,4*32768/10 ; 给出 N/2=4个系数
98
.text
start,LD #y,DP ; 设置数据存储器页指针的起始位置
SSBX FRCT ;小数乘法
STM #x_new,AR2 ; AR2指向新缓冲区第 1个单元
STM #x_old+( size-1),AR3 ; AR3指向老缓;冲区最后 1个单元
STM #size,BK ; 设置循环缓冲区长度 BK =size
STM #-1,AR0 ;循环控制增量 AR0=-1
PORTR PA1,#x_new ;从 I/O输入端口 PA1;输入数据到 x( n)
99
FIR5,ADD *AR2+0%,*AR3+0%,A ; AH=x( n) +; x( n-7) ( 第一次 )
RPTZ B,#( size-1) ; B=0,下条指令执行 size次
FIRS *AR2+0%,*AR3+0%,COEF ; B+=AH*h0,; AH=x( n-1) +x( n-6) …
STH B,@y ;保存结果到 y
PORTW @y,PA0 ;输出结果到 PA0
MAR *+AR2( 2) % ;修正 AR2,指向新缓; 冲区最老的数据
MAR *AR3+% ;修正 AR3,指向老缓;冲区最老的数据
MVDD *AR2,*AR3+0% 新缓冲区向老缓;冲区传送一个数
BD FIR5 ;执行完下条指令后转移 FIR5并循环
PORTR PA1,*AR2 ;输入新数据至新缓冲区
.end
100
第五节 用 DSP实现 IIR滤波器
1,IIR滤波器的基本概念
101
特 点
y( n) 由两部分构成:第一部分 是
一个对 x( n) 的 M节延时链结构, 每节延时抽
头后加权相加, 是一个横向结构网络;第二部
分 也是一个 N
节延时链的横向结构网络, 不过它是对 y( n)
的延时, 因此是个反馈网络 。
若 ai=0,IIR滤波器就变为 FIR滤波器, 其脉
冲传输函数只有零点, 系统总是稳定的, 其单
位冲激响应是有限长序列 。 而 IIR滤波器的脉
冲传递在 Z平面上有极点存在, 其单位冲激响
应是无限长序列 。
?
?
?M
0i
i )in(xb
?
?
?
N
1i
i )in(ya
102
特 点
IIR滤波器与 FIR滤波器的一个重要区别是, IIR滤波
器可以用较少的阶数获得很高的选择特性, 所用的存
储单元少, 运算次数少, 具有经济, 高效的特点 。 但
是, 在有限精度的运算中, 可能出现不稳定现象 。 而
且, 选择性越好, 相位的非线性越严重, 不像 FIR滤
波器可以得到严格的线性相位 。 因此, 在相位要求不
敏感的场合, 如语言通信等, 选用 IIR滤波器较为合
适;而对于图像信号处理, 数据传输等以波形携带信
息的系统, 对线性相位要求较高, 在条件许可的情况
下, 采用系数对称 FIR滤波器较好 。
103
2,二阶 IIR滤波器的实现方法
3个二阶节级联的六阶 IIR滤波器
对于一个高阶的 IIR滤波器,由于总可化成多个二
阶基本节(或称二阶节)相级联或并联的形式
104
二阶节的标准形式由反馈通道和前向通道的差分
方程构成:
反馈通道,x0=w( n) =x( n) +A1*x1+A2*x2
前向通道,y( n) =B0*x0+B1*x1+B2*x2
二阶节 IIR滤波器
105
( 1)二阶 IIR滤波器的单操作数指令实现法
如存储器分配图 所
示。 x0单元有三个用
处:存放输入数据 x
( n)、暂时存放相
加器的输出 x0和输出
数据 y( n)。
例 5-30 编写二阶
IIR滤波器的程序。
存储器分配图
106
.title,IIR1.ASM” ;给汇编程序取名
.mmregs ;定义存储器映象寄存器
.def start ;定义标号 start的起始位置
X0,usect,x”,1 ;自定义 3个单元的未初始化段 x
X1,usect,x”,1 ;
X2,usect,x”,1 ;
B2,usect,COEF”,1 ;自定义 5个单元的未初始化段
COEF
B1,usect,COEF”,1 ;
B0,usect,COEF”,1 ;
A2,usect,COEF”,1 ;
A1,usect,COEF”,1 ;
PA0,set 0 ;设置数据输出端口 I/O,PA0=0
PA1,set 1 ;设置数据输入端口 I/O,PA1=1
.data
table,.word 0,0 ; x(n-1),x(n-2)
.word 1*32768/10,2*32768/10,3*32768/10 ; B2,B1,B0
.word 5*32768/10,-4*32768/10 ; A2,A1
107
.text
start,LD #x0,DP ;以 x0的地址为数据存储器;页指针起始位置
SSBX FRCT ;小数乘法
STM #x1,AR1 ; x1首地址传给 AR1
RPT #1 ;重复 2次下条指令
MVPD #table,*AR1+ ;用程序空间的 2个;系数 0对 x1,x2单元清零
STM #B2,AR1 ; B2首地址传给 AR1
RPT #4 ;重复 5次下条指令
MVPD #table+2,*AR1+ ;用 5个系数对; B2,B1,B0,A2,A1单元赋值
108
IIR1,PORTR PA1,@x0 ;从 PA1输入数据到 x( n)
LD @x0,16,A ;计算反馈通道,x0送 A的 16位高端字
LD @x1,T ; x1送 T寄存器
MAC @A1,A ; x0+x1*A1→A
LD @x2,T ; x2送 T寄存器
MAC @A2,A ; x0+x1*A1+x2*A2→A
STH A,@x0 ;暂存 x0+x1*A1+x2*A2→x0 单元
MPY @B2,A ;计算前向通道,x2*B2→A
LTD @x1 ; x1送 T寄存器,x1移至 x2单元
MAC @B1,A ; x2*B2+x1*B1→A
LTD @x0 ; x0送 T寄存器,x0移至 x1单元
MAC @B0,A ; x2*B2+x1*B1+x0*B0→A
STH A,@x0 ; 暂存 y( n) =x2*B2+x1*B1+x0*B0→x0 单元
BD IIR1 ;执行完下条指令后循环
PORTW @x0,PA0 ;给出结果 y( n)到 PA0端口
.end
109
( 2)二阶 IIR滤波器的双操作数指令实现
特点是,乘法累加运算利用双操作数指令,数
据和系数表在数据存储器( DARAM),其存储器分
配图如图
110
例 5-31 用双操作数指令实现二阶 IIR滤波器 。
H(z)=
.title,IIR2.ASM” ;给汇编程序取名
.mmregs ;定义存储器映象寄存器
.def start ;定义标号 start的起始位置
x2,usect,x”,1 ;自定义 3个单元的未初始化段 x
X1,usect,x”,1 ;
X0,usect,x”,1 ;
COEF,usect,COEF”,5 ; 自定义 5个单元的未初始化段 COEF
PA0,set 0 ;设置数据输出端口 I/O,PA0=0
PA1,set 1 ;设置数据输入端口 I/O,PA1=1
21
21
z4 1 4 2.0z4 1 4 2.11
)zz21(0 6 7 6.0
??
??
??
??
111
.data
table,.word 0,0 ; x(n-2),x(n-1)
.word 676*32768/10000,1352*32768/10000; B2,B1
.word 676*32768/10000 ; B0
.word -4174*32768/10000,707*32768/10000 ; A2,A1/2
.text
start,SSBX FRCT ;小数乘法
STM #x2,AR1 ; x2首地址传给 AR1
RPT #1 ;重复 2次下条指令
MVPD #table,*AR1+ ; 用程序空间的 2个系数 0对 x2,x1单元清零
STM #COEF,AR1 ; COEF 首地址传给 AR1
RPT #4 ;重复 5次下条指令
MVPD #table+2,*AR1+ ;将 5个系数传到 COEF单元
STM #x2,AR3 ; x2首地址传给 AR3
STM #COEF+4,AR4 ; COEF中的 A1地址传给 AR4
MVMM AR4,AR1 ;保存 AR4地址值在 AR1中
STM #3,BK ;设置循环缓冲区长度
STM #-1,AR0 ;设置间接寻址步长
112
IIR2,PORTR PA1,*AR3 ;从 PA1口输入数据到 x( n)
LD *AR3+0%,16,A ;计算反馈通道, A=x( n)
MAC *AR3,*AR4,A ; A=x( n) +A1*x1
MAC *AR3+0%,*AR4-,A ; A=x( n) +A1*x1+A1*x1
MAC *AR3+0%,*AR4-,A ; A=x( n) +; 2*A1*x1+A2*x2=x0
STH A,*AR3 ;保存 x0
MPY *AR3+0%,*AR4-,A ;计算前向通道 。 A=B0*x0
MAC *AR3+0%,*AR4-,A ; A=B0*x0+B1*x1
MAC *AR3,*AR4-,A ; A=B0*x0+B1*x1+B2*x2=y( n)
STH A,*AR3 ;保存 y( n)
MVMM AR1,AR4 ; AR4重新指向 A1
BD IIR2 ;执行完下条指令后循环
PORTW *AR3,PA0 ;向 PA0口输出数据
.end
113
( 3)直接形式二阶 IIR滤波器的实现法
直接形式二阶 IIR滤波器,在迭代运算中对信号
先衰减后增益,系统的动态范围和鲁棒性较好。
IIR差分方程为:
y( n) =B0*x( n) +B1*x( n-1) +B2*x( n-2)
+A1*y( n-1) +A2*y( n-2)
2
2
1
1
2
2
1
10
zA+zA1
zB+zB+BH(z)=
IIR的脉冲传递函数为:
114
编程时, 将变量和系数都存放在 DARAM中, 并采用循
环缓冲区方式寻址, 共需开辟 4个循环缓冲区, 用来
存放变量和系数 。 这 4个循环缓冲区的结构如图所示:
115
例 5-32 编写直接形式二阶 IIR滤波器的源程序 。
.title,IIR3.asm” ;给汇编程序取名
.mmregs ;说明存储器映象寄存器
def start ;定义标号 start的起始位置
X,usect,X”,3 ;自定义 3个单元的未初始化段 X
Y,usect,Y”,3 ;自定义 3个单元的未初始化段 Y
B,usect,B”,3 ;自定义 3个单元的未初始化段 B
A,usect,A”,3 ;自定义 3个单元的未初始化段 A
PA0,set 0 ;设置数据输出端口 I/O,PA0=0
PA1,set 1 ;设置数据输入端口 I/O,PA1=1
.data
table,.word 0,0 ;为 x( n-2), x( n-1) 预留一单元空间
.word 0,0 ;为 y( n-2), y( n-1) 预留一单元空间
.word 1*32768/10,2*32768/10,3*32768/10;放置系数 B2,B1,B0
.word 5*32768/10,-4*32768/10 ;放置系数 A2,A1
116
.text
start,SSBX FRCT ;指明进行小数乘法
STM #x,AR1 ;传送初始数据 x( n-2), x( n-1)
RPT #1 ;重复二次下条指令
MVPD #table,*AR1+ ; x( n-2) =0,x( n-1) =0
STM #Y,AR1 ;传送初始数据 y( n-2), y( n-1)
RPT #1 ;重复二次下条指令
MVPD #table+2,*AR1+ ; y( n-2) =0,y( n-1) =0
STM #B,AR1 ;传送系数 B2,B1,B0
RPT #2 ;重复三次下条指令
MVPD #table+4,*AR1+; 系数 B从程序存储器传到数据存储器
STM #A,AR1 ;传送系数 A2,A1
RPT #1 ;重复二次下条指令
MVPD #table+7,*AR1+;将系数 A从程序存储器传到数据存储器
117
STM #X+2,AR2 ;辅助寄存器指针初始化,AR2指向 x( n)
STM #A+1,AR3 ;辅助寄存器指针初始化,AR3指向 A1
STM #Y+1,AR4 ;辅助寄存器指针初始化,AR4指向 y( n-1)
STM #B+2,AR5 ;辅助寄存器指针初始化,AR5指向 B0
STM #3,BK ;设置循环缓冲区长度,( BK) =3
STM #-1,AR0 ;设置间接寻址步长,( AR0) =-1
118
IIR3,PORTR PA1,*AR2 ;从 PA1口输入数据到 x( n)
MPY *AR2+0%,*AR5+0%,A ; 计算前向通道,A=x( n) *B0
MAC *AR2+0%,*AR5+0%,A ; A=x( n) *B0+x( n-1) *B1
MAC *AR2,*AR5+0%,A; A=x( n) *B0+x( n-1) *B1+x( n-2) *B2
MAC *AR4+0%,*AR3+0%,A ; 计算反馈通道,A=A+y( n-1) *A1
MAC *AR4+0%,*AR3+0%,A ; A=A+y( n-2) *A2
MAR *AR3+0% ; AR3指向 A1
STH A,*AR4 ;保存 y( n)
BD IIR3 ;执行完下条指令后循环
PORTW *AR4,PA0 ;输出 y( n)到 I/O端口 PA0
.end
119
3,高阶 IIR滤波器的实现
一个高阶 IIR滤波器可以分解成若干个二阶基本节
相级联 。
由于调整每个二阶基本节的系数, 只涉及到这个二
阶节的一对极点和零点, 不影响其他零, 极点, 因
此便于调整系统的性能 。
此外, 由于字长有限, 每个二阶基本节运算后都会
带来一定的误差, 合理安排各二阶基本节的前后次
序, 将使系统的精度得到优化 。
120
对高 阶 IIR滤波器的 几点特殊处理
当出现一个或一个以上系数 ≥ 1 。 此时, 既可
以用最大的系数来定标, 即用最大的系数去除所
有的系数, 也可以将此 ≥ 1的系数分解成两个<
1的系数进行运算和相加, 例如 B0=1.2,则:
x( n) *B0=x( n) *( B0/2) +x( n) *( B0/2)
=0.6*x( n) +0.6*x( n)
这样, 将使所有的系数保持精度, 而仅仅多开
销一个机器周期 。 前面的例 5-31中的系数 A1为是
这样处理的 。
( 1)系数 ≥ 1时的定标方法
121
( 2)对输入数据定标
一般地, 从外设口输入一个数据加载到累加器 A,
可用以下指令:
PORTR 0001h,@Xin
LD @Xin,16,A
如果运算过程中可能出现 ≥ 1的输出值, 可在输入
数据时将其缩小若干倍, 如:
PORTR 0001h,@Xin
LD @Xin,16-3,A
将输入数据除以 8,将使输出值小于1 。 上面用多
种不同的方法进行了滤波器的设计, 在实现滤波器
功能的前提下, 程序的繁简和对存储器的使用情况
是不同的, 应用中应根据具体情况进行选择 。
122