2024.2.1 (목)
$ sudo halt
그냥 전원을 빼버리면 메모리에 있는 데이터가 하드웨어에 동기화가 되지 않고 종료돼서 다음에 켰을 때 업데이트 등의 문제가 생길 수 있음
halt 명령어로 정상 종료하는 것이 좋음 !
+ --->|---- -
+ : 애노드 (A)
- : 캐소드 (K)
전류는 +에서 -로 흐른다
(전자는 -에서 +로!)
전압이 같으면 흐르지 않음
발광 다이오드를 그냥 연결하면 몇 분 안 가서 고장난다. 따라서 저항을 연결해줘야 함 (330옴)
D0: 12 pin (GPIO18)
GND : 6 pin (GND)
$ echo "18" > /sys/class/gpio/export
echo: print문과 흡사
export를 하면 direction과 value 파일이 생성된다
GPIO 18번을 exporting 한다
$ echo "out" > /sys/class/gpio/gpio18/direction
// 불 켜기
$ echo "1" > /sys/class/gpio/gpio18/value
// 불 끄기
$ echo "0" > /sys/class/gpio/gpio18/value
8개 LED 껐다 켰다 하기
$ mkdir gpio.d
$ cd gpio.d/
$ cp /srv/samba/for_led.sh .
$ sudo ./for_led.sh
#!/bin/bash
for ((i=6 ; i<14 ; i++))
do
echo "$i" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio${i}/direction
echo "1" > /sys/class/gpio/gpio${i}/value
echo -n "gpio$i : "
cat /sys/class/gpio/gpio${i}/value
sleep 1
echo -n "gpio$i : "
echo "0" > /sys/class/gpio/gpio${i}/value
cat /sys/class/gpio/gpio${i}/value
sleep 1
echo "$i" > /sys/class/gpio/unexport
done
LED GPIO : 6, 7, 8, 9, 10, 11, 12, 13
KEY GPIO : 16, 17, 17, 19, 20, 21, 22, 23
(14, 15는 시리얼 통신용이라 사용하면 안 됨)
$ cp /srv/samba/for_ledkey.sh .
$ sudo ./for_ledkey.sh
#!/bin/bash
for ((i=6 ; i<14 ; i++))
do
echo "$i" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio${i}/direction
echo "1" > /sys/class/gpio/gpio${i}/value
echo -n "gpio$i : "
cat /sys/class/gpio/gpio${i}/value
sleep 1
echo -n "gpio$i : "
echo "0" > /sys/class/gpio/gpio${i}/value
cat /sys/class/gpio/gpio${i}/value
sleep 1
echo "$i" > /sys/class/gpio/unexport
done
for ((i=16 ; i<24 ; i++))
do
echo "$i" > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio${i}/direction
# echo "1" > /sys/class/gpio/gpio${i}/value
echo -n "gpio$i : "
cat /sys/class/gpio/gpio${i}/value
sleep 1
echo -n "gpio$i : "
# echo "0" > /sys/class/gpio/gpio${i}/value
cat /sys/class/gpio/gpio${i}/value
sleep 1
echo "$i" > /sys/class/gpio/unexport
done
#include <stdio.h>
#include <stdlib.h> // atoi() 함수
#include <string.h>
#include <fcntl.h>
#include <unistd.h> // close() 함수
int ledControl(int gpio)
{
int fd;
char buf[BUFSIZ];
fd = open("/sys/class/gpio/export", O_WRONLY); // 장치 열어서 Write Only로 디바이스 사용 준비
// 0 : 표준 입력 (키보드), 1 : 표준 출력 (모니터), 2: 오류 (모니터)
sprintf(buf, "%d", gpio); // buffer에 gpio 핀 문자열로 서식화
write(fd, buf, strlen(buf));
close(fd);
sprintf(buf, "/sys/class/gpio/gpio%d/direction", gpio); // 해당 GPIO 디바이스의 방향 설정
fd = open(buf, O_WRONLY);
write(fd, "out", 4); // 출력으로 설정
close(fd);
sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio); // 디바이스에 값 출력
fd = open(buf, O_WRONLY);
write(fd, "1", 2);
close(fd);
getchar(); // LED 확인을 위한 대기
fd = open("/sys/class/gpio/unexport", O_WRONLY); // 사용한 GPIO 디바이스 해제하기
sprintf(buf, "%d", gpio);
write(fd, buf, strlen(buf));
close(fd);
return 0;
}
int main(int argc, char **argv)
{
int gno;
if(argc < 2) { // 숫자를 안 주면 오류가 남 (argument count가 1밖에 없기 때문)
// sudo ./gpioled 6 이런 식으로 줘야 함
printf("Usage : %s GPIO_NO\n", argv[0]);
return 1; // main 함수에서 return 할 때는 양수를 리턴할 것
// (echo $?를 통해 return 값을 확인할 수 있음)
}
gno = atoi(argv[1]);
ledControl(gno);
return 0;
}
int main(int argc, char **argv)
int main(int argc, char *argv[]) // 포인터 배열은 이중 포인터로 받을 수 있다
cp gpioled.c led
argc : 3개
argv : 문자 각각의 주소를 담는다
argv[0] = 0x100 ("cp"의 주소)
argv[1] = 0x110 ("gpioled.c"의 주소)
argv[2] = 0x120 ("led"의 주소)
argv[3] = 0x00 (null)
배열명은 첫 번째 배열 원소의 주소 값이다
wiringPi는 라즈베리 파이에서 사용하는 브로드컴의 CPU에서 GPIO를 사용하기 위한 C언어 라이브러리이다. wiringPi를 이용하면 라즈베리 파이의 GPIO보다 간단하게 접근할 수 있는데, 아두이노와 비슷한 문법으로 쉽게 프로그래밍할 수 있다.
$ git clone https://github.com/WiringPi/WiringPi.git
$ cd WiringPi/
$ ./build
vi blink.c
cp WiringPi/examples/blink.c .
gcc blink.c -o blink -lwiringPi
sudo ./blink
프로그래밍 소스코드의 태그 (전역변수 선언, 함수 정의, 매크로 선언)들의 Database(tags file)를 생성하는 Unix 명령어
$ sudo apt install universal-ctags
$ vi ~/.vimrc
에 들어가서 아래 코드 추가해주기
$ set tags=/home/ubuntu/Ctags_ex/tags ( 현재 tags 파일이 있는 경로 , 개개인마다 다릅니다. )
단축어
Ctrl + ] : 해당 함수나 변수가 선언된 위치로 이동
Ctrl + t : 이전 태그로 돌아감
앞으로 학습할 내용
1. C로 부트로더 기능 추가
2. 커널에서 시스템 콜 함수 이해하기 (나만의 커널 만들기)
3. CPU 내부 이해하기
4. HAL SYSTEM이 어떤 원리로 구동시키는지 이해하기
5. Device Driver : 운영체제 위에서는 모듈이 어떻게 동작하는지
6. QT로 디바이스 드라이버(커널 소스의 일부분)와 어플리케이션 만들기
혼자 공부하는 C언어 p497
명령행에서 프로그램을 실행시킬 때는 프로그램 이름 외에도 프로그램에 필요한 정보를 함께 줄 수 있는데 이를 명령행 인수라고 한다. 프로그램의 실행 방법은 운영체제마다 다르다. 윈도우에서는 바탕화면의 프로그램 아이콘을 더블 클릭해야 하며 유닉스에서는 명령행에 실행 파일의 이름을 직접 입력해야 한다.
운영체제가 명령행 인수를 프로그램의 main 함수로 넘기는 방법을 통해 포인터로 동적 할당한 영역을 배열처럼 사용하는 예시이다.
#include <stdio.h>
int main(int argc, char **argv) // 명령행 인수를 받을 매개변수
{
int i;
for (i = 0; i < argc; i++) // 인수 개수만큼 반복
{
printf("%s\n", argv[i]); // 인수로 받은 문자열 출력
}
return 0;
}
ubuntu@ubuntu09:~/study$ ./16_6 first_arg second_arg
./16_6
first_arg
second_arg