일상다반사 로그

임베디드 리눅스 - LED(2) 본문

IT/임베디드 리눅스

임베디드 리눅스 - LED(2)

일상다반사로그 2017. 10. 12. 19:22
반응형

* 실습10 mmap 함수를 통한 가상번지 접근


#include <sys/mman.h>

#include <sys/fcntl.h>

#include <stdio.h>


#define ADDRESSOFSRAM 0x0c000000


int main()

{

        unsigned long *addr_sram;

        fd=open("/dev/mem",O_RDWR|O_SYNC)


        addr_sram = mmap(NULL,1,PROT_READ, MAP_SHARED,fd,ADDRESSOFSRAM);

        printf("sram_Val:[ %x]\n",*addr_sram);

}


소스를 작성하고 arm-linux용으로 컴파일하여, 타겟보드에서 SRAM영역에 값을 넣은후 확인한다.


EMPOS # write b32 0x0c000000 12345678

EMPOS # boot

# ./readsram

sram_val:12345678


값이 제대로 나오면 mmap 함수통한 가상번지 접근 실습은 완료


* 실습 11 LED 제어 프로그램


 타겟보드 상에서 사용자가 “L,R,Q" 누르면 LED가 좌,우로 움직이고, 종료가 되는 프로그램작성하기


 먼저 타겟보드에서 키보드의 입력이 있는지 그리고 입력이 있으면 그 값을 읽는 함수와 터미널 환경을 설정하는 함수도 구현해야한다. 함수에 필요한 전역변수 역시 선언해야한다.


fd는 메모리에 관한 파일기술자, *led_addr는 mmap에서 넘겨받을 외부 LED에 접근할 번지를 저장할 포인터

mmap 함수는 메모리 파일기술자를 필요하므로 먼저 /dev/mem을 열어서 파일 기술자를 받아온다. 다음 mmap함수를 이용하여 외부 LED에 접근할 주소를 led_addr포인터에 저장한다. 포인터를 얻지못하면 메모리 파일 기술자를 닫고 프로그램을 종료해야한다.


#include <sys/mman.h>

#include <sys/fcntl.h>

#include <stdio.h>

#include <termios.h>                        //termios 구조체


#define ADDR_OF_LED                      0x10600000      //LED에 접근하기위한 물리주소


struct termios initial_settings, new_settings;

char peek_character;                          // warnings 뜨면 변수타입을 바꾼다.

void init_keyboard()                         //터미널 환경설정

{

        tcgetattr(0,&initial_settings);

        new_settings = initial_settings;

        new_settings.c_lflag &= ~ICANON;

        new_settings.c_lflag &= ~ECHO;

        new_settings.c_lflag &= ~ISIG;

        new_settings.c_cc[ VMIN] =1;

        new_settings.c_cc[ VTIME] =0;

        tcsetattr(0, TCSANOW, &new_settings);

}

void close_keyboard()

{

        tcsetattr(0, TCSANOW, &initial_settings);

}

 

int kbhit()                                 //키보드 입력 감지

{

        char ch;

        int nread;


        if(peek_character !=-1) return 1;


        new_settings.c_cc[ VMIN] = 0;

        tcsetattr(0, TCSANOW, &new_settings);

        nread = read(0, &ch, 1);

        new_settings.c_cc[ VMIN] =1;

        tcsetattr(0, TCSANOW, &new_settings);


        if(nread == 1){

                peek_character = ch;

                return 1;

        }

        return 0;

}

int readch()                               //키보드 입력값 확인

{

        char ch;

        if(peek_character != -1){

                ch = peek_character;

                peek_character = -1;

                return ch;

        }

        read(0, &ch, 1);

        return ch;

}

int main()

{

        int fd, i;

        unsinged char *led_addr, led_status;

        int blink_counter, blinc_delay;

        char ch;                          //문자 입력값을 넣어주는 변수

        int status = 1;                    //문자 입력값에 따라 좌, 우 움직일때의 변수


        if((fd=open("/dev/mem", O_RDWR|O_SYNC)) <0) {

                        perror("mem open fail\n");

                        exit (1);

        }

        led_addr = mmap(NULL, 1, PROT_WRITE, MAP_SHARED, fd, ADDR_OF_LED);

        if(led_addr <0){

                led_addr = NULL;

                close(fd);

                exit(2);

        }


        *led_addr = 0xAA;                 //0xAA로 초기화 LED 오프 시킨다.

        //blink_count = 8;          //여기소스에서는 반복적으로 움직이기에 blink_count사용안한다.

        blink_delay = 1000000;              //led 움직일때 delay값을 준다.

        led_status = 1;

        

        while(1){

                printf("led 제어 시작\n");

                init_keyboard();            //터미널 환경함수 불러오기

                if(kbhit()){                 //키보드 입력감지 함수 불러오기

                        ch= readch();     // 입력받은값을 ch 변수에 넣기


                        switch(ch){       // 좌, 우 입력받았을때 status 값을 설정

                        case 'l' : case :'L' : status =1; break;

                        case 'r' : case :'R' : status =2; break;

                        case 'q' : case : 'Q': munmap(led_addr,1); close(fd); exit(1);                                break;

                        default : printf("ERROR"); break;

                        }

                }

                

                if(status == 1){            //1일때 왼쪽, 2일때 오른쪽

                led_status=(led_status=128)?1:(led_status<<1);

                }

                else if(status ==2){

                led_status=(led_status=1)?128:(led_status>>1);

                }

                *led_addr= led_status; usleep(blink_delay);       

        

                close_keyboard();

                return 0;

        }

}


 소스작성완료하고 컴파일 후 타겟보드에서 잘움직이는지 확인한다. ‘l’누르면 반복으로 잘가는지, 다른버튼을 눌렀을때 실행이 잘되는지 확인한다.


 처음에 while문안에 status값에 의해 움직이는 if문을 whlie문 밖에다가 넣어서 키보드를 누르면 한칸씩 밖에 가지 않았다. 결국엔 한번 누르면 계속 움직이는줄 모르고 그렇게 해버린것이다. 다시 수정하여 while문안에다가 넣으니 결국 한번 누르면 반복으로 계속 움직였다.

반응형
Comments