실험 예비 과제
1. 다음은 AVR MCU의 내부 ADC를 사용하기 위한 초기화 작업을 하는 함수이다. 내용을 완성하여라.
void adc_init(void)
{
// ADC enable, single conversion 모드
// AD 변환 범위는 0 ~ AVCC가 되도록 설정
// ADC clock이 50 KHz와 200 KHz 사이의 값을 가지도록 prescaler 설정
}
2. 다음은 single-ended single conversion 모드에서 원하는 채널의 AD 변환을 시작시킨 후 변환이 끝날 때까지 기다린 변환 결과를 읽어서 값을 반환하는 함수이다. 내용을 완성하여라.
uint16_t adc_get_result(uint8_t channel_num)
{
// channel_num은 0 ~ 7 사이의 값으로 ADC 입력 번호임
// 이 신호가 ADC에 입력되도록 ADMUX 설정 (MUX 입력을 제외한 다른 비트의 값을 바꾸면 안됨)
// AD 변환 시작
// AD 변환이 끝날 때까지 기다림
// 변환 결과를 반환
}
1. ADMUX 레지스터의 상위 3비트(비트 7:5)는 보존하고 하위 5비트(비트 4:0)만 수정
2. ADSC(ADC Start Conversion) 비트를 1로 설정하여 ADC 변환을 시작
3. ADC 변환이 완료되면 1이 되는 ADIF(ADC Interrupt Flag) 비트가 1이 될 때까지 대기
4. 다음 변환을 위해 인터럽트 플래그인 ADIF 비트에 1을 쓰면 플래그가 클리어
5. ADC 변환 결과를 반환
3. ADC의 변환 완료 인터럽트를 사용하도록 1 번에서 작성한 adc_init() 함수를 수정하려고 한다 어떤 부분을 어떻게 수정하면 되는지 설명하여라.
4. (3 번과 무관) ADC가 free running 모드로 동작하도록 1 번에서 작성한 adc_init() 함수를 수정하려고 한다 어떤 부분을 어떻게 수정하면 되는지 설명하여라. free running 모드로 동작한다면 1 번에서 설정한 ADC 클럭을 사용할 때 1 초에 대략 몇 번의 AD 변환이 가능한지 계산하여라.
Free Running 모드에서는:
- 첫 번째 변환이 완료되면 자동으로 다음 변환 시작
- ADIF 플래그를 수동으로 클리어할 필요 없음
- 채널 변경 없이 같은 채널에서 연속적으로 샘플링
- ADC 인터럽트 루틴에서 결과값 처리 가능
(예비1.)에서 128-prescaler를 설정했으므로 ADC 클럭주파수는 16MHz/128 = 125kHz
Signle ended에 해당하는 free running mode는 총 13s가 걸린다.
첫 변환시간은 25/125k = 200us, 이후는 13/125k = 104us이다.
1 초에 대략 몇 번의 AD 변환이 가능한지 계산
- 첫 번째 변환: 200μs
- 나머지 시간: 1,000,000μs - 200μs = 999,800μs
- 나머지 시간 동안의 변환 횟수: 999,800μs ÷ 104μs ≈ 9,613.46회
- 총 변환 횟수: 1회(첫 변환) + 9,613회(나머지) = 9,614회
따라서 1초에 약 9614회 AD 변환이 가능하다.
실험 과정
1. 아래의 회로를 구성하고 표시한 신호를 AVR 보드의 ADC1 핀에 연결하여라. ADC1에 연결하기 전에 가변 저항을 조절하면 ADC1에 연결할 신호의 전압이 변하는지 오실로스코우프로 먼저 확인하여라.
A. 0~5V(5V보다는 작음) 사이로 ADC1에 연결한 신호의 전압이 변한다.
2. 예비 과제 1 번에서 작성한 adc_init() 함수를 호출하여 ADC를 초기화하여라. 물론 ADC 이외의 다른
장치를 초기화하는 것도 잊어서는 안 된다.
3. main() 함수 내부의 while() 루프에서 SW3이 눌려진 상태라면 adc_get_result(1)을 계속 실행하면서 AD 변환을 하여라. 그리고 adc_get_result() 함수와 printf() 함수를 사용하여 변환된 값을 화면에 출력하여라. 이 때 한 번 출력한 다음에는 줄을 바꾸어 다음 변환 결과는 새로운 줄에 출력되도록 하여라. SW3이 눌려지지 않았다면 화면에 출력을 하지 않아야 한다. 가변 저항을 조절하며 ADC1의 전압을 오실로스코우프로 확인하여라. 그리고 화면에 출력되는 값이 이 전압에 대응되는 정확한 변환 값인지 확인하여라.
#include <avr/io.h>
#include "board.h"
#include "fnd.h"
#include "uart.h"
#include <stdio.h>
void adc_init(void){
ADCSRA = _BV(ADEN);
ADMUX = _BV(REFS0);// 0 ~ AVCC
ADCSRA |= _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);// set a prescaler - "50 KHz < ADC clock < 200 KHz" : 128
}
uint16_t adc_get_result(uint8_t channel_num){
ADMUX = (ADMUX & 0xE0) | (channel_num & 0x1F);
ADCSRA |= _BV(ADSC);
while (!(ADCSRA & _BV(ADIF)));
ADCSRA |= _BV(ADIF);
return ADC;
}
void ioport_init(){
PORTD |= _BV(SW3);
}
int main(void)
{
ioport_init();
uart_init();
adc_init();
fdevopen(uart_putch, uart_getch);
while (1)
{
if(!(PIND & _BV(SW3))){
printf("ADC_value : %x\r\n", adc_get_result(1));
_delay_ms(100);
}
}
}
4. ADC1에 연결된 신호를 ADC3으로 옮기고 3 번의 과정을 되풀이하여라. 3 번의 코드와는 달리 이번에는
adc_get_result(3)을 호출해야 한다. 이번에도 잘 동작한다면 adc_get_result() 함수의 ADMUX
설정이 잘 되고 있다는 것을 의미한다.
5. adc_get_result() 함수는 AD 변환 시작 명령을 내린 후 변환 완료가 될 때까지 계속 기다리는 함수이다. 따라서 while() 문에서 AD 변환 이외에도 다른 할 일이 많이 있는 상황이라면 이 함수는유용하지 않다. 이제부터는 AD 변환 완료 인터럽트를 사용해보자. 4 번 코드에서 작성한 main() 함수의 while() 루프 내부의 코드를 모두 지우고 실험 5의 예비과제 4 번의 코드를 추가하여라. 그리고 adc_init() 함수에서 AD 변환 완료 인터럽트를 활성화시키고 uart_init() 함수에서 UART 수신
완료 인터럽트를 활성화시켜라.
AD conversion 완료 인터럽트(ADIE)를 활성화하고, UART 수신 완료 인터럽트(RXCIE0)활성화
6. 사용자가 키보드의 문자 ‘a’를 누르면 그 순간 ADC 변환을 시작시키는 명령을 UART 수신 완료 ISR에 추가하여라. 그리고 AD 변환 완료 ISR에서는 변환 결과를 읽어서 FND에 출력하여라. 가변 저항을 조절하면서 ADC 입력 전압에 대응되는 정확한 값이 FND에 출력되는지 확인하여라.
https://github.com/Shoons23/AVR_basic/tree/main/ADC
AVR_basic/ADC at main · Shoons23/AVR_basic
microprocessor basic in AVR. Contribute to Shoons23/AVR_basic development by creating an account on GitHub.
github.com
issue
- UDR0 = UDR0는 수신된 문자를 다시 UDR0에 쓰는 작업 (에코)
- 이 작업이 수신 버퍼를 비우는 효과가 있음
- 그 다음 if(UDR0 == 'a')에서 다시 한번 읽을 때는 방금 에코된 값을 읽게 됨
1. UDR0 = UDR0 방식은 입력 문자가 화면에 표시되어 사용자가 입력을 확인할 수 있지만, UDR0를 여러 번 읽어 데이터가 불안정
2. 변수에 저장하는 방식은 데이터를 안정적으로 한 번만 읽어 처리할 수 있지만, 사용자는 자신의 입력을 화면에서 확인 X
'전자공학 > 마이크로프로세서' 카테고리의 다른 글
2024.2 마이크로프로세서 실험 시험 복기 (0) | 2024.12.27 |
---|---|
[atmega1281] 실험 10. AVR의 UART를 사용한 비동기 직렬 통신 (0) | 2024.12.02 |
[atmega1281] 실험 9. AVR MCU의 타이머 활용 3 – PWM (1) | 2024.11.27 |
[atmega1281] 실험 8. AVR MCU의 타이머 활용 2 – 스피커 구동 (1) | 2024.11.21 |
[atmega1281] 실험 7. AVR MCU의 타이머 활용 1 – 기초 (1) | 2024.11.20 |