Brise

[atmega128] RC servo 예제 본문

MCU

[atmega128] RC servo 예제

naudhizb 2017. 4. 22. 23:06
반응형

이 예제에서는 가변저항의 전압값을 읽어온 후 전압값에 따라 서보모터를 움직인다.


가변저항은 이전 adc예제를 이용하여 전압값을 읽어오며, 읽어오는 전압값은


0~5V, 값으로는 0~1023사이의 값으로 읽어들여진다. 



RC 서보모터의 경우 PWM 신호를 받아 동작한다. 


서보모터의 한 주기는 20ms로 1초당 50번 반복되어야 하며

핀의 값이 HIGH인 시간이 0.5ms일 때 서보모터의 각도가 0도가 되며

핀의 값이 HIGH인 시간이 2.5ms일 때 서보모터의 각도가 180도가 된다. 



아트메가128에서 서보모터를 제어하기 위해서 20ms주기의 PWM을 발생시킨다.


아트메가128에는 타이머 1,3(8비트 타이머) 타이머 2,4(16비트 타이머)가 있으며


8비트 타이머로는 충분한 정밀도를 확보하기 어렵기 때문에 16비트 타이머를 사용하도록 한다.



이 예제에서는 16비트 타이머인 타이머 3의 B핀의 PWM을 이용하여 서보모터를 제어한다.


데이터시트에 따르면 OCR3B는 Port E의 4번 핀에 연결되어 있으므로 


서보모터의 신호선을 PE4에 연결한다. 


그리고 서보모터에 GND와 VCC를 연결한다.



연결이 완료 되었으면 소스코드를 작성하여 빌드한 뒤 실행한다.




"main.c"


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#define F_CPU 16000000UL
 
#include <avr/io.h>
#include <util/delay.h>
//#include <avr/delay.h>
#include "nb_adc.h"
#include "nb_pwm.h"
 
float map_value(float value,
                float input_min,
                float input_max,
                float output_min,
                float output_max){
    // need blocker
    float ratio = (value-input_min) / (input_max - input_min);
    float target = 0.0f;
    float output_band = output_max - output_min;
    target += output_min;
    target += ratio * output_band ;
 
    return target;
}
 
#define ADC_MIN                0
#define ADC_MAX                1023
#define SERVO_0_DEG         800
#define SERVO_180_DEG         5000
 
#define FILTER_LEN        8
int main(){
    DDRA = 0xFF;
    PORTA = 0xFF;    
    adc_init();
    pwm3_init();
    int16_t adc_value = 0;
    uint16_t pwm_array[FILTER_LEN];
    uint16_t pwm_value = 0;
    
    while(1){
        for(int i=0; i<FILTER_LEN ; i++){
            adc_value = adc_read();
            pwm_value = (uint16_t) map_value(adc_value, 
                                    ADC_MIN, ADC_MAX, 
                                    SERVO_0_DEG , SERVO_180_DEG);
            pwm_array[i] = pwm_value / FILTER_LEN;
            pwm_value = 0;
            for(int j = 0; j<FILTER_LEN; j++)
                pwm_value += pwm_array[j];
            pwm3_set(pwm_value);
        }
    }
    return 0;
}
 
cs


"nb_pwm.h"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef NB_PWM_H
#define NB_PWM_H
 
#include <avr/io.h>
#include <avr/interrupt.h>
 
#include <stdio.h>
#include <stdint.h>
 
void pwm2_init();
void pwm2_set (uint8_t value);
 
void pwm3_init();
void pwm3_set(uint16_t value);
#endif
 
cs


"nb_pwm.c"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "nb_pwm.h"
 
#define PWM_SCALE_MAX 8
#define PWM_TCNT_MAX 255
 
 
void pwm3_init(){
    // set port
    DDRE |= 0x10;
    // mode select : #14 Fast PWM
    TCCR3A |= (1 << WGM31) | (0 << WGM30);
    TCCR3B |= (1 << WGM33) | (1 << WGM32);
    // Fast PWM output pin mode    
    TCCR3A |= (1 << COM3B1) | (0 << COM3B0);
    // set timer clock scale
    TCCR3B |= (0 << CS32) | (1 << CS31) | (0 << CS30); 
 
    ICR3 = 6000;
}
 
void pwm3_set(uint16_t value){
    OCR3B = value;
}
 
cs


adc관련 파일은 adc예제에 있으며


최대한 가독성을 높게 하기 위하여 각 조작에 주석을 달았으니 크게 어렵지 않게 볼 수 있을 것이다. 


코드를 변형하고 싶다면 이 코드를 기준삼아 datasheet를 검색하는 것이 좋다. 

반응형
Comments