|
本帖最后由 gujiamao 于 2015-5-3 10:41 编辑 & k, w, n9 ~& W- Y& ?) C \ 最近要用到正弦波,就用STM32内部的DAC产生。' R$ p0 d3 M! B+ b" k0 \ 思路主要有以下三个:8 E: ?5 z: u! j O 1.用matlab或者excel产生一个N长度的正弦码表,如果要产生频率为f的正弦波,则每隔fclk / (N * f)个定时器中断给DAC的数据寄存器赋值一次(fclk是定时器中断频率);# m2 j: X, g M9 g: G* L2 U 2.根据定时器频率fclk和信号频率f计算出一个周期内点的个数N = fclk / f,动态生成正弦码表,则每个定时器中断给DAC的数据寄存器赋值一次;1 R9 [$ f+ l6 Z* ^% r+ A 先总结下,思路1和思路2的方法差不多,在频率的范围上,f = fclk / (N * M)(M是多少个中断赋值DAC),思路2的M为1,频率范围应该更大些; 在波形的美观上,思路1更好些,因为频率大的时候,2中的点数会少,导致波形中高频能量比较大; 但是,都是时钟的分频,比如说fclk / 8, fclk / 16,两者之间的频率是肯定产生不了的。 以上的方法都不尽如人意。5 ?4 @% a7 l% } 想到在学校里参加电子设计比赛时,用过AD9850产生过正弦波,为何不用DDS的原理实现呢?5 h% t3 [8 Y5 b8 V; r 1.高速dac; 2.正弦码表;3.相位累加器;4.低通滤波器,STM32都有,试一试呗。. v5 }6 d6 l; I4 g6 k+ B- k, h% D% K7 j ) _: c) w" S/ N, s 3.DDS的方法:以下是个人的理解,不知道对不对。sin(ΔΦ) = sin(w*t) = sin(2*pi*f*Ts),其中f是要得的信号频率,Ts = 1 / fclk, fclk是定时器中断频率,相位Φ就是ΔΦ的不断累积。 程序里是这么做的,当串口输入f时,计算出delta_phase_temp = 2.0 * f / fclk,显然这是一个浮点数,总不能在中断内部计算浮点数吧,听同事说有一个Q15的数据格式,将浮点数 转化成short类型的方法,网上查了下,发现STM32的DSP库里有这样的东西,能够快速计算出某相位的正弦值(下面会介绍),接下来把delta_phase_temp 转换成Q15格式, delta_phase = float_to_Q15(delta_phase_temp),这样基本工作就OK了,接下来打开定时器中断,写中断服务程序,主要就是相位累加和计算出给DAC赋值的数字量,: k+ k! R2 p* S3 M0 t" m8 y; ~ o- d phase += delta_phase,相位累加够简单吧,给DAC赋值的数字量就是此相位对应的正弦值啦,这就用到了CMSIS的DSP库里面的东东了,第一次接触,感慨,聪明人真的太多了,) @5 o" L% j& p2 J& w$ ]2 a Q15的格式不说了,避免浮点运算,选用查表法,自己怎么想不出来呢。' \8 D* N5 b1 O' l 下面的函数就是把Q15格式的theta算成Q15格式的正弦值,函数我就不分析了,论坛里大大们一看就懂。: Q( D3 ^4 l1 L- x' t' I; n void arm_sin_q15(q15_t theta, q15_t* pSinVal)* \* d( [9 q& H, F {% H6 U. R) N+ v* l" C q15_t x0; q15_t y0,y1;* s' }* a) G/ T/ y9 W q15_t xSpacing = 0xB6;& }( K, s) ^& p. {: I+ K7 o8 r1 F unsigned int i = 0; q15_t oneByXSpacing; q15_t out;$ R4 B4 ^" W- d1 c c unsigned int sign_bits; short firstX = 0x8000; i = (unsigned int)(theta - firstX) / (unsigned int)xSpacing;. f% |0 |( n1 z1 k8 d if(i < 0){ i = 0;$ v7 ~( O/ O) q3 Y8 d3 y4 G( a } else if(i >= 358){ i = 358;1 A1 j2 M1 e" W }3 z& E% Z% v% W" J7 O! R4 | x0 = (q15_t)firstX + ((q15_t)i * xSpacing); y0 = SinTabQ15; y1 = SinTabQ15[i + 1u];- O, \9 n" a8 S B sign_bits = 8u; oneByXSpacing = 0x5A00;( g d7 `; N. K# z out =(((q15_t) (((int) (theta - x0) * oneByXSpacing) >> 16)) << sign_bits); *pSinVal = y0 + ((q15_t) (((int) (y1 - y0) * out) >> 15)); }$ `5 {: F w0 T. x H' W 算出Q15格式的正弦值之后,当然还是转成0~1之间的浮点数啦,之后再进行DAC赋值,dac_ch2.write((int)(Q15_to_float(sin) * 4095));- b+ `! M* n) l1 j+ m# w) W/ ^ 下午看了下效果还不错,当然没有AD9850产生的波形准而好看了。等去公司了,上点图看看。 相比思路1和2,思路3的明显方法好多了。 |
| 沙发,支持原创 |
| 路过看看。。。。。。。 |
微信公众号
手机版