[AVR] atmega1281 - switch / delay 함수
새로운 자료형
C의 data type의 변수 길이는 MCU에 따라 달라진다.
- sizeof(short) ≤ sizeof(int) ≤ sizeof(long) // 기본
- 8bit MCU : sizeof(int)= 2 / 32bit MCU: sizeof(int)= 4 / 64bit CPU: sizeof(int)= 8
https://www.ibm.com/docs/ko/i/7.5?topic=files-stdinth
<stdint.h>
<stdint.h> 포함 파일은 너비를 지정하고 해당 매크로 세트를 정의하는 정수 유형 세트를 선언합니다. 또한 다른 표준 포함 파일에 정의된 유형에 대응하는 정수 유형의 한계를 지정하는 매크로도
www.ibm.com
변수 선언 때 변수나 상수의 길이를 명시할 필요가 있음
- Embedded software 개발 시 흔히 사용
- MCU의 종류가 달라지면 typedef만 수정하면 됨
- <stdint.h>에 아래와 같이 정의되어 있음
ex)
typedef signed char int8_t; (8bit)
typedef unsigned int uint16_t; (16bit) (8bit MCU에서는 int)
typedef signed long int int32_t;
typedef unsigned long long int uint64_t;
스위치 관련 함수
- 스위치가 눌려져 있으면 1, 아니면 0을 반환하는 함수
inline uint8_t switch_pressed(){
return !(PINE&_BV(SW2));
}
inline 함수를 쓰는 이유: 함수호출 시 오버헤드(함수 활용을 위해 스택 메모리를 발행 등)를 방지하기 위해
=> 프로그램 속도가 최적화됨, but 남발하면 더 느려짐
- 스위치가 눌려지는 순간만 1을 반환하고, 아니면 0을 반환하는 함수(하강 엣지 검출)

uint8_t switch_hit(void) {
static uint8_t prev_state = _BV(SW2);
uint8_t cur_state;
cur_state = PINE&_BV(SW2);
if(prev_state != cur_state) {
prev_state = cur_state;
if(!cur_state) return 1;
else return 0;
}
else
return 0;
}
Q1. static 키워드를 왜 쓰는가?
- 이전 상태를 저장하여 다시 함수를 호출할 때마다 이전 상태는 유지해야 되기 때문이다.?
- 일반 지역 변수로 선언한 변수는 함수가 끝나면 소멸 되지만 static은 메모리에서 데이터 영역에 저장되어 프로그램이 종료될 때까지 지워지지 않는다.

EX)
int main(void){
uint8_t i = 0;
uint8_t led_pattern[4] = {0x0e, 0x0c, 0x08, 0x0};
DDRC = _BV(LED1) | _BV(LED2) | _BV(LED3) | _BV(LED4);
PORTE = _BV(SW2);
PORTC |= _BV(LED1) | _BV(LED2) | _BV(LED3) | _BV(LED4);
while(1) {
if(switch_hit()) {
PORTC = (PORTC & 0xf0) | led_pattern[i++%4];
}
}
}
Delay 함수
- ms와 us 분해능 delay 제공
- CPU는 NOP(no operation 명령어 실행: 아무 것도 안하는 명령)을 이용하여 시간 지연
- 클럭 주파수에 따라 값이 달리짐
Q2. _delay_ms(), _delay_us() 함수가 만들 수 있는 최대 지연 값은 각각 얼마인가?
https://www.nongnu.org/avr-libc/user-manual/index.html
avr-libc: AVR Libc
Introduction The latest version of this document is always available from http://savannah.nongnu.org/projects/avr-libc/ The AVR Libc package provides a subset of the standard C library for Atmel AVR 8-bit RISC microcontrollers. In addition, the library pro
www.nongnu.org
위 사이트에서 참조된 내용으로 AVR compiler가 제한한 최대 지연값이 다음과 같다.
_delay_ms()의 최대 지연 값: 262.14 ms / F_CPU (MHz)
_delay_us()의 최대 지연 값: 768 µs / F_CPU (MHz)
Q3. 이 값보다 큰 값을 입력 함수들은 어떻게 동작하는가? (F_CPU = 16MHz)
최대 지연 시간을 초과하면, _delay_ms()는 1ms의 정밀도를 유지할 수 없게 되고, 대신 0.1ms 단위로 나누어 더 큰 지연 시간을 제공한다.

- AVR 마이크로컨트롤러의 기본적인 루프 카운터는 16비트(2바이트)로 이루어져 있습니다. 16비트 정수형은 표현 가능한 값의 범위가 0에서 65535까지입니다.
- _delay_ms() 함수는 _delay_loop_2()을 사용하여 최대 65535번 반복할 수 있습니다.
- ex) 1초의 지연이 요청되면, 0.1ms를 만 번 실행하도록 하고, 1ms의 지연은 정확하지 않다.
_delay_ms()는 최대 약 16.38ms의 정확한 지연을 제공하고, 그 이상의 지연 시간에 대해서는 0.1ms 단위로 내부에서 분할하여 처리하고 최대 6.5535s까지 지연할 수 있으며, CPU 속도와 상관없이 이 동작 가능
_delay_us()는 최대 약 48µs의 정확한 지연을 제공하고, 그 이상의 지연 시간에 대해서는 분할 처리가 불가능하므로 사용 불가
또는 그냥 최대지연값 16ms를 고려하여 _delay_ms() 함수를 여러 번 실행하면 된다!
for(uint8_t i=0 ; i++ ; i <100)
_delay_ms(10);
#define F_CPU 16000000L
#include <avr/io.h>
#include <util/delay.h>
int main(){
uint8_t led_pattern[] = {0x0e, 0x0c, 0x08, 0x0, 0x08, 0x0c, 0x0e, 0x0f};
while(1) {
_delay_ms(500);
PORTC = (PORTC & 0xf0) | led_pattern[i++%8];
}
Q. i 값이 255에서 1이 증가 되면?
overflow가 발생하여 i=0