질문게시판 > pwm 출력과 ad conversion 과정

TODAY996 TOTAL2,152,382
사이트 이용안내
Login▼/회원가입
최신글보기 질문게시판 기술자료 동영상강좌

아두이노 센서 ATMEGA128 PWM LED 초음파 AVR 블루투스 LCD UART 모터 적외선


BASIC4MCU | 질문게시판 | pwm 출력과 ad conversion 과정

페이지 정보

작성자 412904 작성일2022-05-05 20:05 조회344회 댓글18건

본문

	

안녕하세요, 가변저항을 사용해 AD 변환값에 따라 PWM 듀티를 가변시키는 코드를 작성 중인데 질문 몇 가지 남겨봅니다.

현재 스위칭 주파수는 5kHz이고 오버플로우 인터럽트 사용하고 있습니다.

따라서 오버플로우 인터럽트 서비스 루틴을 수행하는 시간은 0.2ms이고 오버플로우가 발생했을 때 AD 변환을 수행하도록 코드를 작성했습니다.

여기서 두 가지정도 궁금한 점이 있습니다.

 

Q1)  AD 변환에도 수 마이크로초에서 수백 마이크로초가 소요된다는 것을 데이터시트에서 보았는데,

여기서 스위칭주파수를 더 높이고 싶다면 성능이 더 좋은 DSP를 사용하는 것이 맞을까요?

 

Q2) 오버플로우가 발생했을 때 AD 변환을 수행하도록 코드를 작성했다면, 오버플로우가 발생해서 초기화된 카운터 값이 AD 변환을 수행하면서 같이 올라가나요, 변환이 다 끝나고 카운터값이 올라가나요?

이 부분은 글로만 보면 이해가 가지 않을 수도 있을 것 같아 이미지 사진을 첨부하도록 하겠습니다.

* 만약 전자라면, AD 변환하는 데에도 클럭이 소모되어 OCR 값이 제대로 출력이 안 될 수도 있다는 생각이 들었습니다.

근데 또 생각해보면 OCR 업데이트 지점을 TOP으로 설정해주면 그 다음 캐리어 주파수에서 반영이 될 수도 있겠구나 라는 생각도 듭니다.

무엇이 맞는 걸까요?

 

 

 

  • BASIC4MCU 작성글 SNS에 공유하기
  • 페이스북으로 보내기
  • 트위터로 보내기
  • 구글플러스로 보내기

댓글 18

조회수 344

master님의 댓글

master 작성일

mcu 디바이스가 뭔가요?
전체 소스코드를 첨부해서 질문하셔야 이해를 하는데 도움이 될 것 같습니다.
AVR경우 OCR값이 적용되는 시점은 데이터시트에 나와있습니다.

412904님의 댓글

412904 댓글의 댓글 작성일

현재 사용하고 있는 MCU는 ATmega128입니다.

master님의 댓글

master 댓글의 댓글 작성일

전체 소스코드를 텍스트로 첨부해보세요

412904님의 댓글

412904 댓글의 댓글 작성일

간단하게 작성한 코드 첨부하겠습니다

#define F_CPU 16000000UL
#define k 3.1250 // the ratio of ICR1 to c(ADCW)

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

void Pwm_Generator(void);
void ADC_init(void);
unsigned int c;

ISR(TIMER1_OVF_vect) // execution this loop every 0.2ms -> switching frequency=5kHz
{
ADCSRA|=(0x01<<ADSC); // AD conversion start
c=ADCW;
OCR1A=c*k; // k=3.125
ICR1=3199; // 16MHz -> 62.5(ns/clk) -> 62.5ns*3200=0.2ms -> 5kHz
}

int main(void)
{
//// i/o settings ////
DDRB=0xff; // PWM output(using OC1A(PB5))
PORTB=0x00; // initialization

//// function call ////
cli();
Pwm_Generator();
ADC_init();
sei();

    /* Replace with your application code */
    while (1)
    {
    }
}

void Pwm_Generator(void)
{
TCCR1A=(0x01<<COM1A1)|(0x01<<COM1A0)|(0x01<<WGM11)|(0x00<<WGM10); // INV mode
TCCR1B=(0x01<<WGM13)|(0x01<<WGM12)|(0x00<<CS12)|(0x00<<CS11)|(0x01<<CS10); // prescale:1 WGM13:10=1110(Fast PWM)
TCCR1C=0x00;

TCNT1=0;
ICR1=3199; // 0.0000000625*3200 = 0.0002 -> 0.2ms

TIMSK=(0x01<<TOIE1); // overflow interrupt enable
//TIFR=0xff;
}

void ADC_init(void)
{
ADMUX=(0x00<<REFS0)|(0x00<<MUX0); //  ADC0
ADCSRA=(0x01<<ADEN)|(0x00<<ADSC)|(0x00<<ADFR)|(0x01<<ADPS2)|(0x00<<ADPS1)|(0x00<<ADPS0); //  AD Conversion start
}

master님의 댓글

master 작성일

Q1)  AD 변환에도 수 마이크로초에서 수백 마이크로초가 소요된다는 것을 데이터시트에서 보았는데,
여기서 스위칭주파수를 더 높이고 싶다면 성능이 더 좋은 DSP를 사용하는 것이 맞을까요?
PWM주파수를 늘리고 싶다는 말인가요?
5KHz의 주기는 200us로 가장 느린 ADC 샘플링 주기보다 더 느립니다.
ADC 분주비를 변경하면 ADC 변환속도는 아주 짧게 변경이 가능합니다.

Q2) 오버플로우가 발생했을 때 AD 변환을 수행하도록 코드를 작성했다면, 오버플로우가 발생해서 초기화된 카운터 값이 AD 변환을 수행하면서 같이 올라가나요, 변환이 다 끝나고 카운터값이 올라가나요?
타이머 카운터와 ADC변환은 각각 독립적으로 실행 됩니다.

master님의 댓글

master 작성일

OCR1A=c*k; // k=3.125
실수 연산은 시간이 제법 걸립니다.
가장 긴 시간은 실수의 나누기입니다.
AVRStudio 시뮬레이션으로 실수 곱하기에 관한 시간을 측정 해보세요
인터럽트 주기는 이 시간보다 조금 더 길어야 합니다.

master님의 댓글

master 작성일

OCR1A=c*k; // k=3.125
여기서 3.125는
2 + 1 + 1/8
OCR1A=(c<<1)+c+(c>>3);
이렇게 연산하는 것이 더 빠를겁니다.

master님의 댓글

master 작성일

ICR1=3199; // 16MHz -> 62.5(ns/clk) -> 62.5ns*3200=0.2ms -> 5kHz
동일한 설정을 인터럽트에서 매번 해 줄 필요가 없겠죠?
Pwm_Generator() 함수에서 이미 하고 있으므로 인터럽트에 있는 코드는 삭제하세요

master님의 댓글

master 작성일

#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
//
ISR(TIMER1_OVF_vect){ // 0.2ms -> 5kHz
  unsigned int c;
  c=ADCW;
  OCR1A=(c<<1)+c+(c>>3); // k=3.125
}
//
int main(void){
  DDRB=0x20; // PWM output(using OC1A(PB5))
  ADCSRA=0xE4;
  TCCR1A=(1<<COM1A1)|(1<<COM1A0)|(1<<WGM11); // INV mode
  TCCR1B=(1<<WGM13)|(1<<WGM12)|(0x01<<CS10); // prescale:1 WGM13:10=1110(Fast PWM)
  ICR1=3199; // 0.0000000625*3200 = 0.0002 -> 0.2ms
  TIMSK=(1<<TOIE1);
  SREG=0x80;
  while(1){}
}

412904님의 댓글

412904 댓글의 댓글 작성일

메인 문에서 프리러닝모드로 실행하고 인터럽트 서비스 루틴에서 변환 값만 저장한 뒤 그 다음 연산을 하는군요. 시프트 연산도 인상 깊네요. 정말 감사드립니다.

master님의 댓글

master 댓글의 댓글 작성일

AVRStudio 시뮬레이션에서 인터럽트 함수 코드 실행 시간을 측정하세요
이 시간이 가장 중요합니다.
예를들어서 20us가 나왔다고 가정해보죠
인터럽트 자체의 실행에 짧은 시간이 추가되어야 하며
1~2us를 넘지 않습니다.
그렇다면 여유를 줘서 25us 주기로 보고 최대 40KHz가 가능해집니다.
//
ADC분주비 계산식을 알아야 합니다.
128분주가 104us인데
16000000/128=125000Hz가 ADC클럭이고, ADC에는 13클럭(25클럭)이 샘플링 시간이므로
125000Hz/13=9615.384615384615Hz=104us
질문코드에서는 16분주이므로 샘플링 시간은 13us 입니다.
ADC는 건드릴 것이 없군요
//
PWM을 40KHz로 높일 수 있는지 체크 해보세요
TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS10); // prescale:1 WGM13:10=1110(Fast PWM)
분주비 1 이므로 분주비를 건드릴 것은 없습니다.
ICR1=399; // 0.0000000625*400 = 0.000025 -> 25us
ICR을 변경하면 8배 빠르게 주기를 변경 할 수 있지만
분해능도 1/8로 낮아집니다.

master님의 댓글

master 작성일

지금보다 3배 정도 짧게 주기를 변경해도 충분하다면
ICR1=1023; // 0.0000000625*1024 = 0.000064 -> 64us
//
ADC 샘플링은 위에서 계산했으므로 충분한 것은 확인했고
16분주 대신 32분주로 변경해도 됩니다
 ADCSRA=0xE5;
//

ISR(TIMER1_OVF_vect){ // 64us -> 15.625kHz
  OCR1A=ADCW;
}
분해능이 10비트이므로 인터럽트 함수 안의 코드는 간단해지죠
//
OCR1A(ICR1) 분해능이 아무리 높아봤자 ADC값으로 PWM듀티를 만드는 것이므로
10비트가 한계입니다.
따라서 ICR1 및 OCR1A를 10비트로 설정해서 ADC값을 직접 넣으면 분해능은 동일합니다.
연산이 필요없어지므로 코드 실행 시간은 굉장히 짧아지죠

master님의 댓글

master 작성일

k=3.125
위 댓글에서 정확하게 3.125배 주기가 짧아졌는데요
여기에 추가로 1/2로 주기를 더 줄인다면

ICR1=511; // 0.0000000625*512 = 0.000032 -> 32us
//
ADC 샘플링은 16분주로 다시 변경합니다.
 ADCSRA=0xE4;
//
ISR(TIMER1_OVF_vect){ // 31.250KHz
  OCR1A=ADCW>>1; // 9비트 저장 (0~511)
}
9비트로 분해능은 1/2로 줄어들게 됩니다.

몇개의 댓글로 방법을 설명드렸으니
8비트로 변경해서 주파수를 62KHz로 높일 수도 있겠죠

412904님의 댓글

412904 댓글의 댓글 작성일

정성스러운 답변 정말정말 감사드립니다.
아직 비기너 수준이라 설명해주신 것을 완벽하게 이해하지는 못했으나
제가 이해한 바로는 AD 변환 시간과 인터럽트 함수 실행 시간 등이 인터럽트 발생 주기보다 빠르면 안 된다고 이해했는데,
제가 이해한 것이 맞나요??

예를 들어, ICR 값이 399일 때 399클럭이 소모된다고 가정하면,
인터럽트는 매 400클럭마다 발생할 것인데, AD 변환에서 소모되는 클럭과 인터럽트 실행할 때 소모되는 클럭이 400클럭을 넘게 되면
문제가 될 것이라고 이해했습니다.

master님의 댓글

master 댓글의 댓글 작성일

0~399 는 400 단계입니다.
인터럽트 함수의 코드 실행 시간 <-- 이 시간이 인터럽트 주기보다 길게 되면 메인함수 무한루프의 코드가 있는 경우 심각한 문제가 발생할 수 있습니다.(메인함수가 동작 안함)

ADC샘플링 주기는 큰 문제는 없습니다.
매주기 새로운 ADC값을 PWM 출력하느냐
ADC 두번째 변환된 값을 PWM 출력하느냐
같은 ADC값을 두번씩 PWM 출력하느냐
정도의 문제죠

412904님의 댓글

412904 댓글의 댓글 작성일

아, 그리고 말씀하신 인터럽트 함수 실행 시간을 측정해 보라고 하셨는데,
AVR스튜디오 내에 Simulator를 이용해서 측정해 본 결과
인터럽트 실행 시간은 81클럭이 소모되더군요. 제가 한 것이 맞는지는 모르겠습니다. 이 기능이 있다는 것도 덕분에 오늘 처음 알았거든요.

master님의 댓글

master 댓글의 댓글 작성일

실수 타입의 나누기 연산이 가장 오래 걸립니다.

412904님의 댓글

412904 댓글의 댓글 작성일

감사합니다. 형편없는 코드임에도 많은 걸 알아가네요.

질문게시판HOME > 질문게시판 목록

MCU, AVR, 아두이노 등 전자공학에 관련된 질문을 무료회원가입 후 작성해주시면 전문가가 답변해드립니다.
ATMEGA128PWMLED초음파
아두이노AVR블루투스LCD
UART모터적외선ATMEGA
전체 스위치 센서
질문게시판 목록
제목 작성자 작성일 조회
공지 MCU, AVR, 아두이노 등 전자공학에 관련된 질문은 질문게시판에서만 작성 가능합니다. 스태프 19-01-15 9600
공지 사이트 이용 안내댓글[24] master 17-10-29 29473
질문 아두이노 심전도 센서 BPM 계산댓글[1] 새글 쥬쥬 11:15 12
질문 아두이노 서로 다른 전압을 가진 부품 제어 이미지새글 chovo 10:09 12
질문 앱인벤터 질문입니다.댓글[2] 이미지새글 귀끠우유 09:51 16
질문 아두이노 우노끼리 블루투스 통신댓글[1] 새글첨부파일 pyoleo 02:18 25
질문 마이크로 받은 입력을 주파수로 변경댓글[3] 새글 생늧판출 01:37 18
질문 while문 안 if문 빠져나오는 방법 새글 kyho3855 22-05-15 16
답변 답변글 답변 : while문 안 if문 빠져나오는 방법 새글 master 07:19 15
질문 초음파센서로 속도구하기(코드 합치는법) 새글 쥰니 22-05-15 29
답변 답변글 답변 : 초음파센서로 속도구하기(코드 합치는법) 새글 master 06:50 12
질문 360서보모터 질문입니다댓글[1] 한잔해2 22-05-14 59
질문 아두이노 초보 24V DC 제품 제어댓글[2] 제로펲시 22-05-13 57
질문 임베디드 시스템 디지털 도어락 구현댓글[1] 이미지첨부파일 ejdog 22-05-12 50
질문 임베디드 시스템 디지털 도어락 구현댓글[1] ejdog 22-05-12 46
질문 ATMEGA128 TCCR2 = 0X0B가 의미하는것은 무엇인지 궁금합니다. dfas123 22-05-12 85
답변 답변글 답변 : ATMEGA128 TCCR2 = 0X0B가 의미하는것은 무엇인지 궁금합니다.댓글[1] master 22-05-12 92
질문 ATMEGA128 0번핀과1번핀 스위치를 누르면 LED점등 속도 제어댓글[3] dfas123 22-05-11 113
질문 아두이노 로드셀 관련 질문드립니다.댓글[1] 끼약 22-05-11 76
질문 앱 인벤터 및 아두이노 질문 suhosin 22-05-10 88
답변 답변글 답변 : 앱 인벤터 및 아두이노 질문댓글[1] master 22-05-11 89
질문 블루투스 모듈, 적외선온도센서, 스피커 모듈댓글[4] 죠르디 22-05-10 146
질문 Hm-10블루투스 사용하여 rc카 조종기로부터 데이터 받는방법을 모르겠습니다.댓글[1] 뚱보개 22-05-10 674
질문 아두이노 로드셀 [졸업작품]댓글[1] 이미지 졸업작품 22-05-10 125
질문 아두이노 조이스틱으로 스텝모터2개제어댓글[4] 초보진 22-05-10 182
질문 초음파센서 스텝모터 질문입니다댓글[1] 응애 22-05-09 145
질문 아두이노 적외선온도센서 스피커모듈댓글[4] 죠르디 22-05-09 148
질문 stm32 uart serial 통신댓글[1] 하리 22-05-09 136
질문 적외선,금속,조도,서보모터 질문댓글[2] 하허히 22-05-08 133
질문 analogRead 관련 문의댓글[2] toemm 22-05-08 107
게시물 검색

2022년 1월 2월 3월 4월 5월 6월 7월 8월 9월 10월 11월 12월
2021년 1월 2월 3월 4월 5월 6월 7월 8월 9월 10월 11월 12월
2020년 1월 2월 3월 4월 5월 6월 7월 8월 9월 10월 11월 12월
2019년 1월 2월 3월 4월 5월 6월 7월 8월 9월 10월 11월 12월
2018년 1월 2월 3월 4월 5월 6월 7월 8월 9월 10월 11월 12월
Privacy Policy
MCU BASIC ⓒ 2020
모바일버전으로보기