当前位置: 首页 > backend >正文

0X. Linux嵌入式系统(课堂笔记)

目录

一. 开发板桥接

二. 开发板白屏

三. 0324-MPU6050开发

3.1 函数详解

3.2 常用 ioctl 请求码(request)

3.3  头文件详解

四. 获取鼠标信息

4.1 获取鼠标信息

4.2 内核修改并编译

五. QT基础使用

六. 内核打印Hello world

七. 内核GPIO

八. 内核i2c通信,mpu信息获取

8.1 input_button

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>

int ioctl(int fd, unsigned long request, ... /* void *arg */);
参数说明
参数类型说明
fdint已打开的设备文件的文件描述符(如 /dev/tty/dev/sda 等)。
requestunsigned long设备控制命令(由驱动定义,如 TIOCGWINSZ 获取终端大小)。
...void * 或 int可选参数,通常是指向数据的指针(如结构体)或整数值。

返回值:​​​​​​

成功:返回 0 或驱动定义的非负值(具体取决于 request)。

失败:返回 -1,并设置 errno 表示错误原因(如 EBADF 表示无效的文件描述符)。

主要功能

终端控制(调整窗口大小、获取终端属性)。

网络设备配置(获取/设置网卡参数)。

存储设备管理(如硬盘格式化、读取扇区)。

自定义设备驱动交互(如 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获取接口标志(如 UPRUNNING)。

(3) 存储设备控制(Disk I/O)

请求码功能
HDIO_GETGEO获取磁盘几何信息(struct hd_geometry)。
BLKRRPART重新读取分区表。

3.3 <linux/i2c-dev.h> 头文件详解

1.主要功能

定义 I2C 设备控制相关的 ioctl 命令

设置 I2C 从设备地址(I2C_SLAVE)。

执行 I2C 读写操作(I2C_RDWR)。

控制 I2C 总线(I2C_FUNCSI2C_SLAVE_FORCE 等)。

提供 I2C 数据传输结构体

struct i2c_msg:描述单个 I2C 消息(读/写操作)。

struct i2c_rdwr_ioctl_data:用于批量传输多个消息。

支持标准 I2C 和 SMBus(System Management Bus)协议

适用于传感器、EEPROM、RTC 等 I2C 设备。

2. 关键函数原型与 ioctl 命令

(1) 设置从设备地址

ioctl(fd, I2C_SLAVE, addr);  // 设置默认通信的 I2C 从设备地址
参数说明
fd打开的 I2C 设备文件描述符(如 /dev/i2c-1)。
addr7 位 I2C 从设备地址(0x03~0x77)。
返回值成功返回 0,失败返回 -1(设置 errno)。

(2) 执行 I2C 读写(I2C_RDWR

struct i2c_rdwr_ioctl_data packets;
ioctl(fd, I2C_RDWR, &packets);  // 执行组合读写操作

参数struct i2c_rdwr_ioctl_data 结构体:

struct i2c_rdwr_ioctl_data {struct i2c_msg *msgs;  // 消息数组int nmsgs;             // 消息数量
};

struct i2c_msg 结构体:

struct i2c_msg {__u16 addr;     // 从设备地址__u16 flags;    // 标志(I2C_M_RD 表示读)__u16 len;      // 数据长度__u8 *buf;      // 数据缓冲区
};
标志位

I2C_M_RD:读操作(否则为写操作)。

I2C_M_TEN:使用 10 位地址(默认 7 位)。

返回值成功返回 0,失败返回 -1

(3) 查询适配器功能(I2C_FUNCS

unsigned long funcs;
ioctl(fd, I2C_FUNCS, &funcs);  // 获取 I2C 适配器支持的功能
返回值funcs 是一个位掩码,表示适配器支持的功能(如 I2C_FUNC_I2CI2C_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

http://www.xdnf.cn/news/4893.html

相关文章:

  • 基于STM32、HAL库的FT232RL USB转UART收发器 驱动程序设计
  • 基于主成分分析(PCA)的数据降维
  • 泰勒展开式
  • Ollama调优,提高性能与安全性
  • 15.thinkphp的上传功能
  • 基于redis的定时状态更新
  • SpringBoot指定项目层日志记录
  • 广东省省考备考(第五天5.8)—言语:逻辑填空(每日一练)
  • 2025 EAU UTUC指南学习笔记③:诊断策略精读——从症状到活检,如何科学判断治疗路径?
  • nextjs站点地图sitemap添加
  • Don’t Mesh with Me 论文阅读 brep llm
  • YY/T 1732-2020口腔曲面体层X射线模体
  • 系统思考助力富维东阳
  • ui生成提示词
  • ROP链-BUUCTF-cmcc_simplerop(ret2syscall)
  • 【JS逆向基础】面向对象
  • Spring AI 集成 DeepSeek V3 模型开发指南
  • Dify工作流接收API请求带文件(有小坑)
  • Android开发补充内容
  • python作业5
  • 基于大数据分析的Facebook隐私保护策略
  • 沃伦森电容器支路阻抗特性监控系统 电容器组智能健康管理专家
  • 【Linux】module list的用法
  • 大模型原理初步了解
  • 软件工程之形式化说明技术深度解析
  • Vulfocus靶场-文件上传-1
  • 通义灵码编码插件支持MCP
  • 从0到1构建前端监控系统:错误捕获、性能采集、用户体验全链路追踪实战指南SDK实现
  • Vue.js Watch 侦听器:深入理解与应用
  • 键盘弹起导致页面上移