资源描述
课 程 设 计
信号发生器
学生姓名: 安小鹏
学 号: 131001201
学 院: 理学院
专 业: 应用物理
指导教师: 任世伟 刘天山
2016 年 06 月 28 日
信号发生器
摘要:本文以STC89C51单片机为核心设计了一个低频函数信号发生器。信号发生器采用数字波形合成技术,通过硬件电路和软件程序相结合,可输出自定义波形,如正弦波、方波、三角波、锯齿波、波形的频率和幅度在一定范围内可任意改变。波形和频率的改变通过软件控制,幅度的改变通过硬件实现。介绍了波形的生成原理、硬件电路和软件部分的设计原理。
关键词:单片机,信号发生器,D/A转换
一、设计要求
利用单片机的控制及编程能力,采用查询法设计一个函数发生器,要求能够产生方波、正弦波,分析采样点数量与频率之间的关系。
二、设计原理
向单片机输入所需要的程序并通过扩展D/A转换接口就可以方便地产生正弦信号。正弦波的产生比较特殊,它不是由单片机直接产生波形的,它只能产生连续的阶梯波来向正弦波不断地逼近。很显然,在一个周期内阶梯波的阶梯数目越多,单片机输出的波形也就越接近正弦波。如图所所示
一般而言,计算机要形成正弦波信号的最简便办法就是使用D/A转换器,因计算机可以隔一定时间向D/A转换器输出一个数字量,而输出的该数字量为相应时刻的函数值,则在D/A转换器输出端就可以得到一个相应的函数信号。D/A转换器形成的函数信号实际上是一个阶梯状波。所以用D/A转化器形成的正弦波信号除了正弦基频分量(所需要的信号)外,还包含了各种高次谐波与余弦基频分量。因而形成的正弦波信号只能是一逼近的正弦波信号。为了正弦信号的数字量逼近,可以有多种方案。而逼近一个正弦函数的精确程度是和正弦波信号的细分度N和D/A转换器的分辨率直接有关。细分度N越大产生的正弦信号就越精确,但是这要求计算机速度也相应的高;D/A转化器的分辨率越高产生的正弦信号也就越精确,但是D/A转化器的分辨率受其价格和计算速度以及字长的制约,不宜过高,应取一个合理的分辨率。故对正弦信号逼近方案的讨论,是在确定的细分度N和D/A转化器的分辨率基础上比较的。把其结果转换为十六进制,并把计算的十六进制以表格的形式存放于EPROM内存中,然后以查表的方式来形成正弦信号。采用查表的方式单片机正弦波发生器的工作原理如下:
对正弦信号进行采样,将正弦波的第一个周期的波形均分为若干等份,设正弦波一个周期采样点数共N个。则有:
①
上式中n取0,1,2,......N-1,考虑到正弦函数值的范围是从-1 0 +1,将它们转化为定点无符号数值存放,例如存放的位数(即M)是8,那么对公式①:进行数值迁移,则有:
②
这样正弦函数值范围-1-->0--> +1,因为00H~FFH对应的数字量为0~255,存放的8位(即M)二进制数据则相应为0-->128--> 255(十进制表示)。依次对公式②采样可得X(n),n=0,1,2,......N-1共N 个数据,组成了一张正弦数据表,单片机将这一个周期的数据表存入EPROM中。EPROM的地址线和地址发生器的输出端相连。地址发生器在时钟作用下依次产生选通地址,就会依次选中EPROM的0单元、1单元、2单元......N-1单元地址,再由D/A转化器输出相应幅值的模拟信号,当地址发生器输出满N个地址时,一个完整的正弦波就产生了。假设从数据表中每取一个数据,并将它从D/A转化器输出至少需要时间为,那么输出一个完整的正弦波所需要的时间为,则有= N。查表程序周而复始进行下去,便可产生连续的正弦波信号。
固定周期是由若干机器周期组成,机器周期一般又是单片机时钟周期的若干倍,则有:
一旦时钟确定,也就固定了。一个固定周期内的计数脉冲数就可以通过下式计算出来:
三、程序设计:
3.1、设计流程图:
输出锯齿波
检测有按键按下
输出三角波
检测有按键按下
打开总中断
配置定时器(T0)
默认输出正弦波
检测有按键按下
3.2程序源代码:(见附录1)
3.3产生波形图:(见附录2)
四、正弦波误差分析
4.1计数脉冲数M对正弦波的影响
固定周期是由若干机器周期组成,机器周期一般又是单片机时钟周期的若干倍,产生的正弦波周期为:
在一个周期内相对误差为:
若用16MHz时钟的单片机产生的正弦波,设其定时器输入脉冲周期是时钟脉冲的2倍时,则计算如下:
(
若要产生2300HZ的正弦波,其周期应为
(
取N=128则:
(
因为,所以M=27,则最大相对误差为:
由此可见,要减小误差,只能通过减小 ,就可以是误差接近真实值。
4.2采样点N对正弦波的影响
正弦波发生器是用N个顺序的以正弦变化的数值来驱动D/A芯片来产生正弦波的。按前面假设的来说,当每输出一点X(n),需要的最少时间为,那么输出一个完整的正弦波(即一个周期)需要的时间为,则=N。此时正弦波的最高频率为:
③
设编制的子程序。约为1s,如N取300
则Hz
即如果要求输出正弦波的频率f大于3333Hz,只能使N小于300。所以可以得出这样的结论:N越大,正弦波的精确度越高,但正弦波最高频率限也越小。
正弦波的波形精度R这一概念,R的定义式为:
④
将公式①代入公式④,可得
⑤
微机化正弦波是取出正弦波数据表中的数值,由D/A转化器输出产生阶跃状的模拟量正弦波。正弦波表格中的数据值直接影响着阶跃状正弦波的形状。波形精度R是对正弦波表格中的数据优劣的一种描述。对模拟正弦波的描述波形精度等价于失真度。
根据理想采样的原则,数据X(n)点与点之间的采样时间的间隔是恒定的,即前面的,即X(n)序列在时间上是均匀地分布在正弦波上的N个点的采样值。因为N是有限的,所以这些点不能组成光滑的正弦波波形,而是有落差R的波形,且R=X(n)—X(n—1),它的大小反映了曲线的不光滑程度。正弦波的斜率变化最大应在n=0处,所以。下面分别用公式④定量计算N=300,N=200的波形精度和:
显然 < ,可以知道N=300相比N=200而言其阶跃状正弦波更趋向于光滑的理论值。
五、总结与体会
参考文献:
1、 胡汉才 单片机原理及其接口技术(第2版) 北京:清华大学出版社 2008
2、 阎石 数字电子技术基础(第三版)北京:高等教育出版社 1989
3、 郭天祥 新概念51单片机C语言教程 入门、提高、开发全;北京 电子工业出版社
4、 童诗白 模拟电路技术基础[M] 北京:高等教育出版社
附录1:
设计源程序:(c语言)
1. #include <reg52.h>
2.
3. unsigned char code SinWave[] = { //正弦波波表
4. 127, 152, 176, 198, 217, 233, 245, 252,
5. 255, 252, 245, 233, 217, 198, 176, 152,
6. 127, 102, 78, 56, 37, 21, 9, 2,
7. 0, 2, 9, 21, 37, 56, 78, 102
8. };
9. unsigned char code TriWave[] = { //三角波波表
10. 0, 16, 32, 48, 64, 80, 96, 112,
11. 128, 144, 160, 176, 192, 208, 224, 240,
12. 255, 240, 224, 208, 192, 176, 160, 144,
13. 128, 112, 96, 80, 64, 48, 32, 16
14. };
15. unsigned char code SawWave[] = { //锯齿波表
16. 0, 8, 16, 24, 32, 40, 48, 56,
17. 64, 72, 80, 88, 96, 104, 112, 120,
18. 128, 136, 144, 152, 160, 168, 176, 184,
19. 192, 200, 208, 216, 224, 232, 240, 248
20. };
21. unsigned char code *pWave; //波表指针
22. unsigned char T0RH = 0; //T0 重载值的高字节
23. unsigned char T0RL = 0; //T0 重载值的低字节
24. unsigned char T1RH = 1; //T1 重载值的高字节
25. unsigned char T1RL = 1; //T1 重载值的低字节
26.
27. void ConfigTimer0(unsigned int ms);
28. void SetWaveFreq(unsigned char freq);
29. extern void KeyScan();
30. extern void KeyDriver();
31. extern void I2CStart();
32. extern void I2CStop();
33. extern bit I2CWrite(unsigned char dat);
34.
35. void main(){
36. EA = 1; //开总中断
37. ConfigTimer0(1); //配置 T0 定时 1ms
38. pWave = SinWave; //默认正弦波
39. SetWaveFreq(10); //默认频率 10Hz
40.
41. while (1){
42. KeyDriver(); //调用按键驱动
43. }
44. }
45. /* 按键动作函数,根据键码执行相应的操作,keycode-按键键码 */
46. void KeyAction(unsigned char keycode){
47. static unsigned char i = 0;
48. if (keycode == 0x26){ //向上键,切换波形
49. //在 3 种波形间循环切换
50. if (i == 0){
51. i = 1;
52. pWave = TriWave;
53. }else if (i == 1){
54. i = 2;
55. pWave = SawWave;
56. }else{
57. i = 0;
58. pWave = SinWave;
59. }
60. }
61. }
62.
63. /* 设置 DAC 输出值,val-设定值 */
64. void SetDACOut(unsigned char val){
65. I2CStart();
66. if (!I2CWrite(0x48<<1)){ //寻址 PCF8591,如未应答,则停止操作并返回
67. I2CStop();
68. return;
69. }
70. I2CWrite(0x40); //写入控制字节
71. I2CWrite(val); //写入 DA 值
72. I2CStop();
73. }
74. /* 设置输出波形的频率,freq-设定频率 */
75. void SetWaveFreq(unsigned char freq){
76. unsigned long tmp;
77. tmp = (11059200/12) / (freq*32); //定时器计数频率,是波形频率的 32 倍
78. tmp = 65536 - tmp; //计算定时器重载值
79. tmp = tmp + 33; //修正中断响应延时造成的误差
80. T1RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节
81. T1RL = (unsigned char)tmp;
82. TMOD &= 0x0F; //清零 T1 的控制位
83. TMOD |= 0x10; //配置 T1 为模式 1
84. TH1 = T1RH; //加载 T1 重载值
85. TL1 = T1RL;
86. ET1 = 1; //使能 T1 中断
87. PT1 = 1; //设置为高优先级
88. TR1 = 1; //启动 T1
89. }
90. /* 配置并启动 T0,ms-T0 定时时间 */
91. void ConfigTimer0(unsigned int ms){
92. unsigned long tmp; //临时变量
93. tmp = 11059200 / 12; //定时器计数频率
94. tmp = (tmp * ms) / 1000; //计算所需的计数值
95. tmp = 65536 - tmp; //计算定时器重载值
96. tmp = tmp + 28;//补偿中断响应延时造成的误差
97. T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节
98. T0RL = (unsigned char)tmp;
99. TMOD &= 0xF0; //清零 T0 的控制位
100. TMOD |= 0x01; //配置 T0 为模式 1
101. TH0 = T0RH; //加载 T0 重载值
102. TL0 = T0RL;
103. ET0 = 1; //使能 T0 中断
104. TR0 = 1; //启动 T0
105. }
106. /* T0 中断服务函数,执行按键扫描 */
107. void InterruptTimer0() interrupt 1{
108. TH0 = T0RH; //重新加载重载值
109. TL0 = T0RL;
110. KeyScan(); //按键扫描
111. }
112. /* T1 中断服务函数,执行波形输出 */
113. void InterruptTimer1() interrupt 3{
114. static unsigned char i = 0;
115. TH1 = T1RH; //重新加载重载值
116. TL1 = T1RL;
117. //循环输出波表中的数据
118. SetDACOut(pWave[i]);
119. i++;
120. if (i >= 32){
121. i = 0;
122. }
123. }
124.
附录2:仿真波形
正弦波:
三角波:
锯齿波:
展开阅读全文