본문 바로가기
코스웨어/15년 스마트컨트롤러

2015-04-28 32번 천정호

by 알 수 없는 사용자 2015. 4. 29.
728x90
반응형

1교시 

ATmega 2560 USART

#define DDRE  (*(volatile unsigned char *)0x2D)
#define PORTE  (*(volatile unsigned char *)0x2E)
#define UBRR0H  (*(volatile unsigned char *)0xC5)
#define UBRR0L  (*(volatile unsigned char *)0xC4)
#define UCSR0A  (*(volatile unsigned char *)0xC0)
#define UCSR0B  (*(volatile unsigned char *)0xC1)
#define UCSR0C  (*(volatile unsigned char *)0xC2)
#define UDR0  (*(volatile unsigned char *)0xC6)
#define RXEN0  4
#define TXEN0  3
#define USBS  3
#define UCSZ00  1
#define UDRE0  5

void USART_Transmit(unsigned char data) {
   /*Wait for empty transmit buffer*/
   while(!(UCSR0A & (1 << UDRE0))) {}
   
   /*Put data into buffer, sends the data */
   UDR0 =data;
}

//USART_Init
void USART_Init(unsigned int ubrr) {
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr >> 8);
UBRR0L = (unsigned char)ubrr;

/*Enable recevier and transmitter */
UCSR0A = 0b00000000//(U2X0(Bit 1) = 0 비동기 일반 모드

/*Enable recevier and transmitter */
UCSR0B = (1 << RXEN0) | (1 << TXEN0); // Rx, Tx 활성

/* Set frame format: 8data, 2stop bit */
UCSR0C = (1 << USBS) | (3 << UCSZ00);

   return;
}

void Putch(unsigned char data) {
      while(!(UCSR0A & 0b00100000));
      UDR0 = data;
}

void Putstr(char * string) {
  while (*string != '\0') {
    Putch(*string);
    string++;
  }
}

unsigned char Getch(void) {
   while(!(UCSR0A & 0b10000000));
   return UDR0;
}

int main(void) {
  volatile unsigned int count;
     DDRE = 0xFE; //Tx : Out, Rx : In
  USART_Init(8);
  
  for(count = 0; count < 100000; count++);
  
  while(1) {
    //Putch(65);
    //Putch('\n');
    Putstr("Good Morning\r\n");
     }
   return 0;
}

<문자 전송>

void Putch(unsigned char data) {

      while(!(UCSR0A & 0b00100000));

      UDR0 = data;

}

위의 Putch 함수를 통하여 매개변수 data에 main에서 호출할때 인자값을 받아온다.

인자값을 받아오고 함수의 명령부에서 먼저 UCSR0A의 5번째 비트 UDRE 비트를 확인한다.

UDRE는 UDR에 데이터가 아직 전송이 되지 않고 남아있는지를 확인하는 비트이다.

while문을 통하여 UDR에 데이터가 비어있으면 빠져나와 UDR에 데이터를 넣는다.

UDR에 넣은 데이터는 Shift Register에 넘어가서 데이터의 검사 후 전송이 된다.


<문자열 전송>

문자열 방식은 문자 하나를 전송하는 방식과 비슷하다. 하나의 문자를 찍는것을 NULL 문자가 나올때까지 찍으면 되기 때문에 이 코드를 사용하면 된다.

void Putstr(char * string) {

while (*string != '\0') {

Putch(*string);

string++;

}

}

문자열은 주소이기 때문에 매개변수가 포인터 형식으로 인자를 받아야하므로 char * string 이라는 매개변수를 만들어 놓는다.

그리고 while 문에서 한 비트씩 주소의 값이 NULL '\0' '0' 인지 판별 후 NULL이 아니면 Putch함수로 주소의 값을 넘기게 된다.

그렇게 한 비트씩 차례로 넘기다 문자열의 끝은 항상 NULL로 끝이 나니까 NULL일때 반복문을 종료하고 함수를 끝내면 된다.


2교시

C Programming

main 함수의 매개변수

main 함수도 제한된 매개변수를 선언하여 인자를 전달 받을 수 있다.

main 함수로의 인자 전달은 운영체제가 넣어주고 인자의 전달 방식은 "실행파일 전달할 값1 전달할 값2 ..." 이다.


#include <stdio.h>

/*
일반적인 main 함수의 첫 번째 인자는 int,
두 번째 인자는 char * 형을 가져야하며
인자의 이름은 사용자 임의로 결정이 가능하다.
*/

int main(int argc, char * argv[]) {
  printf("%d\n", argc);

  return 0;

}

main 함수로의 인자 전달은 모두 운영체제에서 값을 넘겨주며 인자의 첫 번째는 항상 실행파일의 이름을 넣어야한다.

위의 코드에 첫 번째 인자로 실행파일의 이름만 넣게되면 파일의 실행과 1이 출력되게 된다.

실행파일의 이름을 넣는것은 파일의 실행을 위해서이고 1이 출력되는것은 파일의 실행을 위해서 실행파일 이름 하나만 넣었기 때문에 1이 출력이된다.

이 1의 출력은 main 함수의 매개변수 중 int argc라는 매개변수로 1이 반환되어 1이 출력된다.

그리고 전달받는 인자의 개수의 구분은 스페이스바 즉 띄어쓰기로 구분이 되어 인자의 개수를 카운트 시킨다.

두 번째의 실행결과는 MainFunc라는 실행파일명과 Hello라는 두 번째 인자, Word라는 세 번째 인자 이렇게 세개의 인자로 구분이 되어 운영체제가 main함수의 첫 번째 매개변수에 3을 넘긴다.


#include <stdio.h>

/*
일반적인 main 함수의 첫 번째 인자는 int,
두 번째 인자는 char * 형을 가져야하며
인자의 이름은 사용자 임의로 결정이 가능하다.
*/

int main(int argc, char * argv[]) {

  if(strcmp(argv[0], "main") != 0) {
    printf("실행파일 이름을 main으로 변경하여 주십시오.\n");
    return 100;  
  }
  
  printf("정상종료\n");
  return 0;
}

main 함수의 두 번째 매개변수는 전달 받은 인자를 포인터 배열로 각 인자들의 주소를 가르킬 수 있게해준다.

main 함수의 인자들은 모두 문자열 형태의 주소이기 때문에 인자가 하나씩 늘어나면 포인터 배열의 크기가 자동으로 할당이 되어서 넘겨받은 각각의 인자주소를 가지고 있다.

항상 첫 번째 인자는 실행파일명을 의미하기 때문에 0번째 포인터 배열은 실행파일명을 가르키는 중이므로 argv[0]과 "main" 이라는 문자열을 비교하게 되면 현재 실행파일이 main 이라는 실행파일명이여야만 실행이되는 조건을 가지는 프로그램을 만들수가 있다.


#include <stdio.h>

int main(int argc) {
  if(argc == 1) {
    printf("Microsoft (R) C/C++ Optimizing Compiler Version 18.00.31101 for x86\n");
    printf("Copyright (C) Microsoft Corporation.  All rights reserved.\n\n");
    printf("usage: cl [ option... ] filename... [ /link linkoption... ]\n");

    return 100;
   }

   return 0;

}


위에서 설명을 하였지만 한번 더 설명을하면 전달인자의 개수가 하나이면 실행파일명만을 입력한것이기 때문에 우리가 컴파일시에 나오는 화면을 비슷하게 만들어서 출력해보았다.

이런식으로 cl /? 명령인 cl 의 옵션들의 내용이 담긴 프로그램도 우리가 만들수도 있고 그 이외의 일상적으로 자주 많이 쓰이는 프로그램, 그 이외의 파일들도 이렇게 조금만 생각의 변환만으로도 만들 수 있다는것을 알 수 있다.


변수와 문자열의 저장 위치와 사용되는 방식

#include <stdio.h>

char B[] = "ABCDEF1234";
int C = 0X12345678;

int main() {
  char A[] = "Test\n";
  char * P = "Test\n";

  printf("Address Of A     : %08X\n", A);
  printf("Address Of Main   : %08X\n", main);

  printf("Address Of String : %08X\n""Test\n");
  printf("Address Of P    : %08X\n"&P);

  printf("Address Of P Val  : %08X\n", P);

  printf("Test\n");
  printf(P);
  printf(A);

  return 0;
}

현재 주소의 범위를 보게되면 앞의 세 자리에서 001 과 00D 두 가지로 분류가 되있는것을 볼 수 있다.

이렇게 분리가 되어있는 차이는 변수, 상수, 함수가 모두 메모리에 저장되는 공간이 다르기 때문에 현재 결과와 같은 모습을 볼수가 있다.


위의 그림과 같이 함수와 상수는 메모리에서 코드영역에 저장이 되고 지역변수는 메모리에서 스텍이라는 영역에 저장이 된다.

이렇게 종류에 따라서 메모리에서 이렇게 5가지 위치에 저장이 된다.

하지만 우리는 이렇게 메모리에 저장되는 방식만을 알고 메모리에서 저장되어서 사용되는 방법은 위의 코드를 보면 알 수 있다.

위의 코드에서 먼저 printf("Address Of String : %08X\n""Test\n"); 이 코드를 보고 결과를 비교해보면 우리가 쓰는 문자열도 주소값을가지고 메모리의 코드영역에 저장이 되어있는 상수인걸 알수 있다. 이 문자열은 주소를 가지는 상수이기 때문에 * P가 가르키게 할 수 있으므로 P가 문자열 "Test\n"을 가르키게 하여 P의 값을 16진수로 출력을하면 코드영역에 있는 "Test\n"의 주소가 나오게 된다.

그리고 이런 문자열을 가르키는 P를 printf에 던져서 출력을하면 Test라는 단어와 한줄을 띄우게 된다.

이렇게 P를 printf에 던져서 출력을하였을때 Test가 나오는것은 문자열은 주소로 존재하고 심지어 printf의 괄호안에 존재하는 "내용" 이것도 문자열로서 코드영역에 저장이 되어서 사용이되기 때문이다.

문자열만이 그런것이 아니고 모든 함수 변수 상수들은 메모리에 주소로 저장이 되고 우리는 그 주소를 찾아가며 함수나 변수나 상수들을 사용하는것이다.


파일 스트림

C 언어에서 파일 스트림은 두 가지로 구분이 된다.

파일 스트림에서 스트림은 두 가지로 구분이 되는데 이는 프로그램과 하드드라이브를 연결하는 스트림이라는 통로가 하나의 일밖에 못하기 때문에 두 가지의 스트림으로 구분이 된다.

첫 번째 스트림은 스트림을 생성하고 쓰는 즉 전송하는 일을 하고 또 다른 스트림은 스트림을 닫고 읽어들이는 일을한다.

즉 두 개의 스트림은 열고, 쓰고, 읽고, 닫고 이렇게 네 가지의 기능으로 이루어져있다.

이런 네가지 기능을 수행하기 위해서는 fopen 함수롸 fclose 함수가 필요한데 먼저 fopen 함수부터 알아본다.

FILE * fopen(const char * filename, const char * mode);

fopen 함수의 원형이다. 여기서 fopen 함수의 TYPE은 FILE * 이고 매개변수는 filename 과 mode 두 가지가 존재한다.

먼저 첫 번째 매개변수는 우리가 파일에 데이터를 쓰고 읽고 하기 위해서는 먼저 파이을 열어야되는데 이때 어디에 위치한 어떤 파일을 열것인가를 결정하는 곳이 첫 번째 매개변수이다.

인자로 파일의 명이나 파일의 경로를 문자열로 던지게 되면 첫 번째 매개변수가 그 문자열을 따라가 파일을 열게된다.

하지만 항상 파일의 모든 경로를 입력해야되는 것은 아니다. 만약에 열거나 생성할 파일이 자신이 작성하는 코드와 같은 폴더 내에 있으면 첫 번째 인자로는 파일 이름만 던지면 된다.

하지만 위와같이 같은 폴더 내에 존재하지 않고 다른 폴더나 같은 컴퓨터 내의 다른 드라이브에 저장되어있는 파일이나 그곳에 파일을 생성하고 싶다면 파일이 존재하는 곳의 전체경로 또는 생성하고 싶은곳의 전체 경로를 입력하여 줘야지만 파일을 열거나 생성이 가능하다.


<Linux>

man 이라는 프로그램을 이용하여 각 함수의 특징, 사용법등의 많은 정보들을 알 수 있으며 간편하게 검색이 가능하다.

먼저 모든 함수들을 검색가능하기 위해서 라이브러리파일들을 받아야된다.

항상 어떠한 패키지를 설치하기 전에는 현재 깔려있는 패키지들의 업데이트 상태를 확안히고 패키지 설치를 하는것이 좋다.

apt-get update를 통하여 먼저 업데이트를한다.

업데이트가 끝이 나면 man-pages-dev glibc-doc 이 두 개의 패키지를 설치한다.

apt-get install man-pages-dev glibc-doc

설치가 완료됬으면 man을 사용하면된다.

man의 사용방법은 man 뒤에 한칸을 띄우고 검색하고 싶은 함수같은 자료를 검색하면 된다.

Ex) man printf    man strcmp, man fopen

검색시에는 Section 번호와 Synopsis, Return Value를 자세히 봐야지만 사용법과 특징을 알 수 있다.

CONFORMAING은 검색한 함수가 사용되는 운용체제 기반이다.

SeeAlso는 검색한 함수와 비슷한 함수들을 나타내준다.






728x90