모터 구동 강좌의 연습 코드 입니다.
출처 : cafe.naver.com/laydigital/
5-3. 솔솔 자연풍 선풍기 [과제수행]
안녕하세요, 이번 과제를 욕심을 내서 해보았는데 의도한바를 다 적용해보지 못해 아쉬운 부분이 많습니다.
진도를 나가기 위해 아쉽지만 과제수행으로 올리니 살펴보시고 개선 사항이나 필요한 부분이 보인다면 마음껏
알려주시면 대단히 감사드리겠습니당.
[과제] ------------------------------------------------------------------
SW1을 한 번 누르면 미풍, 두번 누르면 약풍, 세번 누르면 강풍, 네번 누르면 다시 미풍이 되며, SW2를 누르면 정지가 되는 선풍기를 프로그램해 보세요. (집에서 쓰는 선풍기처럼 말이지요.)
------------------------------------------------------------------------
추가: 1. 구조체를 이용하여 꾸며 보자. (sigled list 형태를 취해보자)
-> 스위치 없이 해보았는데 스위치 포함하면 의미가 없어 보여서 list 형태를 빼고 구조체 형태로 구성
2. Num_click : one click, double click, triple click 으로 작동 (일정 시간 동안 증가한 클릭수)
-> 중간 진행하다 코드가 의도와 다르게 애매해서 매 클릭시마다 상태를 변경으로 수정
-----------------------------------------------------------------------------------
질문1. 아래 구성에서 Timer2의 OCn 신호를 제어하기 위해 Datasheet 상에 명시된 조건중에 DDRn 값의 상태에 따라 Output 신호의 출력 상태가 정해진다는 내용을 보고 DDRn값으로 신호의 출력 상태를 제어하고 상태에 따라 OCRn 값을 주는 식으로 구성하였는데 괜찮은 방법인지 잘모르겠어서 질문 드려봅니다. 이방법외에도 OCn의 신호 출력 상태를
제어 할수있는 방법이 있다면 소개해주시면 적용해 보겠습니다.
질문2. 제가 추가 해보려했던 추가사항중 버튼+singled list 형태나 Num_click 중 추가해볼수있는 코드형태가 딱히 않떠오르는데요 힌트가 있으시면 알려주시면 감사하겠습니다.
------------------------------------------------------------------------------------------------
/* MCU_init: using timer2(fast pwm mode), external interrupt alternative port function. */
/* CODE: struct & singled list*/
#include <avr/io.h>
#define kilo 1000UL
#define Mega (kilo*kilo)
#define F_CPU 16*Mega
#include <util/delay.h>
#include <avr/interrupt.h>
#define ST0P 0
#define GO 1
#define MODE1 0
#define MODE2 1
#define MODE3 2
#define NULL 0
void current_motor(void);
void current_sw(void);
void mcu_timer2_fPWM(void);
//void mcu_timer0_ctc(void);
void mcu_exinterrupt_switch(void);
void chattering(char);
struct op
{
volatile uint8_t state;
volatile uint8_t mode_sel;
uint8_t array_ocr2[];
//struct op *next;
}motor_op =
{
ST0P,
MODE3, //after reset "MODE3" trans to "MODE1" by INT4
{ 76,156,220 } //TCNT2(256),30%,60%,90%
};
int main()
{
current_motor();
current_sw();
mcu_timer2_fPWM();
mcu_exinterrupt_switch();
struct op *ptr = &motor_op;
DDRA = 0xff;
while(1)
{
if(ptr->state)
{
switch(ptr->mode_sel)
{
case MODE1: OCR2 = ptr->array_ocr2[0]; PORTA=0x10; break;
case MODE2: OCR2 = ptr->array_ocr2[1]; PORTA=0x20; break;
case MODE3: OCR2 = ptr->array_ocr2[2]; PORTA=0x40; break;
}
}else {
PORTA ^= 0x01;
_delay_ms(100);
}
}
}
/*-----------------Timer2 & Motor section------------------------*/
void current_motor(void)
{
DDRB = (1<<DDB6)|(0<DDB7); //for use OC2 (1<<DDB7) //enabled by ISR(INT4_vect).
}
/*----------Timer02_8bit--------------------*/
void mcu_timer2_fPWM(void)
{
/*--Fast PWM---*/
TCCR2 = (1<<WGM21)|(1<<WGM20)|(1<<COM21)|(0<<COM20)|(1<<CS22)|(0<<CS21)|(1<<CS20); //OC2: enable (COM21:0 =2)
//(fast mode) ( clear:up, set:down) (clock : 1024) = small motor didn't respond high frequency
/*--OCF2-------*/
//TIMSK = (1<<OCR2); //timer2: compare match interrupt enable. //ISR(TIMER2_COMP_VECT) : enable.
}
/*--ISR OCF2-------*/
ISR(TIMER2_COMP_vect)
{
/*none*/
}
/*------------ External interrupt --------------*/
void current_sw(void)
{
DDRE = 0xff;
DDRE ^= (1<<DDE4)|(1<<DDE5); //default: 0 //use for INT4,5 port pin function enable.
}
/*-------------(INT4,INT5)-----------------*/
void mcu_exinterrupt_switch(void)
{
EIMSK = (1<<INT4)|(1<<INT5); // INT4,5 enable.
EICRB = (1<<ISC41)|(0<<ISC40)|(1<<ISC51)|(0<<ISC50); //interrupt source collect, trigger: rising edge.
sei();
}
void chattering(char num)
{
EIFR= (1<<num);
_delay_ms(30);
}
/*-------------- (ISR, INT4)---------------*/ //use trans array table.
ISR(INT4_vect)
{ // mode1 mode2 mode3
static uint8_t trans_mode[3] = {MODE2,MODE3,MODE1};
motor_op.mode_sel = trans_mode[motor_op.mode_sel];
//stop go
static uint8_t trans_array[2] = { GO, GO };
motor_op.state = trans_array[motor_op.state];
DDRB |= 1<<DDB7; //motor: start. (DDR: connect OC2 signal)
chattering(4);
}
/*-------------- (ISR, INT5)---------------*/ //use trans array table.
ISR(INT5_vect)
{ //mode 1 mode2 mode3
static uint8_t trans_mode[3] = {MODE3,MODE3,MODE3};
motor_op.mode_sel = trans_mode[motor_op.mode_sel];
// stop go
static uint8_t tran_array[2] = {ST0P,ST0P};
motor_op.state = tran_array[motor_op.state];
DDRB &= 0<<DDB7; // motor: stop (DDR: cut OC2 signal)
OCR2 = 0;
chattering(5);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
DDRB &= 0<<DDB7; // motor: stop (DDR: cut OC2 signal)
해당 비트만 처리 하실려면
DDRB &= ~(1 << DDB7);
이렇게 해야 합니다.
물론 위의 코드는
DDRB &= 0 << DDRB7;
=
DDRB &= 0;
DDRB의 모든 비트를 0으로 바꿉니다.
oid chattering(char num)
{
EIFR= (1<<num);
_delay_ms(30);
}
EIFR과 _delay_ms 간 순서를 바꿔야 의미가 있습니다.
EIFR은 하나의 인터럽트 마다 하나씩 기억하는 flag입니다.
버턴 눌러짐 이후에 30 ms 후까지 기다린 다음
그 사이에 발생한 다수의 인터럽트가 EIFR에 설정된걸 지우는 겁니다.
외부 인터럽트를 이용하는 경우 누를때 외에 버턴을놓을때도 채터링이발생하므로
완전한 해결을 할려면
버턴은 인터럽트로 처리하지 않고
10ms 주기의 타이머에서 버턴의 상태를 보고
일정시간 low일때 누름 판단하는게 좋습니다.
tick_10ms()
{
if( button1_pressed() && button_cnt != 255) {
if(++button_cnt >= 5) // 50 ms 이상 눌러짐
{
눌러질때 처리할것..
button_cnt = 255; // 누른 상태임을 기억
}
}
if( !button1_pressed()) button_cnt = 0;
}
상태 machine으로도 구현가능한데, 위 코드는
버턴 누른 상태를 button_cnt 변수의 최대 값으로 대신해서
state machine 없이 한겁니다.
그래도 state machine을 많이 연습하는게 나중에도 도움이 될겁니다.
가능하면 state machine으로 해 보세요.
No comments:
Post a Comment