BASIC4MCU | 질문게시판 | AVR ADC FND 딜레이 관련 문의
페이지 정보
작성자 총체적난국 작성일2021-07-02 17:33 조회4,677회 댓글2건본문
안녕하세요.
제가 ADC 코드를 짜서 돌려봤는데 작동은 잘 됩니다. 그런데 제가 만든 제품이 설치될 곳의 입력이 스테이블하지 않고 떨림이 많습니다.
이런 상황에서 제가 짠 ADC 코드는 변경된 입력값을 즉시 받아들여 FND에 표시하기 때문에 입력의 떨림이 그대로 FND에 표현이 됩니다.
그런데 저희 제품은 이렇게 변경 값을 실시간으로 자세히 표현해 줄 필요는 없고 2~3초에 한 번씩만 바뀌는 값을 표현해줘도 충분합니다. (오히려 값이 계속 바뀌면 문제가 생깁니다)
그래서 하기 코드에서 어떠한 기능을 추가하면 FND에 표현되는 값의 변동성을 줄일 수 있는지 조언 부탁 드립니다.
#include <avr/io.h>
#include <avr/delay.h>
#define DELAY_TIME_MS (2) // 3이 최대임
char fnd[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
char buff4,buff3,buff2,buff1;
unsigned int i,p;
int remainder;
char r;
void initial()
{
DDRC=0xff; // FND 출력
DDRD=0b11110000; // TN 출력
DDRA= 0x00; // ADC 입력
ADMUX=0x00; // ADC0
ADCSRA=0x87;
}
void fnd_on()
{
if(p < 1000)
{
PORTD=0b00100000; PORTC=fnd[buff3]; _delay_ms(DELAY_TIME_MS); PORTC=0xff;
PORTD=0b00100000; PORTC=0b01111111; _delay_ms(DELAY_TIME_MS); PORTC=0xff;
PORTD=0b01000000; PORTC=fnd[buff2]; _delay_ms(DELAY_TIME_MS); PORTC=0xff;
PORTD=0b10000000; PORTC=fnd[buff1]; _delay_ms(DELAY_TIME_MS); PORTC=0xff;
}
else if ((p > 1000 ) && (p < 1020))
{
PORTD=0b00010000; PORTC=fnd[buff4]; _delay_ms(DELAY_TIME_MS); PORTC=0xff;
PORTD=0b00100000; PORTC=fnd[buff3]; _delay_ms(DELAY_TIME_MS); PORTC=0xff;
PORTD=0b00100000; PORTC=0b01111111; _delay_ms(DELAY_TIME_MS); PORTC=0xff;
PORTD=0b01000000; PORTC=fnd[buff2]; _delay_ms(DELAY_TIME_MS); PORTC=0xff;
PORTD=0b10000000; PORTC=fnd[buff1]; _delay_ms(DELAY_TIME_MS); PORTC=0xff;
}
else if (p > 1020 )
{
PORTD=0b00010000; PORTC=0b10001001; _delay_ms(DELAY_TIME_MS); PORTC=0xff;
PORTD=0b00100000; PORTC=0b10111111; _delay_ms(DELAY_TIME_MS); PORTC=0xff;
PORTD=0b01000000; PORTC=0b10000110; _delay_ms(DELAY_TIME_MS); PORTC=0xff;
PORTD=0b10000000; PORTC=0b10101111; _delay_ms(DELAY_TIME_MS); PORTC=0xff;
}
}
void adc()
{
p = 1.08*(i/12);
buff4 =p/1000;
remainder = p % 1000;
buff3 =remainder/100;
remainder = remainder % 100;
buff2 =remainder/10;
remainder = remainder %10;
buff1 = remainder;
}
void convert()
{
i = 0;
for(r = 1; r <=12; r++)
{
ADCSRA |= 0x40;
while((ADCSRA & 0x10) == 0);
i +=(int)ADCL+((int)ADCH << 8);
_delay_us(1000);
}
}
int main(void)
{
initial();
while(1)
{
convert();
adc();
fnd_on();
}
}
댓글 2
조회수 4,677master님의 댓글
master 작성일10K저항 및 수uF의 커패시터로 RC 필터를 만들면 하드웨어적인 적분회로가 구성되므로 리플 및 떨림현상을 잡을 수도 있습니다.
master님의 댓글
master 작성일
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
//
volatile char fnd[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
//
ISR(TIMER0_COMP_vect){ // 1ms
static unsigned int cnt=0,av=0;
static unsigned long sum=0;
static unsigned char r=0,buf[4]={0,};
unsigned int v;
PORTD=0; // fnd off
v=ADCW; // v=ADC; 컴파일러 버전에 따라서 골라서 사용
sum+=v;
if(++cnt>=1024){ cnt=0; // 1024ms
av=sum/948; // av=sum*1.08/1024=sum/948.1481481481481;
sum=0;
buf[3]=av/1000; buf[2]=av/100%10; buf[1]=av/10%10; buf[0]=av%10;
}
//
if(av>1020){
switch(r){
case 0: PORTD=0x80; PORTC=0b10101111; break; // r
case 1: PORTD=0x40; PORTC=0b10000110; break; // E
case 2: PORTD=0x20; PORTC=0b10111111; break; // -
case 3: PORTD=0x10; PORTC=0b10001001; break; // H
}
if(++r>3)r=0;
}
else{
switch(r){
case 0: PORTD=0x80; PORTC=fnd[buf[0]]; r=1; break;
case 1: PORTD=0x40; PORTC=fnd[buf[1]]; r=2; break;
case 2: PORTD=0x20; PORTC=fnd[buf[2]]&0x7F; if(av<1000)r=0; else r=3; break;
case 3: PORTD=0x10; PORTC=fnd[buf[3]]; r=0; break;
}
}
}
//
int main(void){
DDRC=0xFF; // FND 출력
DDRD=0xF0; // TN 출력
ADCSRA=0xE7;
TCCR0=0x0C; OCR0=249; TIMSK=2; //16000000/64/(1+249),1ms
SREG=0x80;
while(1){}
}
mcu 디바이스에 따라서 타이머 인터럽트 설정이 다를 수 있으니 사용하는 mcu에 맞춰서 설정을 변경하세요
1ms 인터럽트마다 ADC를 누적하고, 1024개(1.024sec)마다 평균값을 갱신합니다.