ATtiny10を使ったESC

ATtiny10を使ったESCをなんだかんだで作ってしまったのでメモをかねて公開しておこうと思います。基本的には、サーボ信号(PPM)を受信してPWMに変換しています。PPMの信号は基本は1000us〜2000usまでの間で可変する信号で、大きくなるほどPWM出力を強くしてあげる感じです。

servo_01

プログラムには、「Atmel® Studio 7」と「Atmel-ICE」を使いました。接続方法はTPIと言う方式で接続して書き込みを行います、色々サイトがあるのでそこいら辺を参照して下さい。

img_1857

PB2からサーボ信号を入力してPB0よりPWM出力をします。出力はPB1に変更することも出来ますので載せるデバイスというか基板の回路配置によっては入れ替えられます。

■回路図

ppm_pwm

#include <avr/io.h>
#include <util/delay.h>

#define F_CPU 8000000UL  // internal clock @ 8MHz
#define PWM_MODE_BIT 10
#define PPM_MIN 1008//1520-512=>1008
#define PPM_CENTER 1520//CE/CCW
#define PPM_MAX 2032//1520+512=>2032

#define PPM_LEN 1
#define PWM_MAX 1024
#define PWM_CUT_OFF 975

//#define PPM_LEN ((PPM_MAX - PPM_MIN) / 2^PWM_MODE_BIT)
//#define PWM_CUT_OFF PPM_MIN / ((PPM_MAX - PPM_MIN) / 2^PWM_MODE_BIT)
//#define PWM_MAX PPM_MAX / ((PPM_MAX - PPM_MIN) / 2^PWM_MODE_BIT)

void PWM_setup(void)
{
    TCCR0A  |= ((1 << COM0A1) | (0 << COM0A0)   // COM0A1 - COM0A0 (Clear OC0A on Compare Match when up-counting. Set OC0A on Compare Match when down-counting.)
    //| (1<<COM0B1) | (0<<COM0B0)                   // COM0B1 - COM0B0 (Clear OC0B on Compare Match when up-counting. Set OC0B on Compare Match when down-counting.)
    | (1 << WGM01) | (1 << WGM00));             // WGM01 - WGM00 (set Phase Correct PWM Mode-10Bit_1023step)
    //TCCR0A = (1<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (1<<WGM00);

    TCCR0B  |= (1 << CS01) | (1 << CS00); //clk/8 prescaler
    //TCCR0B = (0<<ICNC0) | (0<<ICES0) | (0<<WGM03) | (0<<WGM02) | (0<<CS02) | (1<<CS01) | (1<<CS00);
    
    OCR0A = 0x0000;
    //OCR0B = 0x0000;
}

void PWM_write(int val)
{
    OCR0A = val; //This value sets the duty cycle 0 to 255 (8-bit timer)
}

int main(void)
{
    // Function: Bit3=In Bit2=Out Bit1=In Bit0=Out
    DDRB |= (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (1<<DDB0);//PortB0 = output(PWM-OCR0A)
    //DDRB |= (0<<DDB3) | (0<<DDB2) | (1<<DDB1) | (1<<DDB0);//PortB0/B1 = output(PWM-OCR0A/OCR0B)
    PUEB |= (0<<PUEB) | (1<<PUEB) | (0<<PUEB) | (0<<PUEB);//PortB2 = input(Servo_In)
    
    // Main Clock source: Internal Clock(8Mhz)
    CCP=0xd8;
    CLKMSR=(0<<CLKMS1) | (0<<CLKMS0);
    
    // Clock Prescaler division factor: 1
    CCP=0xd8;
    CLKPSR=(0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0);
    
    PWM_setup();
    
    uint16_t Pulslen = 0;
    uint16_t TimeOut = 0;
    //const int PWM_CUT_OFF = PPM_MIN/PPM_LEN;
    //const uint8_t PPM_LEN = ((PPM_MAX - PPM_MIN) / pow(2,PWM_MODE_BIT))-.5;
    
    while(1)
    {
        while((PINB&_BV(PB2)))  // while the servoPWM input is high
        {
            Pulslen++; // increment
            _delay_us(PPM_LEN); //resolution setting, may require further adjustment
        }
        if(Pulslen > PWM_CUT_OFF) //throttle must be low initially
        {
            
            while(1)
            {
                
                while((PINB&_BV(PB2)))  // while the servoPWM input is high
                {
                    Pulslen++; // increment
                    _delay_us(PPM_LEN); //resolution setting, may require further adjustment
                }
                
                if (TimeOut > 20000) //this will shut off the motor if the RX signal is lost
                {
                    Pulslen = PWM_CUT_OFF;
                }
                
                if (Pulslen > PWM_CUT_OFF-1)  // ignore false triggers and only set the PWM when a pulse is received
                {
                    Pulslen = (Pulslen - PWM_CUT_OFF);
                    
                    //if(Pulslen<0){Pulslen=0;} //just in case there is a negative
                    
                    if (Pulslen < 8) //lower threshold, produces a dead-band
                    {Pulslen = 0;}
                    
                    if (Pulslen >= PWM_MAX-8) //Full power after crossing a threshold determined by trial and error
                    {Pulslen = PWM_MAX-1;}
                    
                    PWM_write(Pulslen);

                    TimeOut = 0;  //resets the timeout counter
                }
                
                if (Pulslen == 0) //counts every time the loop completes and a pulse is not registered
                {TimeOut++;}
                
                Pulslen = 0; // resets the variable for the next pulse measurement and starts the timeout counter
            }
        }
        else
        {Pulslen = 0;}
    }
}

 

  1. コメントはまだありません。

  1. トラックバックはまだありません。


Warning: Undefined variable $user_ID in /home/r3087696/public_html/blog.eldhrimnir.com/wp-content/themes/monochrome/comments.php on line 172

Fatal error: Uncaught Error: Undefined constant "cs_print_smilies" in /home/r3087696/public_html/blog.eldhrimnir.com/wp-content/themes/monochrome/comments.php:185 Stack trace: #0 /home/r3087696/public_html/blog.eldhrimnir.com/wp-includes/comment-template.php(1617): require() #1 /home/r3087696/public_html/blog.eldhrimnir.com/wp-content/themes/monochrome/single.php(57): comments_template() #2 /home/r3087696/public_html/blog.eldhrimnir.com/wp-includes/template-loader.php(106): include('/home/r3087696/...') #3 /home/r3087696/public_html/blog.eldhrimnir.com/wp-blog-header.php(19): require_once('/home/r3087696/...') #4 /home/r3087696/public_html/blog.eldhrimnir.com/index.php(17): require('/home/r3087696/...') #5 {main} thrown in /home/r3087696/public_html/blog.eldhrimnir.com/wp-content/themes/monochrome/comments.php on line 185