需要帮助了解AVR ATMEGA / ATTINY计时器镜像输出


10

我正在尝试使用Atmel AVR微控制器的Timer1(用于Arduino的AtMega328或ATTiny85)来输出两个彼此互为镜像的时钟信号。我试图生成的频率是一个1 MHz到2 MHz或更高的变量,除非使用控制器中几乎不需要执行的其他任何操作,否则它们太高了,无法使用代码来切换输出引脚。因此,我想直接在关联的引脚上使用计时器输出。我正在使用GCC工具链,因此不受arduino库或语言的限制。

Atmega328中的Timer1有两个与之相关的引脚,我可以从中获得两个相同的1MHz至2MHz信号。尽管数据表似乎说我可以得到一个反相波形,但它使我感到困惑。通过使用Timer1的PWM设置,我还能够获得两个在1 MHz时占空比不同的信号,但是两个信号同时变为高电平,而较短的信号则较早变为低电平。这不适合我的项目。我什至不需要PWM脉冲宽度变化,仅需要两个相位相同的相同“时钟”类型信号即可。

我并不是要有人为此写代码,我只需要有人告诉我定时器的哪个模式/标志应该在与定时器相关的两个引脚之一上给我一个简单的反相波形。如果可能的话,我想避免对其中一个输出使用外部反相电路,除非这是唯一的选择。

如果在ATTiny中完全可行,那就更好了。ATTiny也有2个与一个定时器相关的引脚,但是我不确定它具有与ATMega相同的选项。

我已经在PCB上连接了20 MHz晶体和电容器,并且ATMega328上的20 MHz时钟工作可靠。在ATTiny85 PCB上,我有一个8 MHz的晶体,该晶体也能可靠地工作。

请帮忙。谢谢。


更新:到目前为止,答案和评论中存在一些无效的假设,所以也许我应该澄清一下:请注意,在我的原始帖子中,我已声明我使用的是20 MHz时钟,而不是8 MHz,并且不需要PWM

提供足够高输出频率的唯一模式似乎是CTC模式,因为PWM模式不适用于2 MHz输出。有没有办法在CTC模式下将定时器1的输出A或输出B反相?

我现在已经切换到标准的Arduino Uno(ATMega328,16 MHz)而不是我自己的20 MHz板上来检查我的代码,这是我的代码,用于在CTC模式下从9和10引脚(定时器)获得一个稳定的2 MHz稳定时钟1个输出引脚:

#define tick 9
#define tock 10

void setup() {
  pinMode(tick, OUTPUT);  
  pinMode(tock, OUTPUT); 

  TCCR1A = _BV(COM1A0) | _BV(COM1B0) ;   // activate both output pins 
  TCCR1B = _BV(WGM12)| 1;                // set CTC mode, prescaler mode 1

  // various frustrating attempts to invert OC1B failed. What do I put here?

  OCR1A = 3;                             // set the counter max for 2 MHz

}

void loop() {
}

两个引脚的示波器走线是相同且同步的,如何使两个信号之一反相?数据表中的反相模式在CTC模式下似乎无能为力。我是否读错了数据手册,还是毕竟会被迫使用较低的频率和PWM模式?

在我的原始查询中添加一个特定的“赏金”问题:
因此,我需要对上面的代码进行哪些更改,以使其在引脚9和11处以16 MHz时钟最高可能频率给出完全反相的信号,是否那是不是2 MHz?

我现在将继续使用标准的Arduino Uno,以便我的本地调试板不会引入任何错误模式,因此具有arduino的任何人都可以尝试上面的代码,并确认它可以像我之前提到的那样工作,而不是像我所说的那样工作。需要!


1
查看atmega8L 数据表的第97-98页,其中有一个工作模式表。第108页指出“ COM21:0位控制生成的PWM输出是否应反相(反相或同相PWM)”。让我们发布您的成功!
Vorac 2012年

为什么不对镜像输出使用简单的晶体管逆变器?
Jonny B

Answers:


10

从ATtiny85数据表:

工作模式,即定时器/计数器和输出比较引脚的行为,由波形生成模式(WGM0 [2:0])和比较输出模式(COM0x [1:0])组合定义位。比较输出模式位不会影响计数序列,而波形生成模式位会影响计数序列。COM0x [1:0]位控制生成的PWM输出是否应反相(反相或同相PWM)。

表11-5显示了如何设置模式。

Mode   WGM  WGM  WGM  Timer/Counter Mode    TOP      Update of    TOV Flag
c0     02   01   00   of Operation                   OCRx at      Set on
==========================================================================
0      0    0    0    Normal                0xFF     Immediate    MAX(1)
1      0    0    1    PWM, Phase Correct    0xFF     TOP          BOTTOM
2      0    1    0    CTC                   OCRA     Immediate    MAX
3      0    1    1    Fast PWM              0xFF     BOTTOM       MAX
4      1    0    0    Reserved                                  
5      1    0    1    PWM, Phase Correct    OCRA     TOP          BOTTOM
6      1    1    0    Reserved                                  
7      1    1    1    Fast PWM              OCRA     BOTTOM       TOP

您需要快速PWM模式(因此模式3或模式7)。如果您想改变占空比,听起来像您一样,则需要模式7,并通过设置OCRA来改变占空比。

表11-3显示了如何将比较输出模式设置为快速PWM模式。

COM0A1/   COM0A0/
COM0B1    COM0B0     Description
===============================================================================
0         0          Normal port operation, OC0A/OC0B disconnected.
0         1          Reserved
1         0          Clear OC0A/OC0B on Compare Match, set OC0A/OC0B at BOTTOM
                     (non-inverting mode)
1         1          Set OC0A/OC0B on Compare Match, clear OC0A/OC0B at BOTTOM
                     (inverting mode)

也就是说,通过设置COM0A1:COM0A0 = 0b10,可以将OC0A输出设置为在Timer值== OCR0A时为低电平,在Timer值== 0x00时为高电平。反之亦然,方法是将COM0A1:COM0A0设置为0b11。对于OC0B,OCR0B,COM0B0,COM0B1同样如此。

PWM频率由I / O时钟(听起来像是8MHz)和定时器预分频器设置确定。对于快速PWM模式,公式为f_clk_IO /(N * 256)。

因此,通过将OCR0A和OCR0B设置为相同的值,并将COM0A1:COM0A0 = 0b10和COM0B1:COM0B0设置为0b11,可以将OC0A用于“正常”极性,将OC0B用于“反向”极性。

更新

如果您想尽快切换输出,并且您正在使用以16MHz运行的Mega328,那么CTC工作模式将允许您获得以下开关频率:

f_OCnA = f_clk_IO /(2 * N * [1 + OCRnA)= 16e6 /(2 * 1 * [1 + 1])= 4MHz

快速PWM模式可让您在以下位置切换引脚:

f_OCnxPWM = f_clk_IO /(N * [1 + TOP])= 16e6 /(1 * [1 + 1])= 8MHz

所以我仍然认为您想要快速PWM模式。特别是在占空比为50%的情况下,模式3的OCR0A = OCR0B = 0x80。并将COM0A位设置为0x3,将COM0B位设置为0x2,以使OC0A和OC0B反相上的两个波形相互转换。

更新#2 更多Mega328请尝试以下Arduino代码:

#define tick 9
#define tock 10

void setup(){

  pinMode(tick, OUTPUT);  
  pinMode(tock, OUTPUT); 

  // Setup Waveform Generation Mode 15
  // OC1A Compare Output Mode = inverting mode
  // OC1B Compare Output Mode = non-inverting mode
  // Timer Prescaler = 1
  // TOP = OCR1A = 1

  //COM1A[1:0] = 0b11, COM1B[1:0] = 0b10, WGM1[1:0] = 0b11
  TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(COM1B1) | _BV(WGM11) | _BV(WGM10);

  //WGM1[3:2] = 0b11, CS1[2:0] = 0b001
  TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);

  OCR1A = 0x0001;
  OCR1B = 0x0001;
}

void loop(){

}

让我仔细研究一下,看看是否可行。谢谢。
ExcitingProjects 2012年

在重新阅读了您今天的答案以进行尝试之后,我看到了两个无效的假设:我指定了20 MHz时钟(现在我已经切换到16 MHz),而不是“(听起来像是8MHz)”。我还指定了我不需要PWM脉冲宽度变化,所以不确定您在哪里“如果您想改变占空比,这听起来像您一样”
ExcitingProjects 2012年

@ExcitingProjects我要引用您的陈述“在ATTiny85 PCB上,我有一个8 MHz的晶体,并且也可以可靠地工作。” 我的回答是参考ATtiny85。我会尝试更新我的答案,以回应您的更新问题。
vicatcu,2012年

@vicateu谢谢。我已经更新了问题,因为除非缺少一些步骤,否则反转模式在CTC模式下似乎无效。
ExcitingProjects 2012年

ATmega328数据表中的@ExcitingProjects:“对于非PWM模式,COM0x1:0位控制是否应在比较匹配时设置,清除或切换输出”
vicatcu,2012年

1

ATtinyX5系列里面有PLL,用它大个子。

我也使用内部PLL来为CPU时钟供电,并且在没有XTAL的情况下具有16Mhz。这很珍贵,因为您只有5个引脚。(我不算复位针)。XTAL引脚上还运行一个PLL'ed PWM(OCR1B),具有其可选的互补输出。您只需要为16Mhz Xtalless ATtiny调整保险丝...或者让CPU以8Mhz运行,但以64Mhz时钟运行PWM,而无需更换保险丝。

您最多可以具有64 Mhz时钟PWM(但分辨率为1位)。或125Khz @ 8位分辨率。您可以通过减少OCR1C寄存器来降低PWM分辨率并提高速度。

对于1 Mhz,您需要将OCR1C设置为63。对于2 Mhz,您需要将OCR1C设置为31。对于4 Mhz,您需要将OCR1C设置为15。

只需使用以下代码启用PLL:

PLLCSR |= (1 << PLLE);           //Start PLL
while( !(PLLCSR & (1<<PLOCK)) ); //Wait for PLL lock
//PLLCSR |= (1<<LSM );           //Low Speed PLL that clocks 32Mhz, not 64Mhz
PLLCSR |= (1 << PCKE);           //Enable PLL

现在,“ OCR1B0 / OCR1A0” PWM上具有64 Mhz时钟。

另外,您可以为镜像输出调整OCR1 [A / B] 0和XOCR1 [A / B] 0。

if(0){ //Synch mode
     //OCR1A & XOCR1A enable for Synch operation but not allow odd PWM values!
     TCCR1 |= (1 << PWM1A) | (0 << COM1A1) | (1 << COM1A0); 
     //Also ATtinyX5 has "Dead Time Generator", use it ;)
     DTPS1 = 3;   //8x Prescaler for dead time generator (maximum)
     DT1A = 0xff; //Clk dead on both channels (maximum)
     }
   else
     TCCR1 |= (1 << PWM1A) | (1 << COM1A1) | (0 << COM1A0);  //ONLY OCR1A enabled

您需要知道,如果将OCR1A设置为1,则死区时间发生器将吞噬PWM输出。您需要比空载时间更高的值。

问候,

埃德姆

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.