계수기를 만들자라는 강좌에 나온 과제와 관련한 질문과 답변을 정리한 글입니다.
출처 : cafe.naver.com/laydigital/
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 16000000UL
#include <util/delay.h>
#define FNDD PORTC
#define FNDC PORTG
typedef unsigned char u_8t ;
u_8t fnd_img[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x6f}; //(0~9);
//u_8t fnd_map[]={0x01,0x02,0x04,0x08};
#define FND_locate(x) (0x01<<(x))
#define figure_num(x,y) fnd_img[( ( (x)%10000 )/n_size[(y)] )%10]
int n_size[] ={1,10,100,1000};
volatile int count =0;
int main(void)
{
unsigned int i=0,k=0,j=0;
DDRC = 0xff;
DDRG = 0x0f;
DDRA = 0xff;
DDRE = (0xff)&((0<<DDE4)|(0<<DDE5)); // 입력으로 사용 PINE에 값 read 가능
sei();
EIMSK = (1<<INT4)|(1<<INT5); // 핀int4(PE4),int5(PE5) 에 해당하는 alternative function을 사용.(enable)
EICRB = (1<<ISC40)|(1<<ISC41)|(1<<ISC50)|(1<<ISC51); //상승 에지 트리거
while(1)
{
j = (log10(count%10000));
//j = (log10(count%10000))+1(결과가 다름.);
k = j+1;
for(i=0; i< k ; i++)
{
FNDD = figure_num(count,i); //fnd_img
FNDC = FND_locate(i);
_delay_ms(5);
}
}
}
ISR(INT4_vect)
{
count++;
}
ISR(INT5_vect)
{
count=0;
}
3-2강좌를 보고 과제가 없어서 COUNT 계수기 연습을 해보고자 코드를 짜서 해보던중에 의문점이 생겨
질문드립니다. 1의 자리부터 1000 자리까지 숫자가 올라갈수록 FND에 자릿수를 동일하게 증가 시키면서
숫자를 표현해보는걸로 연습해보았는데요 위에 코드중에 이부분을 아래 주황색 처럼 바꾸면
j = (log10(count%10000));
k = j+1;
for(i=0; i< k ; i++)
{
FNDD = figure_num(count,i);
FNDC = FND_locate(i);
_delay_ms(5);
}
-------------------------------------------------------------------------------------------------------------------
j = (log10(count%10000))+1;
for(i=0; i< j ; i++)
{
FNDD = figure_num(count,i); //fnd_img
FNDC = FND_locate(i);
_delay_ms(5);
}
위와 아래 코드 모두 수식상 큰차이는 못느끼겠는데요. 실제로 동작시켜 보면 아래 주황색 코드는 의도한데로 않움직입니다..
시작에서 0 일때 아무런 표시가 없고 1부터 표시하고 9999 에서 10000으로 가서 0값으로 초기화 될때 fnd의 0x01 자리가 아닌 0x08 자리에 0이 표시가 됩니당.
위에 처럼 k 변수를 하나 더 선언해서 하면 의도한대로 나오고요 이유가 궁금해서 여러가지 해봤는데 왜그런지 이유를 못찾아서
이렇게 질문드려봅니다.
일단 log 함수에서
log10(x)
에서 x가 0인 값은 음수의 무한대 입니다.
0인 값에 대한 log 값을 받을려고 한거는 의도가 아닐 것으로 생각합니다.
x가 1이면 log 값이 0이 되죠..
큰값을 다 표현하기 어려워서 log 함수를 취한 것가요?
log 함수는 리턴값이 float 입니다.
log10(0) 값이나
log10(0) + 1
값이나 모두 float 값으로 너무 작은 값이라서
ing 타입의 값으로 둘다 최소 음수 값으로 assign 됩니다.
즉 log10(0) => int 타입으로 0x8000(16비트 음수로 최소값)
log10(0) + 1 => 이 또한 음수 최소값 0x8000
그런데 위 원 소스에서는 unsigned int 로 하셨죠?
unsigned int 일 경우에는
log10(0) 도 해당 음수값을 양수로 넣어야 하므로 0값이 되고
당연히
log10(0) + 1 도 unsigned 값에 넣으면 0이 들어갑니다.
즉
unsigned int j;
j = log10(0);
이 경우 log10(0)가 float형으로 최소가 음수이어서 j = 0; 이 되고
j = log10(0) + 1;
이 도한 우측이 음수 float 값이고 j 는 0이 됨.
답변 감사드립니다 log함수는 계수한 값을 1의자리부터 1000자리 자릿수값을 리턴할려고 썼는데 log함수의
리턴값이 float형 인건 생각하지도 못했네요 정말 감사합니당. 해당함수에 대한 상세한 답변도 정말 감사드립니당.
의도가 0 ~ 9,
10 ~ 99
100 ~ 999
이런 단위를 생각하신거라면
log10 같이 시간이 많이 걸리는 함수보다도 따로 함수 하나를 만드시는 것도 방법입니다.
unsigned char num_digit(unsigned int val)
{
if(val < 10) return 1; // 1자리 숫자
else if(val < 100) return 2; // 2자리 숫자
else if(val < 1000) return 3;
else if(val < 10000) return 4;
else return 0; // overflow 조건
}
main()
{
..
j = num_digit(count);
for( i = 0 ; i < j ; i ++)
{
}
}
No comments:
Post a Comment