ATMega168でサーボモータとDCモータの制御を試す回路とプログラムの例。
開発中なので、不具合があるかもしれない。
//
// servo-control-atmega168.c
//
//
// Created by kaimunantai on 2015/09/06.
//
//
// Target : AT mega 168 (CLOCK 20MHz)
//
// I/O PORTS
// PD0 (PIN 2) : Servo motor control
// PD2, PD3 (PIN 4, 5) : DC Motor control
//
#include <avr/io.h>
#include <avr/interrupt.h>
#define SERVO_PORT PORTD
#define SERVO_PORT_DDR DDRD
#define SERVO_PORT_NO PD0
#define DCMOTOR_PORT PORTD
#define DCMOTOR_PORT_DDR DDRD
#define DCMOTOR_PORT_NO_0 PD2
#define DCMOTOR_PORT_NO_1 PD3
#define TPWM 200 // Period of Servo-motor control PWM signal
void wait(volatile long i)
// delay loop
{
while( i-- > 0 );
}
void initTimer0(void)
// Initialize TIMER0
{
// CTC mode , TOP is OCR0A
TCCR0A = (1 << WGM01) | (0 << WGM00) ;
// I/O clock prescaler N = 8
TCCR0B = (0 << WGM02) | (0 << CS02) | (1 << CS01) | (0 << CS00);
// Timer0 on OCR0A compare match interrupt enable
TIMSK0 |= ( 1<< OCIE0A );
// set TOP value . Interrupt every 0.1 ms
OCR0A = 250; // OCR0A = interrupt period [s] * f_clkio [Hz] / I/O clock prescaler N
sei(); // Enable Interrupt
}
void initPorts(void)
// Initialize I/O Ports
{
SERVO_PORT = 0x00; // Servo port Pull-up Resistor Disable
// Servo Port : OUTPUT MODE
SERVO_PORT_DDR |= (1<<SERVO_PORT_NO);
// DC-MOTOR Ports : OUTPUT MODE
DCMOTOR_PORT_DDR |= (1<<DCMOTOR_PORT_NO_0) | (1<<DCMOTOR_PORT_NO_1);
}
volatile unsigned int T0count; // Timer0 interrupt counter
volatile int ServoSignalHigh = 15; // count while servo control signal HIGH level
// value of ServoSignalHigh -> angle
// 15 -> 0 degree, 6 -> -90 deg., 24 -> +90 deg.
ISR(TIMER0_COMPA_vect)
// Timer0 Timer counter Compair match Interrupt
{
if (T0count > TPWM) {
T0count = 0;
} else {
T0count++;
if (T0count >= ServoSignalHigh) {
SERVO_PORT &= ~( 1 << SERVO_PORT_NO ); // set Servo signal LOW level
} else {
SERVO_PORT |= ( 1 << SERVO_PORT_NO ); // set Servo signal HIGH level
}
}
}
void moveServo(int angle)
// set Servo Motor angle
// arguments:
// angle : -90 to 90 , angle of servo horn , unit: degree
{
if (angle >= -90 && angle <= 90) {
ServoSignalHigh = 15 + angle / 10;
} else {
ServoSignalHigh = 15;
}
T0count = 0;
}
void moveMotor(int sig0, int sig1)
// DC Motor control
{
DCMOTOR_PORT &= ~((1 << DCMOTOR_PORT_NO_0) | (1 << DCMOTOR_PORT_NO_1) );
DCMOTOR_PORT |= (sig0 << DCMOTOR_PORT_NO_0) | (sig1 << DCMOTOR_PORT_NO_1);
}
int main(void)
{
int angle = 0; // servo motor angle
initPorts(); // Initialize I/O Ports
initTimer0(); // Initialize TIMER0
while(1) {
moveMotor(0, 0); // Stop Motor
angle = 60; moveServo(angle); // Control Command for Servo motor
wait(1000000L);
moveMotor(0, 1); // rotate Motor
angle = 0; moveServo(angle); // Control Command for Servo motor
wait(1000000L);
}
}
//
// servo-control-atmega168.c
//
//
// Created by kaimunantai on 2015/09/13.
//
//
// Target : AT mega 168 (CLOCK 20MHz)
//
// I/O PORTS
// PD0 (PIN 2) : 1st-Servo motor control
// PD1 (PIN 3) : 2nd-Servo motor control
// PD2, PD3 (PIN 4, 5) : DC Motor control
//
#include <avr/io.h>
#include <avr/interrupt.h>
#define SERVO_PORT_0 PORTD
#define SERVO_PORT_0_DDR DDRD
#define SERVO_PORT_0_NO PD0
#define SERVO_PORT_1 PORTD
#define SERVO_PORT_1_DDR DDRD
#define SERVO_PORT_1_NO PD1
#define DCMOTOR_PORT PORTD
#define DCMOTOR_PORT_DDR DDRD
#define DCMOTOR_PORT_NO_0 PD2
#define DCMOTOR_PORT_NO_1 PD3
#define TPWM 200 // Period of Servo-motor control PWM signal
void wait(volatile long i)
// delay loop
{
while( i-- > 0 );
}
void initTimer0(void)
// Initialize TIMER0
{
// CTC mode , TOP is OCR0A
TCCR0A = (1 << WGM01) | (0 << WGM00) ;
// I/O clock prescaler N = 8
TCCR0B = (0 << WGM02) | (0 << CS02) | (1 << CS01) | (0 << CS00);
// Timer0 on OCR0A compare match interrupt enable
TIMSK0 |= ( 1<< OCIE0A );
// set TOP value . Interrupt every 0.1 ms
OCR0A = 250; // OCR0A = interrupt period [s] * f_clkio [Hz] / I/O clock prescaler N
sei(); // Enable Interrupt
}
void initPorts(void)
// Initialize I/O Ports
{
SERVO_PORT_0 |= (1<<SERVO_PORT_0_NO); // Servo port Pull-up Resistor Disable
SERVO_PORT_1 |= (1<<SERVO_PORT_1_NO); // Servo port Pull-up Resistor Disable
// Servo Port : OUTPUT MODE
SERVO_PORT_0_DDR |= (1<<SERVO_PORT_0_NO);
SERVO_PORT_1_DDR |= (1<<SERVO_PORT_1_NO);
// DC-MOTOR Ports : OUTPUT MODE
DCMOTOR_PORT_DDR |= (1<<DCMOTOR_PORT_NO_0) | (1<<DCMOTOR_PORT_NO_1);
}
volatile unsigned int T0count[2]; // Timer0 interrupt counter for each servo motor
volatile int ServoSignalHigh[2] = { 15, 15 }; // count while servo #1,2 control signal HIGH level for each servo motor
// value of ServoSignalHigh -> angle
// 15 -> 0 degree, 6 -> -90 deg., 24 -> +90 deg.
ISR(TIMER0_COMPA_vect)
// Timer0 Timer counter Compair match Interrupt
{
int i;
for (i = 0; i < 2; i++) {
if (T0count[i] > TPWM) {
T0count[i] = 0;
} else {
T0count[i]++;
}
}
if (T0count[0] >= ServoSignalHigh[0]) {
SERVO_PORT_0 &= ~( 1 << SERVO_PORT_0_NO ); // set Servo signal LOW level
} else {
SERVO_PORT_0 |= ( 1 << SERVO_PORT_0_NO ); // set Servo signal HIGH level
}
if (T0count[1] >= ServoSignalHigh[1]) {
SERVO_PORT_1 &= ~( 1 << SERVO_PORT_1_NO ); // set Servo signal LOW level
} else {
SERVO_PORT_1 |= ( 1 << SERVO_PORT_1_NO ); // set Servo signal HIGH level
}
}
void moveServo(int no, int angle)
// set Servo Motor angle
// arguments:
// no : servo motor no ( 0 ~ )
// angle : -90 to 90 , angle of servo horn , unit: degree
{
if (angle >= -90 && angle <= 90) {
ServoSignalHigh[no] = 15 + angle / 10;
} else {
ServoSignalHigh[no] = 15;
}
T0count[no] = 0;
}
void moveMotor(int sig0, int sig1)
// DC Motor control
{
DCMOTOR_PORT &= ~((1 << DCMOTOR_PORT_NO_0) | (1 << DCMOTOR_PORT_NO_1) );
DCMOTOR_PORT |= (sig0 << DCMOTOR_PORT_NO_0) | (sig1 << DCMOTOR_PORT_NO_1);
}
int main(void)
{
int angle = 0; // servo motor angle
initPorts(); // Initialize I/O Ports
initTimer0(); // Initialize TIMER0
while(1) {
moveMotor(0, 0); // Stop Motor
angle = 60; moveServo(0, angle); // Control Command for Servo motor
angle = 0; moveServo(1, angle); // Control Command for Servo motor
wait(1000000L);
moveMotor(0, 1); // rotate Motor
angle = 0; moveServo(0, angle); // Control Command for Servo motor
wait(1000000L);
angle = 60; moveServo(1, angle); // Control Command for Servo motor
wait(1000000L);
}
}
# AVR-GCC Makefile
PROJECT=servo-control-atmega168
SOURCES=$(PROJECT).c
CC=avr-gcc
OBJCOPY=avr-objcopy
MMCU=atmega168
TARGETDEV=m168p
CFLAGS=-mmcu=$(MMCU) -Wall
$(PROJECT).hex: $(PROJECT).out
$(OBJCOPY) -j .text -O ihex $(PROJECT).out $(PROJECT).hex
$(PROJECT).out: $(SOURCES)
$(CC) $(CFLAGS) -I./ -o $(PROJECT).out $(SOURCES)
program: $(PROJECT).hex
sudo avrdude -p $(TARGETDEV) -P usb -c avrispmkII -e -U flash:w:$(PROJECT).hex
clean:
rm -f $(PROJECT).out
rm -f $(PROJECT).hex
※ヒューズビットは、外部クリスタル20MHzに設定するが、Makefileには書いてない。