728x90

외부 인터럽트 벡터

- 인터럽트 벡터 테이블에서 상위에 위치

 

ATmega128에서 외부 인터럽트 핀 결정

- GPIO 핀 -> 범용 입출력 핀

- ATmega128의 53개의 핀만으로 다양한 기능을 동작하기엔 부족 -> 한 핀이 다른 기능도 사용 가능

 

 

 

외부 인터럽트 핀

- PD0 ~ PD3까지가 INT0 ~ INT3

- PE4 ~ PE7 까지가 INT4 ~INT7

- 해당 GPIO핀들을 외부 인터럽트 핀으로 사용가능

 

 

외부 인터럽트 회로

- 인터럽트 설정을 해야 외부 인터럽트 사용 가능

외부 인터럽트 사용 회로

 

외부 인터럽트 벡터 매크로

- 외부 인터럽트 0과 외부 인터럽트 3을 사용 시 벡터 매크로 설정

- 스위치 첫번째와 네번째를 외부 인터럽트 핀으로 사용

#include <avr/interrupt.h>

ISR(INT0_vect)
{

}

ISR(INT3_vect)
{

}

 

 

SREG Register

- 인터럽트 사용시 내부에 인터럽트 관련 설정을 했을때만 동작

-> 아무때나 인터럽트 발생 방지 

-> 레지스터 설정을 해야함 ->SREG 레지스터

- Status Register : 상태 레지스터

- 인터럽트를 사용하기 위해서 SREG 레지스터의 7번 비트에 1을 써야함(글로벌 인터럽트)

Status Register

 

글로벌 인터럽트 설정

- SREG 레지스터 7번 비트에 1을 저장

- 상태 레지스터는 다른 역활도 수행하므로 잘못 변경되지 않도록 주의

SREG |= (1<<SREG_I)
// SREG |= (1<<7);
// SREG = SERG | (1<<7);

 

SEI와 CLI 명령어

- sei() : Global Interrupt Enable -> 전체 인터럽트 활성

- cli() : Global Intterupt Disable -> 전체 인터럽트 비활성

sei();
// SREG |= (1 << SREG_I)와 같다.

cli();
// SREG |= (0 <<SREG_I)와 같다.

 

EIMSK Register

- External Interrupt MaSK Resgister

- 외부 인터럽트를 개별적으로 허용하는데 사용

- 사용하려는 외부 인터럽트를 high를 주면 된다.

ex) INT0 ~ INT3 을 1로 주면 외부 인터럽트 0 ~ 3 사용 가능

EIMSK Register

EIMSK Register 사용 예시

EIMSK = (1 << INT3);// 1 << 3 = 0b0000 1000;
EIMSK = (1 << INT0) | (1 << INT2); // 0b000 0101

 

EICRA/EICRB Register

- External Interrupt Control Register A/B

- EICRA : 외부 인트럽트 INT0 ~ INT3 감지 방법 결정

- EICRB : 외부 인터럽트 INT4 ~ INT7 감지 방법 결정

EICRA Register
ERCIB Register

EICRA Register

- ISC(숫자)1/0 과 같은 이름 규칙을 가짐

-> ISC01, ISC00 : 외부 인터럽트 0번 설정

-> ISC11, ISC10 : 외부 인터럽트 1번 실징

아래의 테이블 참고

ex 1) ISC01 = 1, ISC00 = 0 일 시

 -> 외부 인터럽트 0번에 폴링 에지 때 인터럽트 발생

ex 2) ISC71 = 1, ISC70 = 1 인 경우

 -> 외부 인터럽트 7번이 라이징 에지 때 인터럽트 발생

=> 스위치가 눌릴때 인터럽트? 눌리고 땔때 인터럽트?

- 스위치 여러개 사용 시 각각에 대해 별도로 코딩해야함

EICRA 레지스터 동작 설명

 

EICRA 코드 구현

EICRA |= (0<<ISC21) | (0<<ISC20); //INT2핀에 Low 신호 입력 순간 인터럽트 발생

EICRA = (1<<ISC21) | (1<<ISC20) | (1<<ISC11) | (0<<ISC10);
// INT2 핀 라이징 에지 시 인터럽트 발생 + INT1핀 폴링 에지시 인터럽트 발생

 

 

 

1. 외부 인터럽트 0 로우 레벨 시 LED on/Off

#include <avr/io.h>
#include <avr/intterupt.h>
#include <util/delay.h>

ISR (INT0_vect)
{
	PORTC = 0x00;
    _delay_ms(50);
    PORTC = 0xFF;
    _delay_ms(50);
}

int main(void)
{
	DDRC = 0xFF; // 출력 모드
    PORTC = 0xFF; // 하이레벨
    DDRD = 0x00; //입력 모드
    PORTD = 0xFF; // 내부 풀업 사용
    
    EICRA = (0 << ISC01) | (0 << ISC00);
    //Low가 들어오는 순간 인터럽트 발생 -> 내부 풀업으로 기본 상태 1 -> 스위치 클릭시 0-> INT0 발생
    EIMSK = (1 << INT0); //INT0 허용
    sei();//글로벌 인터럽트 인에이블
    while(1);
}

회로 설정

D1 VDD n1 ;LED D1이 VDD와 n1 node사이에 연결1
R1 n1 PC0 330 ; 저항 R1을 n1 node와 PC0 사이에 연결

D2 VDD n2
R2 n2 PC1 330

D3 VDD n3
R3 n3 PC2 330

D4 VDD n4
R4 n4 PC3 330

D5 VDD n5
R5 n5 PC4 330

D6 VDD n6
R6 n6 PC5 330

D7 VDD n7
R7 n7 PC6 330

D8 VDD n8
R8 n8 PC7 330

K0 PD0 VSS  LATCHEd ;K0 스위치는 래치타입 

- 래치 스위치를 사용하여 한번 누르면 눌린 상태가 유지됨

-> 눌린 상태서 HIGH, 다시 누르면 LOW로 변함

 

300x250
728x90

인터럽트

- HW 인터럽트, SW인터럽트

 

소프트웨어 SW 인터럽트

- 소프트웨어 요청으로 발생되는 인터럽트

- 마이크로 프로세서 내부에서 발생

- ex) 타이머/카운터

 

하드웨어 인터럽트

- 하드웨어 요청으로 발생

- 마이크로 프로세서 외부에서 발생

- ex) 스위치, 센서류

 

인터럽트 처리 순서

1. 일반 작업 실행

2. 인터럽트 발생(요청)

3. 수행작업 정지(복귀 주소 저장)

- 인터럽트 벡터 테이블 -> ISR(Interupt Service Routine) 주소로 점프

4. 인터럽트 서비스 루틴 실행

5. ISR 종료후 복귀

6. 멈췃던 작업 실행

인터럽트 처리 순서

 

인터럽트의 종류

- ATmega128은 35개의 인터럽트로 구성

- 인터럽트 우선 순위는 하드웨어적으로 설정됨

인터럽트 벡터 테이블

 

 

폴링 Polling

- 명령어로 특정 레지스터 값을 계속 읽어 레지스터 값이나 핀 값 변화를 체크하는 방식

- 작업 중에 계속 변화가 있는지 확임함

 

폴링 예시

- while문으로 !(UCSRA & (1<<RXC))가 1인지 계속 확인함

- 1이 아니면(0이면) 계속 루프에 머무름

- 1이 된 상태에서 루프를 넘어감

unsigned char USART_Receive(void)
{
	while ( !(UCSRA & (1<<RXC)) )
    
    return UDR;
}

 

인터럽트 inturrupt

- 하드웨어적으로 변화를 체크하여 변화시에만 동작함

 

인터럽트 벡터 매크로

- 벡터 테이블에서 외부 인터럽트 4개를 사용한다고 하는 경우. 인터럽트 서비스 루틴을 쓸때 매크로를 선언을 해주어야함

 ex) vector no.2 ~ 5

- iom 128 헤더파일에서 벡터테이블에 해당되는 인터럽트 벡터 매크로 확인 가능

#define INT0_vector		_VECTOR(1)
#define SIG_INTERRUPT0	_VECTOR(1)

#define INT1_vector		_VECTOR(2)
#define SIG_INTERRUPT1	_VECTOR(2)

#define INT2_vector		_VECTOR(3)
#define SIG_INTERRUPT2	_VECTOR(3)

#define INT3_vector		_VECTOR(4)
#define SIG_INTERRUPT3	_VECTOR(5)

 

iom128 헤더 파일 열어봐야하는 이유

- 외부 인터럽트 마스크인 EMSK 레지스터의 비트 값들이 숫자로 정의됨

* EMSK레지스터 : External Interrupt Mask register

- 비트코딩 사용하기 위함

 EIMSK = (1<<INT0) | (1<<INT2);

-> EIMSK = (1<<0) | (1<<2);

 

iom128 헤더파일내 EIMSK 레지스터

 

iom128내 인터럽트 벡터 매크로

 

 

iom128내 외부 인터럽트 마스크 레지스터

 

 

인터럽트 서비스 루틴

1. 인터럽트 서비스 루틴은 함수가 아님

 * 인터럽트 호출이 발생 뒤 실행되는 구간이라 특정 메모리 주소로 지정됨.

 * 인터럽트 서비스 루틴 작성 규칙에 따라 구현해야함

2. 인터럽트 서비스 루틴 선언 방식

- SIGNAL(벡터) 형식 : 일부 통합 개발환경에서 지원 x

- ISR(뻭터, 속성)

#include <avr/interrupt.h>

ISR (벡터, 속성)
{
	//인터럽트 서비스 루틴 코드 삽입
}

3. AVR GCC 인터럽트 서비스 루틴 속성

- GCC Manual에서 설명

- EMPTY_INTERRUPT(벡터) : 빈 인터럽트 처리

- ISR_ALIASOF(벡터) : 동일한 ISR 수행

- BADISR_vect : 선언되지 않은 인터럽트 처리

- ISR_NOBLOCK : 중첩 인터럽트 처리. sei()

 * 8비트 마이크로 컨트롤러에서는 중첩을 쓸 일은 없음

- ISR_NAKED : ISR 루틴 직접 작성시, reti() 반드시 호출

 

 

벡터 매크로

- no 1 : 리셋

- 35가지가 있으며 아래의 벡터 매크로를 참고해서 인터럽트 사용시 해당 벡터 매크로 선언해야함

 

 

인터럽트 서비스 루틴과 벡터 매크로 작성예 1

#include <avr/interrupt.h>

ISR (INT0_vect)// INT0 인터럽트가 발생시 이 인터럽트 서비스 루틴 동작함
{
	//routine
}

/*
지원하지 않는 경우 존쟈
SIGNAL (SIG_INTERRUPT0)
{
	//routine
}
*/

 

인터럽트 서비스 루틴과 벡터 매크로 작성예 2

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

volatile unsigned int flag;

//외부 인터럽트 0번 발생시 동작
ISR (INT0_vect)
{
	PORTC = 0xFF;
    _delay_ms(50);
    PORTC = 0x00;
    _dela_ms(50);
}

//외부 인터럽트 2번 발생시 동작
ISR (INT2_vect)
{
	flag = run;
}
300x250
728x90

문자 LCD 제어 예제 1

 

#define F_CPU 8000000	//클럭 설정
#include <avr\io.h>              // Most basic include files
#include <util/delay.h>

//DDRAM 설정 : 0x80+DDRAM addr 값
#define LINE1 0x80	//첫번째 라인의 DDRAM addr : 0x00->0x80+0x00
#define LINE2 0xC0	//두번째 라인의 DDRAM addr : 0x40->0x80+0x40

//PG2=LCD_EN, PG1=RW, PG0=RS에 연결
#define CMD_WRITE		0xFC	//명령어 쓰기 E=1, RW=0, RS=0
#define CMD_READ		0xFE	//명령어 읽기 E=1, RW=1, RS=0
#define DATA_WRITE	0xFD	//데이터 쓰기 E=1, RW=0, RS=1
#define DATA_READ		0xFF	//데이터 읽기 E=1, RW=1, RS=1
#define LCD_EN			0x04	//PG2에 연결

//LCD에 명령을 쓰기위한 함수
void LCD_cmd_write(unsigned char cmd)
{
	PORTG = CMD_WRITE;
	PORTB = cmd;
	PORTG =PORTG^LCD_EN;
	_delay_ms(2);
}
//LCD에 데이터를 쓰기 위한 함수
void LCD_data_write(unsigned char data)
{
	PORTG = DATA_WRITE;
	PORTB = data;
	PORTG = PORTG^LCD_EN;
	_delay_ms(2);
}

void init_LCD(void)
{
	_delay_ms(15);
	LCD_cmd_write(0x38);//명령레지스터에 0x38 전달
	_delay_ms(5);
	LCD_cmd_write(0x38);
	_delay_us(100);
	LCD_cmd_write(0x38);
	LCD_cmd_write(0x08);
	LCD_cmd_write(0x01);
	LCD_cmd_write(0x06);
	LCD_cmd_write(0x0C);
}

//LCD에 문자열 표시하기위한 함수
void LCD_wr_string(char d_line, char *str)
{
	LCD_cmd_write(d_line);
	while(*str != '\0')
	{
		LCD_data_write(*str);
		str++;
	}
}
//ATmega128 포트 초기화
void init_system(void)
{
	DDRB=0xFF;
	DDRG=0xFF;
}

int main()
{
	init_system();
	init_LCD();

	LCD_wr_string(LINE1, "Hello AVR!");
	LCD_wr_string(LINE2, "LCD Test ");	
	while (1)
	{
	}
	return 1;
}

 

초기화 코드는 아래를 참고하여 작성

 

 

스위치 조작을 이용한 LCD 상태 표시

 

// ***********************************************************
// Project:
// Author:
// Module description:
// ***********************************************************

#include <avr\io.h>              // Most basic include files
#include <util/delay.h>

//DDRAM 설정 : 0x80+DDRAM addr 값
#define LINE1 0x80	//첫번째 라인의 DDRAM addr : 0x00->0x80+0x00
#define LINE2 0xC0	//두번째 라인의 DDRAM addr : 0x40->0x80+0x40

//PG2=LCD_EN, PG1=RW, PG0=RS에 연결
#define CMD_WRITE		0xFC	//명령어 쓰기 E=1, RW=0, RS=0
#define CMD_READ		0xFE	//명령어 읽기 E=1, RW=1, RS=0
#define DATA_WRITE	0xFD	//데이터 쓰기 E=1, RW=0, RS=1
#define DATA_READ		0xFF	//데이터 읽기 E=1, RW=1, RS=1
#define LCD_EN			0x04	//PG2에 연결

//LCD에 명령을 쓰기위한 함수
void LCD_cmd_write(unsigned char cmd)
{
	PORTG = CMD_WRITE;
	PORTB = cmd;
	PORTG =PORTG^LCD_EN;
	_delay_ms(2);
}
//LCD에 데이터를 쓰기 위한 함수
void LCD_data_write(unsigned char data)
{
	PORTG = DATA_WRITE;
	PORTB = data;
	PORTG = PORTG^LCD_EN;
	_delay_ms(2);
}

void init_LCD(void)
{
	_delay_ms(15);
	LCD_cmd_write(0x38);//명령레지스터에 0x38 전달
	_delay_ms(5);
	LCD_cmd_write(0x38);
	_delay_us(100);
	LCD_cmd_write(0x38);
	LCD_cmd_write(0x08);
	LCD_cmd_write(0x01);
	LCD_cmd_write(0x06);
	LCD_cmd_write(0x0C);
}

//LCD에 문자열 표시하기위한 함수
void LCD_wr_string(char d_line, char *str)
{
	LCD_cmd_write(d_line);
	while(*str != '\0')
	{
		LCD_data_write(*str);
		str++;
	}
}
//ATmega128 포트 초기화
void init_system(void)
{
	//B,G- LCD
	DDRB=0xFF;
	DDRG=0xFF;
	//C- LED, D-SWITCH
	DDRC=0xFF;
	DDRD=0x00;
	PORTC=0xFF;
	PORTD=0xFF;//내부풀업 사용
}

int main()
{
	init_system();
	init_LCD();


	unsigned char sw1, sw2;
	while(1)
	{
		sw1 = PIND & 0xFE;//1111 1110 -PD 0번 스위치 눌릴때
		sw2 = PIND & 0xFD;//1111 1101 -PD 1번 스위치가 눌릴때
		
		if (sw1 == PIND)
		{
			LCD_wr_string(LINE1, "   switch 1 ");
			LCD_wr_string(LINE2, "200ms Blinking");
			PORTC = 0xFE;//1111 1110 0번 LED 블링크
			_delay_ms(200);
			PORTC = 0xFF;
			_delay_ms(200);
		}	
		else if (sw2 == PIND)
		{
			LCD_wr_string(LINE1, "  switch 2");
			LCD_wr_string(LINE2, " 500ms blinking!");
			PORTC= 0xFD;
			_delay_ms(500);
			PORTC= 0xFF;
			_delay_ms(500);
		}
		else
		{
			LCD_wr_string(LINE1, "    ");
			LCD_wr_string(LINE2, "     ");
		}
	}
	return 1;
}


 

회로 설정 프로젝트 코드

D1 VDD n1 ;LED D1이 VDD와 n1 node사이에 연결1
R1 n1 PC0 330 ; 저항 R1을 n1 node와 PC0 사이에 연결

D2 VDD n2
R2 n2 PC1 330

D3 VDD n3
R3 n3 PC2 330

D4 VDD n4
R4 n4 PC3 330

D5 VDD n5
R5 n5 PC4 330

D6 VDD n6
R6 n6 PC5 330

D7 VDD n7
R7 n7 PC6 330

D8 VDD n8
R8 n8 PC7 330

K0 PD0 VSS
K1 PD1 VSS

Xdisp LCD(16 2 250K) PG0 PG1 PG2 PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0

 

- 스위치 LCD 테스트 중 실수한게

스위치를 꾹 누르고 있어야 적절한 PIND 입력이 전달된다.

살짝 눌러놓고 왜 LCD가 안뜨나 했다..

 

300x250
728x90

LCD 액정 디스플레이

- 대부분 디스플레이에 사용

- FND 같은 단순한 형태부터

- 실제 가까운 OLED까지

 

 

문자 LCD

- Liquid Crystal Display 약자

- Character Type LCD와 Graphic Type LCD로 구분

- 최대 가로로 쓰이는 문자수와 세로로 표시되는 줄 수로 규격이 정해짐

 -> 16 x 2(16글자 2줄), 20 x 4 (20글자 4줄), 40 x 2 등 다양한 종류

- LCD와 컨트롤러가 결합된 모듈형태

- 대부분 Hitachi의 HD44780 컨트롤러 내장 -> DH44780의 데이터시트를 보면서 해야함

 

문자 LCD

 

C-LCD 핀 구성

- MCU가 통해 신호를 보내야함

- MCU 측 PB0~7 까지 8개 핀, PG0~2 3개 -> 11개 핀 할당

- LCD Driver에선 RS, RW, E와 DB0~7핀이 받음

MCU - LCD 
컨트롤트롤러와 LCD

 

 C_LCD 핀의 기능 

- CN-LCD는 LCD 모듈

 

LCD 핀의 기능

- 1,2  그라운드와 전원

- 3 가변저항

- 15, 16은 백라이트 전원과 그라운드 연결 

- 4 : PG0 핀으로 high를 보내면 데이터 레지스터 선택, low를 보내면 명령레지스터 선택

LCD 회로도

 

 

 

DDRAM Display Data RAM

- 최대 80*8bit 기억 용량 (최대 80글자 기억)

-  DDRAM의 1행 0x00 ~ 0x27 addr(40문자) : 0x80 + (0x00 ~ 0x27)

- DDRAM의 2행 0x40 ~ 0x67 addr(40문자) : 0x80 + (0x40 ~ 0x67)

- DDRAM의 address 동작 상태 (실제 메모리 공간 : 0x80~0xA7, 0xC0 ~ 0xE7)

-> 0x80하는 이유는 뒤에 서술

 

CG ROM(Character Generator ROM)

- 문자 생성 ROM

- 가로 16 x 세로 12개의 address code를 가짐

- 192개의 숫자, 문자 패턴을 가짐

 

CG RAM(character generator ram)

- 문자 생성 ram

- 사용자가 프로그램으로 문자 패턴을 만들 경우 사용하는 ram

- 0x00 ~ 0x3f 번지 저장

- 8개의 사용자 공간 활용 가능

- 전원 off 시 data는 삭제됨

-> 잘 사용하지 않으나 문자 생성 필요시 사용

 

 

레지스터 선택 신호

- 명령어/데이터 쓰기 작업만 집중 : CGROM에 있는 192개의 숫자, 문자 패턴을 씀

- Instruction Register IR : Text LCD 모듈 환경 설정

- Data Register DR : 모듈에 글자를 표시하기 위한 데이터 값이 들어가는 레지스터

- IR에 명령어 세팅 -> DR에 표시하는 값 write

- rs=0, rw=0 명령어 쓰기 -> Instruction Register에 제어 데이터 쓰기

- rs=1, rw=0 데이터 쓰기-> LCD에 표시할 문자를 Data Register에 쓰기

 

 

 

문자 LCD 명령 테이블

- I/D, S/C, R/L은 명령 옵션 아래의 명령 옵션 참고

 

문자 LCD 명령 옵션

 

8비트 LCD 초기화

 

8비트 데이터 버스를 사용하는 LCD 초기화 방법

//LCD 초기화
void init_LCD()
{
	_delay_ms(15);
    
    /*
    0x38의 의미 -> 문자 LCD 명령 테이블 참고
    0x38 == 0011 10xx
    Function set 명령을 의미
    DL 옵션이 1, N 옵션 1, F옵션 0 / 인터페이스(DL), 라인(N), 폰트(F)
    => 문자 LCD 명령 옵션 참고
    DL =1 -> 8비트 데이터 버스 사용 data line
    N = 1 -> 두줄 사용 number line
    F = 0 -> 5x8 dot 사이즈 글자 font / F=1 인경우 5 x 10 dot size 글자 사용 -> 0011 11xx을 write하면됨
    
    */
    LCD_cmd_write(0x38); 
    
    _delay_ms(5);
    LCD_cmd_write(0x38);
    _delay_ms(100);
    LCD_cmd_write(0x38);
    
    LCD_cmd_write(0x08); //표시 off
    LCD_cmd_write(0x01); // 화면 지우기
    LCD_cmd_write(0x06); // 엔트리 모드 셋
    LCD_cmd_write(0x0C); //표시 on
    
}

 

쓰기 동작 타이밍도

- 데이터 시트 마지막에 있음

- 유효한 명령/데이터로 하기 위해서 E을 high에서 low로 중간에 떨어뜨려야 함

 

문자 LCD 표시 예제

//LCD 8비트 인터페이스 초기화 함수
void LCD_init()
{
	DDRB = 0xFF;
	DDRG = 0xFF;
	_delay_ms(20);
	LCD_command(0x38);
	LCD_command(0x08);
	LCD_command(0x01);
	_delay_ms(1);
	LCD_command(0x06);
	LCD_command(0x0E);

}

//LCD 명령 처리 함수
void LCD_command(unsigned char cmd)
{
	//0000 0100
	PORTG = 0x04; //E=1, RW=0, RS=0 -> 명령 레지스터에 명령쓰기
	PORTB = cmd;  // 명령 전달
	_delay_us(1);
	PORTG = 0x00; //E=0, RW=0, RS=0
	// enable을 high에서 low로 떨어져야 valid data   -동작 타이밍도 참고
	_delay_us(1); //명령 쓰기
	
}
// LCD 데이터 처리 함수
void LCD_data(unsigned char data)
{
	PORTG = 0x05;//E=1, RW=0, RS=1  LCD에 표시할 문자를 데이터레지스터에 쓰기
	PORTB = data;//데이터 값 전달
	_delay_us(1);
	PORTG = 0x01;//E=0, RW=0, RS=1 LCD 데이터 처리신호 high->low
	_delay_us(1);
}

// 문자열 처리 함수
void LCD_string(unsigned char cmd, unsigned char *str)
{
	//문자열 출력 위치 명령 전달
	LCD_command(cmd);
	// 문자열 마지막 null에서 루프 종료
	while (*str != '\0')
	{
		LCD_data(*str);
		str++;
	}
}

// ***********************************************************
// Main program
//
int main(void) {

	LCD_init();
	
	unsigned char str1[] ="LCD display";
	unsigned char str2[] = "  Example ";
	while (1)
	{
		LCD_string(0x80, str1);// 첫째줄 0x80부터 시작
		LCD_string(0xC0, str2);// 둘째줄 0xC0부터 시
		_delay_ms(100);
	}
	return 1;
}

LCD VMLAB 프로젝트 코드

 ;                     rs  rw  E   -------------8bit interface----
 Xdisp	LCD(16 2 250K) PG0 PG1 PG2 PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0
 ;X(이름)disp(모듈)
 ;16 x 2 , 250K 크리스탈 동작

300x250
728x90

FND 세븐 세그먼트

- Flexible Numeric Display

- 숫자 표현을 위한 디스플레이용 소자

- .을 포함하여 8개 LED 배열하여 표현

FND

 

 

FND 내부 회로

- 커먼 캐소드형 : 컴 단자가 - , 공통으로 -단자에 연결

- 커먼 애노드형 : com 단자가 + 전압, 공통으로 + 단자에 연결

Common Cathod형 FND
Common Anode 형

 

FND 동작 원리

- 캐소드 타입 : 핀에 하이 신호 시 불켜짐

- 애노드 타입 : 핀에 로 신호시 불켜짐

 

 

FND 캐소드 타입 테이블

- 애노드 타입의 경우 캐소드 타입을 반전시키면 된다.

 

핀 연결

 

모든 세그먼트를 연결시

- 총 54개 핀이 필요

- 6개의 COM(COM0~COM5), 8(a~h) x 6

 

세그먼트 공통 연결시

- 14개 핀으로 제어

 - 8(a~h) + 6(COM0 ~ COM5)

문제 : 8개의 비트 만으로 6개 FND 값 전체를 한번에 제어할수 없음

-> 잔상 효과로 각 LED를 시간차 주어 제어

 

잔상효과를 이용한 FND 제어

- 자리를 바꾸면서 남는 잔상으로 숫자 표시 -> 모든 세그먼트 연결하는것보다 핀 수를 줄일 수 있음

-> 가장 흔한 FND 제어 방식

 

FND 회로도

- 캐소드 공통형 회로도

- 사용된 핀 확인해야함

- PE2~5 4개, PA0~PA7 8개

 

FND 제어 예제 1

- FND를 사용하기 위해 커먼과 핀을 출력설정해야함

#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
	DDRA = 0xFF;
    DDRE = 0xFF;
    
    while (1)
    {
    	PORTA = 0x3F;	// 숫자 '0'
        PORTE = 0x00;	// X1~X2 FND ENABLE
        _delay_ms(10);
    }
}

 

회로도 코드

;_led7cc : 커먼 캐소드 타입 FND
; PA0~PA7를 입력
; PE0를 캐소드에 연결
X1 _led7cc PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 PE0
X2 _led7cc PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 PE1
X3 _led7cc PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 PE2
X4 _led7cc PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 PE3
X5 _led7cc PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 PE4
X6 _led7cc PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 PE5
X7 _led7cc PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 PE6
X8 _led7cc PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 PE7

; 커먼 애노드 타입 사용시 _led7ca
;FND 설정, Xn _led7cc seg_a seg_b seg_c seg_h ... seg_h GND

 

FND 제어 예제 2

#include <avr/io.h>
#include <util/delay.h>

int main(void)
{

	unsigned char seg[8] = {0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F};
    unsigned char i;
    
	DDRA = 0xFF;
    DDRE = 0xFF;
    PORTE - 0x00;	//전체 FND enable
    
    while (1)
    {
  		for (i = 0; i < 8; i++)
        {
        	PORTA = seg[i];
            _delay_ms(100);
        }
  	}
}

 

다이나믹 FND

- VMLAB에서 사용불가.

300x250
728x90

스위치 종류

- 로터리 스위치, 푸시 스위치, 반도체 스위치, 동축 스위치, 다방향 스위치

- 딥 스위치 : 스위치가 배열형태로 됨

- 전기전자 회로에서 전류 흐름을 제어

- 사용자와 상호 작용 또는 제어를 필요로하는 회로의 중요한 요소

푸시 스위치

 

슬라이드 스위치
마이크로 스위치
딥 스위치

 

스위치 역활

- OFF 상태와 ON 상태로 있음

- OFF 상태 : 회로가 열린 상태로 전류 흐름 막음

- ON 상태 : 회로가 닫힘 상태로 전류는 방해받지 않고 흐름

 

 SPST Single Pole Sing Throw

- 1A 접점

- 온오프 스위치로 가장 일반적인 형태

- 두 개의 단자 필요

SPST 심볼 회로

 

온오프 스위치

 

SPDT Singlee Pole Double Throw

- 1C 접점 1A1B

- 슬라이드 스위치

- 세개 단자 필요

SPDT 심볼 회로
슬라이드 스위치

 

 

DPDT Double Pole Double Throw

- 2C접점 (2A 2B)

- 두개의 SPDT 스위치

- 여섯개 단자 필요

DPDT 심볼 회로
로커 스위치

 

4PDT Four Pole Double Throw

- 네 개의 별도 회로로 구성

- 회로당 두 위치 제어 가능

 

토글 스위치
4PDT 심볼 회로

 

 

 

PINx 레지스터는 스위치에서 입력 처리

-> 핀으로 들어오는 신호값을 저장

-> 저장된 값을 호출해서 사용하면 됨

 

내부 풀업 사용 시

- 내부에 내부 풀업 회로가 있음

- DDRxn =0, PORTxn=1, PUD=0 시 내부의 풀업을 사용하게 됨

 

풀업 저항

- 저항이 전원에 연결

- 스위치 off 시 1이 입력, on일시 0이 입력

풀다운 저항

- 저항이 접지에 연결

-  스위치 off시 0이 입력, 스위치 on시 1이 입력

 

풀업/다운 저항이 없는경우

- 스위치 off 시 플로팅 현상 발생 -> 0,1인지 구분못함 -> 이를 해결하기위해 풀업/다운 저항 사용

 ex) 손 가까이 대서 정전기 발생시 스위치가 off여도 1로 판단

- 하이 임피던스 상태

 

 

 

스위치 회로

- 저항이 전원측에 연결됨 -> 풀업

- PD0 측 스위치 on -> PIND 레지스터 0번 비트에 0이 들어감

 

 

채터링 현상

- 한번의 기계적 개폐동작에 전기적으로 여러번 개폐동작이 발생

-> 한번 눌렀는데 여러번 눌린걸로 판단할수있음

- 디바운싱(debouncing) 채터링 문제를 방지하는것으로 하드웨어적인 방법(콘덴서 사용->비용발생), 소프트웨어 적인 방법이 있음

 

 

소프트웨어 디바운싱

while(1)
{
	//pind에는 풀업 저항을 취하여 기본으로 1값이 됨
    // pind ==  1111 1111
    // ~pind == 0000 0000
    // 0x01 ==  0000 0001
    
    // 키조작 발생
    // pind == 1111 1110
    // ~pind ==0000 0001
    // 0x01 == 0000 0001
    // ~pind&0x01 == 0000 00001
    // !(~pind & 0x01)은 0x00이므로 루프 탈출 x
    // pind에 조작이 있으면 !(~pind &0x01)은 1이되어 탈출
    
	while (!(~PIND & 0x01)); //Falling edge
    _delay_ms(10); //디바운싱 지연: 키조작 발생시 -> 10ms 지연 -> 10ms간 채터링 현상 무시
    
    if(++i == 8) i=0;
    PORTC=led[i];
    
    while(~PIND &0x01);
    _delay_ms(10);
    
}

 

 

제어 예제1

#include <avr/io.h>

int main(void)
{
	DDRC = 0xFF;
    DDRD = 0xF0;
    PORTC = 0xFF; //LED 끈 상태에서 시작
    PORTD = 0xF0;
    
    // c언어에서 한줄만 반복시 for (;;)사용 가능
    for (;;)
    	PORTC = PIND;
    
}

 

 

제어 예제2

#include <avr/io.h>

int main(void)
{
	DDRC = 0xFF;
    PORTC = 0xFF; //LED 끈 상태에서 시작
    DDRD = 0xF0;
    unsigned char key;
    
    while (1)
    {
    	key = PIND & 0x0F;
        switch (key)
        {
        	case 0x0E:
            	PORTC = ~_BV(0); //PC0번 비트 킴
                break;
            case 0x0D:
            	PORTC = ~_BV(1);//PC1번 비트 킴
                break;
            case 0x0B:
            	PORTC = ~_BV(2);
                break;
            case 0x07:
            	PORTC = ~_BV(3);
                break;
        	
        }
    }
}

=> 예제 2를 정리하면 닫은 스위치의 LED만 켜고 끄는 예제

 

제어 예제 3

- PIND 0번 비트 스위치를 누르면 전체 LED가 켜지는 예제

#include <avr\io.h>       
#include <util/delay.h>


int main(void)
{
	DDRC = 0xFF;
    PORTC = 0xFF;
    DDRD = 0x00;
    PORTD = 0xFF;
    unsigned char key;

    while (1)
    {
    	key = PIND & 0xFE;
		
        if (key == PIND)
        {
        	PORTC=0xFF;
            _delay_ms(200);
            PORTC =0x00;
            _delay_ms(200);
        }
        else
        	PORTC = 0xFF;
	}
}

 

 

회로도 설정

- 기존 VCC- LED- PORTC 레지스터 연결

- 전압 측정을 위한 프로브 

- PIND 0번 레지스터와 전원 사이에 K0 연결

D1 VDD n1 ;LED D1이 VDD와 n1 node사이에 연결
R1 n1 PC0 330 ; 저항 R1을 n1 node와 PC0 사이에 연결

D2 VDD n2
R2 n2 PC1 330

D3 VDD n3
R3 n3 PC2 330

D4 VDD n4
R4 n4 PC3 330

D5 VDD n5
R5 n5 PC4 330

D6 VDD n6
R6 n6 PC5 330

D7 VDD n7
R7 n7 PC6 330

D8 VDD n8
R8 n8 PC7 330

;프로브 설정 (PC0~pC7, PD0?포트에 전압 프로브 연결)
.PLOT V(PC0) V(PC1) V(PC2) V(PC3) V(PC4) V(PC5) V(PC6) V(PC7)
.PLOT V(PD0)
;스위치 설정
K0 PD0 VSS ;K0 스위치를 PD0와 VSS 사이에 연결

;WMLAB에서 LED는 Dx를 가리키지만 스위치는 Kx로 사용가능

 

-PC0에 풀업 저항으로 1이 들어오다 스위치를 누르면 0이 들어오면서

펌웨어 로직에 따라 전체 LED가 켜기게 된다

300x250
728x90

릴레이

- 전기적 스위치

- 물리적 스위치 보다 크기를 줄여 편의성 높임

 

릴레이 동작 원리에 따른 구분

- 기계식 릴레이 :코일이 감겨진 전자석에 제어 전류를 흘려 그 자력으로 스위칭 동작

- 무접점 릴레이 : 기계적인 접점 부분을 반도체 소자로 대체하여 전자적인 스위칭 동작

 

코일 유형에 따른 구분

- 래칭 latching

 기본 상태 없이 쌍 접점의 한 상태에 있다가 전원이 한순간이라도 공급되면 다른 상태로 변경되고  유지

- 비래칭(non latching)

 푸시 버튼이나 스위치 처럼 릴레이에 외부 입력이 가해지다가 멈추면 접점이 기본상태로 돌아감

 

접점 구성에 따른 구분

 

다양한 릴레이

- 릴레이의 핀 배치가 표준화되지 않아 선택시 겉 모양만보고 선택시 문제 발생

- 소형 릴레이의 핀 간격이 매우 좁기 때문에 사용전 데이터시트를 꼼꼼히 확인해야함

- 래칭 릴레이와 비래칭 릴레이 외형이 똑같아 확인 필요

- AC 전원과 DC 전원용 구분해야함

- 소음과 전압 스파이크 등의 발생에 주의

다양한 릴레이

 

릴레이와 핀 구성

 

릴레이와 LED 연결

 

300x250
728x90

LED 회로도

- LED가 어떤 핀에 연결되어있는지

- Ground 인지 전원에 연결되어있는지

LED 회로도

 

레지스터 설정

- DDRC = 0xFF;

-> 핀C 8개 비트 모두 출력 설정

- PORTC = 0xFF;

-> 핀 C 8개 비트 모두 HIGH -> 다이오드가 전원과 연결됨 -> 전위차 0 -> LED가 꺼진상태 시작

 

 

회도로 프로젝트 파일

D1 VDD n1 ;LED D1이 VDD와 n1 node사이에 연결 
R18 n1 PC0 1k ; 저항 R18이 n1 node와 PC0 사이에 연결 

D2 VDD n2 
R19 n2 PC1 1k 

D3 VDD n3 
R20 n3 PC2 1k 

D4 VDD n4 
R21 n4 PC3 1k 

D5 VDD n5 
R22 n5 PC4 1k 

D6 VDD n6 
R23 n6 PC5 1k 

D7 VDD n7 
R24 n7 PC6 1k 

D8 VDD n8 
R25 n8 PC7 1k 

 

 

 

20번 LED 블링크 하기

#include <avr\io.h>              // Most basic include files
#include <util/delay.h>       // Add the necessary ones

int main()
{
	unsigned int k=20;
	DDRC = 0xFF;
	PORTC = 0xFF;
	
	while (k != 0)
	{
		PORTC = 0xFE;
		_delay_ms(200);
		PORTC = 0xFF;
		_delay_ms(200);
		k--;
	}
}

 

특정 LED 켜기

- _BV는 메크로

- _BV(4) == (1<<4)

#include <avr\io.h>              // Most basic include files
#include <util/delay.h>       // Add the necessary ones

int main()
{
	DDRC = 0xFF;
	PORTC = 0xFF;
	
	while (1)
	{
		PORTC = ~( (1<<3)|(1<<5)); //0x1010 1111 LED D4, D6 on
		_delay_ms(200);
		PORTC = ~(_BV(4)|_BV(6)); //0x0101 1111 LED D5, D7 on
		_delay_ms(200);
	}
	return 1;
}

 

 

_BV 매크로 함수 이해

- sfr_defs.h 파일에 선언되어있음

- _BV(bit)는 해당 bit에 1을 쓴다

#define _BV(bit) (1<<(bit))

ex) _BV(4) -> (1<<4)

 

LED 전체 점멸

 

#include <avr\io.h>              // Most basic include files
#include <util/delay.h>       // Add the necessary ones

#define DDR_LED DDRC
#define PORT_LED PORTC

int main()
{
	unsigned char led_status = 0xFF;
	
	DDR_LED=0xFF;
	PORT_LED=0xFF;
	
	while (1)
	{
		led_status=~led_status;
		PORT_LED=led_status;
		_delay_ms(200);
	}
	return 1;
}

 

300x250
728x90

vmlab 시뮬레이터

- VMLAB 통합 개발환경은 무료이나 컴파일러 추가 설치 필요 

 -> GCC 기반 WinAVR 필요

- 원래 받을수 있는 사이트가 사라져선지 다운받을수가 없더라 대신 찾아서 블로그에다가 올려놨다.

https://throwexception.tistory.com/150

 

1. 새 프로젝트 생성

 

프로젝트 생성창

1.1 프로젝트 폴더 설정

1.2 타겟보드 설정

- ATmega128 사용하므로 선택

 

1.3 툴체인 경로 선택

1.4 소스 코드 파일 생성

- add this로 파일 추가하자

 

1.5 프로젝트 생성 완료

- hex 파일과 .prj 파일이 열림

- hex 파일 -> c 프로그래밍

- prj 파일 -> 회로도 정의

 

 

2. 코드 작성

 

3. 빌드

* 윈도우 10에서 빌드 중 오류 발생시

처음 WMLAB에서 코드 빌드하면 이런 에러가 나오는데 잠깐 구글링하다보니

 

winavr은 2010년에 나온게 가장 마지막 버전인데 지금은 2020년이고 윈도우 10에서 쓰면 이런 에러가 발생할수 있다고 한다.

https://www.avrfreaks.net/forum/winavr-error-new-computer

 

다행이 다른분이 비슷한 에러를 해결하는 방법을 올린데로 해보니 해결되더라

 

winavr/utils/bin 위치에

아래의 msys-1.0.dll을 덮어 씌워주면 해결된다

msys-1.0.dll
0.69MB

 

 

https://m.blog.naver.com/PostView.nhn?blogId=newbongman&logNo=221224568952&proxyReferer=https:%2F%2Fwww.google.com%2F

 

 

 

msys를 옮긴후 re-build를 해주면 성공

 

 

 

 

컨트롤 패널

 

 

코드 실행하기

- 신호등 클릭

IO 포트 보기

- view 의 IO 포트에 들어오면 각 핀별로 레지스터를 볼수 있다.

 

 

 

LED 회로 정의하기

- VCC -> 다이오드 -> 핀 형태로 정의

LED 회로도

- 프로젝트 파일에 아래 처럼 작성하면 위 LED 회로가 구현된다.

 

LED 블링크

1. 코드 작성

2. 회로도 설계 후

- 위 코드를 빌드 -> 실행 -> IO 포트 확인하면

 

0.2초 간격으로 PC0에 연결한 D1 LED가 깜빡깜박하는모습을 볼수있다

 

#include <avr/io.h>	// 생략/winavr/include/avr/io.h
#include <util/delay.h> // 생략/winavr/include/util/delay.h

int main(void)
{
	DDRC=0xFF;
    PORTC=0xFF;
    
    while(1)
    {
    	PORTC=0xFE;
        _delay_ms(200);;
        PORTC=0xFF;
        _delay_ms(200);
    }
    return 1;
}

 

1. 초기화 시점에 DDRC 레지스터와 PORTC 레지스터 전체 비트를 1로 설정 -> 전위차 x -> D1 ~ D8 LED가 꺼진다

 

2. 코드가 무한 루프를 돌면서 PORTC 레지스터 0번 비트를 0이 되면 -> 전위차 발생 -> 불켜짐 

 

 

LED 시프트하기

300x250
728x90

원래 vmlab 사이트가 사라졌는지

 

vmlab 다운 받을수있는데가 안보이더라

 

한참 해매다가 겨우 찾았다

 

Install_VMLAB315.exe
4.39MB

 

300x250

+ Recent posts