AVR에서 인터럽트가 발생하였을 때 이를 처리하기 위한 ISR 함수는 ISR()이라는 매크로를 사용하면 된다고 앞의 글에서 설명하였다. UART RX 인터럽트가 발생하였을 때 이를 처리하기 위하여 ISR(USART_RX_vect)라고 정의해 주면 되었다. 그러나, AVR 프로그램을 처음 시작하는 프로그래머는 어디서 이런 정보를 얻어야 되는지 몰라서 무척 당황하게 된다. 물론 요즘은 인터넷 검색으로 'AVR 인터럽트'라고 치면 많은 정보를 쉽게 찾을 수 있겠지만, 이렇게 찾아낸 것들은 주로 많이 사용하는 인터럽트 몇개의 경우에 한정된다. 만약 Analog Comparator에서 발생하는 인터럽트를 사용하려면 ISR() 안에 무엇을 넣어야 되는지 빨리 못찾을수가 있다. 답부터 얘기하면 Atmel Studio..
이번에는 UART를 이용하여 AVR에서 인터럽트를 발생 시키는 방법과 인터럽트가 발생하여 현재 수행중인 프로그램을 멈추고 인터럽트 벡터 주소로 점프하여 인터럽트를 처리한 후, 다시 인터럽트로 인하여 멈추어진 프로그램을 다시 실행 시키는 절차에 대하여 설명하도록 하겠다. 이전에 설명하였던 UART 글들을 참조하여 다음과 같은 메시지가 출력되도록 한다. #include #include "uart.h" void setup(void) { uart_init(); printf("UART RX Interrupt Test Program. [%s %s]\n",__DATE__,__TIME__); } void loop(void) { } int main(void) { setup(); while (1) { loop(); } }..
이번 글에서는 프로그램이 정상적인 흐름대로 실행되고 있는 도중에, 어떤 이유에 의해서 수행중인 프로그램을 멈추고 특정 위치에서 명령어를 읽어 와서 실행하는 인터럽트에 대해서 설명하도록 하겠다. 사실, 인터럽트는 이게 전부다. 수행중인 프로그램을 멈추고 지정된 주소에서 프로그램을 실행하도록 하는거. 문제를 해결한 다음엔 멈춘 위치로 다시 돌아가 아무일 없는듯이 정상적인 동작을 계속하도록 한다. 그럼 AVR에서는 어떤 경우에 수행중인 프로그램을 중단시키는지 그 이유를 알아보겠다. 위에 보이는 표가 ATmega328에서 사용가능한 인터럽트 종류이다. 모두 26개의 인터럽트가 있다. 만약 UART로 데이터가 수신되면 19번 인터럽트가 발생하고 그에 따라 CPU는 0x0024번지에서부터 명령어를 수행하게 된다. ..
힘들게 구현했던 LED 온도계를 이번에는 UART를 이용하여 컴퓨터 화면에 숫자로 현재 온도를 출력하는 프로젝트를 진행해 보도록 하겠다. 출력되는 온도 해상도는 소수점 세자리로 표시하도록 하겠다. DS18B20을 제어하는 driver 파일인 ds18b20.c 파일은 다음과 같이 작성한다. int ds18b20_init(void) { uint8_t rom[8]; int ret = 0; read_rom_code(rom); if (crc8(rom, sizeof(rom)) == 0) { if(rom[0] != DS18B20_CODE) ret = -1; } else { ret = -1; } return ret; } int16_t get_current_temperature(void) { int16_t tempera..
이제 UART를 이용하여 AVR에서 printf() 함수를 사용할 수 있게 되었으니, 개발환경 구축 글에서 하고자 했던 "hello, world"라는 메시지를 컴퓨터 화면으로 출력하는 프로젝트를 만들어 보겠다. 물론 이미 앞의 글에서 printf()를 사용하여 문자를 출력하는 것을 해 보았기 때문에 굳이 "hello, world"를 출력해 보는 것을 따로 해 볼 필요는 없다. 그러나 이번 글은 단순히 printf를 이용해서 문자를 출력해 보는것이 목적이 아니라, uart관련된 코드를 별도의 c와 h파일로 분리 시켜, 이후에 진행 되는 프로젝트에서 쉽게 재활용할 수 있는 방법에 대해서 설명하기 위하여 이번 프로젝트를 진행하게 되었다. 먼저 uart.h 파일을 다음과 같이 만든다. #define UART_R..
앞의 글에서 my_printf()를 이용하여 printf() 대신 사용할 수 있는 방법에 대해서 알아보았다. 그러나 실제 프로젝트를 진행하다 보면 이미 기존에 수행했던 코드를 참조하거나 인터넷에서 찾은 오픈소스를 재활용하게 되는 경우가 상당히 많은데, 그 안에 들어있는 printf() 함수를 모두 my_printf()함수로 대체 하여야 된다. #define printf my_printf 물론 위와 같은 #define을 이용하면 간단히 대체할 수는 있다. 그러나 이번 글에서는 위와 같은 방법을 사용하여 printf를 사용하는 것이 아니라 진짜 printf를 사용하는 방법에 대해서 설명하도록 하겠다. 이미 앞에서도 한번 언급하였는데 printf() 함수는 stdout으로 데이터를 내 보내도록 되어 있다. 그..
UART를 이용하여 AVR에서 만든 문자열이 컴퓨터의 터미널에서 보여지는것을 확인하였다. 이번글에서는 I/O 레지스터에 있는 현재 값이나, 변수에 현재 어떤값이 있는지 알아보기 위하여 데이터를 문자열로 변환한 후 UART를 통하여 내 보내는 방법에 대해서 설명하도록 하겠다. printf()함수를 사용하면 좋은데 지금 당장은 사용할 수 없으므로 다른 방법을 이용하여 printf()를 대신하여야 한다. 가장 쉽게 사용할 수 있는 것이 sprintf()이다. printf() 함수는 인자로 들어오는 값을 stdout으로 내보내는 동작을 하고, sprintf에는 인자로 제공하는 char형 배열에 값을 변환하여 넣어주는 기능을 한다. 따라서 sprintf를 수행한 후 배열에 저장된 문자열을 uart_puts()를 ..
UART - 원리와 연결과 UART - 송신을 통해서 AVR의 UART 설정을 어떻게 하고 컴퓨터와의 통신은 어떻게 이루어 지는지 이미 설명하였다. 이번 글에서는 앞의 글에서 설정한 값들을 그대로 이용하여 AVR의 UART 수신에 대해서 설명하도록 하겠다. 이미 UART 송신을 위해서 UART설정은 해 둔 상태이므로 수신 코드만 구현하면 된다. 수신코드는 송신 코드와 유사하다. uint8_t uart_rx(void) { while (!(uart->ucsr_a & RXC)); return uart->udr; } UCSRA레지스터의 RXC 비트 값이 1이 되면 UDR레지스터에 데이터가 수신되었음을 알려주므로 RXC 비트가 1이 될때까지 UCSRA레지스터를 polling하고 있다가 RXC 비트값이 1이 되면 ..
위의 그림은 AVR에 있는 UART블럭의 블럭도이다. UART블럭은 크게 세부분으로 나누어 볼 수 있다. 데이터를 정확한 시간에 맞춰 내보내거나, 수신되는 데이터를 정확한 위치에서 샘플링할 수 있게 하기 위한 clock generator가 있고, 송신기능을 처리해 주는 transmitter가 있다. 그리고 수신기능을 담당하는 receiver블럭이 있다. 그림을 자세히 보면 알겠지만 UART 블럭에는 Data bus에 연결된 다섯개의 레지스터를 찾을수가 있다. 클럭 설정을 하기 위한 UBRR레지스터가 있다. UART에서 통신 속도를 baud rate라고 하는데 이 값은 아무값이나 설정해서 사용하는 것이 아니고 정해진 몇개의 값들이 있다. 예전에는 9600bps를 많이 사용하였다. 그러나 최근의 임베디드 시..
처음 계획은 AVR 내부 기능과 관련된 내용을 모두 설명한 다음, 이어서 다른 디바이스와의 정보를 교환하는 방법인 UART, TWSI, SPI에 대해서 설명하려고 하였다. 그러나 이미 앞에서 다룬 LED 온도계처럼 확인하고 싶은 내용을 LED를 이용하여 표시하다보니 보고싶은 결과를 한눈에 쉽게 알아볼 수 없는 불편함이 있었다. 앞으로 이어질 내용인 타이머/카운터나 ADC 등등 여러가지 기능을 설명하기 위하여 중간 중간 I/O 레지스터에 어떤 값이 들어가 있는지 수시로 확인하여야 한다. 이를 위하여 C에서 사용하는 가장 기본적인 printf()를 사용하고 싶은데, 이미 이 블로그의 앞 부분에서 printf()함수를 사용해도 아무것도 표시되지 않는것을 확인 하였다. 그렇다면 임베디드 환경에서는 어떻게 pri..