Нещодавно я почав освоювати програмування на базі мікроконтролерів ATmega. Зацікавило, що ці навички можна застосувати і для моделізму.
Після перших експериментів з кнопочками та світлодіодами, захотілося зробити щось корисне та пов’язане з моделізмом. Мій вибір припав на “Сервотестер“. За основу функціоналу сервотестера було взято готовий екземпляр Turnigy Servo Tester.

Як працює серва

Серви, що застосовуються в моделізмі, використовують три дроти для роботи. Дріт для живлення зазвичай від 4.8В до 6В, загальний дріт (земля) і сигнальний дріт. Керуючий сигнал передає інформацію про необхідне положення вихідного валу. Вал пов’язаний із потенціометром, який визначає його положення. Контролер у серві по опору потенціометра і значенням сигналу, що управляє, визначає, в яку сторону потрібно обертати мотор, щоб отримати потрібне положення вихідного валу. Чим вище напруга живлення серви, тим швидше вона працює та більший момент розвиває.
Керуючий сигнал
Керуючий сигнал є імпульсами змінної ширини. Імпульси повторюються із постійною частотою (як правило, із частотою 50Гц). Положення серви визначається шириною імпульсу. Для типової серви, яка використовується в радіокерованих моделях, тривалість імпульсу 1500 мкс означає, що серва повинна зайняти середнє положення. Збільшення або зменшення довжини імпульсу змусить серву повернутися за годинниковою або проти годинникової стрілки відповідно.

Таким чином, для управління сервою нам потрібно формувати ШІМ (PWM) із частотою 50 герц. При цьому для положення “0” тривалість імпульсу повинна становити 1000 мікросекунд, а для положення “максимум” 2000 мікросекунди. Середнє положення – 1500 мікросекунд.
Схема сервотестера

Мій сервотестер працюватиме з двома сервами. На ньому буде три світлодіоди, що відображають режим сервотестера. ШІМ (PWM) буде формуватися за допомогою мікроконтролера ATMega8, а сигнал, що задає, буде формуватися за допомогою потенціометра. Управляючі сигнали для серв формуються на ногах OC1A, OC1B. Режими перемикатимуться кнопкою.
- Режим 1 – положення серв задається потенціометром;
- Режим 2 – задається середнє положення сірв;
- Режим 3 – сигнал, що задає, циклічно змінюється від одного крайнього положення до іншого.
Живлення сервотестора здійснюється від батарей напругою 6-12В.
Друкована плата

Завантажити – файл друкованої плати у форматі *.lay можна завантажити за цим посиланням.
Вихідний код
#include <stdio.h>
#include <avr/io.h>
#include <util/delay.h>
//=================================== АЦП ==================================
//Ініціалізація АЦП:
void adc_init(void){
ADCSRA = _BV(ADEN) | _BV(ADPS0) | _BV(ADPS1) | _BV(ADPS2); // prescaler = 128
}
//Чтение канала АЦП:
uint32_t adc_read(uint8_t ch){
ADMUX = _BV(REFS0) | (ch & 0x1F); // set channel (VREF = VCC)
ADCSRA &= ~_BV(ADIF); // clear hardware "conversion complete" flag
ADCSRA |= _BV(ADSC); // start conversion
while(ADCSRA & _BV(ADSC)); // wait until conversion complete
return ADC; // read ADC (full 10 bits);
}
int main() {
char mode=0; // Режим - за замовчуванням 0
int direct=0;
uint16_t adc_result;
#define ICR_MAX F_CPU/50 // ICR1(TOP) = fclk/(N*f) ; N-Делитель; f-Частота; 1000000/1/50 = 20000
#define OCR_MIN ICR_MAX/20
#define OCR_MAX ICR_MAX/10
#define OCR_CENTER (ICR_MAX/4/10)*3
// На порту кнопки включаємо підтягуючий резистор
DDRB &= ~(1<<4);
PORTB |= (1<<4);
// Налаштовуємо порт світлодіодів
DDRC = (1<<1) | (1<<2) | (1<<3);
PORTC |= (1<<(mode+1));
// Налаштовуємо PWM на таймері 1 (вихід на ногах PB1, PB2)
TCCR1A = 0; // Відключаємо PWM поки конфігуруватимемо
ICR1 = ICR_MAX; // Частота завжди 50 Гц
// Включаємо Fast PWM mode via ICR1 на Таймері 1 без дільника частоти
TCCR1A = (1<<WGM11);
TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
// Встановлює PB1 та PB2 як вихід
DDRB |= (1<<1) | (1<<2);
// Включаємо PWM на port B1 та B2
TCCR1A |= (1<<COM1A1) | (1<<COM1B1);
// Включаємо АЦП
adc_init();
while(1){
// Якщо кнопка натиснута (Переключення режимів)
if ((PINB & (1<<4)) == 0)
{
// Чекаємо поки кнопку відпустять
while ((PINB & (1<<4)) == 0) {
_delay_ms(200);
}
mode++;
if (mode > 2) {
mode = 0;
}
// Включаємо потрібний світлодіод
PORTC &= ~((1<<1) | (1<<2) | (1<<3));
PORTC |= (1<<(mode+1));
}
switch (mode){
case 0:{
// Задаємо положення сервомеханізму, залежно від положення потенціометра adc_result
adc_result=adc_read(0);
OCR1A = OCR_MIN+(adc_result * (OCR_MAX-OCR_MIN)/1024);
OCR1B = OCR1A;
break;
}
case 1:{
// Задаємо центральне положення серви
direct=0;
OCR1A = OCR_CENTER;
OCR1B = OCR1A;
break;
}
case 2:{
// Циклічна зміна положення серви
if (direct==0){
OCR1A++;
OCR1B++;
if (OCR1A >= OCR_MAX) {
direct=1;
}
}
if (direct==1){
OCR1A--;
OCR1B--;
if (OCR1A <= OCR_MIN) {
direct=0;
}
}
_delay_ms(1);
break;
}
}
}
}
Завантажити – усі ресурси проекту (плата, прошивка, вихідний код).
Фюзи не чіпати! Всі значення за замовчуванням. Кого таки цікавлять значення за замовчуванням, їх легко знайти у пошуку.
І на завершення статті відеоогляд роботи сервотестера:
Хочу висловити велику подяку за допомогу в реалізації проекту Корягину Андрію (створення друкованої плати та оптимізація коду).



Залишити відповідь