搜索
bottom↓
回复: 99

使用AVR定时/计数器的PWM功能设计要点

[复制链接]
(523177294)

出0入0汤圆

发表于 2004-12-27 01:15:05 | 显示全部楼层 |阅读模式
取自《M128》上。供参考。



一、定时/计数器PWM设计要点



  根据PWM的特点,在使用ATmega128的定时/计数器设计输出PWM时应注意以下几点:

  1.首先应根据实际的情况,确定需要输出的PWM频率范围,这个频率与控制的对象有关。如输出PWM波用于控制灯的亮度,由于人眼不能分辨42Hz以上的频率,所以PWM的频率应高于42Hz,否则人眼会察觉到灯的闪烁。

  2.然后根据需要PWM的频率范围确定ATmega128定时/计数器的PWM工作方式。AVR定时/计数器的PWM模式可以分成快速PWM和频率(相位)调整PWM两大类。

  3.快速PWM可以的到比较高频率的PWM输出,但占空比的调节精度稍微差一些。此时计数器仅工作在单程正向计数方式,计数器的上限值决定PWM的频率,而比较匹配寄存器的值决定了占空比的大小。PWM频率的计算公式为:

    PWM频率 = 系统时钟频率/(分频系数*(1+计数器上限值))

  4.快速PWM模式适合要求输出PWM频率较高,但频率固定,占空比调节精度要求不高的应用。

  5.频率(相位)调整PWM模式的占空比调节精度高,但输出频率比较低,因为此时计数器仅工作在双向计数方式。同样计数器的上限值决定了PWM的频率,比较匹配寄存器的值决定了占空比的大小。PWM频率的计算公式为:

    PWM频率 = 系统时钟频率/(分频系数*2*计数器上限值))

  6.相位调整PWM模式适合要求输出PWM频率较低,但频率固定,占空比调节精度要求高的应用。当调整占空比时,PWM的相位也相应的跟着变化(Phase Correct)。

  7.频率和相位调整PWM模式适合要求输出PWM频率较低,输出频率需要变化,占空比调节精度要求高的应用。此时应注意:不仅调整占空比时,PWM的相位会相应的跟着变化;而一但改变计数器上限值,即改变PWM的输出频率时,会使PWM的占空比和相位都相应的跟着变化(Phase and Frequency Correct)。

  8.在PWM方式中,计数器的上限值有固定的0xFF(8位T/C);0xFF、0x1FF、0x3FF(16位T/C)。或由用户设定的0x0000-0xFFFF,设定值在16位T/C的ICP或OCRA寄存器中。而比较匹配寄存器的值与计数器上限值之比即为占空比。



二、 PWM应用设计参考

  下面给出一个设计示例,在示例中使用PWM方式来产生一个1KHz左右的正弦波,幅度为0-Vcc/2。

  首先按照下面的公式建立一个正弦波样本表,样本表将一个正弦波周期分为128个点,每点按7位量化(127对应最高幅值Vcc/2):

          f(x) = 64 + 63 * sin(2πx/180)  x∈[0…127]

  如果在一个正弦波周期中采用128个样点,那么对应1KHz的正弦波PWM的频率为128KHz。实际上,按照采样频率至少为信号频率的2倍的取样定理来计算,PWM的频率的理论值为2KHz即可。考虑尽量提高PWM的输出精度,实际设计使用PWM的频率为16KHz,即一个正弦波周期(1KHz)中输出16个正弦波样本值。这意味着在128点的正弦波样本表中,每隔8点取出一点作为PWM的输出。

  程序中使用ATmega128的8位T/C0,工作模式为相位调整PWM模式输出,系统时钟为8MHz,分频系数为1,其可以产生最高PWM频率为:   8000000Hz / 510 = 15686Hz。每16次输出构成一个周期正弦波,正弦波的频率为980.4Hz。PWM由OC0(PB4)引脚输出。参考程序如下(ICCAVR)。



//ICC-AVR application builder : 2004-08

// Target : M128

// Crystal: 8.0000Mhz



#include <iom128v.h>

#include <macros.h>



#pragma data:code

// 128点正弦波样本表

const 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};

   #pragma data:data

   

   unsigned char x_SW = 8,X_LUT = 0;



#pragma interrupt_handler timer0_ovf_isr:17

void timer0_ovf_isr(void)

{

       X_LUT += x_SW;            // 新样点指针

if (X_LUT > 127) X_LUT -= 128;   // 样点指针调整

OCR0 = auc_SinParam[X_LUT];      // 取样点指针到比较匹配寄存器

}



   void main(void)

   {

      DDRB |= 0x10;         // PB4(OC0)输出

      TCCR0 = 0x71;       // 相位调整PWM模式,分频系数=1,正向控制OC0

TIMSK = 0x01;       // T/C0溢出中断允许

SEI();            // 使能全局中断

while(1)

{……};

}



  每次计数器溢出中断的服务中取出一个正弦波的样点值到比较匹配寄存器中,用于调整下一个PWM的脉冲宽度,这样在PB4引脚上输出了按正弦波调制的PWM方波。当PB4的输出通过一个低通滤波器后,便得到一个980.4Hz的正弦波了。如要得到更精确的1KHz的正弦波,可使用定时/计数器T/C1,选择工作模式10,设置ICR1=250为计数器的上限值。

  在ATMEL公司网站上,给出了使用一个定时/计数器实现双音频拨号的应用设计参考(AVR314.pdf),读者可以从中学习到如何更好设计和使用PWM的功能。
(521637218)

出0入0汤圆

发表于 2005-1-13 21:03:01 | 显示全部楼层
顶一下
(521635526)

出0入0汤圆

发表于 2005-1-13 21:31:13 | 显示全部楼层
so good!
(520701951)

出0入0汤圆

发表于 2005-1-24 16:50:48 | 显示全部楼层
GOOD!!!!!
(520690919)

出0入0汤圆

发表于 2005-1-24 19:54:40 | 显示全部楼层
太感谢了!总结得太好了。
(520690433)

出0入0汤圆

发表于 2005-1-24 20:02:46 | 显示全部楼层
向哪去找这么好的教材啊!!

项了!
(519603055)

出0入0汤圆

发表于 2005-2-6 10:05:44 | 显示全部楼层
为什么我在MEGA8产生PWM中的实际测试发现改变计数的初值为0和1时,这两种不同的初值产生的PWM占空比相差很大?
(519516993)

出0入0汤圆

 楼主| 发表于 2005-2-7 10:00:06 | 显示全部楼层
1。调整PWM的占空比,合理的方法是改变比较匹配寄存器中(如OCR0)的设定值。

   2。调整PWM的频率,合理的方法是改变计数器的上限的设定值。

   3。改变这些值的时机通常在计数器溢出中断服务中。

   4。比较匹配寄存器中(如OCR0)的设定值与计数器的初值(0x00)相近时,可能会产生一次奇变的(第一个)PWM输出。

   5。你可以尝试使用VMLAB进行软件的仿真测试,观察PWM的输出(无需任何硬件),编写和调试你的PWM程序。



   请仔细看M8器件手册中关于T/C的PWM工作方式的说明,你调整改变“计数的初值为0和1”是错误的方法。说明你对PWM的概念和产生还不清楚。
(514388393)

出0入0汤圆

发表于 2005-4-7 18:36:46 | 显示全部楼层
马老师:请问,是不是MEGA8用了OC1A输出的PWM功能的话,ICP的捕捉功能就不能用了?
(514324531)

出0入0汤圆

 楼主| 发表于 2005-4-8 12:21:08 | 显示全部楼层
应该可以使用。
(514296583)

出0入0汤圆

发表于 2005-4-8 20:06:56 | 显示全部楼层
但是使用PWM时,定时器1的TOP是由ICP1的寄存器来设定,假如ICP捕获了脉冲信号,该ICP1寄存器的值就会发生变化吧,那么PWM的定时器TOP就会改变,影响到PWM的频率,不知我的理解对不对。
(514280227)

出0入0汤圆

 楼主| 发表于 2005-4-9 00:39:32 | 显示全部楼层
使用PWM时,定时器1的TOP值不仅仅是由ICR1的寄存器来设定,还可以由OCRA1、固定的8、9、10位等。

    你使用T1,即要产生PWM,又要捕获脉冲,具体要做什么?
(514239160)

出0入0汤圆

发表于 2005-4-9 12:03:59 | 显示全部楼层
ICP测量转速,测量结果用PWM作为电流信号输出的控制.原来打算用两片M8或者M16,如果选M128感觉贵了一些.还有一个问题,如果定时器1的Top不是16位的,那么ICP的捕捉时间也不能按16位来计算了吧.

由于买的仿真器正在返修,自己无法试验,只好多问问了.
-----此内容被bucker于2005-04-09,12:07:51编辑过
(514225760)

出0入0汤圆

 楼主| 发表于 2005-4-9 15:47:19 | 显示全部楼层
建议使用M8时,用T1测转速,T2产生PWM。用T1又测转速又产生PWM,处理上不方便。



    ICP的捕捉的本质是记录下当前T1的值,至于怎样换算成速度你要认真考虑的。



    你还得仔细弄懂T1是如何工作的,根据你的提问,估计你目前的水平做这样的系统有一定的困难。
(514212783)

出0入0汤圆

发表于 2005-4-9 19:23:36 | 显示全部楼层
是的,由于仿真器无法使用,还没有开始实践,可能会有一些提问不着边际。过去曾用8098的HSI捕捉功能作过转速测量装置,但他的硬件PWM只有8位分辨率,现在选用了AVR的CPU,就是看中了其PWM分辨率可高于8位的优点,这也是不打算使用T2实现PWM的原因。原来的计划是使用两片M8的解决方案,用一片M8实现用ICP测频率/转速的功能,另一片M8实现PWM输出控制、键盘、显示模块的控制,两者之间用I2C通信来交换数据。我认为这个方案中的用单独的M8完成PWM比使用一个串行D/A器件的方案要便宜一些,同时,用PWM容易实现信号地的隔离。这样做的难点可能是开始的时候调试不方便,特别是在两芯片通信方面,所以,会先用M16仿真,将电路分模块调试,再将调试成功的模块移植到M8。如果这个方案能够得以成功地实现,我将得到一种串行的用PWM实现的D/A及键盘/显示功能的通用芯片,为今后的单片机应用提供很大的便利。通过马老师的指点,本人受益很大,基本确定了对原方案的信心,但用单片M8同时进行ICP捕捉和PWM输出的试验我还是要做。在此,感谢马老师的帮助!
-----此内容被bucker于2005-04-10,09:25:32编辑过
(512498564)

出0入0汤圆

发表于 2005-4-29 15:33:55 | 显示全部楼层
请教:mega16设置为 模式14 WGM13:0(1 1 1 0)快速PWM 计数上限值POP为ICR1时我发现是计数到0x1ff,并不是计数到ICR1,而且也不是快速PWM,是相位修正的,下面是程序,在avrstudio中软件仿真,用iccavr编译,下面是源程序,请指教:

#include <iom16.h>  

#include <macros.h>  



   void main(void)  

   {  

           DDRD |= 0xff;  

                

           OCR1AH=0x00;

          OCR1AL=0x3F;

                

          ICR1H=0x00;

          ICR1L=0x7F;



          TCCR1A = 0xC2;   

          TCCR1B = 0x19;

      

          while(1);

   }
(510680266)

出0入0汤圆

发表于 2005-5-20 16:38:53 | 显示全部楼层
楼上的兄弟

我也遇到同样的问题

我用icp测速

用OCR1A控制频率发现TOP不是我设定的值

          OCR1A=10000;

          OCR1B=500;

          TCCR1A=(1<<COM1B1)|(1<<COM1B0)|(1<<WGM11)|(1<<WGM10);

          TCCR1B=(1<<ICNC1)|(1<<ICES1)|(1<<CS10)|(1<<WGM12)|(1<<WGM13);

执行完这句后OCR1A变成了0X0310

改变OCR1A 最大变成0X03FF



我想是不是最多只能计到03ff啊?

但是马老师的书上说可以计到0XFFFF
-----此内容被lanxieyu于2005-05-20,16:47:21编辑过
(510672729)

出0入0汤圆

 楼主| 发表于 2005-5-20 18:44:30 | 显示全部楼层
请用ICC或CVAVR中的程序生成向导生成T1初始化程序,与你的比较一下,看初始化有没有问题。
(510670267)

出0入0汤圆

发表于 2005-5-20 19:25:32 | 显示全部楼层
今天下午编程用M8做了关于ICP1测速和OCR1A设定TOP控制12位快速PWM的实验,还不成功,表现为计算出的值有时正确,有时为零,PWM还没来得及检测。由于没用JTAG仿真器(用M16来试验)来调试,暂未分析到原因,争取下周一搞定。
(510669520)

出0入0汤圆

 楼主| 发表于 2005-5-20 19:37:59 | 显示全部楼层
建议先单个功能的实现,然后在考虑如何合在一起使用。
(510414810)

出0入0汤圆

发表于 2005-5-23 18:23:09 | 显示全部楼层
我呆会儿试试用ICC生成初始化程序

谢谢马老师
(510301499)

出0入0汤圆

发表于 2005-5-25 01:51:40 | 显示全部楼层
我由于没有仿真机

只好用ICCAVR6.31A生成的cof文件在studio4.10/4.11里面仿真

好象我试过了所有的PWM方式

没有利用OCR1A作为TOP值可以超过0X3FF的

是不是ICC 生成的代码有误,

还是studio不支持。

/////我用WGM13:0=15方式,icp测速,PWM输出频率一定100,占空比可调的方波信号/////

上面马老师教我用ICC生成了初始化文件

我试过了,跟我自己写的只是在COM1X上有一点区别 ,

我不知道COM1X口是不是与WGM方式有关联,只知道COM1B设置与输出电平有关系,

而COM1A不可以用。

请马老师教教我该怎么办????
(510249970)

出0入0汤圆

发表于 2005-5-25 16:10:29 | 显示全部楼层
我今天在论坛里看到有关 studio     不可以调试pwm

可能是这样子
(510243601)

出0入0汤圆

发表于 2005-5-25 17:56:38 | 显示全部楼层
我在技术论坛里以发了一个“M16测频及PWM”的帖子,有程序代码,用的就是12位PWM。定时器1方式15,OCR1A=0XFFF,PWM的效果不错。
(510242070)

出0入0汤圆

发表于 2005-5-25 18:22:09 | 显示全部楼层
先谢谢楼上的兄弟





我找不到

请说说在哪好吗?



要不麻烦发到我的邮箱  xilin19830302@163.com
-----此内容被lanxieyu于2005-05-25,19:06:51编辑过
(510233039)

出0入0汤圆

发表于 2005-5-25 20:52:40 | 显示全部楼层
到PWM分类中去找。
(509980622)

出0入0汤圆

发表于 2005-5-28 18:59:37 | 显示全部楼层
经过一段时间的考验,我的ICP捕捉及PWM实验成功了,分别在M8、M16上测试运行,效果令人满意。
(509492609)

出0入0汤圆

发表于 2005-6-3 10:33:10 | 显示全部楼层
转贴: (请马潮老师挤点时间核对一下)



马老师的M128PWM文章中有一处错误!

http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=302922&bbs_page_no=1&bbs_id=1000



使用AVR定时计数器的PWM功能设计要点



取自《M128》上。供参考。   



一、定时/计数器PWM设计要点   



  根据PWM的特点,在使用ATmega128的定时/计数器设计输出PWM时应注意以下几点:   

  1.首先应根据实际的情况,确定需要输出的PWM频率范围,这个频率与控制的对象有关。如输出PWM波用于控制灯的亮度,由于人眼不能分辨42Hz以上的频率,所以PWM的频率应高于42Hz,否则人眼会察觉到灯的闪烁。   

  2.然后根据需要PWM的频率范围确定ATmega128定时/计数器的PWM工作方式。AVR定时/计数器的PWM模式可以分成快速PWM和频率(相位)调整PWM两大类。   

  3.快速PWM可以的到比较高频率的PWM输出,但占空比的调节精度稍微差一些。此时计数器仅工作在单程正向计数方式,计数器的上限值决定PWM的频率,而比较匹配寄存器的值决定了占空比的大小。PWM频率的计算公式为:   

    PWM频率 = 系统时钟频率/(分频系数*(1+计数器上限值))   

  4.快速PWM模式适合要求输出PWM频率较高,但频率固定,占空比调节精度要求不高的应用。   

  5.频率(相位)调整PWM模式的占空比调节精度高,但输出频率比较低,因为此时计数器仅工作在双向计数方式。同样计数器的上限值决定了PWM的频率,比较匹配寄存器的值决定了占空比的大小。PWM频率的计算公式为:   

    PWM频率 = 系统时钟频率/(分频系数*2*计数器上限值))   

  6.相位调整PWM模式适合要求输出PWM频率较低,但频率固定,占空比调节精度要求高的应用。当调整占空比时,PWM的相位也相应的跟着变化(Phase Correct)。   

  7.频率和相位调整PWM模式适合要求输出PWM频率较低,输出频率需要变化,占空比调节精度要求高的应用。此时应注意:不仅调整占空比时,PWM的相位会相应的跟着变化;而一但改变计数器上限值,即改变PWM的输出频率时,会使PWM的占空比和相位都相应的跟着变化(Phase and Frequency Correct)。   

  8.在PWM方式中,计数器的上限值有固定的0xFF(8位T/C);0xFF、0x1FF、0x3FF(16位T/C)。或由用户设定的0x0000-0xFFFF,设定值在16位T/C的ICP或OCRA寄存器中。而比较匹配寄存器的值与计数器上限值之比即为占空比。   



二、 PWM应用设计参考   

  下面给出一个设计示例,在示例中使用PWM方式来产生一个1KHz左右的正弦波,幅度为0-Vcc/2。   

  首先按照下面的公式建立一个正弦波样本表,样本表将一个正弦波周期分为128个点,每点按7位量化(127对应最高幅值Vcc/2):   

          f(x) = 64 + 63 * sin(2πx/180)  x∈[0…127]   





这个公式是错误的,今天我在上面差点晕了。正确的应该是

f(x) = 63 + 63 * sin(2πx/128)  x∈[0…127]




-----此内容被zhaofree2001于2005-06-03,14:23:20编辑过
(509470088)

出0入0汤圆

 楼主| 发表于 2005-6-3 16:48:31 | 显示全部楼层
谢谢!我早已经知道了。180〈-〉128 笔误。
(509293753)

出0入0汤圆

发表于 2005-6-5 17:47:26 | 显示全部楼层
感谢马老师的总结



这段时间正在看这个, 在这里受益不少
(494089751)

出0入4汤圆

发表于 2005-11-28 17:07:28 | 显示全部楼层
马老师,ATMEL 网站上生成 DTMF 的那个 Application Note 最后一段我没有弄懂,希望你指点一下,提前谢谢!



(494089394)

出0入4汤圆

发表于 2005-11-28 17:13:25 | 显示全部楼层
/*****************************************************

Project : phone                                   

Version :                                         

Date    : 2005-11-26                              

Author  :                                         

Company :                                       

Comments:                                         

                                                   

Chip type           : ATmega16L                  

Program type        : Application                 

Clock frequency     : 8.000000 MHz               

Memory model        : Small                       

External SRAM size  : 0                           

Data Stack size     : 256                        



Description                                       

DTMF generator                                    

*****************************************************/



#include <mega16.h>  



#define  Xtal       8000000          // system clock frequency

#define  prescaler  1                // timer1 prescaler

#define  N_samples  128              // Number of samples in lookup table

#define  Fck        Xtal/prescaler   // Timer1 working frequency

#define  delaycyc   10               // port B setup delay cycles



// Function prototype

void init(void);

void delay(void);

void keypad_scan(void);



/************************** Sin Table **********************

* Samples table : one period sampled on 128 samples and   *

* quantized on 7 bit                                      *

***********************************************************/

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  

Table of x_SW (excess 8):

x_SW = ROUND(8*N_samples*f*510/Fck)

*************************************/



//high frequency (coloun)

//1209hz  ---> x_SW = 79

//1336hz  ---> x_SW = 87

//1477hz  ---> x_SW = 96

//1633hz  ---> x_SW = 107



const unsigned char auc_frequencyH[4] = {

107, 96, 87, 79};



//low frequency (row)

//697hz  ---> x_SW = 46

//770hz  ---> x_SW = 50

//852hz  ---> x_SW = 56

//941hz  ---> x_SW = 61



const unsigned char auc_frequencyL[4] = {

61, 56, 50, 46};





/*******************************  Global Variables  *********************************/

unsigned char x_SWa = 0x00;               // step width of high frequency

unsigned char x_SWb = 0x00;               // step width of low frequency

unsigned int  i_CurSinValA = 0;           // position freq. A in LUT (extended format)

unsigned int  i_CurSinValB = 0;           // position freq. B in LUT (extended format)

unsigned int  i_TmpSinValA;               // position freq. A in LUT (actual position)

unsigned int  i_TmpSinValB;               // position freq. B in LUT (actual position)



/****** Main *******/

void main (void)

{

  init();

  keypad_scan();

}





/******************************

Initialization

*******************************/

void init (void)

{

  TIMSK  = 0x04;            // Timer1 溢出中断允许

  TCCR1A = 0x81;            // 正相8位PWM输出

  TCCR1B = 0x01;            // Timer1工作频率 = 系统时钟频率/1

  DDRD   = 0x20;            // PD5 (OC1A) 用于输出信号

  #asm("sei")                   // 全局中断使能

}



/*****************************

4*4 keypad scanner

******************************/

void keypad_scan(void)

{

  unsigned char uc_Input;

  unsigned char uc_Counter = 0;



  for(;;){

    // high nibble - rows

    DDRB  = 0x0F;                     // high nibble input / low nibble output

    PORTB = 0xF0;                     // high nibble pull up / low nibble low value

    uc_Counter = 0;

    delay();                          // wait for Port B lines to be set up correctly

    uc_Input = PINB;                  // read Port B

    do

    {

      if(!(uc_Input & 0x80))          // check if MSB is low

      {

                                      // if yes get step width and end loop

        x_SWb = auc_frequencyL[uc_Counter];  

        uc_Counter = 4;

      }

      else

      {

        x_SWb = 0;                    // no frequency modulation needed

      }

      uc_Counter++;

      uc_Input = uc_Input << 1;       // shift Bits one left

    } while ((uc_Counter < 4));



    // low nibble - columns

    DDRB  = 0xF0;                     // high nibble output / low nibble input

    PORTB = 0x0F;                     // high nibble low value / low nibble pull up

    uc_Counter = 0;

    delay();                          // wait for Port B lines to be set up correctly

    uc_Input = PINB;

    uc_Input = uc_Input << 4;     

    do

    {

      if(!(uc_Input & 0x80))          // check if MSB is low

      {

                                      // if yes get delay and end loop

        x_SWa = auc_frequencyH[uc_Counter];

        uc_Counter = 4;

      }

      else

      {

        x_SWa = 0;                 

      }

      uc_Counter++;

      uc_Input = uc_Input << 1;

    } while (uc_Counter < 4);

  }

}



/********************************

Time delay to ensure a correct

setting of the pins of Port B

*********************************/

void delay (void)

{

  int i;

  for (i = 0; i < delaycyc; i++)

    #asm("nop")

}



/**********************************************



Timer1 Overflow Interrupt Service Routine



***********************************************/

interrupt [TIM1_OVF] void ISR_T1_Overflow (void)

{

  // move Pointer about step width aheaed

  i_CurSinValA += x_SWa;      

  i_CurSinValB += x_SWb;

  

  // normalize Temp-Pointer

  i_TmpSinValA = (char)(((i_CurSinValA + 4) >> 3)&(0x007F));

  i_TmpSinValB = (char)(((i_CurSinValB + 4) >> 3)&(0x007F));

  

  // calculate PWM value: high frequency value + 3/4 low frequency value

  OCR1A = (auc_SinParam[i_TmpSinValA] + (auc_SinParam[i_TmpSinValB] - (auc_SinParam[i_TmpSinValB] >> 2)));

}
(494087256)

出0入4汤圆

发表于 2005-11-28 17:49:03 | 显示全部楼层
上面的程序是根据 ATMEL 网站上的C源码改的(根据 ATmega16L 的 datasheet)

主要更改了以后部分:

/******************************

Initialization

*******************************/

void init (void)

{

  TIMSK  = 0x04;            // Timer1 溢出中断允许

  TCCR1A = 0x81;            // 正相8位PWM输出

  TCCR1B = 0x01;            // Timer1工作频率 = 系统时钟频率/1

  DDRD   = 0x20;            // PD5 (OC1A) 用于输出信号

  #asm("sei")                   // 全局中断使能

}



还有就是头文件部分,ATMEL 的包含头文件部分是这样的:

#include <stdio.h>

#define __IAR_SYSTEMS_ASM__   

#include <io4414.h>

#include "ina90.h"



Application Note 中的汇编程序,把

.include "4414def.inc"

改为

.include "m16def.inc"

就在AVR Studio中调试成功,输出了相应的DTMF信号。(几乎和电话声音拨号声一样)



但是,我上面所贴的那个程序在 CodeVision 中编译后写入 mcu ,按键时,虽然能发出音频信号,但是,有很大的噪音!
(494087158)

出0入4汤圆

发表于 2005-11-28 17:50:41 | 显示全部楼层
不知何故?
(494006995)

出0入4汤圆

发表于 2005-11-29 16:06:44 | 显示全部楼层
输出噪音很大,如果用另一片 mcu + Motorola MT8870 之类的 DTMF 解码芯片能解码出正确的数字,那应该说明生成的正弦波叠加信号(DTMF)是正确的。



我再继续折腾吧!不弄个清楚决不罢休。
(493110064)

出0入0汤圆

 楼主| 发表于 2005-12-10 01:15:35 | 显示全部楼层
输出后应该串入模拟的低通滤波器电路,把高频的数字噪声去掉。
(482339021)

出0入0汤圆

发表于 2006-4-13 17:12:58 | 显示全部楼层
f(x) = 64 + 63 * sin(2πx/180)  x∈[0…127]  

这个公式是什么意思啊

我看不太懂

为什么生成占空比不一的pwm波,而近似是一个正弦波
(451758952)

出0入0汤圆

发表于 2007-4-2 15:40:47 | 显示全部楼层
请教:我在用PWM输出的时候,ATMEGA8515不能响应外部中断,不知是不是中断优先的问题,为能响应外部中断,要不要关掉T1的中断触发允许?
(450777117)

出0入0汤圆

 楼主| 发表于 2007-4-14 00:24:42 | 显示全部楼层
外部中断的优先级比内部中断都高,检查你外部中断的初始化和设置。
(448140737)

出0入0汤圆

发表于 2007-5-14 12:44:22 | 显示全部楼层
谢谢,
(448062273)

出0入0汤圆

发表于 2007-5-15 10:32:06 | 显示全部楼层
请问定时器的PWM功能,和输出比较功能有什么差别?

用输出比较方式不也能生成PWM波吗?
(448058281)

出0入0汤圆

 楼主| 发表于 2007-5-15 11:38:38 | 显示全部楼层
定时器的PWM功能用到了比较匹配输出,它是自动PWM生成方式。



仅用输出比较方式(ctc)不能生成PWM波。



具体讲区别在:



PWM方式时,定时器的计数从0到TOP过程中,与比较寄存器相同时,将自动将输出情“0”(或置“1”);而当从TOP值回零时,是自动将输出置“1”(或清“0”的)。因此程序员需要在比较中断服务中改变比较寄存器的值来改变占空比即可。



而比较匹配输出(ctc)模式是不能产生PWM的。实际上你认为的可以,是T/C工作在正常计数器模式,配合输出比较功能的使用。这种情况也可以产生PWM,但程序中必须使用溢出中断,在溢出中断中用软件改变输出电平。另外程序员还是需要在比较中断服务中改变比较寄存器的值来改变占空比。这种使用方式不如PWM方式方便,需要多用一个中断,消耗更多CPU的效率,所以在手册中说明不提倡使用这种方式产生PWM。
(448055411)

出0入0汤圆

发表于 2007-5-15 12:26:28 | 显示全部楼层
谢谢马老师的精彩点评
(448055399)

出0入0汤圆

发表于 2007-5-15 12:26:40 | 显示全部楼层
谢谢马老师的精彩点评
(448055395)

出0入0汤圆

发表于 2007-5-15 12:26:44 | 显示全部楼层
谢谢马老师的精彩点评
(426676440)

出0入0汤圆

发表于 2008-1-17 23:02:39 | 显示全部楼层
好好学习了,谢马老师了!
(412847510)

出0入0汤圆

发表于 2008-6-26 00:24:49 | 显示全部楼层
这个公式是怎么来的呀?
(412817147)

出0入0汤圆

发表于 2008-6-26 08:50:52 | 显示全部楼层
谢谢
(410916827)

出0入0汤圆

发表于 2008-7-18 08:42:52 | 显示全部楼层
学习了
(410726941)

出625入0汤圆

发表于 2008-7-20 13:27:38 | 显示全部楼层
谢谢LZ了,正在学习AVR
(406241645)

出0入0汤圆

发表于 2008-9-10 11:22:34 | 显示全部楼层
顶上去。
(391539609)

出0入0汤圆

发表于 2009-2-27 15:16:30 | 显示全部楼层
谢谢LZ了..........
(381513431)

出0入0汤圆

发表于 2009-6-23 16:19:28 | 显示全部楼层
原来觉得05年的贴现在顶觉得过意不去了。不过怀着对知识的渴望。学习了有收获了就应该顶下!!
i love the website,thanks to MR ma and armok.
(376774503)

出0入0汤圆

发表于 2009-8-17 12:41:36 | 显示全部楼层
谢谢
(374447283)

出0入0汤圆

发表于 2009-9-13 11:08:36 | 显示全部楼层
mark
(374272680)

出0入0汤圆

发表于 2009-9-15 11:38:39 | 显示全部楼层
学习了。!!
(374194424)

出0入0汤圆

发表于 2009-9-16 09:22:55 | 显示全部楼层
学习学习
(374193687)

出0入0汤圆

发表于 2009-9-16 09:35:12 | 显示全部楼层
谢谢,学习。
(369665828)

出0入0汤圆

发表于 2009-11-7 19:19:31 | 显示全部楼层
ji
(368837496)

出0入0汤圆

发表于 2009-11-17 09:25:03 | 显示全部楼层
好帖,不能不顶!!!
(368359643)

出0入0汤圆

发表于 2009-11-22 22:09:16 | 显示全部楼层
(367947118)

出0入0汤圆

发表于 2009-11-27 16:44:41 | 显示全部楼层
又学了一遍,谢谢。
(366550605)

出0入0汤圆

发表于 2009-12-13 20:39:54 | 显示全部楼层
学习!
(364896103)

出0入0汤圆

发表于 2010-1-2 00:14:56 | 显示全部楼层
这个一定要留名…
(362077232)

出0入0汤圆

发表于 2010-2-3 15:16:07 | 显示全部楼层
\(^o^)/~
(361872031)

出0入0汤圆

发表于 2010-2-6 00:16:08 | 显示全部楼层
收获很大。
(360683930)

出0入0汤圆

发表于 2010-2-19 18:17:49 | 显示全部楼层
回复【楼主位】machao
-----------------------------------------------------------------------
做个记号,谢谢楼主
(358258561)

出0入0汤圆

发表于 2010-3-19 20:00:38 | 显示全部楼层
懂了一点 谢谢老师
(351159189)

出0入0汤圆

发表于 2010-6-10 00:03:30 | 显示全部楼层
谢谢马老师,我的良师益友,支持你
(350690210)

出0入0汤圆

发表于 2010-6-15 10:19:49 | 显示全部楼层
mark
(345589029)

出0入0汤圆

发表于 2010-8-13 11:19:30 | 显示全部楼层
mark
(345328778)

出0入0汤圆

发表于 2010-8-16 11:37:01 | 显示全部楼层
mark
(332454466)

出0入0汤圆

发表于 2011-1-12 11:48:53 | 显示全部楼层
关注下
(328561881)

出0入0汤圆

发表于 2011-2-26 13:05:18 | 显示全部楼层
收获很大,顶
(328558156)

出0入0汤圆

发表于 2011-2-26 14:07:23 | 显示全部楼层
MARK
(326107893)

出0入0汤圆

发表于 2011-3-26 22:45:06 | 显示全部楼层
mark
(313925320)

出0入0汤圆

发表于 2011-8-14 22:47:59 | 显示全部楼层
回复【9楼】machao
-----------------------------------------------------------------------

不可以使用 PWM时 icp功能断开 datasheet里说明了
(313659082)

出0入0汤圆

 楼主| 发表于 2011-8-18 00:45:17 | 显示全部楼层
回复【78楼】dody1209 小卿
回复【9楼】machao  
-----------------------------------------------------------------------
不可以使用 pwm时 icp功能断开 datasheet里说明了
-----------------------------------------------------------------------

请把datasheet里说明贴上(英文的)。
(312135619)

出0入0汤圆

发表于 2011-9-4 15:56:20 | 显示全部楼层
mark
(310584424)

出0入0汤圆

发表于 2011-9-22 14:49:35 | 显示全部楼层
mark
(309637268)

出0入0汤圆

发表于 2011-10-3 13:55:31 | 显示全部楼层
关注下
(308074027)

出0入0汤圆

发表于 2011-10-21 16:09:32 | 显示全部楼层
很好啊
(305492204)

出0入0汤圆

发表于 2011-11-20 13:19:55 | 显示全部楼层
本帖最后由 machao 于 2013-3-11 11:34 编辑

此贴从05年讨论到现在,神奇啊,顶起,我想问下在pwm模式下当计数值等于top值时,能不能产生溢出中断,datasheet上说当计数值到的top值时溢出标志位置位,如果我使能了全局中断和溢出中断,应该能产生才对,但我之前试过让定时器1(mega128)工作在快速pwm模式,top值由ICP1决定,使能比较匹配中断和溢出中断,让一个io口在比较匹配时拉低,溢出时再置高,有点类似用比较匹配输出(ctc)模式产生pwm,但用示波器观察,那个IO口却没有pwm输出,如果去掉溢出中断,单独使用比较匹配中断(就是简单在比较匹配中断里翻转一下那个IO口电平),用示波器看得到IO口电平确实又被翻转,所以我怀疑是不是比较匹配中断不能和溢出中断一起使用,望指教

=============================================================
神奇在于8年里各个学校的教学还是以过时的51为主,教材也是老的。(至少也应该使用改良51,如STC12C5A60S2,使用里面的新功能)。

首先我判定你是学51的,根本不知道使用你所描述的方法产生PWM是多么的低效率。新的芯片和许多改良51都具备自动产生PWM的功能,应该掌握新的方法。

如果你一定要用你上面的方法,或者想弄明白道理,那就是你使用了错误的工作方式或错误的设置。

在使用PWM模式时,通常只需要一个中断,比较匹配中断,在中断中改变比较匹配寄存器的值就可以了(改变占空比),根本不需要拉低或置位I/O的,硬件上会自动在一个指定的I/O上产生PWM波。
另外,比较匹配寄存器的值不能超过TOP值。(不明白的是,你连基本产生PWM的功能都不明白,为什么使用ICP1决定TOP值的方法?)
(281723251)

出0入0汤圆

发表于 2012-8-21 15:49:08 | 显示全部楼层
很多年过去了,终于用到了。终于得以了解其真相了。谢谢!
(264549586)

出0入0汤圆

发表于 2013-3-8 10:16:53 | 显示全部楼层
请教个问题:我用pwm驱动步进电机,一开始好好的,串口开始收数据时步进电机就乱转(一会正转,一会反转,速度还挺快),请教一下这是什么原因呢?(串口数据比较多)是串口中断影响了吗?
(264285529)

出0入0汤圆

 楼主| 发表于 2013-3-11 11:37:50 | 显示全部楼层
wangyeqing333 发表于 2013-3-8 10:16
请教个问题:我用pwm驱动步进电机,一开始好好的,串口开始收数据时步进电机就乱转(一会正转,一会反转, ...

为什么用PWM驱动步进电机?如何驱动的?PWM如何产生的?先解释清楚这些问题
(264285504)

出0入0汤圆

 楼主| 发表于 2013-3-11 11:38:15 | 显示全部楼层
lauyual 发表于 2011-11-20 13:19
此贴从05年讨论到现在,神奇啊,顶起,我想问下在pwm模式下当计数值等于top值时,能不能产生溢出中断,data ...

神奇在于8年里各个学校的教学还是以过时的51为主,教材也是老的。(至少也应该使用改良51,如STC12C5A60S2,使用里面的新功能)。

首先我判定你是学51的,根本不知道使用你所描述的方法产生PWM是多么的低效率。新的芯片和许多改良51都具备自动产生PWM的功能,应该掌握新的方法。

如果你一定要用你上面的方法,或者想弄明白道理,那就是你使用了错误的工作方式或错误的设置。

在使用PWM模式时,通常只需要一个中断,比较匹配中断,在中断中改变比较匹配寄存器的值就可以了(改变占空比),根本不需要拉低或置位I/O的,硬件上会自动在一个指定的I/O上产生PWM波。
另外,比较匹配寄存器的值不能超过TOP值。(不明白的是,你连基本产生PWM的功能都不明白,为什么使用ICP1决定TOP值的方法?)
(261355491)

出0入0汤圆

发表于 2013-4-14 09:31:48 | 显示全部楼层
记录一下
(261130655)

出0入0汤圆

 楼主| 发表于 2013-4-16 23:59:04 | 显示全部楼层
yinhe 发表于 2013-4-14 09:31
记录一下

呵呵,你到处记录,看懂和理解了多少?我坛子里的精品贴,一般人是看不懂的。
(252485000)

出0入0汤圆

发表于 2013-7-26 01:33:19 | 显示全部楼层
本帖最后由 fx8125 于 2013-7-26 01:52 编辑

马老师请问一下改变顶部值照样使用OC1A脚位输出吗??
我看手册写说如果使用OCR1A改变TOP值就不能使用OC1A输出
那么我该如何对示波器看显事呢?新手不好意思

忘记问马老师老师你出的书编译器是真相与和解委员会吗?感谢老师解答
(252461834)

出0入0汤圆

发表于 2013-7-26 07:59:25 | 显示全部楼层
mark......
(249174176)

出0入0汤圆

发表于 2013-9-2 09:13:43 | 显示全部楼层
马老师 原来长这样呀  
(231655506)

出0入0汤圆

发表于 2014-3-24 03:31:33 | 显示全部楼层
MARK MARK MARK
(222561034)

出0入0汤圆

发表于 2014-7-7 09:46:05 | 显示全部楼层
潮哥就是牛呀。
(216635758)

出0入0汤圆

发表于 2014-9-13 23:40:41 | 显示全部楼层
学习了,这是个好东西
(216609583)

出0入0汤圆

发表于 2014-9-14 06:56:56 | 显示全部楼层
长期潜水员,躺枪了,努力发帖升级
(216602213)

出0入0汤圆

发表于 2014-9-14 08:59:46 | 显示全部楼层
学习了,很好的总结!
(216600817)

出0入0汤圆

发表于 2014-9-14 09:23:02 | 显示全部楼层
长期潜水员,躺枪了,努力发帖升级
(211582993)

出0入0汤圆

发表于 2014-11-11 11:13:26 | 显示全部楼层
mark~~~~~~~~~~~~
(55536351)

出0入0汤圆

发表于 2019-10-22 13:30:48 | 显示全部楼层
好资料,谢谢!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子论坛 ( 公安交互式论坛备案:44190002001997 粤ICP备09047143号 )

GMT+8, 2021-7-26 08:16

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表