크하하하하하 여러분의 열렬한 성원 덕분에 11월의 챌린저가 되었습니다. 앞으로도 더욱 열심히 정진하는 교육생 최진철이 되도록 하겠습니다. 여러분 모두 쌩유. 😘😘
그럼 바로 본론으로 .
7주차에는 리눅스 쉘 문법과 라이브러리 구성 방법에 대해 상세히 배워보았습니다. 8주차에는 이전까지의 학습 교과 평가와 라즈베리 파이를 활용한 리눅스 시스템 프로그래밍을 진행하였습니다.
make는 자동으로 실행 파일을 빌드해주기 위한 툴입니다. C 기반의 여러 임베디드 시스템에서 주로 사용되니 기본 Make 시스템을 이해해보도록 합시다!
Make file의 종류
GNUmakefile
makefile
Makefile
동일한 3가지가 있을 때 위의 적힌 순서대로 수행 .
-f : 옵션으로 특정한 makefile의 수행이 가능하다.
조건
$ cat Makefile
#
# hello world //comment
#
VAR = world
hello:$(VAR) #world라는 파일이 있어야 된다.
@echo hello\
$(VAR)
:execute
$ make -f Makefile
make: *** No rule to make target 'world', needed by 'hello'. Stop.
#dir 에 world가 없어서 타겟 생성이 안된다.
$ nano Makefile
$ touch world
$ ls
__exer__ __exer__.tar makefile Makefile world
$ make -f Makefile #world 파일 생성 후에는 됨
hello world
⚠️shell 과 makfile 에서의 문법 차이
shell : $echo $(VAR)
⇒ VAR을 명령어로 인식
makefile : 변수 확장
변수 표기법: $(VAR) 또는 $VAR
make는 VAR 변수의 값을 찾아 해당 위치에 문자 그대로 대체한다.
⇒ make는 $(VAR)를 world로 확장합니다.
→ 이처럼 문법이 유사한 듯하나 다른 것들이 존재하니 유의해서 사용하자
make 파일을 계층 구조화 하여 복잡 - 거대한 makefile 시스템을 만들 수 있다. 이처럼 거대한 빌드 시스템을 구성할 수 있지만 그 과정에서 변수는 프로세스를 넘어다닐 수 없습니다.
⇒ 이때 export 를 활용 하여 특정 변수를 자식 makefile에서 사용할 수 있도록 만들 수 있습니다.
⇒ 외워 둘 필요가 있다
$ cat makefile
all:hello
hello: hello.o world.o
@echo compile $@ to $^
compare: hello.o world.o
@echo compile $@ to $<
$ make
compile hello to hello.o world.o
$ make compare
compile compare to hello.o
```해당 내용은 그리 중요하지 않을 수 있지만 직접 구현하면서 의아했던 내용을 정리해보도록 하겠습니다.
리눅스에는 Implicit rule이 존재합니다 그 중 .c: 와 같은 오래된 형태의 패턴 룰이 존재하는데 이는 make 빌드 중에 동일한 패턴 발견시 수행할 명령어를 지정할 수 있습니다.
$ make -p |cat -n |head -1250| tail -50
1213 # Not a target:
1214 .c:
1215 # Builtin rule
1216 # Implicit rule search has not been done.
1217 # Modification time never checked.
1218 # File has not been updated.
1219 # recipe to execute (built-in):
1220 $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
위의 결과에서 확인할 수 있듯이 .c: 는 $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@ 명령어를 수행합니다.
그리고 이 suffix rule을 비울 수 있습니다.
$ cat makefile
.SUFFIXES: ##SUFFIXES : 룰 비우기
all:
hello: hello.c
.c:
@echo compile $< to $@
$ make -p | grep .SUFFIXES
.SUFFIXES: #아무 값도 나오지 않는다.
makefile 내에서 .SUFFIXES를 사용한다면 기존의 SUFFIXES를 비울 수 있습니다.
그렇다면 .SUFFIXES : .k 를 추가한다면 어떻게 될까요?
저는 비워진 이후 .K만 추가될 것이라 생각했지만 그렇지 않았습니다.
$ cat makefile
.SUFFIXES:.c .k
all:
hello: hello.c
world: world.k
.c:
@echo compile $< to $@
.k:
@echo use k
$ make -p | grep .SUFFIXES
.SUFFIXES: .out .a .ln .o .c .cc .C .cpp .p .f .F .m .r .y .l .ym
.yl .s .S .mod .sym .def .h .info .dvi .tex .texinfo .texi
.txinfo .w .ch .web .sh .elc .el .k # ->k 추가
출력에서 확인할 수 있듯이 내장 SUFFIXES뒤에 사용자 정의 rule이 추가되었습니다.
💡.SUFFIXES: 에 아무것도 안 쓰면 → 모든 내장 suffix rule을 완전히 비활성화
.SUFFIXES: 에 하나라도 쓰면 → 내장된 수십 개의 suffix rule이 전부 자동으로 깨어남
이러한 차이를 발견할 수 있었습니다 .
그렇다면 .k 만을 추가하고 싶다면 어떻게 해야할까요?
.SUFFIXES: # 다 비우기
.SUFFIXES:.k # 비운 다음에 추가
all:
hello: hello.c
world: world.k
.c:
@echo compile $< to $@
.k:
@echo use k
이렇게 먼저 다 비운 뒤 추가를 하면 .k만 출력되는 것을 확인해볼 수 있습니다. 다들 실습으로 확인해보시길 바랍니다!!!
다음은 또 다른 build 시스템인 CMake에 대해 간략히 정리해보겠습니다.
Cmake는 빌드 파일로 CMakeLists.txt를 가지며 해당 파일 내에 필요한 라이브러리,타겟 파일,소스 파일, 빌드 형식등에 대한 메타 데이터를 가집니다
cmake -S [source dir] - B [build dir]
$ cat CMakeLists.txt
cmake_minimum_required(VERSION 3.2)
message("hello world")
project(Helloworld)
add_executable (${CMAKE_PROJECT_NAME} hello.c world.c
$ ls
build CMakeLists.txt hello.c world.c world.h
$ cmake -B build
$ ls build/Makefile #makefile 생성 됨
build/Makefile
$ ls
build CMakeLists.txt hello.c world.c world.h
$ cmake --build build # build 파일 안에 Makefile로 빌드
[ 33%] Building C object CMakeFiles/Helloworld.dir/hello.c.o
/home/ros2man/work/CMake/project/hello.c: In function ‘main’:
/home/ros2man/work/CMake/project/hello.c:6:9: warning: implicit declaration of function ‘world’ [-Wimplicit-function-declaration]
6 | world();
| ^~~~~
[ 66%] Building C object CMakeFiles/Helloworld.dir/world.c.o
[100%] Linking C executable Helloworld
[100%] Built target Helloworld
$ ./build/Helloworld
hello
world
===============> 실행 가능
위의 코드는 간략하게 Cmake 빌드의 구성을 예시로 들었습니다.
현업에서 주로 사용되는 Build 시스템을 파악하여 연습 과정을 가져야겠다는 생각을 했습니다. 복잡한 계층 Build 시스템에서 경로 오류가 발생할 경우 난감했던 상황이 종종 있었는데 이제는 이해하면서 해결할 수 있을 것만 같은 느낌이 듭니다.
👍레쯔 꼬우 ~
→ 시스템 프로그래밍 구조 , 파일 시스템, 정보와 권한
To Embedded Linux
linux @arm/ppc (non pc ) ⇒ embedded linux (by “porting”)
⇒ 포팅의 과정
1. bootloader(”u-boot”)
1. linux /Makefile → make → 1. vmlinux
2. vmlinux → vmlinux.gz → zImage // kernel image
3. device tree
4. root file system
ext4 on “ / == root “
/proc : 커널이 관리하는 정보를 저장한다./etc : 설정 파일 보관/bin : 시스템 부팅과 기본 복구 시 반드시 필요한 가장 기본적인 실행 파일들/sys : 드라이버가 관리하는 정보/dev : 장치 정보pinout 확인 예시
$ gpio readall
#1. pin 번호를 확인
+-----+-----+---------+------+---+---Pi 4B--+---+------+---------+-----+-----+
| BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
| | | 3.3v | | | 1 || 2 | | | 5v | | |
| 2 | 8 | SDA.1 | ALT0 | 1 | 3 || 4 | | | 5v | | |
| 3 | 9 | SCL.1 | ALT0 | 1 | 5 || 6 | | | 0v | | |
| 4 | 7 | GPIO. 7 | IN | 1 | 7 || 8 | 1 | ALT5 | TxD | 15 | 14 |
| | | 0v | | | 9 || 10 | 1 | ALT5 | RxD | 16 | 15 |
| 17 | 0 | GPIO. 0 | IN | 0 | 11 || 12 | 0 | IN | GPIO. 1 | 1 | 18 |
| 27 | 2 | GPIO. 2 | IN | 0 | 13 || 14 | | | 0v | | |
| 22 | 3 | GPIO. 3 | IN | 0 | 15 || 16 | 0 | IN | GPIO. 4 | 4 | 23 |
| | | 3.3v | | | 17 || 18 | 0 | IN | GPIO. 5 | 5 | 24 |
| 10 | 12 | MOSI | ALT0 | 0 | 19 || 20 | | | 0v | | |
| 9 | 13 | MISO | ALT0 | 0 | 21 || 22 | 0 | IN | GPIO. 6 | 6 | 25 |
| 11 | 14 | SCLK | ALT0 | 0 | 23 || 24 | 1 | OUT | CE0 | 10 | 8 |
| | | 0v | | | 25 || 26 | 1 | OUT | CE1 | 11 | 7 |
| 0 | 30 | SDA.0 | IN | 1 | 27 || 28 | 1 | IN | SCL.0 | 31 | 1 |
| 5 | 21 | GPIO.21 | IN | 1 | 29 || 30 | | | 0v | | |
| 6 | 22 | GPIO.22 | IN | 1 | 31 || 32 | 0 | IN | GPIO.26 | 26 | 12 |
| 13 | 23 | GPIO.23 | IN | 0 | 33 || 34 | | | 0v | | |
| 19 | 24 | GPIO.24 | IN | 0 | 35 || 36 | 0 | IN | GPIO.27 | 27 | 16 |
| 26 | 25 | GPIO.25 | IN | 0 | 37 || 38 | 0 | IN | GPIO.28 | 28 | 20 |
| | | 0v | | | 39 || 40 | 0 | IN | GPIO.29 | 29 | 21 |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
| BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM |
+-----+-----+---------+------+---+---Pi 4B--+---+------+---------+-----+-----+
return
5byte { 1 1 1 1 1}
RH T checksum
상대습도 온도
온도,습도 모두 decimal , integral 로 두 바이트씩
Communication Process
single wire 통신 : 별도의 클럭핀 없이 데이터 핀의 전압 레벨이 VCC와 GND 사이에서 바뀐다.
⇒ 전압의 지속 시간으로 모든 것을 구분함
Start Signal
mcu sends out Start Signal : ⇒ 최소 18ms 동안 pull-down voltage → DHT11에서 탐지
이후에 전압의 유지 시간으로 0과 1을 구분해 값을 읽어들인다
Data 0 : 26~ 28us의 전압 지속
Data 1 : 70us의 전압 지속
// 1. DHT11 깨우기: 18ms 이상 Low 신호 전송
pinMode(DHT_PIN, OUTPUT);
digitalWrite(DHT_PIN, LOW);
delay(18);pinMode(DHT_PIN, INPUT);
for (i = 0; i < MAX_TIMINGS; i++) {
//MAX_TIMINGS : 85 번 동안만 신호 감지를 하겠다.
while (digitalRead(DHT_PIN) == laststate) {
counter++;
delayMicroseconds(1);
// ms 단위로 counter값 증가 // 첫 4번 펄스는 시작 신호이므로 무시 (i >= 4부터 데이터 시작)
if ((i >= 4) && (i % 2 == 0))
{
data[j / 8] <<= 1; // 왼쪽으로 시프트 (MSB 먼저 오므로)
if (counter > THRESHOLD) // 70μs 이상 → 비트 1
// THRESHOLD: 40 -> 27과 70을 구분
data[j / 8] |= 1; // 1 설정
j++;
}if ((j >= 40) && (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)))
printf("Humidity = %d.%d %% Temperature = %d.%d C\n", ...); 체크썸 방식 = > data[4] == ((data[0] + data[1] + data[2] + data[3])& 0xFF 해서 1바이트 값만 확인 .빌드 방법
cc -o dht11_app dht11_app.c -lwiringPi
sudo ./dht11_app
" root 권한이 필요 (GPIO 접근 때문) "
이렇게 8주차에는 직접 실습을 진행하며 빌드 시스템과 센서 사용법에 대해 더 자세히 알아갈 수 있는 시간을 가질 수 있었다. 더 다양한 센서 및 시스템을 개발해보며 학습하는 시간을 가져야겠다는 느낌을 받음
.. 교과 평가 후기
범위가 넓은 만큼 생각보다 많이 틀렸음 . 2개 정도 ..ㅎㅎ 문제를 잘 못 보고 이상하게 풀었는데 다음 교과평가는 더 꼼꼼하게 풀도록 해야겠씀니다.
이만 8주차 VEDA 기록 끗. !!!!
이것은 원인을 모르겠는 피사의 빵판...
기울여야지만 FND가 정상적으로 작동하는 기적을 맛보았노라..
원인을 아시는 분은 댓글로 알려주세욥 ㅠㅠㅠㅠ
이번 주는 맛집 사진을 찍은 것이 없네요...
양상추가 빠진 맥도날드에서 생각보다 양상추는 위대함을 깨달았습니다.
++ 돼지벅스라는 강력한 녀석의 등장으로 맛집 탐방은 뜸해질 예정 .
왜 why? 바로 단백질 , 포만감 G.O.A.T 이기 때문입니다.
그럼에도 독자분들을 위해 분발하도록 하겠습니다!