目录
一. 开发板桥接
二. 开发板白屏
三. 0324-MPU6050开发
3.1 函数详解
3.2 常用 ioctl 请求码(request)
3.3 头文件详解
四. 获取鼠标信息
4.1 获取鼠标信息
4.2 内核修改并编译
五. QT基础使用
六. 内核打印Hello world
七. 内核GPIO
八. 内核i2c通信,mpu信息获取
8.2 kmpu
一. 开发板桥接
1.连接开发板:sudo minicom -D /dev/ttyUSB0
密码:emb
用户:root
password:root
2.开发板桥接虚拟机:
用usb桥接,虚拟机有线链接PCI关闭,以太网设置手动,主机192.168.1.99,子网掩码设置
桥接完成后:ping ip地址(互相)
3.通过联网,拷贝文件到开发板
虚拟机编译:arm-linux-gnueabihf-gcc -o hello.out hello.c
拷贝到开发板:scp hello.out root@192.168.1.10:/home/root
二. 开发板白屏
(1)开发板白屏示例:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>struct fb_fix_screeninfo finfo;
struct fb_var_screeninfo vinfo;int main() {int fd = open("/dev/fb0",O_RDWR,0);ioctl(fd,FBIOGET_FSCREENINFO,&finfo);ioctl(fd,FBIOGET_VSCREENINFO,&vinfo);int screensize = vinfo.xres*vinfo.yres*vinfo.bits_per_pixel/8;printf("screensize:%d Byte\r\n",screensize);printf("x:%d, y:%d, %d", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);int* fb_buffer=(int*)mmap(NULL,screensize,PROT_READ | PROT_WRITE, MAP_SHARED, fd,0);memset(fb_buffer, 0xff, screensize);munmap(fb_buffer, screensize);close(fd);return 0;
}
(2)开发板按键示例:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>struct fb_fix_screeninfo finfo;
struct fb_var_screeninfo vinfo;int main() {int fd = open("/dev/mem",O_RDWR|O_SYNC);if(fd < 0){perror("Cant Open /dev/mem!\r\n");return -1;}void* a=mmap(NULL, 0x1000,PROT_READ | PROT_WRITE, MAP_SHARED, fd,0xf8000000);if((int)a == -1){perror("mmap fail!\r\n");close(fd);return -1;}int tmp = *(unsigned int*)(a + 0x12c);*((unsigned int*)(a + 0x12c)) = tmp | 0x00400000;munmap(a, 0x1000);a = mmap(NULL, 0x1000,PROT_READ | PROT_WRITE, MAP_SHARED, fd,0xe000a000);if((int)a == -1){perror("mmap fail!\r\n");close(fd);return -1;}tmp = *(unsigned int*)(a + 0x048);printf("GPIO0:%d\r\n", tmp);munmap(a, 0x1000);close(fd);return 0;
}
点灯:960\906
cd /sys/class/gpio/
echo 960 > export
cd gpio960
ls
echo out > direction
# 灭灯
echo 1 > value
三. 0324-MPU6050开发
#include<stdio.h>
#include<fcntl.h>
#include<sys/ioctl.h>
#include<unistd.h>
#include<linux/i2c-dev.h>int main()
{int fd;if((fd = open("/dev/i2c-0", O_RDWR)) < 0){perror("open i2c-0 fail!\n");return -1;}unsigned char buf[] = {0};unsigned char wrbuf[] = {0x75};ioctl(fd, I2C_SLAVE, 0x68);write(fd, wrbuf, 1);read(fd, buf, 1);printf("%x\r\n", buf[0]);return 0;
}
返回值:0x68
获取mpu6050返回值
#include<stdio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h> int main()
{int fd;if((fd = open("/dev/i2c-0", O_RDWR)) < 0){perror("open i2c-0 fail!\n");return -1;}unsigned char buf[] = {0};unsigned char wrbuf[] = {0x6B,0x00};ioctl(fd, I2C_SLAVE, 0x68);struct i2c_rdwr_ioctl_data transmit;struct i2c_msg msgs[2];write(fd, wrbuf, 2);char wbuf[1] = {0x3B};char rbuf[10] = {0};msgs[0].len = 1;msgs[0].buf = wbuf;msgs[0].addr =0x68;msgs[0].flags = I2C_M_STOP;msgs[1].len = 6;msgs[1].buf = rbuf;msgs[1].addr = 0x68;msgs[1].flags = I2C_M_RD | I2C_M_STOP; transmit.msgs=msgs;transmit.nmsgs = 2;ioctl(fd, I2C_RDWR, &transmit);printf("%x %x\r\n", rbuf[0], rbuf[1]);return 0;
}
3.1 函数详解
功能:Unix/Linux 系统中用于 设备 I/O 控制(Input/Output Control)的头文件,允许用户程序与设备驱动进行交互,执行设备特定的操作(如配置、状态查询等) | ||
函数原型:#include <sys/ioctl.h> | ||
参数说明 | ||
参数 | 类型 | 说明 |
---|---|---|
fd | int | 已打开的设备文件的文件描述符(如 /dev/tty 、/dev/sda 等)。 |
request | unsigned long | 设备控制命令(由驱动定义,如 TIOCGWINSZ 获取终端大小)。 |
... | void * 或 int | 可选参数,通常是指向数据的指针(如结构体)或整数值。 |
返回值: | 成功:返回 失败:返回 | |
主要功能 | 终端控制(调整窗口大小、获取终端属性)。 网络设备配置(获取/设置网卡参数)。 存储设备管理(如硬盘格式化、读取扇区)。 自定义设备驱动交互(如 LED 控制、传感器数据读取)。 |
3.2 常用 ioctl
请求码(request
)
<sys/ioctl.h>
定义了许多标准请求码,例如:
(1) 终端控制(Terminal I/O)
请求码 | 功能 |
---|---|
TIOCGWINSZ | 获取终端窗口大小(struct winsize )。 |
TIOCSWINSZ | 设置终端窗口大小。 |
TCGETS | 获取终端属性(struct termios )。 |
TCSETS | 设置终端属性。 |
(2) 网络设备控制(Socket I/O)
请求码 | 功能 |
---|---|
SIOCGIFADDR | 获取网络接口 IP 地址(struct ifreq )。 |
SIOCSIFADDR | 设置网络接口 IP 地址。 |
SIOCGIFFLAGS | 获取接口标志(如 UP 、RUNNING )。 |
(3) 存储设备控制(Disk I/O)
请求码 | 功能 |
---|---|
HDIO_GETGEO | 获取磁盘几何信息(struct hd_geometry )。 |
BLKRRPART | 重新读取分区表。 |
3.3 <linux/i2c-dev.h>
头文件详解
1.主要功能
定义 I2C 设备控制相关的 | 设置 I2C 从设备地址( |
执行 I2C 读写操作( | |
控制 I2C 总线(I2C_FUNCS 、I2C_SLAVE_FORCE 等)。 | |
提供 I2C 数据传输结构体 |
|
| |
支持标准 I2C 和 SMBus(System Management Bus)协议 | 适用于传感器、EEPROM、RTC 等 I2C 设备。 |
2. 关键函数原型与 ioctl
命令
(1) 设置从设备地址
| |
参数 | 说明 |
---|---|
fd | 打开的 I2C 设备文件描述符(如 /dev/i2c-1 )。 |
addr | 7 位 I2C 从设备地址(0x03~0x77)。 |
返回值 | 成功返回 0 ,失败返回 -1 (设置 errno )。 |
(2) 执行 I2C 读写(I2C_RDWR
)
| |
参数: | |
| |
标志位 |
|
返回值 | 成功返回 0 ,失败返回 -1 。 |
(3) 查询适配器功能(I2C_FUNCS
)
| |
返回值 | funcs 是一个位掩码,表示适配器支持的功能(如 I2C_FUNC_I2C 、I2C_FUNC_SMBUS_READ_BYTE )。 |
(4) 其他常用 ioctl
命令
命令 | 功能 |
---|---|
I2C_SLAVE_FORCE | 强制设置从设备地址(即使设备忙)。 |
I2C_TENBIT | 启用 10 位地址模式(默认 7 位)。 |
I2C_PEC | 启用 SMBus 数据包错误检查(PEC)。 |
四. 获取鼠标信息
4.1 获取鼠标信息
cd /dev/input/sudo cat mouse0cdcd work/cd 03usrSpaceDriver/gedit input.c
#include <linux/input.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>int main()
{struct input_event event;int fd=open("/dev/input/mouse)",O_RDWR);int nread = read(fd, &event,sizeof(event));printf("type:%d, code:%d, value:%d\r\n", event.type, event.code, event.value);return 0;
}
gcc input.c -o input.out // 编译
./input.out // 运行
4.2 内核修改并编译
# 内核修改并编译
# 拷贝开发板的配置文件
scp root@192.168.1.10:/proc/config.gz ./
# 解压配置文件config.gz
gzip -d config.gz
# 将解压后的文件移动到kernel/.config,命名为.config隐藏文件
mv config kernel/.config
# 进入kernel
cd kernel/
ls
# 图形化界面选择
make ARCH=arm menuconfig
# 编译内核
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- LOADADDR=0x00008000 uImage
# 若有修改,则要更新
五. QT基础使用
1. 新建并拷贝qt生成的python文件到开发板
# 新建qt文件
designer
# 将qt文件转换为py文件
pyuic5 -x pyqt1.ui -o pyqt1.py
# 传输到开发板上运行
scp pyqt1.py root@192.168.1.10:/home/root
2. 在运行qt的python脚本之前要先添加环境变量,选择自己需要的环境变量添加
# Qt-embedded需要的环境变量
# • 指定显示设备
export QT_QPA_PLATFORM=linuxfb
# • 指定输入设备(触摸屏)
export QT_QPA_GENERIC_PLUGINS=evdevtouch:/dev/input/event0
export QWS_MOUSE_PROTO=evdevtouch:/dev/input/event0
# • 指定输入设备(鼠标)
export QT_QPA_GENERIC_PLUGINS=evdevmouse:/dev/input/event0
export QWS_MOUSE_PROTO=evdevmouse:/dev/input/event0
3. 运行拷贝的pyqt脚本
python pyqt1.py
六. 内核打印Hello world
1. 编写内核模块
/* mhello.c */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int hello_init(void)
{pr_alert("Hello, world\n");return 0;
}
static void hello_exit(void)
{pr_alert("Goodbye, world\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("XXX");
MODULE_DESCRIPTION("A simple Hello World Module");
2. 编写Makefile 内核模块编译为可加载模块(obj-m为输出文件名,根据c文件不同名称进行修改)
ifneq ($(KERNELRELEASE),)
obj-m := mhello.o
else
KDIR := /home/emb-zynq/kernel/
all:$(MAKE) -C $(KDIR) M=$$PWD
endif
3. 将生成的.ko文件拷贝到开发板并执行
(1)更新内核
# kernel/arch/arm/boot$ 将此文件下 uImage 文件 覆盖开发板 /media/card 下的uImage
scp uImage root@192.168.1.10:/media/card 直接覆盖
# 重启开发板
reboot
(2)交叉编译并拷贝.ko到开发板并执行
# 交叉编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
# 也可以在当前终端添加临时环境变量,再运行
# export ARCH=arm
# export CROSS_COMPILE=arm-linux-gnueabihf-
# make# scp 将.ko文件传入开发板
scp mhello.ko root@192.168.1.10:/home/root
# 动态加载内核模块
insmod mhello.ko
# 查看加载的内核模块
lsmod
# 卸载内核模块
rmmod mhello.ko
七. 内核GPIO
内核获取gpio状态
# 交叉编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
# 也可以在当前终端添加临时环境变量,再运行
# export ARCH=arm
# export CROSS_COMPILE=arm-linux-gnueabihf-
# make# scp 将.ko文件传入开发板
scp gpios.ko root@192.168.1.10:/home/root
# 动态加载内核模块
insmod gpios.ko# 注册设备号
mknod /dev/gpios c 245 0
# 查看设备状态
cat /dev/gpios# 卸载内核模块
rmmod gpios.ko
内核使用led灯
# 交叉编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
# 也可以在当前终端添加临时环境变量,再运行
# export ARCH=arm
# export CROSS_COMPILE=arm-linux-gnueabihf-
# make# scp 将.ko文件传入开发板
scp led-gpios.ko.ko root@192.168.1.10:/home/root
# 动态加载内核模块
insmod led-gpios.ko.ko# 注册设备号
mknod /dev/led0 c 245 0
mknod /dev/led1 c 245 0
mknod /dev/led2 c 245 0
# 点灯
./ledapp /dev/led0
./ledapp /dev/led1
./ledapp /dev/led2# 卸载内核模块
rmmod led-gpios.ko
八. 内核i2c通信,mpu信息获取
8.1 input_button
编译和测试
编译button.c驱动程序和inputtest.c测试程序 修改前面例子中的Makefile,运行make命令编译驱动程序button.c产生button.ko 修改并编译测试应用:arm-linux-gnueabihf-gcc inputtest.c –o inputtest 下载button.ko 和inputtest到目标板。 加载设备驱动:insmod ./button.ko, 查看/dev/input/event*,找到新增的event文件。 用cat命令查看event文件,按动按键观察输出。 执行测试程序./inputtest /dev/input/event1,观察输出
8.2 kmpu
mount命令:查看设备
练习
• 编译并加载MPU6050驱动kmpu.c,观察输出结果。
• 修改并更新设备树文件system.dtb,更新后reboot
• 设备树文件示例:
scp root@192.168.1.10:/media/card/system.dtb ./
# dtb 改 dts
dtc -I dtb -O dts system.dtb -o system.dts
# 修改system.dts
# dts 改 dtb
dtc -I dts -O dtb system.dts -o system.dtb
#重启开发板
reboot# 编译kmpu.c
make# 将kmpu.c拷贝到开发板
scp kmpu.ko root@192.168.1.10:/home/root/test/0416/kmpu
# insmod加载设备
insmod kmpu.ko