초음파 센서 타이밍도(mode1)에 따른 소스구현


 

 

 

 

 

 

 

 

 

 

20140514 - Time Counter

ATMega128 2014. 5. 14. 13:47 Posted by Owen.K

14. 8bit Timer/Counter0 with PWM and Asynchronous operation


TIMSK 레지스터

Bit 1 – OCIE0: Timer/Counter0 Output Compare Match Interrupt Enable

- 비교해서 일치하면 인터럽트 발생.

Bit 0 – TOIE0: Timer/Counter0 Overflow Interrupt Enable

- 255를 넘어서면 인터럽트 발생.



 

 

 

 

 

 

 

 

 

 

 


 


20140513 - Timer Count 수정중

ATMega128 2014. 5. 13. 11:17 Posted by Owen.K


인터럽트  -  H/W(외부 인터럽트)

    -  S/W OS 

JAVA는 이벤트

Win은 메시지

Linux는 시그널

Android는 푸쉬(Push)


external -> INT0~7

internal -> ADC ->(interrupt request) Vector 22번 -> 21번 함수

     -> USART ->(interrupt request) Vector 19번 -> 18번 함수


Timer Count

 

 

 

 

 

 

 

 

 

 

 




LCD에 대한 의존성


위는 INT.c의 소스이다.

위 처럼 LCD_Str없이는 Interrupt를 쓸 수 없게 된다. 이를 의존성(Depandency)라고 한다.


다른곳에도 인터럽트 활용해 보기

인터럽트를 여러곳에 사용하기 위해 INT.h에 있던 인터럽트 활성화 소스 부분을 smart.h로 이동하여 전체적으로 사용 가능하도록 위치를 바꿔주었다.




ADC에 인터럽트 활성화 


ADC인터럽트를 활성화 하기 위해서는 레지스터 ADCSRA의 3번 포트인 ADIE를 통하여 인터럽트 활성화를 해주어야 한다.

인터럽트 벡터를 보면 ADC인터럽트 22번에 있는것을 확인할 수 있다. 그렇기 때문에 함수로 선언하기 위해서는 1을 뺀 __vector_21로 함수를 선언해 주어야 한다.(ADC 변환이 완료되면 인터럽트 발생)

기존의 ADC.c 소스를 활용하여 인트럽트 함수를 따로 선언하고 인터럽트 전체를 0으로 만드는 함수인 cli() 을 호출해 준 뒤 기존의 소스의 오른쪽 정렬을 왼쪽 정렬로 바꾸고 인터럽트 활성화 부분인 ADCSRA의 ADIE를 1로 바꿔준다.

그런 뒤 변환부분에서 while로 돌리던 부분을 없애주고 반환값도 없애준 뒤 벡터함수 21(vocter 22번 ADC)을 선언해 준다. 이 인터럽트는 ADC 변환이 완료되면 자동으로 이 함수로 이동하여 LCD_Num(ADC); 를 호출해 준다. 그렇게 변환이 완료된 값이 10비트이나 LCD에 숫자로 출력하는 함수가 8비트까지 출력하도록 설정 해 놓았기 때문에 변환된 값을 가지는 ADCH,ADCL 레지스터의 H레지스터를 사용하기 위해 초기 선언을 왼쪽 정렬로 하고 ADC의 주소설정값을 H로 바꿔주었다.


Main.c

인터럽트 설정은 다 끝이났기 때문에 메인 부분에서 호출을 해주면 된다.

먼저 LCD로 출력된 값을 보여주기 때문에 LCD초기화 부터 해준다.  다음에 ADC인터럽트 부분을 초기화 해준다. 인터럽트를 한꺼번에 켜기 위해 sei()함수를 호출해 준다. 마지막으로 LCD 동작을 알아보기 위해 먼저  Start를 출력하고 ADC변환 함수를 호출 한다.

ATMega 칩의 ADC0 번에 선을 연결하여 사용하여 채널 0을 설정한다.

ADC에 Interrupt 활성화 시키기 +에 꽂을 때


ADC에 Interrupt 활성화 시키기 -에 꽂을 때

 +일때 uart 통신을 통하여 값을 알아본 결과 1023이 출력되었었다.

그러나 지금은 8비트로 11 두개가 날라가고 1111 1111이 출력되어 최대 255 가 출력되는 것을 확인 가능하다.

가운데는 아무곳도 연결 안한 상태로 값이 reset을 눌러줄 때 마다 값이 계속 바뀐다.

마지막은 GND(-)에 연결했을 때의 출력 모습이다.


USART에 인터럽트 활성화


 

UART에서도 인터럽트를 활성화 하기 위해서는 레지스터를 봐야 하는데 보게되면 인터럽트 활성화 하는 부분이 여러개 있다. 그러나 우리는 RX 송신시 인터럽트 발생이 되도록 설정하려고 한다.

벡터표를 보게 되면 우리가 사용중인 UART0에서 RX 인터럽트 부분의 벡터 번호는 19번이다. 그렇기 때문에  함수 선언부분의 번호는 18번이 된다.

먼저 마찬가지로 인터럽트들을 모두 활성화를 꺼준다.

RX 인터럽트 활성화가 있는 UCSR0B에 RXCIE를 1로 송신이 완료되면 인터럽트가 발생하도록 설정해 준다.

인터럽트 함수 벡터_18을 선언 해주고 인터럽트 발생시 수행하는 함수호출을 넣어주면 끝!

송신이 완료되면 인터럽트 함수가 호출되면서 LCD_Data(UDR0); 를 호출하여 LCD에 찍어주게 된다.


Main.c에서 호출을 하고 하이퍼터미널을 통하여 통신을 하게 하고

키보드로 입력해 주게 되면 한 문자씩 LCD로 출력이 된다.

USART에 Interrupt 활성화 시키기



하이퍼터미널에서 USART통신으로 키보드에 입력 받아 LCD에 보이는 모습

HI!!I'm Owen.K

인터럽트 EICRA(External Interrupt Control Register A), EICRB(External Interrupt Control Register B) 설명


 ISC71

ISC70 

ISC61 

ISC60 

ISC51 

ISC50 

ISC41 

ISC40 

 Bit 7

Bit 6 

Bit 5 

Bit 4 

Bit 3

Bit 2 

Bit 1 

Bit 0 

Bit 0 과 1, Bit 2 와 3, Bit 4 와 5, Bit 6 과 7은 위 그림의 표처럼 한 쌍이다.

EICRA, EICRB는 각각 두 개 씩 묶어서 INT0(ISC00, ISC01) : INT7(ISC70, ISC71)까지를 의미한다.

이들의 값에 따라 어떤 식으로 작동이 되느냐는 밑의 표에 나와있다.    



 ISCn1

ISCn0 

Description 

 0

 Low이면 인터럽트를 요청.

 0

 어떤 변화가 있으면(positive || negative) 인터럽트를 요청.

 1

 falling edge이면 인터럽트를 요청.

 1

 rising edge이면 인터럽트를 요청.

* ISCn1의 n은 INTn의 n을 의미한다.



인터럽트 EIMSK - External Interrupt Mask Register 설명



Bits 7:0은 INT7 : INT0을 의미한다. 이들 중 하나가 무조건 1이어야 하고, 

SREG 레지스터의 Bit 7 I도 1이 되어야 인터럽트가 구동된다.

INT7 : INT0가 방이라 치고 SREG 레지스터의 Bit 7이 대문이라 치면, 

대문을 잠그면(0) 밖에 나갈 수 없다. 그래서 둘 다 1이어야 인터럽트 요청가능.



INT.h부터 살펴보자

#define cli() __asm__ __volatile__ ("cli" ::)

SREG 인터럽트 비활성화 시키는 어셈블리어

#define sei() __asm__ __volatile__ ("sei" ::)

SREG 인터럽트 활성화 시키는 어셈블리어 sei(set enable interrupt)

자동으로 1을 넣는다.

#define sleep() __asm__ __volatile__ ( "sleep" "\n\t" :: )

SREG 인터럽트 슬립 시키는 어셈블리어

c로만은 cpu를 못 건드는 부분을 어셈블리어로 건들인다.

통틀어 inline assembly라고 부른다. 컴파일이 바뀌면 사용할 수 없다. 

void __vector_8(void) __attribute__((signal, used, externally_visible));

gcc컴파일러만 쓰는 문법 이 함수의 속성을 적어줌.

리눅스에서는 시그널....인터럽트이다. 외부에서 이 함수를 호출할 수 있다.

data sheet 59page 벡터 넘버를 보면 실제 코딩할 때는 번호가 0부터 시작이다.

void INT7_Init(void);



다음 INT.c를 보면,

void __vector_8 (void) 

{

LCD_Str("Interrupt1");

상승엣지일 때 위의 것이 적힘.

USART_Str("Interrupt2");

}

void INT7_Init(void)

{

cli();

이 함수를 실행전에 다른장치의 인터럽트를 먼저 꺼둠.

EICRB = (1<<ISC71)|(1<<ISC70);

상승 엣지일 때 인터럽트 요청.

EIMSK = EIMSK|(1<<INT7);

SREG는 직접 건들여서 세팅하거나,

sei();

SREG = SREG|(1<<I)과 같은 의미.

}



마지막으로 main.c

int main(void)

{

LCD_Init();        LCD초기화

INT7_Init();        INT7초기화

while(1)

{

sleep();

일 안시키면 재운다.

}

return 0;

}



실행결과


ATMega 128A에 연결.

푸쉬스위치에 연결

실행 결과


최종 소스는 

20140509.zip


20140508 - ATMega128A(Interrupt) 수정중

ATMega128 2014. 5. 8. 09:38 Posted by Owen.K

Interrupt


Interrupt - 하드웨어 인터럽트와 소프트웨어 인터럽트로 나뉘는데

 우리가 다루는 것은 주로 하드웨어 인터럽트이다. 

       USART통신이 끝날 때까지 ALU가 뭔가를 할 수 없기 때문에 

 거기서 대안한 방식이 인터럽트 방식이다.

       소프트웨어에서 인터럽트는 자바에서는 이벤트, 윈도우에서는 메세지, 

       리눅스에서는 시그널.

       다른말로 IRQ(Interrupt ReQuest), INT(INTerrupt) 인터럽트 요청을 의미한다.

       코드 함수는 ISR(Interrupt Service Routine).




polling - 폴링방식은 정해진 시간 또는 순번에 상태를 확인해서 상태 변화가 

있는지 없는지를 체크하는 방식이다.



위의 두 개는 컴퓨터 용어에서 서로 반대의 개념이다.






gcrt1.s -> 소스파일이고, crt128.o(Entry Code)가 들어온다. 소스파일과 링크 되있다.


make하고 만들어진 파일들이 배치되어있는 파일을 main.map파일이라 한다. 우리가 짜놓은 소스는 Code영역에 들어가 있다.(make시킨 폴더에 들어가보면 확인 할 수 있다.)




인터럽트 함수 만들기




ADC로 조도 센서에 따른 값의 변화


저항은 전기의 흐름을 방해한다.CDS(빛 센서) 빛을 받으면 저항값이 변함.

 

 

위의 그림은 조도 센서 실물이다. 어둡고 밝기에 따라 저항값이 달라진다.

 

 

ADC.cADC.hLCD.cLCD.hmain.csmart.hUSART.cUSART.h

 

 

vcc 에서는 1023

GND 에서는 0000

조도 센스를 손으로 막으면 다른 값이 나온다.

참...이거 설명이 안되네요..;;

 

 

20140502 - ADC 초기화 실습

ATMega128 2014. 5. 2. 14:40 Posted by Owen.K

ADIF는 한 conversion이 끝나면 변환하게 된다.

• Bit 4 – ADIF: ADC Interrupt Flag

This bit is set when an ADC conversion completes and the data registers are updated.

이 비트가 셋이면 ADC 변환이 완료되었을 때와 데이터레지스터가 업데이트 되었을 때이다.

 

1-1. ADMUX 설정하기.

 

 

 

7 , 6  : 전압 선택 bit // 0 0

* 기본적으로 전압이 vcc5v, gnd-5v 라면 총 10v 인 셈이다. 그러므로 0 5v 로 하기 위해

중간점을 2.5(2.56)v 로 조정해 주기도 한다 ( 1, 1 을 넣음)

 

 

 

5     : 오른쪽 / 왼쪽 정렬  // 오른쪽 0

 

 

4~0 pin 설정

 우리는 single Ended Input 을 활용한다. 그러려면, 입력받는 unsigned char ucCh 는

00111 (0x7)을 넘기지 말아야 한다. 

그걸 막기 위해, ucCh & MASK_MUX 를 설정한다.

 

 

 

 

1-2. ADCSRA 설정하기

 

 

 

 

 

 

7        : 활성화 비트//스위치 같은 기능을 함. 이게 1 이 되어야 작동을 시작한다./ 0

       :             /0

       : FREE mode 의 on / off 설정 /0

4 ,3     : 인터렙트 설정 /0

 

인터렙트 

폴링 

이상이 있을 시, CPU 의 개입이 있음.

CPU가 다른 일을 멀티로 할 수 있다. 

정해진 시각마다 CPU가 개입 함.

CPU의 멀티 기능이 떨어 짐. 

 

ADC_RUN 함수에서 다시 활용된다!!! (뒤에 다시 설명) 

2,1,0    : 주파수 설정 // 0 0 0

 *주파수 설정은 상황과 용도에 맞게 설정해 준다. 작은 일에 많은 주파수를 주는건 낭비다.

 

 

 

unsigned int ADC_Run(void)
{
  ADCSRA   = ADCSRA|(1<<ADSC);
  while(0 == (ADCSRA&(1<<ADIF)));
  return ((ADCH<<8)|ADCL);
}

while 문으로 계속 돌려준단건 일일이 체크하는 '폴링방식'을 채용한것임.

반환값으로 ((ADCH<<8)|ADCL)를 준다.

 

1-3. ETC

void ADC_Init_0CH(void)
{
  ADC_Init(0);
}

unsigned int ADC_Convert(void)
{
  ADC_Init_0CH();

  return ADC_Run();
}

 

1-4.main에서 0000 하이텔/LCD로 보내기!

int main(void)
{
  char cString[] = "0000\n\r";
  unsigned int uiRet;

  USART_Init();
  LCD_Init();

  while(1)
  {
    uiRet = ADC_Convert();

    cString[0= '0' + (uiRet/1000)%10;
    cString[1= '0' + (uiRet/100)%10;
    cString[2= '0' + (uiRet/10)%10;
    cString[3= '0' + (uiRet/1)%10;
    
    USART_Str(cString);

    LCD_Str(cString);


  }

  while(1);
  return 0;
}

 

 

숫자를 넣을 땐, 아스키 코드 추출하는 식으로 보내야 한다.

ADC, DAC, 샘플링이란?





위 그래프에서 세로축은 전압, 가로축은 진동수 이다.

ADC(Analog Digital Converter) : 아날로그 값을 디지털 값으로 변경 해주는 장치.

DAC(Digital Analog Converter) : 디지털 값을 아날로그 값으로 변경 해주는 장치.

위 그래프의 샘플링은 3bit이다.

세로축에 점으로 표현가능한 자리수가 총 8개 이기 때문

예를 들면, 샘플링 10bit라고 하면 2^10승 이기 때문에 1024개의 점으로 표현이 가능하다.

(샘플링을 촘촘하게 할수록 아날로그 데이터에 가까워 진다. 하지만 완변하게 아날로그 데이터를 복사 할 수는 없다.)

 

ADC 스펙, 약도, 설명

 

 

 (ADC의 채널)

 

– 8-channel, 10-bit ADC

아날로그를 디지털로 바꿔주는 8개의 다리를 8-channel이다.

샘플링 비트(주파수)를 분해능력이라 한다.

 

 ADC 블록 스키마

 

ADC Prescaler의 설명

 

 

 ADC 정의


ADC.c

ADC.h



USART_RX통신으로 LCD에 키보드 입력받기


USART.c부터 살펴보면

반복문을 이용해 UCSR0A->RegisterA와 1을 RXC만큼 왼쪽으로 이동시킨게 &연산을 하여 

0과 같으면 반복인데 이 말은 입력값이 있을 때 까지..1이 될 때까지 반복된다는 말이다.

기능성 레지스터이고, cpu register : 0~31까지의 주소 중 하나에 저장된다.  


Main.c에서 LCD_Init과 USART_Init을 이용해 각각 초기화 시켜준 다음에

LCD_Data(USART_RX)를 하면 키보드에 치는 대로 LCD에 출력이 가능해진다.




폰트따서 이름 LCD출력하기



위 그림처럼 엑셀로 폰트를 딴다. 빨간 색 표시가 있는곳에 하나하나 모두 

저런식으로 넣어주면 1로 표시되어있는 곳을 비트단위로 계산하여 16진수로 바꿔준다.