打印

请教各位大侠:单片机可以输出可变频率的正弦波吗?

[复制链接]
6526|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
yuanchsh|  楼主 | 2009-11-12 13:23 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
请问各位大师:PIC单片机可以输出可变频率的正弦波吗?
可变频率范围:400HZ-2KHz不等,可变周期在0.1S-0.6S不等(固定)。
同时可通过选择开关选择至少4中不同的频率特性输出。(类似于语音芯片的功能)
具体如下:1.f1:400HZ-F2:1500HZ-F1:400HZ,变换周期:0.33S;
              2.F1:1350HZ-F2:600HZ-F1:1350HZ,变换周期:0.2S;
              3.F1:600HZ-F21500HZ-F1:600HZ,变换周期:5S;
              4.F1:600HZ-F21500HZ-F1:600HZ,变换周期:0.3S;

相关帖子

沙发
yuanchsh|  楼主 | 2009-11-12 19:21 | 只看该作者
怎么没人啊,自己顶一下!

使用特权

评论回复
板凳
tyw| | 2009-11-12 19:29 | 只看该作者
增加适当硬件是可以的,你想模拟警报声吗,还是买只现成的音乐芯片划算哦

使用特权

评论回复
地板
yuanchsh|  楼主 | 2009-11-12 19:43 | 只看该作者
老T,我想做的是警报声,多种警音的警报声,声音可以根据客户的要求随意调整的,并且可以通过一个电路将其和成为混响效果。我们现在做的是单声道输出的,如果要达到混响效果,必须2只喇叭同时输出两个警音。我想用一个喇叭就能实现,但是,现在的单片机输出的是方波变频信号,再合成技术上有很大难度,如果单片机能够输出正弦波,那我的电路就可以成功了。(如果能够成功,也是我们这个行业的一个创新哦)能不能帮帮忙,告诉俺用什么电路实现?在此先谢谢了。

使用特权

评论回复
5
tyw| | 2009-11-12 20:18 | 只看该作者
本帖最后由 tyw 于 2009-11-12 20:46 编辑

若用I/O基本型的MCU来模拟,所附加的硬件成本远大于现成音乐芯片
用带D/A口的MCU来做,单片机成本也将大出2~3元.(警报芯片才1元多点,人家是大量生产,用的是裸片绑定工艺.)
直接用方波模拟,音色差点,想两路信号用一个喇叭输出,可考虑用运放来迭加信号.
若单片机I/O口有得多,可用R/2R电阻网络来做D/A转换.





http://www.siaaa.com/dianyuan/nb/200909/99226.html

http://www.guangdongdz.com/special_column/techarticle/old/14217.html

http://www.**/soft/33/2009/2009091947441.html

使用特权

评论回复
6
onebyte| | 2009-11-12 21:09 | 只看该作者
单片机可以输出可变频率的正弦波,但需要用带DA的单片机。然后通过内部查询正弦表的方式来实现;
楼上的建议不错。

使用特权

评论回复
7
yuanchsh|  楼主 | 2009-11-13 08:22 | 只看该作者
谢谢LS各位的精确回答,我试试看。

使用特权

评论回复
8
again_gyf| | 2009-11-13 09:25 | 只看该作者
pwm

使用特权

评论回复
9
不亦心| | 2009-11-13 12:51 | 只看该作者
学习的

使用特权

评论回复
10
yuanchsh|  楼主 | 2009-11-13 14:42 | 只看该作者
5# tyw
“直接用方波模拟,音色差点,想两路信号用一个喇叭输出,可考虑用运放来迭加信号.
”这个我早就做过实验,是实现不了的。

使用特权

评论回复
11
jimsboy| | 2009-11-13 22:57 | 只看该作者
PWM,加一个LC缓冲一下,可以得到不错的波形

使用特权

评论回复
12
zteclx| | 2009-11-14 12:36 | 只看该作者
PWM如何转换为正弦波?RC缓冲效果不好吧?

使用特权

评论回复
13
g19860529| | 2009-11-14 14:39 | 只看该作者
用过PIC的18系列,他的那个可以实现你说的4lupwm输出,似乎更多的也能输出。不过那些都是方波。小弟印象里方波变成正弦波不是很难的吧,魔电懂点的应该可以搞定的。
不过我说你要的是不同的声音吧?这个难道方波不能转换成声音的啊?呵呵,我是瞎想的。

使用特权

评论回复
14
zteclx| | 2009-11-14 17:50 | 只看该作者
小弟印象里方波变成正弦波不是很难的吧,魔电懂点的应该可以搞定的。
g19860529 发表于 2009-11-14 14:39

如何变?实践一下,拿出具体的方案来。莫不是要直接产生正弦波?那还要先产生方波干嘛?

使用特权

评论回复
15
tudou2048| | 2009-11-14 19:06 | 只看该作者
老T叔,绑定的报警芯片很多都是方波模拟的。

使用特权

评论回复
16
yuanchsh|  楼主 | 2009-11-14 21:09 | 只看该作者
15# netjob
关键是要产生连续变频输出啊,有时还要进行频率突变(从1500Hz-800Hz跳变),请问有没有好的办法?輸出频率精度要求在±5Hz範圍內。

使用特权

评论回复
17
teddeng| | 2009-11-14 22:07 | 只看该作者
把下面讨论东西的彻底搞清楚,你想要技巧都在里面。

双龙DTMF演示程序的两点疑问,做过DTMF(软件PWM方法)的请进
这是双龙DTMF演示程序

#include <io8515v.h>
#include <macros.h>
#define  XTAL       8000000          // 系统时钟频率
#define  prescaler  1                // T1预分频系数
#define  N_samples  128              // 在查找表中的样本数
#define  Fck        XTAL/prescaler   // T1工作频率
#define  delaycyc   10               // 读取PORT.html">PORT C口延时循环数
#pragma interrupt_handler ISR_T1_Overflow:7
/*************************** 正弦表 *****************************
       样本表: 一个周期分成128个点,每点按7位进行量化
****************************************************************/
FLASH unsigned CHAR auc_SinParam [128] =
{64,67,70,73,76,79,82,85,88,91,94,96,99,102,104,106,109,111,113,115,117,
118,120,121,123,124,125,126,126,127,127,127,127,127,127,127,126,126,125,
124,123,121,120,118,117,115,113,111,109,106,104,102,99,96,94,91,88,85,82,
79,76,73,70,67,64,60,57,54,51,48,45,42,39,36,33,31,28,25,23,21,18,16,14,
12,10,9,7,6,4,3,2,1,1,0,0,0,0,0,0,0,1,1,2,3,4,6,7,9,10,12,14,16,18,21,23,
25,28,31,33,36,39,42,45,48,51,54,57,60};
//***************************  x_SW  *************************
//   x_SW 表(8倍): x_SW = ROUND(8*N_samples*f*510/Fck)
//************************************************************
const unsigned CHAR auc_frequencyH [4] = {
107,96,
87,79};
const unsigned CHAR auc_frequencyL [4] = {
61,56,
50,46};


//**************************  全局变量 ****************************
unsigned CHAR x_SWa = 0x00;               // 高频信号脉冲宽度
unsigned CHAR x_SWb = 0x00;               // 低频信号脉冲宽度
unsigned int  X_LUTaExt = 0;                 
unsigned int  X_LUTbExt = 0;              
unsigned int  X_LUTa;                  
unsigned int  X_LUTb;                     

/*****************************************************************
                    定时器溢出中断服务程序
******************************************************************/
void ISR_T1_Overflow (void)
{
  X_LUTaExt += x_SWa;      
  X_LUTbExt += x_SWb;
  X_LUTa  =  (CHAR)(((X_LUTaExt+4) >> 3)&(0x007F));
  X_LUTb  =  (CHAR)(((X_LUTbExt+4) >> 3)&(0x007F));
           // 计算 PWM 值: 高频值 + 3/4 低频值
  OCR1A = (auc_SinParam[X_LUTa] + (auc_SinParam[X_LUTb]-(auc_SinParam[X_LUTb]>>2)));
}

/***********************************************************
                        初始化
***********************************************************/
void init (void)
{
  MCUCR=0x00;
  TIMSK  = 0x80;                     // T1 溢出中断使能
  TCCR1A = (1<<COM1A1)+(1<<PWM10);   // 不翻转、8位PWM
  TCCR1B = (1<<CS10);                // 预分频系数为1、即CLK/1
  DDRD   = (1 <<PD5);               // PD5 (OC1A)用作输出
  _SEI();                              // 全局中断使能
}
/*********************************************************************
      为从PORT C口读取稳定的按键数据,所必须的延时程序(消抖延时)
*********************************************************************/
void Delay (void)
{
  int i;
  for (i = 0; i < delaycyc; i++) _NOP();
}

/********************************************************************
                            主程序
      从PORT C口读取按键数据(如:SL+ AVR实验板) ,来确定产生哪个
      高频(列)和低频(行)信号的混合信号,并且修正 x_SWa 和 x_SWb。
                   行  -> PINC 高四位
                   列  -> PINC 低四位
*********************************************************************/

void main (void)
{
  unsigned CHAR uc_Input;
  unsigned CHAR uc_Counter = 0;
  init();
  for(;;){
     // 高四位 - 行
    DDRC  = 0x0F;           // 高四位输入、低四位输出
    PORTC = 0xF0;           // 高四位打开上位、低四位输出低电平
    uc_Counter = 0;
    Delay();                          // 延时等待 PORT C 电平稳定
    uc_Input = PINC;                  // 读取 PORT C
    do
    {
      if(!(uc_Input & 0x80))          // 检查MSB是否为低
      {
                                      // 取低音脉冲宽度并结束循环
        x_SWb = auc_frequencyL[uc_Counter];  
        uc_Counter = 4;
      }
      else
      {
        x_SWb = 0;             &nb
2楼: >>参与讨论
作者: 94179411 于 2006-9-5 9:45:00 发布:
--------------------------------------------------------------------------------
关于两点疑问
1:
DTMF音频矩阵的高频组为:
1209,1336,1477,1633
低频组为:697,770,852,941(Hz)
为什么在程序中定义为:
const unsigned CHAR auc_frequencyH [4] = {
107,96,
87,79};
const unsigned CHAR auc_frequencyL [4] = {
61,56,
50,46};
2:
ATMEL官方网站提供的查表算法为
X_LUTa=ROUND( (X_LUTaExt+8*N_samples*f*510/Fck) /8 )
程序中相应语句为:
x_SW = ROUND(8*N_samples*f*510/Fck)
X_LUTaExt += x_SWa;
X_LUTa  =  (CHAR)(((X_LUTaExt+4) >> 3)&(0x007F));
其中的
((X_LUTaExt+4) >> 3)
怎么理解?



3楼: >>参与讨论
作者: 94179411 于 2006-9-5 9:48:00 发布:
--------------------------------------------------------------------------------
第一个问题已经解决
定义中
const unsigned CHAR auc_frequencyH [4] = {
107,96,
87,79};
不是频率,是步长,是经过x_SW = ROUND(8*N_samples*f*510/Fck)
计算过的,如107=(8*128*1633*510)/8 000 000
我主观地认为auc_frequency就是频率的定义了
见笑了


4楼: >>参与讨论
作者: 94179411 于 2006-9-6 16:10:00 发布:
--------------------------------------------------------------------------------
这么久了,都没有高人指点?我该怎么办呢?
  
5楼: >>参与讨论
作者: 94179411 于 2006-9-9 7:02:00 发布:
--------------------------------------------------------------------------------
眼睁睁的看着它沉下去了,伤心
  
6楼: >>参与讨论
作者: 123654789 于 2006-9-9 9:48:00 发布:
--------------------------------------------------------------------------------
请 把电路图  粘贴出来
请 把电路图  粘贴出来
不然很难 解决 问题


7楼: >>参与讨论
作者: mylovetus 于 2006-9-9 14:06:00 发布:
--------------------------------------------------------------------------------
没有认真分析,简单提供一个想法而已
ATMEL官方网站提供的查表算法为
X_LUTa=ROUND( (X_LUTaExt+8*N_samples*f*510/Fck) /8 )
程序中相应语句为:
x_SW = ROUND(8*N_samples*f*510/Fck)
X_LUTaExt += x_SWa;
X_LUTa  =  (CHAR)(((X_LUTaExt+4) >> 3)&(0x007F));
其中的
((X_LUTaExt+4) >> 3)
怎么理解?

简单判断,仅为提供思路!
其中的(X_LUTaExt + 4)>>3有点象除以8!



8楼: >>参与讨论
作者: 94179411 于 2006-9-10 9:40:00 发布:
--------------------------------------------------------------------------------
TO:mylovetus AND 123654789
TO:mylovetus
其中的(X_LUTaExt + 4)>>3其中>>3除以8很容易理解
但是+ 4的涵义我一直搞不懂
TO:123654789
电路图我也没有,我仅仅是研究算法,我觉得这跟硬件关系不大,很显然是个4*4键盘扫描电路,我觉得这跟硬件关系不大,关键是产生DTMF信号的算法实现
不过,要谢谢两位热心人
等待再有高人指点


9楼: >>参与讨论
作者: 94179411 于 2006-9-14 7:19:00 发布:
--------------------------------------------------------------------------------
我自己顶!
  
10楼: >>参与讨论
作者: 94179411 于 2006-9-14 16:20:00 发布:
--------------------------------------------------------------------------------
我再顶...
  
11楼: >>参与讨论
作者: 极限思考 于 2006-9-14 16:27:00 发布:
--------------------------------------------------------------------------------
TO 94
+4应该是为了调整进位,用来划分比例查表,N=x*1/4的关系。
比例对应0-3对应0
       4-7对应1
       。。。。



12楼: >>参与讨论
作者: 94179411 于 2006-9-14 19:33:00 发布:
--------------------------------------------------------------------------------
若有所悟!但是划分查表的意义何在?
划分比例查表到底是怎么回事?都在什么地方有应用?还请极限大哥好人做到底,再点化一下小弟,不胜感激!


13楼: >>参与讨论
作者: Sethhorus 于 2006-9-15 12:53:00 发布:
--------------------------------------------------------------------------------
呵呵
到ATMEL 网站上去看看 那里又详细介绍

不过该程序产生的软件DTMF波还不能用于电话网,需要外加电路

如果真要发DTMF还是用硬件(HT9200)比较可靠

使用特权

评论回复
18
teddeng| | 2009-11-14 22:07 | 只看该作者
14楼: >>参与讨论
作者: teddeng 于 2006-9-18 15:41:00 发布:
--------------------------------------------------------------------------------
我做过用5个I/O再加R-2R电阻网络做D/A的DTMF发生。
我用的51,没PWM,但我想软件上核心是一样的。我的东西已经做成产品了,在省内各偏僻农村用做小数据传输,效果很好。
我没看你写的代码,我也看不懂,跟你讲讲思路,可能更有效。
Fdtmf=Fh+0.9Fl;这里的系数0.9我记不太清了标准是多少了,只告诉你原因:高频群在传输时衰减较大,所以发送时做大点,这样到达交换机时和低频群信号强度差不多,试验时可忽略这系数,程序简单点,城里用没一点问题。
好了说正题,显然你应该知道了基本思路就是用一个较高的采样频率,计算每个采样时刻的Fdtmf值,然后送到I/O口或刷新PWM寄存器。我做的5位D/A采样周期小于60US,我没条件做试验,据我另一个朋友讲,采样频率比DA分辨率更重要,当然分辨率高点,采样率可低点。
f=sin(2*pi*f*t),设采样周期为T,则
f=sin(2*pi*f*T*n),其中,2*pi*f*T是一个随f不同而不同的纯小数,n=0,1,2,,,,,,,N.对应各采样时刻。DTMF持续时间=N*T。显然为了不算SIN,我们就需要一个SIN表。
我们只需每时刻把2*pi*f*T加上上次的值(初始值显然是零),然后查表就可以得到当前时刻得频率幅度了。

基本原理就这么简单,也许难理解的是技巧。
技巧如下:
如果是51,它有10进制加法指令,这样,最直观的,我们把2*pi*f*T保留两个字节(考虑误差允许),每时刻做十进制累加就可以了。理解最关键的一点(个人认为,呵呵),这样的双字节加**好不要考虑溢出,也就是正好不要考虑累加的整数部分。整数部分的物理意义是什么?它表示正弦波的周期数,而正弦波是周期函数,计算幅度时不用考虑的。查表的时候取累加和的第一个字节就可以了,记住,这时SIN表是分成100等份的。
这样,每时刻高频群算一次SIN幅度值,低频群算一次SIN幅度值,加起来就是DTMF当前幅度值了。
当用的单片机没有十进制加法时,用其他指令去模拟也是可以的,有没有更好的办法呢?有。
令1.0000(十进制)=10000H(16进制)则2*pi*f*T=?
这样我们就可以用最基本的2进制加法了,每个单片机都有的指令,而且更方便。这时,SIN表是256等份的。
其他:T原则上是随便取的,当然应该是定时器的整数值,而且越小越好;
      如果用0.9的系数,最简单的是做个0.9*sin的表;
      如果嫌表大,可以再利用对称性把表做小点;
      效果是相当好的,我做的软DTMF指标在仪器上测比硬件做的还好。



15楼: >>参与讨论
作者: 94179411 于 2006-9-25 8:21:00 发布:
--------------------------------------------------------------------------------
好人啊,感激涕零!!!
  
16楼: >>参与讨论
作者: xwj 于 2006-9-25 8:28:00 发布:
--------------------------------------------------------------------------------
顶teddeng ,好!
  
17楼: >>参与讨论
作者: teddeng 于 2006-9-26 21:02:00 发布:
--------------------------------------------------------------------------------
我的道理是说清楚了,但有个明显的错误
不更正了,正好让你想想,呵呵。


18楼: >>参与讨论
作者: teddeng 于 2006-9-27 0:53:00 发布:
--------------------------------------------------------------------------------
由于发现了我解释中的错误
谨慎起见,还是看了ATMEL的文档。结论:放心,思路是一样的,我解释得直观点,精度保守起见高点(代价应该是多两个字节RAM)。
+4的意思费好大劲才想通,这个例子里不加也没关系,但这样才是严谨的。想通了很简单,就是+0.5的意思。即算出是10.5XX时,按11查表,而不是按10查表。从表达式看不影响长期累加精度。


19楼: >>参与讨论
作者: 94179411 于 2006-9-28 10:36:00 发布:
--------------------------------------------------------------------------------
teddeng大哥太热心了,我太感动了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:专业开发、设计、生产LED驱动电源,系列齐全(内置球泡灯蜡烛灯裸板系列,GU10系列,天花灯、筒灯、射灯胶壳系列,户外投光灯、洗墙灯铝壳防水系列,集成灯高PF防水系列,大功率路灯系列,T5/T8内置非隔离、隔离系列等)。产品过CE、UL、ROHS等认证。TEL:020-84719319-20,FAX:020-84719319-21。

12

主题

668

帖子

1

粉丝