2015-02-15

AVR과 대화하기 UART 연습강좌 과제

USART 강좌의 과제를 연습한 코드 및 답변내용을 정리한 글입니다.

출처 : cafe.naver.com/laydigital/

------------------------------------------------------------------------
[과제] 위의 UART 통신 예에서, BS(Back Space) 키를 누른 경우는 글자가 지워지지 않고 커서만 왼쪽으로 가게 되는데, 이것을 한 글자가 지워지면서 왼쪽으로 가도록 프로그램해 보세요.
------------------------------------------------------------------------
혹시 위에 과제가 stack ,array 나 queue 등을 이용한 echo input data를 관리하는 형태의 연습을 위한
과제가 아닌지 조심스럽게 여쭈어봅니다. 일단 저는 문자로 문자를 지우는 방법으로 쉽게 작성했습니다..;


#include <avr/io.h>
#define kilo 1000UL
#define Mega kilo*kilo
#define F_CPU 16*Mega
//#define FOSC 16000000 //clock speed
//#define BAUD 115200
//#define Myubrr FOSC/16/BAUD-1  // FOSC/16/BAUD -1 + (-35%)

#include <util/delay.h>

void USART0_SET(uint16_t);
void USART0_Transmit (uint8_t p);
void Transmit_string (uint8_t*p);
uint8_t USART0_Receive(void);


//uint8_t arr[] = {11,'D','Y','N','E',0x20,'C','O','M','P','A','N','Y','!',10,13};
uint8_t arr[] ="DynE Serial Practice>"; //uint8_t *arr="DynE Serial Practice>"; 
uint8_t prr[] = "I like you\r\n\n";  

int main(void)
{
 uint8_t cr; 
 USART0_SET(103);  //baud rate 9600

    while(1)
    {
           cr = USART0_Receive();
    USART0_Transmit(cr);
    
    switch(cr)
    {
      case  8: USART0_Transmit(255); USART0_Transmit(8); break;   //back space 
      case 27: USART0_Transmit(10);  USART0_Transmit(12); break;  //clear terminal
      case 13: USART0_Transmit(10);  Transmit_string(arr); break;    //enter
    }
   }
}

void USART0_SET(uint16_t ubrr)
{
  /*set baud rate */
 UBRR0H = (uint8_t)(ubrr>>8);
 UBRR0L = (uint8_t) ubrr;
 /* Enable receiver and transmitter */
 UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (0<<UCSZ02);  
   
 /*Set frame format : 8data, 1stop bit */
 UCSR0C = (0<<USBS0)|(3<<UCSZ00);
 /*Set Parity mode */
 UCSR0C |=(0<<UPM00); //disabled,  parity
}


void USART0_Transmit(uint8_t p)
{
  /* Wait for empty transmit buffer */
   while( !(UCSR0A &  (1<<UDRE0)) )
   ;
  /* Put data into buffer, sends the data */

   UDR0 = p;
   //_delay_ms(30); //A confirmed

}

void Transmit_string (uint8_t*p)
{
  while(*p)   USART0_Transmit(*p++);
}

uint8_t USART0_Receive(void)
{
 /* Wait for data to be received*/
 while( !(UCSR0A & (1<<RXC0)) )
 ;
 /* Get and return received data from buffer*/
 return UDR0;
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


시리얼 모니터에서 enter 키를 0x0d('\r'), 0x0a('\n') 어떤 조합으로 보내는지에 따라 약간 수정을 해야 하지만

#define ENTER '\r'
#define BS '\b'
#define SPACE ' '

ch = getchar();
swtich(ch)
{
case ENTER : 할일을함/
break;
case BS : Tx(BS); Tx(SPACE); Tx(BS); break;
}
이런 식으로 합니다.

그런데 코드에서 255을 출력하는건 어떤 의미 인가요?

ASCII 확장코드 표에서 255 값이 blank 문자여서 backspace 와 조합하여 커서가 뒤로가면서 터미널에 표시된 문자를 지우는 역활로 이용했습니다. 문자를 빈칸문자로 다시 채우는 형태로 문자가 지워지게 보이게 하여 과제내용 구현 연습을 했습니다.

예 그렇게 하셔도 상관없겠네요.
보통 blank는 스페이스 문자 (' ' . 0x20) 으로 지우거든요..ㅎ

C언어 배열과 포인터 질문 정리

C언어를 배우면서 배열과 포인터에 대한 질문 내용을 정리한 글입니다.


출처 : cafe.naver.com/laydigital/


안녕하세요, 갑자기 궁금해서 질문을 쓰게 됐습니다.

2주정도 C언어 관련 문법들을 살펴보고 정리하다가, 이차원 배열 arr[][] 과 포인터에 관한 내용중 그 관계과 궁금하고 명확하게 설명한 자료가 없어 질문드립니다. 물론, 사용하는건 외워서라도 할수있지만 저의 경우 외워서 하는건 영 마음에 않들어서 이해를 통해 활용하는걸 가장 좋아하는 스타일이라 이렇게 질문 드려봅니다.

질문 내용은 다음과 같습니다.

제가 자료들을 토대로 정리하여 이해한 내용은  1차원 배열의 경우 int arr[]로 선언햇을경우 기본형은  arr= int(*)형 혹은 int* 형은 바로 int *ptr,  ptr =arr 이경우 ptr은 int * 형 , arr도 int(*),int* 형 그러므로 서로의 포인터형이 같은 형이므로 대응된다 여기까지는 참 이해하기 쉬운 부분이였습니다.

그런데 문제는 2차원 배열로 선언할 경우 입니다.

책, C/C++언어 관련사이트에선 다음과 같이 int arr[x][y] 일경우 int **ptr은 arr에 대응되지않고 다음과 같이 포인트배열을 선언
하여 그 주소값을 대응시켜 사용한다고 설명합니다.  int arr[2][3]; 일경우 대응되는 포인터는 int(*ptr)[3]입니다. 물론 그림과
주소 address 등을 첨부하여 잘 정리 되어있습니다 그런데 어디에도 (*prt)붙이는 이유에 대해서 설명이 없습니다.
여기서 어떤 블로그자료에선  int **ptr, prt= (int**)arr 이런식으로 형변환을 시켜서 거의 반 억지로 주소를 배분해서 쓰기도 하던데 저 경우 해본 결과 다음과 같이 할경우 어이없는 일이 벌어집니다.

int a=1 ; ptr = &a;   ptr = (int*)a; 이렇게 하면 주소를 변수a의 상수값 1을 가지고 *ptr 값을 출력해보면 unInitialized error가
발생합니다 당연히 address 1에는 어떤값도 정의 하거나 초기화하지 않았는데 저렇게 어거지로 집어넣으면 변수의 형이 맞기때문에 값은 들어갑니다.. 너무 억지스러워서 쓰기도 참 조심스러운 방법입니다..

제 경우 너무 궁금해서 일부러 visual studio에 컴파일 에러를 만들어서 현재 내가 전달할려는 변수의 수형이 어떤형인지를
일일 확인해 보았는데요.

1차원 배열의경우  int arr[],  arr = int(*), int*,  &arr=int(*)[]
2차원 배열의 경우 int arr[][], arr=int(*)[],    &arr=int(*)[][]

1차원 포인터배열  int(*prr)[], prr=int(*)[], &prr=int(**)[]
2차춴 포인터배열  int(*prr)[][], prr = int(*)[][], &prr=int(**)[][]

다음과 같이 형을 인식하여  prr = arr 은 서로 형이 일치하여 바로 대응 됩니다. 그래서 int arr[2][3], 은 int(*prr)[3]에 바로
대응하여 prr = arr; 이런식으로 바로 바로 대응하여 prr[1][1] = arr[1][1] 은 같은 값을 가리키게 됩니다.

여기까지는 다소의 수고가 들어도 확인 해보고 살펴볼수있는 충분한 방법은 많았습니다 하지만 정작 왜? 2차원 배열의포인터를 선언할 경우 (*ptr)안에 포인터를 선언하지는 어디에도 설명해주는 곳이 없습니다 제가 제일 궁금한건 (  ) 안에 왜 포인터를 선언해 주어야 하는것입니다, 어떤 수식, 형의 상관 관계 때문인지 ..이문제때문에 몇일을 고생했지만 마음에 드는 설명을 해주는곳이 없어서 그냥 묻어 두었다가 C언어 관련 질문은 어느때건 해도 된다고 하신 얘기가 기억나서 질문을 써봤습니다.

가장 근복적인 이해가 부족하면 활용하는데 큰 장애가 될 수있어서 다소 장황하지만 이렇게 질문드리오니 설명의 양이 많아
여건상 힘드시다면 관련 사이트를 알려주시면 참고하여 살펴보겠습니다. 사용법은 그냥 쓰면 되지만  분명 활용에 대한 제약은 굉장히 클거라고 느낍니다. 제경우 이쪽분야는 아니지만 제가 일한 분야는 기구, 금형, 자동차(Exterior), layout 설계인데요 제가 공부해온 경험으로 비추어보면 복잡한 논리와 이론도 가장 밑바탕에서 시작되는 충분한 이해를 기반으로 사용해야 아무리 어려워 보이는 설계나 기능 구현도 쉽게 할 수 있었거든요...  긴 질문 읽어주셔서 감사합니다 __)


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int arr[2][3];

arr[0]는 3개짜리 int 의 첫번째 주소(offset=0)
arr[1]은 3개짜리 int 의 두번쨰 주소(offset = 3 * 2) / int 가 2바이트 인경우
array선언시 arr는 컴파일시 해당 arry의 시작주소가 되는 상수입니다. 
변수로
arr[0]에 대응할려면
*p 가 되야죠. 
*p = p[] 와 같으므로
arr[]와 같은 레벨은 *p

int (*p)[3]; 이 int arr[2][3]의 속성과 같죠.

설명하기가 어렵네요.
복잡한 포인터 사용을 할떄는 저도 다시 찾아보고 사용합니다.
사용할 일이 별로 없어서....

왜 *p로 선언했는지를 궁금해 하신건가요?

선언은 p 라는 변수 하나(array 가 아닌) 선언하는 겁니다.

p 를 선언하는데
*p : p 가 가리키는 곳은
(*p)[3] : 3개짜리 array에 대한 주소이며
int (*p)[3]: 각 3개의 방은 int 타입이다.

()를 하지 않으면 우선순위떄문에 다르게 해석이 됩니다.

int *arr[3];
은 3개의 element를 가지는 array를 선언하며 각자는 int 가 들어있는 주소를 저장합니다.

(*ptr)[] 는
ptr 변수 하나를 선언하며, 그 변수가 가리키는 곳은 array([] 형태 단위) 입니다.

int arr[2][3];
이건 
arr[2][3] : arr로 시작주소를 가지는 2x3(6개)의 변수를 선언하며 해당 변수는 int 타입니다.

int (*arr[2])[3]; 
변수를 2개(array)로 선언하는데, 그 각각의 값은(*arr[])는 3개짜리 integer 수형에 대한 수소입니다.

array :   0   1   2   3   4   5   6   
            ^            ^
         arr[0]      arr[1]
            ^            ^
            p            p+1

int arr[2][3] => int (arr[])[3] => int (*arr)[3];
arr는 변하지 않는 상수이긴 하지만.....

USART 통신을 이용한 AVR로 hi~ 인사하기.

UART 통신을 연습하는 강좌에 올린 질문과 답변 연습 내용을 정리한 글입니다.


출처 : cafe.naver.com/laydigital/

안녕하세요, 통신을 위해서 사전에 준비할것들이 많다는것을 강좌를 통해 처음 알게되었습니다. 실생활에서 쓰는것만큼
편하게 되는게 아닌것을 처음으로 느껴보고 우리가 실생활에서 참 편하게 이용하는구나 라고 세삼 더 느끼게 됐네요...
준비해보면서 하나씩 이유에 대해서 알게되니 점점더 재미가 붙는것 같습니다. 과제가 있어 과제 연습용으로 수행코드를
작성해보았습니다.

터미널 에뮬레이터는 제일 간편한 하이퍼 터미널을 win7에서 실행하여 실습하였습니다. win7은 터미널이 없더군요....

------------------------------------------------------------------------
[과제] 바로 위에 있는 “I Like You!”와 똑 같은 화면이 나타나도록 하되, baudrate를 9600으로 하고 stop 비트를2비트, 패리티는 Even 패리티를 사용하여 프로그램해 보세요. ^^
------------------------------------------------------------------------


#include <avr/io.h>
#define kilo 1000UL
#define Mega kilo*kilo
#define F_CPU 16*Mega
//#define FOSC 16000000 //clock speed
//#define BAUD 115200
//#define Myubrr FOSC/16/BAUD-1  // FOSC/16/BAUD -1 + (-35%)
#include <util/delay.h>
#define NUL 0x00
void USART0_SET(uint16_t);
void USART0_Transmit (int8_t *p);

int8_t arr[] = {11,'I',0x20, 'L','I','K','E', 32, 'Y','O','U','!',11,13};
int8_t *ptr = arr;

int main(void)
{
 USART0_SET(103);  //baud rate 9600
  
    while(1)
    {
      USART0_Transmit(ptr); 
 }
}


void USART0_SET(uint16_t ubrr)
{
  /*set baud rate */
 UBRR0H = (uint8_t)(ubrr>>8);
 UBRR0L = (uint8_t) ubrr;
 /* Enable receiver and transmitter */
 UCSR0B = (0<<RXEN0) | (1<<TXEN0) | (0<<UCSZ02); 
   
 /*Set frame format : 8data, 2stop bit */
 UCSR0C = (1<<USBS0)|(3<<UCSZ00);
 /*Set Parity mode */
 UCSR0C |=(2<<UPM00); //enabled, even parity
}


void USART0_Transmit(int8_t *p)
{
 uint8_t i;
 for(i=0; i<(sizeof(arr)/sizeof(arr[0])) ; i++,p++)
 {
    /* Wait for empty transmit buffer */
 while( !(UCSR0A &  (1<<UDRE0)) )
 ;
 /* Put data into buffer, sends the data */

 UDR0 = *p;
    _delay_ms(50); //A confirmed
 }

}

코드 수행 결과물 


/////////////////////////////////////////////////////////////////////////////////////////////////////


nt8_t arr[] = {11,'I',0x20, 'L','I','K','E', 32, 'Y','O','U','!',11,13};

끝에 11,13은 '\n', '\r' 에 대한 문자 값인듯한데
11이 아니고 10입니다.

문자 string으로 
uint8_t *arr = "I Like You !\r\n";


void USART0_Transmit(int8_t *p)
{

while(*p)
{
/* Wait for empty transmit buffer */
while( !(UCSR0A & (1<<UDRE0)) ) ;
/* Put data into buffer, sends the data */

UDR0 = *p++;
_delay_ms(50); //A confirmed
}

}
이렇게 사용하기도 합니다. 
USART0_Transmit 에 문자열 주소를 받으면서도
global 변수 arr[] 을 통해 size를 얻는 형태가 조금 아쉽네요.. ^^

USART0_Transmit(arr, sizeof(arr)/sizeof(arr[0]));

void USART0_Transmit(int8_t *p, int len)
{

for(;len ; len --, p++)
{
/* Wait for empty transmit buffer */
while( !(UCSR0A & (1<<UDRE0)) )
;
/* Put data into buffer, sends the data */

UDR0 = *p;
_delay_ms(50); //A confirmed
}

이런 방식의 구현도 가능하겠죠.

광센서를 이용한 가로등 만들기 강좌

광선세를 이용해 가로등을 만들어보는 연습 코드와 관련한 질문을 정리한 글입니다.

출처 : cafe.naver.com/laydigital/

6-2. 해지면 켜지고 해뜨면 꺼지는 가로등
과제] ------------------------------------------------------------------

1.     100 Lux 정도에서는 2개의 가로등(LED)만 켜지고, 10 Lux 가 되면 4개, 1 Lux 가 되면 8개의 가로등(LED)이 켜지도록 함
2.     주위환경에 의하여 경계점에서 불이 꺼졌다 켜졌다하는 것을 방지하기 위하여 각 가로등은 일단 한 번 켜지면 어느 정도 수준까지 밝아지지 않으면 꺼지지 않고, 반대로 한 번 꺼지면 어느 정도 수준까지 어두어지지 않으면 켜지지 않도록 함(즉, 완충 공간을 설정)
 ------------------------------------------------------------------------

6-2 강좌에 있던 수행과제 입니다. 코드작성하면서 궁금증이 생겨서 질문 드립니다.
아래는 제가 과제조건에 맞추어 작성한 코드입니다.

질문1 은 아래 작성한 코드중에  while((ADCSRA & adc_start) != adc_start); // question?
이부분이 있는데요, 강좌에서는 (1<<ADIF)로 비트를 확인해서 시작과 끝을 확인해서 ADCH,ADCL data 를 read
하는데요, single mode 에서 바로 (1<<ADSC)를 사용자 set 해주고 시작시키면 conversion 완료시ADSC bit 자동으로 hardware clear된다고 해서 사용했는데 큰 무리가 없는지 일단 궁금합니다. 사용자가 conversion 중에 set 해도 영향을 주지않는다고 해서 괜찮다고 봤거든요.

질문2 는 C언어 문법에 대해  while((ADCSRA & adc_start) != adc_start);  이 mian 안에서 실행될때 실제로
int main()       ---- 1
{
  while(!)        ---- 2
  {
     single_conversion_mode()   ----- 3
  }  
}
위와 같은 구성에서 함수 3 안의 while((ADCSRA & adc_start) != adc_start); 는 함수3안에 있는 while문 아래 있는 code들은  실제로 while() { loop } 형태로 구성하면 원하는 구현동작을 실행시키지 않았습니다. 다른 if(){}형태도 마찮가지 이고 이 loop를 구성하면 뭔가 오작동이 일어나는데 뭔가 타이밍이 않맞는건지 왜그런지 몰라서 이유가 궁금해서 일단 질문으로 정리해봤습니다.

질문3  state_check() 함수를 만들어서 예전 올려주신 자료  [C+AVR 보충자료] high water / low water mark 를 참조해서 코드로 구현했는데  마음에 썩 들지가 않아서 좀더 괜찮은 표현형태나 방법이 있다면 알려주시면 대단히 감사하겠습니다.
물론 작동은 되는데 조건에 충실히 작동되는지 파악해보기 좋은 방법이 떠오르지 않아서 도움을 구합니다.

-------------------------------------------------------------------------------------------------------------------

#include <avr/io.h>

void init_adc_conversion(void);
//void alternative_func_set(void);
uint16_t single_conversion_mode(void);
uint8_t state_check(uint16_t val);

#define _1000lux 1000
#define _100lux 901
#define _10lux 871
#define _1lux 92
#define OFF 0
#define DAY 1
#define NIGHT 2
#define MidNight 3

#define  lights PORTA

struct lux_led
{
  uint16_t ref_val;
  uint8_t  led_num;
             
}light_senosr[]=
{
 {_1000lux,0x00},
 {_100lux,0x03},
 {_10lux,0x0f}, 
 {_1lux,0xff} 
};          //       cds: 10 lux - 35k,  100lux: 8k,  1lux: 2000k 

int main(void)
{
 uint16_t return_val;//,state=DAY;
 init_adc_conversion(); //adc initiate                        
 DDRA = 0xff; //led initiate

 struct lux_led *ptr= light_senosr;

 while(1)     //loop
 {
  return_val = single_conversion_mode();
  
  switch(state_check(return_val))
  {
   case OFF:      lights= ptr[OFF].led_num;      break;
   case DAY:      lights= ptr[DAY].led_num;      break;
   case NIGHT:    lights= ptr[NIGHT].led_num;    break;
   case MidNight: lights= ptr[MidNight].led_num; break;
  }
  
 }

}

void init_adc_conversion()
{
  ADMUX |= (0<<MUX4)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0);  //AD0 enable.
  ADMUX &= ~(1<<ADLAR); //right present.
  ADMUX |= (0<<REFS1)|(0<<REFS0); //ADREF, internal  Vref turned off
  ADCSRA |= (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);  //adc: enable, ad prescale select 111: 128 
  ADCSRA &= ~(1<<ADFR); // ad free running mode 0: single, 1: enable. 
}


uint16_t single_conversion_mode()
{
   uint16_t adc_val,adc_regH;
   uint8_t adc_start, adc_regL;//,adc_flag;
  
   //adc_flag = (1<<ADIF);
   adc_start = (1<<ADSC);
   ADCSRA |= adc_start;           //in single, software give set signal ADSC bit for each single start.
  
   while((ADCSRA & adc_start) != adc_start); //question?
    //PORTA = 0x01;
     adc_regL = ADCL;   // low bit must read before high bit
     adc_regH = ADCH;   // if read ADCH bit conversion data first will update immediately
     adc_val = (adc_regH<<8)|(adc_regL);
     
   return adc_val;
   
}


uint8_t state_check(uint16_t val)
{
  uint16_t state = NIGHT;

  if (state == NIGHT)
  {
   if(900 <=val) state = DAY;
   
   else if((871>val) && (901>val) && (val>=871)) state = NIGHT;
   
   else if ((92<val)&&(871>val)) state = MidNight;
   
  }
  
  if(state == DAY) 
  {
   if((901<val) && (901>=val) && (val>871)) state = DAY;
         
   else if(871>=val) state = NIGHT;
   
  }
  
  if(901<val) state = OFF;

  return state;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

1. ADC 를 동작시키는 ADCSRA의 
비트 6 (ADSC)는 adc 변환을 시작 시키는 비트이고
종료를 체크하는건 비트 4(ADIF) 입니다.
single conversion 모드시에는
ADCSRA |= (1 < ADSC);
while(ADCSRA & (1 << ADIF));
ADCSRA |= (1<< ADIF);
이게 정상적인 과정입니다.
ADIF 는 해당 비트를 1로 쓰기 하거나, 또는 ADC 인터럽트 루틴이 enable 되어서 인터럽트 루틴으로
진입할때 clear 됩니다.

ADSC비트를 체크하도록 코딩하신것 같은데요?

2. ADIF flag를 체크하도록 코딩하시면 되겟죠.

uint8_t state_check(uint16_t val)
{
uint16_t state = NIGHT;

state 변수를 위처럼 선언하면 매번 함수 호출시마다 NIGHT가 됩니다.
해당변수를 state_check에서만 사용하고 계속 그 값이 유지 되게 하실려면

static uint8_t state = NIGHT;
// 8비트로도 충분하므로


if (state == NIGHT)
{
if(NIGHT_TO_DAY <= val) state = DAY;

// 이 줄은 필요없음.. else if((871>val) && (901>val) && (val>=871)) state = NIGHT;

else if ((92<val)&&(871>val)) state = MidNight;

}

if(state == DAY) 
{
if((901<val) && (901>=val) && (val>871)) state = DAY;

else if(871>=val) state = NIGHT;

}

uint8_t state_check(uint16_t val)
그리고 이 함수가 3개의 상태에 대한 코드로 작성되어 있지 않네요(midNight에서 전환하는 
코드가 없음)

모터를 이용하여 자연풍 선풍기를 돌려보자.

모터 구동 강좌의 연습 코드 입니다.

출처 : 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으로 해 보세요.

Total Pageviews