REKLAMA

Servo_controller.zip

Sterownik 12 serw modelarskich na atmega8a

http://obrazki.elektroda.pl/7091107600_1376594921_thumb.jpg Witam! Dzisiaj chciałbym przedstawić mój sterownik serwomechanizmów opary na znanym i (nie)lubianym mikrokontrolerze Atmega8a. http://obrazki.elektroda.pl/8171207800_1376595226_thumb.jpg Jak widać schemat jest banalnie prosty i składa się z dosłownie paru elementów, co pozwoliło ograniczyć koszty i stopień skomplikowania płytki, która wygląda następująco: http://obrazki.elektroda.pl/6690724200_1376595352_thumb.jpg Płytek nie wytrawiałem sam tylko je zamówiłem - są niewielkie, więc mogłem w miarę tanio wypróbować firmę :) http://obrazki.elektroda.pl/3297898600_1376595596_thumb.jpg Sterownik podaje co 17,5 ms na wejścia serw impulsy o długości 0,5 - ~2,5ms z rozdzielczością 8µs (8µs * 255 = ~ 2ms). Sterowanie odbywa się za pomocą interfejsu USART mikrokontrolera (pinologia płytki przystosowana jest do modułu bluetooth HC-05, ale nic nie stoi na przeszkodzie, żeby skorzystać z dowolnego innego źródła sygnału RS232). Sterowanie odbywa się za pomocą prostej ramki składającej się z trzech bajtów, pierwszy to zawsze liczba 170, drugi - kod Ascii wielkiej litery od 'A' do 'L', odpowiadającej jednemu z 12 serw a trzeci - nastawa, z przedziału 0-255. Program napisany w C w całości oparty jest na przerwaniach, mam zamiar go jeszcze zmodyfikować i dodać opcje konfiguracji poszczególnych serw i możliwość ich wyłączenia poprzez zaprzestanie wysyłania sygnałów sterujących. http://obrazki.elektroda.pl/5623145600_1376596932_thumb.jpg W załączniku udostępniam schemat, płytkę, wsad oraz pliki źródłowe programu (projekt Atmel Studio). Chętnie przeczytam wszelkie uwagi i odpowiem na pytania dotyczące projektu! Więcej info na BLOGU Pozdrawiam!


Pobierz plik - link do postu
  • Servo_controller.zip
    • BoardV2.brd
    • BoardV2.sch


Servo_controller.zip > Servo controller.c

/*
* Servo_controller.c
*
* Created: 2013-07-17 17:31:43
* Author: mlodedrwale
*/


#include & lt; avr/io.h & gt;
#include & lt; avr/interrupt.h & gt;

//usart definitions
#define USART_BAUDRATE 9600
#define UART_BAUD_SELECT (((F_CPU) + 8UL * (USART_BAUDRATE)) / (16UL * (USART_BAUDRATE)) -1UL)

// loop counters
volatile uint8_t loop_main;
volatile uint8_t counter_mini_loop;
volatile uint8_t whereiam = 1;
volatile uint8_t current_function = 1;

// uart data register
volatile uint8_t uart_count = 0;
volatile uint8_t uart_data[9];
volatile uint8_t start_byte = 0;
volatile uint8_t uart_shift = 0;

//initial servo values
volatile uint8_t servo1 = 128; //A PC5
volatile uint8_t servo2 = 128; //B PC4
volatile uint8_t servo3 = 128; //C PC3
volatile uint8_t servo4 = 128; //D PC2
volatile uint8_t servo5 = 128; //E PC1
volatile uint8_t servo6 = 128; //F PC0
volatile uint8_t servo7 = 128; //G PB5
volatile uint8_t servo8 = 128; //H PB4
volatile uint8_t servo9 = 128; //I PB3
volatile uint8_t servo10 = 128; //J PB2
volatile uint8_t servo11 = 128; //K PB1
volatile uint8_t servo12 = 128; //L PB0


//naked functions definitions
ISR(TIMER0_OVF_vect) __attribute__ ((naked));

void mini_loop_1(void) __attribute__ ((naked));
void mini_loop_2(void) __attribute__ ((naked));
void mini_loop_3(void) __attribute__ ((naked));
void mini_loop_4(void) __attribute__ ((naked));

typedef void (* mini_loop_pointer) (void);
mini_loop_pointer current_mini_loop;


//PC5 - servo1
//PC4 - servo2
//PC3 - servo3
void mini_loop_1(void)
{
if (servo1 == counter_mini_loop)
{
PORTC & = ~(1 & lt; & lt; PC5);
}
if (servo2 == counter_mini_loop)
{
PORTC & = ~(1 & lt; & lt; PC4);
}
if (servo3 == counter_mini_loop)
{
PORTC & = ~(1 & lt; & lt; PC3);
}
asm volatile ( " ret " );
}

//PC2 - servo4
//PC1 - servo5
//PC0 - servo6
void mini_loop_2(void)
{
if (servo4 == counter_mini_loop)
{
PORTC & = ~(1 & lt; & lt; PC2);
}
if (servo5 == counter_mini_loop)
{
PORTC & = ~(1 & lt; & lt; PC1);
}
if (servo6 == counter_mini_loop)
{
PORTC & = ~(1 & lt; & lt; PC0);
}
asm volatile ( " ret " );
}

//PB5 - servo7
//PB4 - servo8
//PB3 - servo9
void mini_loop_3(void)
{
if (servo7 == counter_mini_loop)
{
PORTB & = ~(1 & lt; & lt; PB5);
}
if (servo8 == counter_mini_loop)
{
PORTB & = ~(1 & lt; & lt; PB4);
}
if (servo9 == counter_mini_loop)
{
PORTB & = ~(1 & lt; & lt; PB3);
}
asm volatile ( " ret " );
}

//PB2 - servo10
//PB1 - servo11
//PB0 - servo12
void mini_loop_4(void)
{
if (servo10 == counter_mini_loop)
{
PORTB & = ~(1 & lt; & lt; PB2);
}
if (servo11 == counter_mini_loop)
{
PORTB & = ~(1 & lt; & lt; PB1);
}
if (servo12 == counter_mini_loop)
{
PORTB & = ~(1 & lt; & lt; PB0);
}
asm volatile ( " ret " );
}

void check_update_registers()
{
if (uart_count & gt; = 2){
if (uart_data[0] == 170){
switch(uart_data[1])
{
case 'A':
servo1 = uart_data[2];
uart_shift = 3;
break;
case 'B':
servo2 = uart_data[2];
uart_shift = 3;
break;
case 'C':
servo3 = uart_data[2];
uart_shift = 3;
break;
case 'D':
servo4 = uart_data[2];
uart_shift = 3;
break;
case 'E':
servo5 = uart_data[2];
uart_shift = 3;
break;
case 'F':
servo6 = uart_data[2];
uart_shift = 3;
break;
case 'G':
servo7 = uart_data[2];
uart_shift = 3;
break;
case 'H':
servo8 = uart_data[2];
uart_shift = 3;
break;
case 'I':
servo9 = uart_data[2];
uart_shift = 3;
break;
case 'J':
servo10 = uart_data[2];
uart_shift = 3;
break;
case 'K':
servo11 = uart_data[2];
uart_shift = 3;
break;
case 'L':
servo12 = uart_data[2];
uart_shift = 3;
break;
}
if (uart_shift == 3){
uart_shift = 0;
uart_count -= 3;
for (int i=0; i & lt; 5; i++){
uart_data[i] = uart_data[i+3];
uart_data[i+3] = 0;
}
}
}
else
{
uart_count -= 1;
for (int i=0; i & lt; 8; i++){
uart_data[i] = uart_data[i+1];

}
uart_data[8] = 0;
}
}
}

//80us
void lo_loop()
{
if(counter_mini_loop & lt; 32){
if ((UCSRA & (1 & lt; & lt; RXC)))
{
uart_count += 1;
uart_data[uart_count] = UDR;
}
check_update_registers();
counter_mini_loop += 1;
}
else {
counter_mini_loop = 0;
whereiam = 2;
current_function +=1;
if (current_function == 1)
{
current_mini_loop = mini_loop_1;
PORTC |= (1 & lt; & lt; PC5) | (1 & lt; & lt; PC4) |(1 & lt; & lt; PC3);
}
if (current_function == 2)
{
current_mini_loop = mini_loop_2;
PORTC |= (1 & lt; & lt; PC2) | (1 & lt; & lt; PC1) |(1 & lt; & lt; PC0);
}
if (current_function == 3)
{
current_mini_loop = mini_loop_3;
PORTB |= (1 & lt; & lt; PB5) | (1 & lt; & lt; PB4) |(1 & lt; & lt; PB3);
}
if (current_function == 4)
{
current_mini_loop = mini_loop_4;
PORTB |= (1 & lt; & lt; PB2) | (1 & lt; & lt; PB1) |(1 & lt; & lt; PB0);
current_function = 0;
}
}
}

// turns servo lines high
void hi_loop()
{
counter_mini_loop +=1;
if ((UCSRA & (1 & lt; & lt; RXC))) //read uart
{
uart_count += 1;
uart_data[uart_count] = UDR;
}
check_update_registers();

if(counter_mini_loop & gt; 7)
{
TIMSK & = ~(1 & lt; & lt; TOIE2); //disable timer2 overflow interrupt
counter_mini_loop = 0;
whereiam = 3;
TCNT0 = 0xF9;
TIMSK = 1 & lt; & lt; TOIE0; //enable timer0 overflow interrupt
}

}

ISR(TIMER0_OVF_vect)
{
TCNT0 = 0xF9; // 8us

current_mini_loop();
counter_mini_loop += 1;

if ((UCSRA & (1 & lt; & lt; RXC))) //read UART
{
uart_count += 1;
uart_data[uart_count] = UDR;
}

if (counter_mini_loop == 0) //255 + 1 == 0 !!
{
TIMSK & = ~(1 & lt; & lt; TOIE0); //disable timer0 overflow interrupt
whereiam = 1;
TCNT2 = 0xB5; // 80ms
TIMSK |= (1 & lt; & lt; TOIE2); //enable timer2 overflow interrupt
}
asm volatile ( " reti " );
}

ISR(TIMER2_OVF_vect)
{
TCNT2 = 0xB5; // 80ms
if (whereiam == 1)
{
lo_loop();
}
if (whereiam == 2)
{
hi_loop();
}
}


int main(void)
{
DDRC = 0xFF;
PORTC = 0;

DDRB = 0xFF;
PORTB = 0;

//UART
UCSRB |= (1 & lt; & lt; RXEN); // Turn on the transmission and reception circuitry
UCSRC |= (1 & lt; & lt; URSEL) | (1 & lt; & lt; UCSZ0) | (1 & lt; & lt; UCSZ1); // Use 8-bit character sizes
UBRRH = (UART_BAUD_SELECT & gt; & gt; 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
UBRRL = UART_BAUD_SELECT; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register

//Timer 0
TCCR0 = (1 & lt; & lt; CS01); //prescaler = 8

//Timer 2
TCCR2 |= (1 & lt; & lt; CS21); //prescaler = 8
TIFR = 1 & lt; & lt; TOV2; //Clear pending interrupts
TIMSK = 1 & lt; & lt; TOIE2; //enable timer2 overflow interrupt
TCNT2 = 0xFE; //do it right now!

sei();

while(1)
{
//simple ;)
}
}