rk3568学习记录 spi-----bmp280(学习资料:瑞芯微-正点原子)

发布时间:2026/10/30 4:16:04

rk3568学习记录 spi-----bmp280(学习资料:瑞芯微-正点原子) 1. 图形化配置界面中打开spi对应内核配置文件1 CONFIG_SPIy 2 CONFIG_SPI_DEBUGy 3 CONFIG_SPI_MASTERy 4 CONFIG_SPI_MEMy 5 CONFIG_SPI_BITBANGy 6 CONFIG_SPI_ROCKCHIPy 7 CONFIG_SPI_SPIDEVy 8 CONFIG_SPI_LOOPBACK_TESTm 9 CONFIG_SPI_SLAVEy 10 CONFIG_SPI_SLAVE_TIMEy 11 CONFIG_SPI_SLAVE_SYSTEM_CONTROLy编译内核rk35568_linux_sdk/下 ./build.sh kernel3. 设备树添加spi节点kernel/arch/arm64/boot/dts/rockchip/rk3568-atk-evb1-ddr4-v10.dtsispi1 { status okay; pinctrl-names default,high_speed; pinctrl-0 spi1m1_pins; pinctrl-1 spi1m1_pins_hs; cs-gpios gpio3 RK_PA1 GPIO_ACTIVE_LOW; // 片选用法与上面同理硬件CS与GPIO CS二选一 spidev0 { compatible linux,spidev; /* 有的主线更严格可用 rohm,dh2228fv 旧兼容ID蹭上 */ reg 0; spi-max-frequency 10000000; status okay; }; };我只用过“linux,spidev”编译、下载boot4. 在/dev中可以看到spidev1.0“linux,spidev”-驱动匹配了字符设备-用户接口dmesg | grep spi*有日志内容内核内核驱动初始化完成5.spi#include stdio.h #include stdlib.h #include unistd.h #include fcntl.h #include sys/ioctl.h #include linux/spi/spidev.h #include stdint.h #include string.h #include math.h // BMP280寄存器地址 #define BMP280_REG_CHIP_ID 0xD0 #define BMP280_REG_RESET 0xE0 #define BMP280_REG_STATUS 0xF3 #define BMP280_REG_CTRL_MEAS 0xF4 #define BMP280_REG_CONFIG 0xF5 #define BMP280_REG_PRESS_MSB 0xF7 #define BMP280_REG_PRESS_LSB 0xF8 #define BMP280_REG_PRESS_XLSB 0xF9 #define BMP280_REG_TEMP_MSB 0xFA #define BMP280_REG_TEMP_LSB 0xFB #define BMP280_REG_TEMP_XLSB 0xFC #define BMP280_REG_CALIB_DATA 0x88 // SPI读写标志 #define SPI_READ_FLAG 0x80 #define SPI_WRITE_FLAG 0x00 // 校准参数结构体 struct bmp280_calib_param { uint16_t dig_T1; int16_t dig_T2; int16_t dig_T3; uint16_t dig_P1; int16_t dig_P2; int16_t dig_P3; int16_t dig_P4; int16_t dig_P5; int16_t dig_P6; int16_t dig_P7; int16_t dig_P8; int16_t dig_P9; int32_t t_fine; }; int spi_init(const char* device, uint32_t speed, uint8_t mode) { int fd open(device, O_RDWR); if (fd 0) { perror(无法打开SPI设备); return -1; } // 设置SPI模式 if (ioctl(fd, SPI_IOC_WR_MODE, mode) 0) { perror(无法设置SPI模式); close(fd); return -1; } // 设置SPI位宽8位 uint8_t bits 8; if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, bits) 0) { perror(无法设置SPI位宽); close(fd); return -1; } // 设置SPI速度 if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, speed) 0) { perror(无法设置SPI速度); close(fd); return -1; } return fd; } // SPI单字节写函数 int spi_write_byte(int fd, uint8_t reg, uint8_t value) { uint8_t tx_buf[2] {reg 0x7F, value}; // 写操作清除最高位 uint8_t rx_buf[2] {0}; struct spi_ioc_transfer tr { .tx_buf (unsigned long)tx_buf, .rx_buf (unsigned long)rx_buf, .len 2, .delay_usecs 0, .speed_hz 1000000, .bits_per_word 8, }; if (ioctl(fd, SPI_IOC_MESSAGE(1), tr) 0) { perror(SPI写操作失败); return -1; } return 0; } // SPI单字节读函数 int spi_read_byte(int fd, uint8_t reg, uint8_t *value) { uint8_t tx_buf[2] {reg | SPI_READ_FLAG, 0x00}; // 读操作设置最高位 uint8_t rx_buf[2] {0}; struct spi_ioc_transfer tr { .tx_buf (unsigned long)tx_buf, .rx_buf (unsigned long)rx_buf, .len 2, .delay_usecs 0, .speed_hz 1000000, .bits_per_word 8, }; if (ioctl(fd, SPI_IOC_MESSAGE(1), tr) 0) { perror(SPI读操作失败); return -1; } *value rx_buf[1]; return 0; } // SPI多字节突发读取重要保证数据一致性 int spi_read_burst(int fd, uint8_t start_reg, uint8_t *buffer, int length) { uint8_t tx_buf[length 1]; uint8_t rx_buf[length 1]; // 设置起始寄存器读模式 tx_buf[0] start_reg | SPI_READ_FLAG; memset(tx_buf[1], 0x00, length); // 填充空数据以产生时钟 struct spi_ioc_transfer tr { .tx_buf (unsigned long)tx_buf, .rx_buf (unsigned long)rx_buf, .len length 1, .delay_usecs 0, .speed_hz 1000000, .bits_per_word 8, }; if (ioctl(fd, SPI_IOC_MESSAGE(1), tr) 0) { perror(SPI突发读取失败); return -1; } // 复制接收到的数据跳过第一个字节 memcpy(buffer, rx_buf[1], length); return 0; } int bmp280_spi_init(int fd, struct bmp280_calib_param *calib) { uint8_t chip_id; // 读取芯片ID确认连接 if (spi_read_byte(fd, BMP280_REG_CHIP_ID, chip_id) 0) { return -1; } if (chip_id ! 0x58) { fprintf(stderr, BMP280未找到芯片ID: 0x%02X\n, chip_id); return -1; } printf(BMP280检测成功芯片ID: 0x%02X\n, chip_id); // 读取校准参数突发读取 uint8_t calib_data[24]; if (spi_read_burst(fd, BMP280_REG_CALIB_DATA, calib_data, 24) 0) { return -1; } // 解析校准参数小端格式 calib-dig_T1 (calib_data[1] 8) | calib_data[0]; calib-dig_T2 (calib_data[3] 8) | calib_data[2]; calib-dig_T3 (calib_data[5] 8) | calib_data[4]; calib-dig_P1 (calib_data[7] 8) | calib_data[6]; calib-dig_P2 (calib_data[9] 8) | calib_data[8]; calib-dig_P3 (calib_data[11] 8) | calib_data[10]; calib-dig_P4 (calib_data[13] 8) | calib_data[12]; calib-dig_P5 (calib_data[15] 8) | calib_data[14]; calib-dig_P6 (calib_data[17] 8) | calib_data[16]; calib-dig_P7 (calib_data[19] 8) | calib_data[18]; calib-dig_P8 (calib_data[21] 8) | calib_data[20]; calib-dig_P9 (calib_data[23] 8) | calib_data[22]; // 软件复位 if (spi_write_byte(fd, BMP280_REG_RESET, 0xB6) 0) { return -1; } usleep(10000); // 等待复位完成 // 配置传感器根据文档第4.3.4和4.3.5节 // 设置测量控制温度4倍过采样压力4倍过采样正常模式 if (spi_write_byte(fd, BMP280_REG_CTRL_MEAS, 0xB7) 0) { // osrs_t2, osrs_p2, mode3 return -1; } // 设置配置standby时间500ms滤波器系数16 if (spi_write_byte(fd, BMP280_REG_CONFIG, 0x94) 0) { // t_sb101, filter100, spi3w_en0 return -1; } calib-t_fine 0; return 0; } // 温度补偿函数文档第3.11.3节 int32_t bmp280_compensate_temperature(struct bmp280_calib_param *calib, int32_t adc_T) { int32_t var1, var2, T; var1 ((((adc_T 3) - ((int32_t)calib-dig_T1 1))) * ((int32_t)calib-dig_T2)) 11; var2 (((((adc_T 4) - ((int32_t)calib-dig_T1)) * ((adc_T 4) - ((int32_t)calib-dig_T1))) 12) * ((int32_t)calib-dig_T3)) 14; calib-t_fine var1 var2; T (calib-t_fine * 5 128) 8; return T; } // 压力补偿函数文档第3.11.3节 uint32_t bmp280_compensate_pressure(struct bmp280_calib_param *calib, int32_t adc_P) { int64_t var1, var2, p; var1 ((int64_t)calib-t_fine) - 128000; var2 var1 * var1 * (int64_t)calib-dig_P6; var2 var2 ((var1 * (int64_t)calib-dig_P5) 17); var2 var2 (((int64_t)calib-dig_P4) 35); var1 ((var1 * var1 * (int64_t)calib-dig_P3) 8) ((var1 * (int64_t)calib-dig_P2) 12); var1 (((((int64_t)1) 47) var1)) * ((int64_t)calib-dig_P1) 33; if (var1 0) { return 0; } p 1048576 - adc_P; p (((p 31) - var2) * 3125) / var1; var1 (((int64_t)calib-dig_P9) * (p 13) * (p 13)) 25; var2 (((int64_t)calib-dig_P8) * p) 19; p ((p var1 var2) 8) (((int64_t)calib-dig_P7) 4); return (uint32_t)p; } int read_bmp280_pressure_spi(int fd, struct bmp280_calib_param *calib, double *pressure_hPa, double *temperature_c) { uint8_t data[6]; // 使用突发读取获取压力和温度数据文档第3.9节 if (spi_read_burst(fd, BMP280_REG_PRESS_MSB, data, 6) 0) { return -1; } // 检查数据是否就绪 uint8_t status; if (spi_read_byte(fd, BMP280_REG_STATUS, status) 0) { return -1; } if (status 0x08) { // 测量进行中 printf(测量进行中等待完成...\n); int timeout 100; while ((status 0x08) timeout 0) { usleep(1000); spi_read_byte(fd, BMP280_REG_STATUS, status); timeout--; } if (timeout 0) { fprintf(stderr, 测量超时\n); return -1; } // 重新读取数据 if (spi_read_burst(fd, BMP280_REG_PRESS_MSB, data, 6) 0) { return -1; } } // 组合20位原始数据 int32_t adc_P ((data[0] 12) | (data[1] 4) | (data[2] 4)); int32_t adc_T ((data[3] 12) | (data[4] 4) | (data[5] 4)); // 补偿计算 int32_t temp_comp bmp280_compensate_temperature(calib, adc_T); uint32_t press_comp bmp280_compensate_pressure(calib, adc_P); // 转换为常用单位 *temperature_c temp_comp / 100.0; *pressure_hPa press_comp / 256.0 / 100.0; return 0; } int main() { int fd; const char *spi_device /dev/spidev1.0; // 根据实际SPI设备调整 struct bmp280_calib_param calib; // 初始化SPI模式0速度1MHz fd spi_init(spi_device, 100000, 0); if (fd 0) { fprintf(stderr, SPI初始化失败\n); return 1; } // 初始化BMP280 if (bmp280_spi_init(fd, calib) 0) { fprintf(stderr, BMP280 SPI初始化失败\n); close(fd); return 1; } printf(BMP280 SPI初始化成功\n); // 连续读取示例 for (int i 0; i 10; i) { double pressure_hPa, temperature_c; if (read_bmp280_pressure_spi(fd, calib, pressure_hPa, temperature_c) 0) { printf(读数 %d: 温度 %.2f°C, 压强 %.2f hPa, 海拔 ≈ %.1f米\n, i 1, temperature_c, pressure_hPa, (1 - pow(pressure_hPa / 1013.25, 0.190284)) * 44307.7); } else { fprintf(stderr, 读取失败\n); } sleep(1); // 每秒读取一次 } close(fd); return 0; }iic#include stdio.h #include stdlib.h #include unistd.h #include fcntl.h #include sys/ioctl.h #include linux/i2c-dev.h #include stdint.h #include math.h // BMP280寄存器地址 #define BMP280_REG_CHIP_ID 0xD0 #define BMP280_REG_RESET 0xE0 #define BMP280_REG_STATUS 0xF3 #define BMP280_REG_CTRL_MEAS 0xF4 #define BMP280_REG_CONFIG 0xF5 #define BMP280_REG_PRESS_MSB 0xF7 #define BMP280_REG_PRESS_LSB 0xF8 #define BMP280_REG_PRESS_XLSB 0xF9 #define BMP280_REG_TEMP_MSB 0xFA #define BMP280_REG_TEMP_LSB 0xFB #define BMP280_REG_TEMP_XLSB 0xFC #define BMP280_REG_CALIB_DATA 0x88 // BMP280校准参数结构体 struct bmp280_calib_param { uint16_t dig_T1; int16_t dig_T2; int16_t dig_T3; uint16_t dig_P1; int16_t dig_P2; int16_t dig_P3; int16_t dig_P4; int16_t dig_P5; int16_t dig_P6; int16_t dig_P7; int16_t dig_P8; int16_t dig_P9; int32_t t_fine; }; // I2C写函数 int i2c_write_byte(int fd, uint8_t reg, uint8_t value) { uint8_t buf[2] {reg, value}; if (write(fd, buf, 2) ! 2) { perror(I2C write failed); return -1; } return 0; } // I2C读函数 int i2c_read_bytes(int fd, uint8_t reg, uint8_t *buf, int len) { if (write(fd, reg, 1) ! 1) { perror(I2C register select failed); return -1; } if (read(fd, buf, len) ! len) { perror(I2C read failed); return -1; } return 0; } int bmp280_init(int fd, struct bmp280_calib_param *calib) { uint8_t chip_id; // 读取芯片ID确认连接 if (i2c_read_bytes(fd, BMP280_REG_CHIP_ID, chip_id, 1) 0) { return -1; } if (chip_id ! 0x58) { fprintf(stderr, BMP280 not found, chip ID: 0x%02X\n, chip_id); return -1; } printf(BMP280 detected, chip ID: 0x%02X\n, chip_id); // 读取校准参数 uint8_t calib_data[24]; if (i2c_read_bytes(fd, BMP280_REG_CALIB_DATA, calib_data, 24) 0) { return -1; } // 解析校准参数小端格式 calib-dig_T1 (calib_data[1] 8) | calib_data[0]; calib-dig_T2 (calib_data[3] 8) | calib_data[2]; calib-dig_T3 (calib_data[5] 8) | calib_data[4]; calib-dig_P1 (calib_data[7] 8) | calib_data[6]; calib-dig_P2 (calib_data[9] 8) | calib_data[8]; calib-dig_P3 (calib_data[11] 8) | calib_data[10]; calib-dig_P4 (calib_data[13] 8) | calib_data[12]; calib-dig_P5 (calib_data[15] 8) | calib_data[14]; calib-dig_P6 (calib_data[17] 8) | calib_data[16]; calib-dig_P7 (calib_data[19] 8) | calib_data[18]; calib-dig_P8 (calib_data[21] 8) | calib_data[20]; calib-dig_P9 (calib_data[23] 8) | calib_data[22]; // 配置传感器文档第4.3.4和4.3.5节 // 设置测量控制温度4倍过采样压力4倍过采样强制模式 if (i2c_write_byte(fd, BMP280_REG_CTRL_MEAS, 0x93) 0) { // osrs_t2, osrs_p2, mode1 return -1; } // 设置配置standby时间500ms滤波器关闭 if (i2c_write_byte(fd, BMP280_REG_CONFIG, 0x00) 0) { // t_sb000, filter000, spi3w_en0 return -1; } calib-t_fine 0; return 0; } int32_t bmp280_compensate_temperature(struct bmp280_calib_param *calib, int32_t adc_T) { int32_t var1, var2, T; var1 ((((adc_T 3) - ((int32_t)calib-dig_T1 1))) * ((int32_t)calib-dig_T2)) 11; var2 (((((adc_T 4) - ((int32_t)calib-dig_T1)) * ((adc_T 4) - ((int32_t)calib-dig_T1))) 12) * ((int32_t)calib-dig_T3)) 14; calib-t_fine var1 var2; T (calib-t_fine * 5 128) 8; return T; // 返回温度值单位0.01°C } uint32_t bmp280_compensate_pressure(struct bmp280_calib_param *calib, int32_t adc_P) { int64_t var1, var2, p; var1 ((int64_t)calib-t_fine) - 128000; var2 var1 * var1 * (int64_t)calib-dig_P6; var2 var2 ((var1 * (int64_t)calib-dig_P5) 17); var2 var2 (((int64_t)calib-dig_P4) 35); var1 ((var1 * var1 * (int64_t)calib-dig_P3) 8) ((var1 * (int64_t)calib-dig_P2) 12); var1 (((((int64_t)1) 47) var1)) * ((int64_t)calib-dig_P1) 33; if (var1 0) { return 0; // 避免除零错误 } p 1048576 - adc_P; p (((p 31) - var2) * 3125) / var1; var1 (((int64_t)calib-dig_P9) * (p 13) * (p 13)) 25; var2 (((int64_t)calib-dig_P8) * p) 19; p ((p var1 var2) 8) (((int64_t)calib-dig_P7) 4); return (uint32_t)p; // 返回压力值单位Pa/256 } int read_bmp280_pressure(int fd, struct bmp280_calib_param *calib, double *pressure_hPa, double *temperature_c) { uint8_t data[6]; // 触发单次测量强制模式 if (i2c_write_byte(fd, BMP280_REG_CTRL_MEAS, 0x93) 0) { return -1; } // 等待测量完成检查状态寄存器 uint8_t status; int timeout 100; // 最大等待100ms do { usleep(1000); // 等待1ms if (i2c_read_bytes(fd, BMP280_REG_STATUS, status, 1) 0) { return -1; } timeout--; } while ((status 0x08) timeout 0); // 检查measuring位文档第4.3.3节 if (timeout 0) { fprintf(stderr, Measurement timeout\n); return -1; } // 读取压力和温度数据文档第3.9节突发读取 if (i2c_read_bytes(fd, BMP280_REG_PRESS_MSB, data, 6) 0) { return -1; } // 组合20位原始数据 int32_t adc_P ((data[0] 12) | (data[1] 4) | (data[2] 4)); int32_t adc_T ((data[3] 12) | (data[4] 4) | (data[5] 4)); // 补偿计算 int32_t temp_comp bmp280_compensate_temperature(calib, adc_T); uint32_t press_comp bmp280_compensate_pressure(calib, adc_P); // 转换为常用单位 *temperature_c temp_comp / 100.0; // 转换为°C *pressure_hPa press_comp / 256.0 / 100.0; // 转换为hPa return 0; } int main() { int fd; const char *i2c_device /dev/i2c-4; // 根据实际I2C总线调整 const int bmp280_addr 0x76; // 或0x77取决于SDO引脚 // 打开I2C设备 if ((fd open(i2c_device, O_RDWR)) 0) { perror(Failed to open I2C device); return 1; } // 设置I2C从设备地址 if (ioctl(fd, I2C_SLAVE, bmp280_addr) 0) { perror(Failed to set I2C address); close(fd); return 1; } struct bmp280_calib_param calib; // 初始化BMP280 if (bmp280_init(fd, calib) 0) { fprintf(stderr, BMP280 initialization failed\n); close(fd); return 1; } printf(BMP280 initialized successfully\n); // 读取压强和温度值 double pressure_hPa, temperature_c; if (read_bmp280_pressure(fd, calib, pressure_hPa, temperature_c) 0) { printf(Temperature: %.2f °C\n, temperature_c); printf(Pressure: %.2f hPa\n, pressure_hPa); printf(Pressure: %.2f mmHg\n, pressure_hPa * 0.750062); } else { fprintf(stderr, Failed to read pressure\n); } close(fd); return 0; }内核源码 .config → 编译 → Image dts源码 dtc工具 → 编译 → dtb 打包 → boot.img
延伸阅读

更多相关文章

2026/10/30 4:16:04

静态库与共享库:原理、对比与应用场景解析

1. 库文件基础概念解析在软件开发领域,库文件(Library)是预先编译好的可重用代码集合,包含函数、类、变量等资源。就像建筑工人使用预制构件快速搭建房屋一样,开发者通过库文件可以避免重复造轮子,显著提升…

2026/10/30 8:01:19

剑网3智能宏教程:全职业一键输出,PVE宏脚本与Lua自动化方案

剑网3智能宏教程:全职业一键输出,PVE宏脚本与Lua自动化方案 【免费下载链接】JX3Toy 全功能减负工具 项目地址: https://gitcode.com/GitHub_Trending/jx/JX3Toy 剑网3的技能循环从来不简单:读条、CD、奇穴条件、目标切换全压在你手指…

2026/10/30 8:01:19

Java算法核心体系与实战优化技巧

1. Java算法核心体系概述作为从业十余年的Java开发者,我深刻体会到算法能力是区分普通程序员与技术专家的分水岭。Java算法体系包含数据结构基础、经典算法实现、性能优化策略三大支柱,这不仅是面试通关的必备技能,更是解决复杂工程问题的利器…

2026/10/30 8:01:19

基于AI智能体的Office自动化:毕设项目架构与实操全解析

1. 项目缘起与整体架构设计1.1 为什么选择“AI智能体 Office套件”这个方向计算机科学与技术专业的毕设选题,每年都有一大批人扎堆做管理系统、推荐算法、图像识别。不是说这些方向不好,而是做得太多了,答辩老师一看标题就能猜到你要讲什么。…

2026/10/29 17:05:52

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/29 17:06:02

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/29 17:06:13

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/30 0:00:46

NCP1342高频准谐振反激控制器:从设计约束到验收的完整方案

简介:NCP1342 高频准谐振反激控制器应用介绍译文文档,面向电源设计工程师、硬件研发人员及开关电源学习者,帮助读者跨越英文原版资料的语言门槛,系统理解这款高集成度 QR Flyback 控制器的设计要点。文档围绕芯片核心特性展开&…

2026/10/30 0:00:46

NCP1342准谐振反激电源设计:从选型到验收的全流程解析

简介:这份文档面向电源设计工程师与开关电源学习者,系统梳理NCP1342高频准谐振反激控制器的应用要点,帮助读者快速理解这款高集成度离线电源变换器控制芯片的工作机制与设计方法。内容涵盖芯片核心特性、引脚功能定义、电气特性参数表、最大额…

2026/10/30 0:00:46

Web系统自动登出机制设计与实现全解析

1. 系统自动登出机制的设计初衷在各类Web应用和后台管理系统中,自动登出功能早已成为标配。这个看似简单的功能背后,实际上涉及用户安全、资源管理和体验优化的多重考量。作为从业十多年的老开发,我见过太多因为登出逻辑设计不当导致的安全事…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑