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 signalvoid 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 countervolatile 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 signalvoid 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 motorvolatile 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 MakefilePROJECT=servo-control-atmega168SOURCES=$(PROJECT).cCC=avr-gccOBJCOPY=avr-objcopyMMCU=atmega168TARGETDEV=m168pCFLAGS=-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).hexsudo avrdude -p $(TARGETDEV) -P usb -c avrispmkII -e -U flash:w:$(PROJECT).hex
clean:rm -f $(PROJECT).out
rm -f $(PROJECT).hex
※ヒューズビットは、外部クリスタル20MHzに設定するが、Makefileには書いてない。