在 Atmel AVR studio 中使用 ATMega2560 读取 RC PWM 信号

Posted

技术标签:

【中文标题】在 Atmel AVR studio 中使用 ATMega2560 读取 RC PWM 信号【英文标题】:Read RC PWM signal using ATMega2560 in Atmel AVR studio 【发布时间】:2015-10-29 10:24:29 【问题描述】:

我正在尝试将几个 PWM 信号从 RC 接收器读取到 ATMega 2560。我无法理解 ICRn 引脚的功能,因为它似乎用于所有三个比较寄存器。

RC PWM 信号的周期为 20ms,其中 2ms 的 HIGH 脉冲为有效上限值,1ms 为有效下限值。所以该值将从 1000us 扫描到 2000us。该周期应从脉冲的上升沿开始。

我已将 16MHz 时钟预分频 8 以拥有一个 2MHz 定时器,因此应该能够以 0.5us 的精度测量信号,这足以满足我的要求。

请注意,我对 PWM 输出没有任何问题,这个问题专门针对 PWM 输入。

到目前为止,我的代码附在下面。我知道我必须使用 ICR3 和 ISR 来测量 PWM 值,但我不确定执行此操作的最佳程序。我也不知道如何检查测量的值是来自 PE3、PE4 还是 PE5。这段代码是否正确?如何获得我正在寻找的价值?

任何帮助将不胜感激。

// Set pins as inputs
DDRE |= ( 0 << PE3 ) | ( 0 << PE4 ) | ( 0 << PE5 );

// Configure Timers for CTC mode
TCCR3A |=   ( 1 << WGM31 ) | ( 1 << WGM30 ); // Set on compare match
TCCR3B |=   ( 1 << WGM33 ) | ( 1 << WGM32 ) | ( 1 << CS31); // Set on compare match, prescale_clk/8

TCCR3B |=   ( 1 << ICES5 ) // Use rising edge as trigger

// 16 bit register - set TOP value
OCR3A = 40000 - 1;
OCR3B = 40000 - 1;
OCR3C = 40000 - 1;

TIMSK3 |= ( 1 << ICIE3 );

【问题讨论】:

【参考方案1】:

几个月前我忘记发布我的解决方案,所以在这里......

我最后使用了一个 PPM 接收器,因此可以轻松编辑此代码以读取简单的 PWM。

在我的头文件中,我为我的项目使用的 6 通道接收器创建了一个结构。对于具有更多或更少频道的接收器,这可以根据需要进行更改。

#ifndef _PPM_H_
#define _PPM_H_

// Libraries included
#include <stdint.h>
#include <avr/interrupt.h>

struct orangeRX_ppm 
    uint16_t ch[6];
    ;
volatile unsigned char ch_index;
struct orangeRX_ppm ppm;

/* Functions */
void ppm_input_init(void); // Initialise the PPM Input to CTC mode
ISR( TIMER5_CAPT_vect ); // Use ISR to handle CTC interrupt and decode PPM

#endif /* _PPM_H_ */

然后我的 .c 文件中有以下内容。

// Libraries included
#include <avr/io.h>
#include <stdint.h>
#include "ppm.h"

/*      PPM INPUT
 *      ---
 *      ICP5    Pin48 on Arduino Mega
 */
void ppm_input_init(void)

    DDRL |= ( 0 << PL1 ); // set ICP5 as an input

    TCCR5A = 0x00; // none
    TCCR5B = ( 1 << ICES5 ) | ( 1 << CS51); // use rising edge as trigger, prescale_clk/8
    TIMSK5 = ( 1 << ICIE5 ); // allow input capture interrupts

    // Clear timer 5
    TCNT5H = 0x00;
    TCNT5L = 0x00;


// Interrupt service routine for reading PPM values from the radio receiver.
ISR( TIMER5_CAPT_vect )

    // Count duration of the high pulse
    uint16_t high_cnt; 
    high_cnt = (unsigned int)ICR5L;
    high_cnt += (unsigned int)ICR5H * 256;

    /* If the duration is greater than 5000 counts then this is the end of the PPM signal 
     * and the next signal being addressed will be Ch0
     */
    if ( high_cnt < 5000 )
    
        // Added for security of the array
        if ( ch_index > 5 )
        
            ch_index = 5;
        

        ppm.ch[ch_index] = high_cnt; // Write channel value to array

        ch_index++; // increment channel index
    
    else
    
        ch_index = 0; // reset channel index
    

    // Reset counter
    TCNT5H = 0;
    TCNT5L = 0;

    TIFR5 = ( 1 << ICF5 ); // clear input capture flag

每次 ICP5 从低到高时,此代码都会使用触发 ISR。在此 ISR 中,16 位 ICR5 寄存器“ICR5H

我附上了在我的示波器上看到的 PPM 图像。

这种读取 PPM 的方法非常有效,因为我们不需要保持轮询引脚来检查它们的逻辑电平。

不要忘记使用 sei() 命令启用中断。否则 ISR 将永远不会运行。

【讨论】:

【参考方案2】:

假设您想要执行以下操作(我并不是说这可以让您准确测量 PWM 信号,但它可以作为如何设置寄存器的示例)

三个计时器正在运行,每 20 毫秒重置一次。这可以通过将它们设置为 OCRnA 的 CTC 模式来完成:wgm3..0 = 0b0100。

//timer 1
TCCR4A = 0;
TCCR1B = (1<<CS11) | (1<<WGM12);
OCR1A = 40000 - 1;
//timer 3 (there's no ICP2)
TCCR3A = 0;
TCCR3B = (1<<CS31) | (1<<WGM32);
OCR3A = 40000 - 1;
//timer 4
TCCR4A = 0;
TCCR4B = (1<<CS41) | (1<<WGM42);
OCR4A = 40000 - 1;

现在将三个 pwm 信号中的每一个连接到它们自己的 ICPn 引脚(其中 n = 定时器)。检查数据表中不同 ICPn 引脚的位置(我很确定它不是 PE3、4、5)

假设 pwm 信号在 t=0 时开始为高电平,并在其高电平时间后在该周期的剩余时间内变为低电平。您想测量高电平时间,因此我们会在 ICPn 引脚上出现下降沿时触发一个中断。

TCCRnB 寄存器中的位 ICESn 设置为 0 将选择下降沿(这在前面的代码块中已经完成)。

要触发中断,请设置相应的中断使能位:

TIMSK1 |= (1<<ICIE1);
TIMSK3 |= (1<<ICIE3);
TIMSK4 |= (1<<ICIE4);
sei();

现在,每次为 ICn 触发中断时,您都可以获取 ICRn 寄存器以查看下降沿发生的时间(以时钟周期/8 为单位)。

【讨论】:

以上是关于在 Atmel AVR studio 中使用 ATMega2560 读取 RC PWM 信号的主要内容,如果未能解决你的问题,请参考以下文章

初学者:AVR C++ Atmel Studio 6

ATMEL AVR STUDIO 程序

将 Arduino 库添加到 Atmel Studio 7 AVR C++ 项目 - 缺少 Arduino.h

如何在不创建新项目的情况下更改 Atmel Studio 6 中 C++ 的 avr32-gcc C 编译器?

使用 Atmel Studio 作为通用 C 编译器

在 atmel studio7 中更改起始地址 .hex