BASIC4MCU | 질문게시판 | 스위치로 PI 모터 제어
페이지 정보
작성자 바밤 작성일2024-11-11 19:33 조회207회 댓글0건본문
ATmega128로 스위치 on됐을 때 PI제어를 하려고 해서 모터 한 개 있을 때까지는 확인이 됐습니다.
모터 두 개 있을 때 소스코드가 어느부분에서 문제가 되는지 잘 모르겠어서 질문 남깁니다..!
OCR을 각 각 0,1번으로 써도 되는지 문제가 되면 어느부분을 수정하면 되는지 질문남겨요 ㅜㅜ
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
//#define F_CPU 16000000UL // CPU 주파수 16MHz
// PID 제어 관련 변수
volatile int reference1 = 100; // 목표 각속도
volatile int reference2 = 100; // 모터 2의 목표 속도
volatile int current_speed1 = 0; // 현재 각속도
volatile int current_speed2 = 0; // 모터 2의 현재 속도
volatile double error1 = 0, error2 = 0;
volatile double integral1 = 0, integral2 = 0;
volatile double control1 = 0, control2 = 0;
// PID 제어 파라미터
volatile double Kp = 0.01;
volatile double Ki = 0.01;
// 엔코더 관련 변수
volatile unsigned int num1 = 0, num2 = 0;
volatile int start = 0; // 스위치
void port_Init()
{
DDRA = 0xFF; // 포트 A를 출력으로 설정
DDRB = 0xFF; // 포트 B를 출력으로 설정 (PWM 신호 출력)
DDRD = 0x00; // 포트 D를 입력으로 설정 (인터럽트 입력, encoder 신호)
DDRE = 0x00; // PORTE의 PE0 핀을 입력으로 설정, 나머지 핀을 출력으로 설정
PORTA = 0xFF; // 포트 A 초기화
PORTE = 0x00; // PE0 핀을 풀다운 저항으로 설정 (기본값 LOW)
}
// 타이머 설정 (100ms 주기)
void Timer1_init()
{
TCCR1A = 0x00;
TCCR1B = 0x03; // 64분주
TIMSK = 0X04; // Timer1 overflow interrupt
TCNT1 = 40536; // 16MHz에서 100ms 주기
}
// 외부 인터럽트 설정
void INT0_init()
{
EICRA = 0x03; // INT0 rising edge
EIMSK = 0x01; // INT0 활성화
}
// PWM 설정
void Timer0_init()
{
DDRB = 0x10; // PB4를 출력으로 설정 (OC0)
TCCR0 = 0b01101010; // Fast PWM 모드, 8분주, Clear OC0 on compare match
}
// PWM 설정 (모터 2)
void Timer2_init()
{
DDRB = 0x02; // PB7를 출력으로 설정 (OC2)
TCCR2 = 0b01101010; // Fast PWM 모드, 8분주, Clear OC2 on compare match
}
// UART 초기화
void usart_Init()
{
UBRR0H = 0;
UBRR0L = 103; // 9600 baud rate 설정
UCSR0B = 0x18; // 송신 가능, 수신 가능 설정
UCSR0C = 0x06; // 데이터 비트 8비트, 패리티 없음, 1 스톱 비트 설정
}
// UART로 송신 함수
void usart_Transmit(unsigned char data)
{
while (!(UCSR0A & (1 << UDRE0))); // 송신 버퍼가 비어질 때까지 대기
UDR0 = data; // 데이터를 버퍼에 저장
}
// 문자열을 UART로 전송
void usart_Print(char* str)
{
while (*str)
{
usart_Transmit(*str++);
}
}
// PI 제어기
void PI_control1()
{
error1 = reference1 - current_speed1;
integral1 += error1;
control1 = Kp * error1 + Ki * integral1;
// 모터 속도 제한: 0~255
if (control1 > 255) control1 = 255;
if (control1 < 0) control1 = 0;
OCR0 = (int)control1;
}
// PI 제어기 (모터 2)
void PI_control2()
{
error2 = reference2 - current_speed2;
integral2 += error2;
control2 = Kp * error2 + Ki * integral2;
if (control2 > 255) control2 = 255;
if (control2 < 0) control2 = 0;
OCR2 = (int)control2; // 모터 2의 PWM 신호
}
// 인터럽트: 엔코더 펄스 카운트
ISR(INT0_vect)
{
num1++;
num2++;
}
// 인터럽트: 100ms마다 각속도 계산 및 PID 제어 수행
ISR(TIMER1_OVF_vect)
{
// 100ms 동안의 엔코더 펄스 수를 이용하여 속도 계산
current_speed1 = (num1 * 10.0); // 각속도 (1초 단위로 환산)
current_speed2 = (num2 * 10.0); // 모터 2 속도
num1 = 0;
num2 = 0;
TCNT1 = 40536;
PI_control1();
PI_control2();
char buffer[200];
snprintf(buffer, sizeof(buffer), "current_speed1: %d %d %d, current_speed2: %d %d %d\r\n", current_speed1 / 100, current_speed1 % 100 / 10, current_speed1 % 10, current_speed2 / 100, current_speed2 % 100 / 10, current_speed2 % 10);
usart_Print(buffer);
_delay_ms(1000);
}
int main(void)
{
port_Init();
Timer0_init();
Timer1_init();
INT0_init();
usart_Init(); // UART 초기화
sei(); // 전역 인터럽트 허용
while (1)
{
// 스위치가 눌렸는지 확인하고 start 변수 업데이트
if (PINE & 0x01) // PE0 핀에서 입력된 스위치 상태 확인
{
start = 1; // 스위치가 켜져 있으면 start = 1로 설정
}
else
{
start = 0; // 스위치가 꺼져 있으면 start = 0으로 설정
}
// start 값에 따라 모터 제어
if (start == 1)
{
OCR0 = (int)control1; // 모터 속도 유지
OCR2 = (int)control2;
}
else
{
OCR0 = 0; // 모터 정지
OCR2 = 0;
}
}
}
댓글 0
조회수 207등록된 댓글이 없습니다.