基于单片机设计的水平仪(STC589C52+MPU6050)

一、前言

【1】项目背景

水平仪是一种常见的测量工具,用于检测物体或设备的水平姿态。在许多应用中,如建筑、制造和航空等领域,保持设备的水平姿态是非常重要的。为了实现实时的水平检测和显示,基于单片机设计的水平仪是一个常见的解决方案。

数字水平仪是一种用于测量物体相对于水平面的角度的仪器。它基于单片机设计,主控芯片为STC89C52,姿态检测采用MPU6050六轴传感器,显示屏用于显示水平姿态数据,锂电池供电。该仪器具有高精度、低功耗、易操作等特点,广泛应用于建筑、工程、测绘等领域。

整个系统的设计思路是通过MPU6050获取设备的姿态数据,然后利用STC89C52进行数据处理和计算,最后将计算得到的水平偏移值通过SPI接口传输到0.96寸的OLED显示屏上进行实时显示。

基于单片机设计的数字水平仪具有以下功能特点:

  1. 主控芯片:本设计采用STC89C52单片机作为主控芯片,具有强大的处理能力和丰富的外设接口,能够满足数字水平仪的功能需求。
  2. 姿态检测:通过MPU6050六轴传感器实现对物体姿态的实时检测,包括加速度计、陀螺仪和磁力计等,能够精确测量物体在三维空间中的倾斜角度。
  3. 显示屏显示:采用液晶显示屏实时显示水平姿态数据,用户可以通过显示屏直观地了解物体的倾斜情况。
  4. 锂电池供电:采用锂电池作为电源,具有高能量密度、长寿命和环保等优点,能够满足数字水平仪长时间工作的需求。
  5. 低功耗设计:通过合理的硬件设计和软件优化,实现低功耗运行,降低能耗,延长电池使用寿命。
  6. 数据存储与传输:内置存储器可存储大量姿态数据,支持USB接口进行数据传输,方便用户进行数据分析和处理。
  7. 易于操作:数字水平仪具有简洁明了的操作界面,用户只需简单设置即可开始测量,无需复杂的操作步骤。
  8. 稳定性高:通过高精度的姿态检测和数据处理算法,实现对物体倾斜角度的准确测量,保证测量结果的稳定性和可靠性。

image-20230913122223179

下面是手机上的水平仪软件显示效果: 原理是一样的

image-20230913122020531

image-20230913121840612

【2】项目的关键点包括

(1)硬件设计:包括将STC89C52和MPU6050连接在一起,确保它们之间的通信正常。同时,需要将OLED显示屏与STC89C52通过SPI接口连接起来,以便将姿态数据显示在屏幕上。

(2)软件设计:需要编写嵌入式软件,包括驱动程序和算法,以实现数据的采集、处理和显示。主控芯片STC89C52上的程序需要读取MPU6050传感器的数据,并进行姿态计算,然后将结果发送到OLED显示屏上进行显示。

(3)界面设计:在OLED显示屏上实时显示水平偏移值,需要设计一个简洁直观的用户界面,使用户能够清楚地了解设备的姿态状态。

通过该项目,能够实现一个基于单片机设计的水平仪,可以实时检测设备的水平姿态,并将结果显示在OLED屏幕上。这对于许多需要保持设备水平的应用场景非常有用,提高了工作效率和准确性。

二、项目软硬件设计思路

【1】硬件设计思路

(1)主控芯片选择:选择了STC89C52作为主控芯片。STC89C52是一款常用的单片机,具有丰富的外设接口和强大的处理能力,适合用于嵌入式应用。它具有8位的数据总线和12MHz的主频,能够满足的需求。

(2)姿态检测传感器选择:选择了MPU6050作为姿态检测传感器。MPU6050是一种集成了三轴陀螺仪和三轴加速度计的传感器模块,能够准确地检测设备的姿态变化。它通过I2C接口与主控芯片进行通信,传输姿态数据。

(3)OLED显示屏选择:选择了一款采用SPI接口的0.96寸OLED显示屏。SPI接口可以提供高速的数据传输,适合实时显示姿态数据。OLED显示屏具有高对比度、低功耗和快速响应的特点,非常适合作为水平偏移值的显示设备。

(4)硬件接线:在硬件设计中,需要将STC89C52、MPU6050和OLED显示屏进行合适的接线连接。具体接线方式如下:

将STC89C52的引脚与MPU6050的I2C接口连接,实现主控芯片与姿态传感器之间的通信。

将STC89C52的引脚与OLED显示屏的SPI接口连接,以便将姿态数据传输到显示屏上。

【2】软件设计思路

(1)初始化:在软件设计中,首先需要进行硬件的初始化设置。包括初始化STC89C52的引脚和外设配置,以及初始化MPU6050和OLED显示屏的通信设置。

(2)数据采集:通过主控芯片的I2C接口,读取MPU6050传感器的原始数据。MPU6050提供了陀螺仪和加速度计的数据,可以通过读取寄存器获取这些数据。

(3)姿态计算:利用获取的陀螺仪和加速度计数据,进行姿态计算。常见的姿态计算算法包括互补滤波算法和卡尔曼滤波算法。

(4)水平偏移值计算:根据姿态计算的结果,计算出水平偏移值。水平偏移值可以通过比较设备的当前姿态与水平状态的差异来确定。

(5)数据显示:将计算得到的水平偏移值通过SPI接口发送到OLED显示屏。需要设计一个简洁的用户界面,在屏幕上实时显示水平偏移值。

(6)循环执行:以上步骤需要在一个循环中不断执行,以实现实时的姿态检测和显示。循环的周期可以根据实际需求进行设置,通常需要考虑到实时性和性能的平衡。

【3】硬件连线说明

在此项目中,硬件模块需要连接到STC89C52单片机的不同引脚。

下面是硬件模块与单片机引脚的连接描述:

(1)MPU6050连接:

  • MPU6050的SCL引脚(时钟线)连接到STC89C52的P1.0引脚,作为I2C总线的时钟线。
  • MPU6050的SDA引脚(数据线)连接到STC89C52的P1.1引脚,作为I2C总线的数据线。
  • MPU6050的VCC引脚连接到电源正极(3.3V或5V)。
  • MPU6050的GND引脚连接到电源地线。

(2)OLED显示屏连接:

  • OLED显示屏的SCL引脚(时钟线)连接到STC89C52的P1.2引脚,作为SPI总线的时钟线。
  • OLED显示屏的SDA引脚(数据线)连接到STC89C52的P1.3引脚,作为SPI总线的数据线。
  • OLED显示屏的RST引脚(复位线)连接到STC89C52的P1.4引脚,用于复位显示屏。
  • OLED显示屏的DC引脚(数据/命令选择线)连接到STC89C52的P1.5引脚,用于选择发送数据或命令。
  • OLED显示屏的CS引脚(片选线)连接到STC89C52的P1.6引脚,用于选中显示屏。
  • OLED显示屏的VCC引脚连接到电源正极(3.3V或5V)。
  • OLED显示屏的GND引脚连接到电源地线。

三、项目代码设计

#include <reg52.h>
#include <intrins.h>

// 定义OLED显示屏引脚
sbit OLED_RST = P1^0;   // RST引脚
sbit OLED_DC = P1^1;    // DC引脚
sbit OLED_DIN = P1^2;   // DIN引脚
sbit OLED_CLK = P1^3;   // CLK引脚
sbit OLED_CS = P1^4;    // CS引脚

// 姿态检测传感器相关定义
sbit MPU_SCL = P2^6;    // I2C时钟引脚
sbit MPU_SDA = P2^7;    // I2C数据引脚

// 定义全局变量
float pitch = 0.0;       // 当前设备的俯仰角

// OLED显示屏相关函数
void OLED_WrCmd(unsigned char cmd);
void OLED_WrDat(unsigned char dat);
void OLED_Init();
void OLED_SetPos(unsigned char x, unsigned char y);
void OLED_Fill(unsigned char bmp_data);
void OLED_ShowString(unsigned char x, unsigned char y, unsigned char *str);

// I2C总线相关函数
void I2C_Start();
void I2C_Stop();
unsigned char I2C_WaitAck();
void I2C_Ack();
void I2C_NAck();
void I2C_SendByte(unsigned char dat);
unsigned char I2C_ReadByte();

// MPU6050相关函数
void MPU_Init();
void MPU_WriteReg(unsigned char reg, unsigned char dat);
unsigned char MPU_ReadReg(unsigned char reg);
void MPU_ReadData(short *data);

// 延时函数
void Delay(unsigned int n);

// 主函数
void main() {
    unsigned char str[16];
    
    MPU_Init();   // 初始化MPU6050
    OLED_Init();   // 初始化OLED显示屏
    
    while (1) {
        short data[3];
        MPU_ReadData(data);   // 读取姿态传感器数据
        
        pitch = -atan2(data[1], data[2]) * (180.0 / 3.14159);   // 计算俯仰角度
        
        sprintf(str, "Pitch:%.2f", pitch);   // 格式化俯仰角数据
        OLED_ShowString(0, 0, str);   // 在OLED显示屏上显示俯仰角度
        
        Delay(100);
    }
}

// OLED显示屏写命令
void OLED_WrCmd(unsigned char cmd) {
    unsigned char i;
    
    OLED_DC = 0;
    OLED_CS = 0;
    
    for (i = 0; i < 8; i++) {
        OLED_CLK = 0;
        if (cmd & 0x80) {
            OLED_DIN = 1;
        } else {
            OLED_DIN = 0;
        }
        OLED_CLK = 1;
        cmd <<= 1;
    }
    
    OLED_CS = 1;
}

// OLED显示屏写数据
void OLED_WrDat(unsigned char dat) {
    unsigned char i;
    
    OLED_DC = 1;
    OLED_CS = 0;
    
    for (i = 0; i < 8; i++) {
        OLED_CLK = 0;
        if (dat & 0x80) {
            OLED_DIN = 1;
        } else {
            OLED_DIN = 0;
        }
        OLED_CLK = 1;
        dat <<= 1;
    }
    
    OLED_CS = 1;
}

// OLED显示屏初始化
void OLED_Init() {
    OLED_RST = 0;
    Delay(100);
    OLED_RST = 1;
    Delay(100);
    
    OLED_WrCmd(0xae);   // 关闭显示
    OLED_WrCmd(0x00);   // 设置低列地址
    OLED_WrCmd(0x10);   // 设置高列地址
    OLED_WrCmd(0x40);   // 设置起始行地址
    OLED_WrCmd(0x81);   // 对比度设置
    OLED_WrCmd(0xcf);   // 设置对比度
    OLED_WrCmd(0xa1);   // 设置段重映射
    OLED_WrCmd(0xc8);   // 设置列重映射
    OLED_WrCmd(0xa6);   // 正常显示
    OLED_WrCmd(0xa8);   // 多路复用设置
    OLED_WrCmd(0x3f);   // 设置多路复用
    OLED_WrCmd(0xd3);   // 设置显示偏移
    OLED_WrCmd(0x00);   // 设置显示偏移
    OLED_WrCmd(0xd5);   // 设置显示时钟分频
    OLED_WrCmd(0x80);   // 设置显示时钟分频
    OLED_WrCmd(0xd9);   // 设置预充电周期
    OLED_WrCmd(0xf1);   // 设置预充电周期
    OLED_WrCmd(0xda);   // 设置COM硬件引脚配置
    OLED_WrCmd(0x12);   // 设置COM硬件引脚配置
    OLED_WrCmd(0xdb);   // 设置VCOMH电压倍率
    OLED_WrCmd(0x40);   // 设置VCOMH电压倍率
    OLED_WrCmd(0x8d);   // 设置DC-DC电压输出开关
    OLED_WrCmd(0x14);   // 设置DC-DC电压输出开关
    OLED_WrCmd(0xaf);   // 打开显示
    OLED_Fill(0x00);    // 清屏
}

// OLED显示屏设置位置
void OLED_SetPos(unsigned char x, unsigned char y) {
    OLED_WrCmd(0xb0 + y);
    OLED_WrCmd(((x & 0xf0) >> 4) | 0x10);
    OLED_WrCmd((x & 0x0f) | 0x01);
}

// OLED显示屏填充
void OLED_Fill(unsigned char bmp_data) {
    unsigned char y, x;
    
    for (y = 0; y < 8; y++) {
        OLED_WrCmd(0xb0 + y);
        OLED_WrCmd(0x00);
        OLED_WrCmd(0x10);
        
        for (x = 0; x < 128; x++) {
            OLED_WrDat(bmp_data);
        }
    }
}

// OLED显示屏显示字符串
void OLED_ShowString(unsigned char x, unsigned char y, unsigned char *str) {
    unsigned char c = 0, i = 0;
    
    while (str[i] != '\0') {
        c = str[i] - 32;
        if (x > 120) {
            x = 0;
            y++;
        }
        OLED_SetPos(x, y);
        for (i = 0; i < 6; i++) {
            OLED_WrDat(F6x8[c][i]);
        }
        i++;
        x += 6;
    }
}

// I2C总线开始信号
void I2C_Start() {
    MPU_SDA = 1;
    MPU_SCL = 1;
    Delay(1);
    MPU_SDA = 0;
    Delay(1);
    MPU_SCL = 0;
}

// I2C总线停止信号
void I2C_Stop() {
    MPU_SDA = 0;
    MPU_SCL = 1;
    Delay(1);
    MPU_SDA = 1;
    Delay(1);
}

// I2C总线等待应答信号
unsigned char I2C_WaitAck() {
    unsigned char ack;
    
    MPU_SDA = 1;
    Delay(1);
    MPU_SCL = 1;
    Delay(1);
    ack = MPU_SDA;
    MPU_SCL = 0;
    
    return ack;
}

// I2C总线发送应答信号
void I2C_Ack() {
    MPU_SCL = 0;
    MPU_SDA = 0;
    Delay(1);
    MPU_SCL = 1;
    Delay(1);
    MPU_SCL = 0;
    MPU_SDA = 1;
    Delay(1);
}

// I2C总线发送非应答信号
void I2C_NAck() {
    MPU_SCL = 0;
    MPU_SDA = 1;
    Delay(1);
    MPU_SCL = 1;
    Delay(1);
    MPU_SCL = 0;
}

// I2C总线发送一个字节数据
void I2C_SendByte(unsigned char dat) {
    unsigned char i;
    
    for (i = 0; i < 8; i++) {
        MPU_SDA = (dat & 0x80) >> 7;
        dat <<= 1;
        Delay(1);
        MPU_SCL = 1;
        Delay(1);
        MPU_SCL = 0;
        Delay(1);
    }
    
    MPU_SDA = 1;
    Delay(1);
    MPU_SCL = 1;
    Delay(1);
    MPU_SCL = 0;
}

// I2C总线读取一个字节数据
unsigned char I2C_ReadByte() {
    unsigned char i, dat;
    
    for (i = 0; i < 8; i++) {
        dat <<= 1;
        MPU_SCL = 1;
        Delay(1);
        dat |= MPU_SDA;
        MPU_SCL = 0;
        Delay(1);
    }
    
    return dat;
}

// MPU6050初始化
void MPU_Init() {
    I2C_Start();
    I2C_SendByte(0xd0);   // 输入器件地址
    I2C_WaitAck();
    I2C_SendByte(0x6b);   // PWR_MGMT_1寄存器地址
    I2C_WaitAck();
    I2C_SendByte(0x00);   // 写0,唤醒设备
    I2C_WaitAck();
    I2C_Stop();
}

// MPU6050写寄存器
void MPU_WriteReg(unsigned char reg, unsigned char dat) {
    I2C_Start();
    I2C_SendByte(0xd0);   // 输入器件地址
    I2C_WaitAck();
    I2C_SendByte(reg);    // 寄存器地址
    I2C_WaitAck();
    I2C_SendByte(dat);    // 数据
    I2C_WaitAck();
    I2C_Stop();
}

// MPU6050读寄存器
unsigned char MPU_ReadReg(unsigned char reg) {
    unsigned char dat;
    
    I2C_Start();
    I2C_SendByte(0xd0);   // 输入器件地址
    I2C_WaitAck();
    I2C_SendByte(reg);    // 寄存器地址
    I2C_WaitAck();
    I2C_Start();
    I2C_SendByte(0xd1);   // 输出器件地址
    I2C_WaitAck();
    dat = I2C_ReadByte();  // 读取数据
    I2C_NAck();
    I2C_Stop();
    
    return dat;
}

// MPU6050读取数据
void MPU_ReadData(short *data) {
    unsigned char i;
    unsigned char buf[14];
    
    I2C_Start();
    I2C_SendByte(0xd0);   // 输入器件地址
    I2C_WaitAck();
    I2C_SendByte(0x3b);   // 寄存器地址
    I2C_WaitAck();
    I2C_Start();
    I2C_SendByte(0xd1);   // 输出器件地址
    I2C_WaitAck();
    
    for (i = 0; i < 13; i++) {
        buf[i] = I2C_ReadByte();   // 读取数据
        I2C_Ack();
    }
    
    buf[13] = I2C_ReadByte();   // 读取数据
    I2C_NAck();
    I2C_Stop();
    
    // 数据转换
    data[0] = ((short)buf[0] << 8) | buf[1];
    data[1] = ((short)buf[2] << 8) | buf[3];
    data[2] = ((short)buf[4] << 8) | buf[5];
}

四、总结

这个项目是基于单片机设计的水平仪,使用了STC89C52作为主控芯片和MPU6050作为姿态检测传感器。其主要功能是检测当前设备的姿态,并计算出水平偏移值,最后通过OLED显示屏实时展示。

整个项目涉及到硬件和软件两个方面。硬件方面,使用STC89C52作为主控芯片,负责控制整个系统的运行和数据处理。MPU6050姿态检测传感器用于获取设备的姿态信息,包括加速度和角速度。OLED显示屏采用SPI接口的0.96寸显示屏,用于将计算得到的水平偏移值实时显示出来。

软件方面,编写嵌入式C程序来实现系统的功能。通过STC89C52与MPU6050进行通信,获取姿态传感器的原始数据。根据这些原始数据进行姿态计算,得到水平偏移值。再将计算得到的水平偏移值通过SPI接口发送给OLED显示屏,实时显示在屏幕上。

项目利用STC89C52和MPU6050实现了一个水平仪,能够检测设备的姿态并计算出水平偏移值,并通过OLED显示屏实时展示。这个水平仪可以在许多应用场景中使用,如建筑工地、航空航天等需要测量水平的领域。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/155809.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

转置矩阵的性质

下面公式中的上标T表示转置的意思。 其中是数

S25FL256S介绍及FPGA实现思路

本文介绍 S25FL256S 这款 FLASH 芯片&#xff0c;并进行 FPGA 读写控制的实现&#xff08;编程思路及注意事项&#xff09;。 文章目录 S25FL-S 介绍管脚功能说明SPI 时钟模式SDRDDR 工作模式FLASH存储阵列&#xff08;地址空间映射&#xff09;常用寄存器及相关指令Status Reg…

php接口api数据签名及验签

api数据签名作用&#xff1a;通过使用签名可以验证数据在传输过程中是否被篡改或修改。接收方可以使用相同的签名算法和密钥对接收到的数据进行验证&#xff0c;如果验证失败则表明数据被篡改过 1、数据发送方进行接口签名并传输签名字段 <?php // 请求URL $url "h…

Xrdp+内网穿透实现远程访问Linux Kali桌面

XrdpCpolar实现远程访问Linux Kali桌面 文章目录 XrdpCpolar实现远程访问Linux Kali桌面前言1. Kali 安装Xrdp2. 本地远程Kali桌面3. Kali 安装Cpolar 内网穿透4. 配置公网远程地址5. 公网远程Kali桌面连接6. 固定连接公网地址7. 固定地址连接测试 前言 Kali远程桌面的好处在于…

LeetCode(19)最后一个单词的长度【数组/字符串】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 58. 最后一个单词的长度 1.题目 给你一个字符串 s&#xff0c;由若干单词组成&#xff0c;单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。 …

Jupyter Notebook的下载安装与使用教程_Python数据分析与可视化

Jupyter Notebook的下载安装与使用 Jupyter简介下载与安装启动与创建NotebookJupyter基本操作 在计算机编程领域&#xff0c;有一个很强大的工具叫做Jupyter。它不仅是一个集成的开发环境&#xff0c;还是一个交互式文档平台。对于初学者来说&#xff0c;Jupyter提供了友好的界…

机器人制作开源方案 | 守护一体化护耆卫士

作者&#xff1a;白玲玲、张硕、孔亚轩单位&#xff1a;兰州理工大学指导老师&#xff1a;毕广利 1. 场景调研 “探索者”平台是结合机械、电子、传感器、计算机软硬件、控制、人工智能和造型技术等众多的先进技术研发推出的专业型机器人设备原型设计工具&#xff0c;包含机构…

第七篇 基于JSP 技术的网上购书系统——新品上架、推荐产品、在线留言、搜索功能实现(网上商城、仿淘宝、当当、亚马逊)

目录 1.新品上架 1.1功能说明 1.2界面设计 1.3处理流程 1.4数据来源和算法 1.4.1数据来源 1.4.2查询条件 1.4.3表间关系 1.4.4相关sql实例 2.推荐产品 2.1功能说明 2.2界面设计 2.3处理流程 2.4数据来源和算法 2.4.1数据来源 2.4.2查询条件 2.4.3表间关…

实战:给docusaurus文档网站配置Algolia 实现全站内容搜索功能-2023.11.16(已解决)

更新于&#xff1a;2023年11月16日 次文档已全部脱敏&#xff01; 实战&#xff1a;给docusaurus文档网站配置Algolia 实现全站内容搜索功能-2023.11.16(已解决) 目录 前提条件 &#x1f340; 前提条件 具备docker环境 具有自己的网站 &#x1f340; 实验软件&#xff08…

【BIM入门实战】Revit属性对话框中“视图范围”工具的使用方法详解

每个平面图都具有视图范围属性&#xff0c;也称为可见范围。视图范围是一组水平平面&#xff0c;可以控制视图中对象的可见性和外观。水平面为顶部平面、剖切面和底部平面。顶部切割平面和底部切割平面表示视图范围的顶部和底部。剖切面是确定视图中某些图元可视剖切面高度的平…

开启Windows11 PC无线热点功能

1.鼠标右键点开始的&#xff0c;选择"设置"选项 2.点“网络和Internet”&#xff0c;点开移动热点&#xff0c;在属性中填SSID&#xff0c;设置接入的key 3.还可以设置频段2.4GHZ或5.8GHz&#xff0c;默认支持8个终端接入&#xff0c;是不是很方便&#xff1f;&#…

SoftwareTest8 - 怎样测试一个系统的性能 ?

Hello , 大家好 , 又给大家带来新的专栏喽 ~ 这个专栏是专门为零基础小白从 0 到 1 了解软件测试基础理论设计的 , 虽然还不足以让你成为软件测试行业的佼佼者 , 但是可以让你了解一下软件测试行业的相关知识 , 具有一定的竞争实力 . 这篇文章是带着大家先了解一些性能测试的概…

LayoutLMv3 : 基于统一文本和带Masking图像的文档AI预训练【论文翻译】

文章目录 专业名词统计文档智能多模态预训练模型LayoutLMv3&#xff1a;兼具通用性与优越性LayoutLMv3 &#xff1a; 基于统一文本和带Masking图像的文档AI预训练ABSTRACT1 INTRODUCTION2 LAYOUTLMV32.1 Model Architecture&#xff08;模型架构&#xff09;2.2 Pre-training O…

linux实现SSH免密登录设置,以及shell脚本实现

原创/朱季谦 最近在搭建linux集群&#xff0c;做了SSH免密登录的设置&#xff0c;正好把过程记录一下&#xff1a; 一.用搭建好的两台虚拟机做演示&#xff0c;A机器&#xff1a;192.168.200.129&#xff0c;B机器&#xff1a;192.168.200.128 二.分别在两台机器上执行以下步…

例解什么是Python装饰器

Python中的装饰器一直是一个比较难理解的概念&#xff0c;我自己理解的就是用一个函数去修改另一个函数&#xff0c;主要是为另一个函数添加计时等功能&#xff0c;而且不用改变另一个函数&#xff0c;这样就大大减少了另一个函数的维护成本。 这个装饰器&#xff0c;英文名就…

休闲娱乐 - 挂耳咖啡

公司有一个小的茶歇间&#xff0c;平时去喝个咖啡、放松身心、锻炼下身体。咖啡机是现磨咖啡豆的&#xff0c;喝喝就习惯了。 而我旁边一位同事习惯每天早上来自己泡一杯挂耳咖啡&#xff0c;再配上牛奶&#xff0c;感觉挺高级的。 关于挂耳咖啡就查了一下资料&#xff0c;介绍…

怎样班群发成绩?

身为老师&#xff0c;定期发布学生成绩是项重要任务。在过去&#xff0c;这项任务需要手动操作&#xff0c;工作量大而且总是发错。不过诶&#xff0c;现在我们可以通过各种方式实现学生自助查询成绩&#xff0c;既提高了效率又不会发错&#xff01; 就是需要制作一个查询系统。…

Python | 机器学习之PCA降维

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《人工智能奇遇记》&#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 目录结构 1. 机器学习之PCA降维概念 1.1 机器学习 1.2 PCA降维 2. PCA降维 2.1 实验目的 2…

RT-Thread STM32F407 定时器

定时器简介 硬件定时器一般有 2 种工作模式&#xff0c;定时器模式和计数器模式。不管是工作在哪一种模式&#xff0c;实质都是通过内部计数器模块对脉冲信号进行计数。下面是定时器的一些重要概念。 计数器模式&#xff1a;对外部输入引脚的外部脉冲信号计数。 定时器模式&…

【项目】云备份系统基础功能实现

目录 一.项目介绍1.云备份认识2.服务端程序负责功能与功能模块划分3.客户端程序负责功能与功能模块划分4.开发环境 二.环境搭建1.gcc升级7.3版本2.安装jsoncpp库3.下载bundle数据压缩库4.下载httplib库 三.第三方库认识1.json(1)json认识(2)jsoncpp认识(3)json实现序列化(4)jso…