FND data 전송
main.c
#include "port.h"
#include "delay_m.h"
int main(void)
{
unsigned char fnd1 = 0x00;
unsigned char fnd2 = 0x00;
int sw_flag = 1; // FND OUTPUT flag
int click_flag = 0;
int click_flag1 = 1;
DDRF = 0xff; // FND OUTPUT PIN
PORTF = 0x00;
DDRE = 0x00; // SWITCH INPUT PIN
PORTE = 0x00;
DDRC = 0x01; // CONTROL PIN
PORTC = 0x00;
DDRD = 0x00; // DATA TRANSFER
PORTD = 0x00;
while(1)
{
// 클릭 감지 부분
if((PINE & 0x01) == 0) // SWITCH PUSH
{
if(click_flag1) // 처음 실행..스위치가 떨어질 때까지 실행 되지 않음
{
click_flag = 1;
click_flag1 = 0;
sw_flag = !sw_flag; // toggle
if(!(sw_flag)) // 현재 값 전송
{
PORTC = 0x01;
DDRD = 0xff;
PORTD = fnd2 | (fnd1 - 1);
delay(100);
PORTC = 0x00;
}
}
}
else if((PINE & 0x01) && click_flag) // 스위치가 떨어 졌을 때
{
click_flag1 = 1;
}
// 수신부
if(PINC & 0x02)
{
DDRD = 0x00;
fnd1 = 0x0f & PIND;
fnd2 = 0xf0 & PIND;
PORTF = fnd2 | fnd1;
}
// FND 카운트 부분
if(sw_flag)
{
PORTF = fnd2 | fnd1;
fnd1++;
if(fnd1 >= 0x0A)
{
fnd1 = 0x00;
if(fnd2 >= 0x90)
{
fnd2 = 0x00;
}
else
{
fnd2 += 0x10;
}
}
delay(500);
}
}
return 0;
}
// 2대의 DK128를 연결해서 FND 카운트 값을 서로 전송하는 코드이다. A DK128에서 먼저 FND에 99까지 카운트 시작, 카운트 도중에 버튼을 입력하면 카운트가 멈추고 현재 카운트 된 값이 B DK128로 전송된다. B DK128은 이 값을 받아 자신의 FND에 출력한다.
// 양 쪽에 같은 값이 찍힌 상태에서 스위치를 누르면 다시 카운트가 시작한다.
Call by reference
함수 인자 값으로 포인터를 사용함으로써 다른 함수에서 현재 함수의 변수들의 값들을 바꿀 수 있다.
p6-6.c
#include <stdio.h>
void swap(int *, int *);
int main()
{
int x = 7;
int y = 9;
printf("A: initial value x = %d, y = %d\n", x, y);
printf("B: &x = %p, &y = %p\n\n", &x, &y);
swap(&x, &y);
printf("G: end of main x = %d, y = %d\n", x, y);
return 0;
}
void swap(int *px, int *py)
{
int temp;
printf("C: px = %p, py = %p\n", px, py);
printf("D: *px = %d, *py = %d\n\n", *px, *py);
temp = *px; // main함수 x변수와 y변수
값을
바꾼다.
*px = *py;
*py = temp;
printf("E: px = %p, py = %p\n", px, py);
printf("F: *px = %d, *py = %d\n\n", *px, *py);
}
// Call by Reference를 보여주는 예제이다. main함수의 x변수와 y변수 값을 swap함수에서 서로 바꾸고 있다. 즉 main함수의 지역변수를 swap함수에서 서로 바꾸기 위해 각 지역변수의 포인터를 인자로 넘겨주고 있다.
재귀함수
함수 자신이 스스로 자신을 호출하는 함수를 재귀함수라고 한다. 재귀함수는 코드 가독성이 떨어 질뿐만 아니라 시스템 자원 활용에 있어서도 매우 비효율적이므로 되도록이면 사용하지 않는 것이 좋다.
p6-8.c
#include <stdio.h>
void recursive_print(int);
int main()
{
int num;
printf("Please enter a positive integer: ");
scanf("%d", &num);
recursive_print(num);
return 0;
}
void recursive_print(int n)
{
if(n <= 0)
{
return;
}
else
{
printf("recursive_print: n = %d\n", n);
recursive_print(n - 1); // 스스로 자신을 호출
}
}
// 숫자를 입력 받아 1씩 감소 시키면서 그때 그때 숫자들을 화면에 출력하는 프로그램이다.
함수 포인터
함수의 이름은 함수의 시작지점을 가리키는 포인터이다. 즉 함수의 시작지점을 저장할 수 있는 포인터를 함수 포인터라 한다. 함수 포인터는 리턴타입과 인자들에 대한 정보를 가지고 있어야만 한다.
에를 들어 int printf(const char *format, ...)는 printf함수의 원형이다. 이 함수의 함수 포인터 타입은 int (*)(const char *, ...)이 된다
main.c
#include <stdio.h>
void test(int A);
int main()
{
void (*fp)(int); // 함수포인터 선언
fp = test; // 함수포인터에 test대입
fp(10);
// test, printf, main, scanf 함수의 시작 주소를 출력
printf("test : %p\n", test);
printf("printf : %p\n", printf);
printf("main : %p\n", main);
printf("scanf : %p\n", scanf);
((void(*)(int))0x8048432)(100); // test함수를 시작 주소로 출력
((int(*)(const char *, ...))0x80482c4)("test...\n"); // printf함수를 시작 주소로 출력
return 0;
}
void test(int A)
{
printf("%d\n", A);
return;
}
// 함수 포인터를 사용한 예이다. 함수의 시작주소만 알면 그 주소를 각 함수의 포인터 타입에 맞게 캐스팅 연산 후 호출 할 수 있다.