STM32 IIC通信

目录

  • IIC简介
  • 硬件电路连接
  • I2C时序基本单元
  • IIC完整数据帧
  • MPU6050封装
  • 硬件IIC
    • 内部电路

IIC简介

IIC(Inter-Integrated Circuit)是 IIC Bus 简称,中文叫集成电路总线。它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展。自2006年10月1日起,使用I²C协议已经不需要支付专利费,但制造商仍然需要付费以获取I²C从属设备地址。
  IIC使用两根信号线进行通信:一根时钟线SCL,一根数据线SDA。IIC将SCL处于高时SDA拉低的动作作为开始信号,SCL处于高时SDA拉高的动作作为结束信号;传输数据时,SDA在SCL低电平时改变数据,在SCL高电平时保持数据,每个SCL脉冲的高电平传递1位数据。

IIC通信时一种同步,半双工的通信协议,带数据应答,支持总线挂载多设备(一主多从、多主多从)。

也正是因为IIC是一种同步时序,所有我们可以软件模拟,串口通信就是一种异步时序,对时序要求很严格,所有我们不能模拟,需要硬件短路来实现才会精准收发数据。

硬件电路连接

所有I2C设备的SCL连在一起,SDA连在一起
设备的SCL和SDA均要配置成开漏输出模式
SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右

在这里插入图片描述
任何时候都是主机完全掌控SCL线,只有从机应答和从机发送的时候才会获得SDA的掌控权。
IIC的设计禁止所有设备输出强上拉的高电平。采用外置弱上拉的电阻加开漏输出的电路结构。这么做的原因也是为了防止主机在结束的时候释放SDA即拉高然后从机立刻拉低响应造成的短路。这个模式也存在“线与”的特性,只要有输出低,那么最后就输出低,所有输出高才输出高。
CPU和被控IC都是上图右边的结构。开漏输出没有强上拉,只有强下拉,当输出高电平的时候,下管断开,不输出低,处于浮空状态,此时就由上拉电阻拉高。

I2C时序基本单元

起始条件:SCL高电平期间,SDA从高电平切换到低电平
终止条件:SCL高电平期间,SDA从低电平切换到高电平

在这里插入图片描述
发送一个字节:
SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节。
在这里插入图片描述

接收一个字节:
SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)。
在这里插入图片描述
发送应答: 主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答
接收应答: 主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA,从机控制,从机拉低就是从机发送应答)

IIC完整数据帧

IIC的完成数据帧包括指定地址写,当前地址读,指定地址读
IIC是一主多从的通信协议,所以如果要和某个从机进行通信必须选中某个从机,所以每个从机就需要一个地址。主机在起始条件后需要先发送一个字节,所有从机都会收到一个字节和自己的地址比较。如果和自己的地址就响应主机的操作,所有同一个IIC总线必须挂载不一样的地址设备。从机设备地址在IIC协议标准种分为七位和十位,七位的比较简单应用也比较广泛。在出厂的时候,厂商就会为他分配一个七位的地址,在芯片手册中都能找到。如果有相同的地址芯片挂在在总线上就需要使用地址的可变部分,一般都是地址的后面一位或者几位。

一个完整的数据帧在起始条件开始,结束条件结束。
指定地址写:
在起始条件后就要跟一个从机地址+写标志位,然后从机发送应答。然后发送指定的地址,然后从机再次应答。

当前地址读:
对于指定设备(Slave Address),在当前地址指针指示的地址下,读取从机数据(Data)。
当前地址指针上电默认是0,但是当我们指定地址写后,然后当前地址读,就是在写的下一位进行读取操作。
指定地址读:
我们使用指定地址写的指定地址时序,但是不写入,此时当前地址指针就不会加一。然后再调用当前地址读的时序,然后就是指定地址读了。我们可以在指定地址读前面加一个结束条件,然后再次发送起始条件,在当前地址读。但是IIC协议官方规定的符合格式是一整个数据帧,就是先起始,再重复起始(在指定地址写的时序后面再加一个起始条件),然后发当前地址读,最后结束了再发送结束条件。

当读取完数据不想再读取了,就需要主机发送非应答,此时从机知道主机不想再接收了,就会释放总线,交还给从机。

MPU6050封装

软件IIC配置:
总体操作:
1.初始化GPIO,包括打开时钟,配置结构体,初始化选用的引脚
2.配置IIC开始函数
3.配置IIC结束函数
4.配置IIC发送一个字节函数
5.配置IIC接收一个字节函数
6.配置IIC发送应答函数
7.配置IIC接收应答函数
具体操作:
1.初始化GPIO,例如,选用Pin10为SCL线,Pin11为SDA线,配置IIC的GPIO为开漏输出

void MyI2C_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10 | GPIO_Pin_11;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_10 | GPIO_Pin_11);
}

1.IIC不论是SDA还是SCL都只有高低两种状态,所有使用时就是把GPIO电平配置为高或者低
例如:

	GPIO_WriteBit(GPIOB,GPIO_Pin_10,1);Delay_us(10);GPIO_WriteBit(GPIOB,GPIO_Pin_11,1);Delay_us(10);

延时10微秒为操作时间,实测不延时也可以。
每次都配置GPIO不仅麻烦还不明了
所以就把GPIO封装起来

void MyI2C_W_SCL(uint8_t BitValue)
{GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue);Delay_us(10);
}//对SCL线封装,便于操作,控制时钟线
void MyI2C_W_SDA(uint8_t BitValue)
{GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)BitValue);Delay_us(10);
}//对SDA线封装,便于操作,发送主机值
uint8_t MyI2C_R_SDA(void)
{uint8_t BitValue;BitValue=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);Delay_us(10);return BitValue; 
}//对SDA线封装,便于操作,读取从机发送的值

封装完以后便可以很简单的配置后面的函数
2.配置开始函数
IIC开启需要在SCL为高的时候拉低SDA,这样为开启IIC信号,从机便知道,IIC开启,主机要发送或者接收数据了

void MyI2C_Start(void)
{MyI2C_W_SDA(1);/*最好先拉高SDA确定,简要原因在最后面的读MPU6050的注释里面有简要说明,这样只是一个以防外一,个人感觉不是特别重要*/MyI2C_W_SCL(1);MyI2C_W_SDA(0);MyI2C_W_SCL(0);//拉低SDA后再把SCL拉低,便可以进行数据传送

3.配置结束函数 IIC结束需要在SCL为高的时候拉高SDA,这样为关闭IIC信号,从机便知道,IIC关闭,主机要结束发送或者接收数据了,实际上,在配置的IIC函数里面,只有结束函数里面SCL以高结束,其他的都为低,这样方便两个函数衔接。

void MyI2C_Stop(void)
{MyI2C_W_SDA(0);//先拉低SDA确保待会可以产生上升沿MyI2C_W_SCL(1);MyI2C_W_SDA(1);
}

4.配置主机发送函数
主机在SCL低的时候只会发送一位,从机在SCL为高的时候一次也只接收一位,每次都是一位一位进行的

void MyI2C_SentByte(uint8_t Byte)
{uint8_t i;for(i=0;i<8;i++){MyI2C_W_SDA(Byte&(0x80>>i));MyI2C_W_SCL(1);MyI2C_W_SCL(0);}
}

一次发送八位数据也就是一个字节的数据,所以在for循环里面循环8次
在8次数据发送完以后,主机需要释放SDA,这时从机会自己占据SDA线给主机发送应答后面写的主机的接收应答就会主动去释放SDA(所有的发送和接收都是相对主机而言的)
5.配置主机接收函数

uint8_t MyI2C_ReceiveByte(void)//主机接收时,从机在时钟线拉低的时候只会发送一位数据
{uint8_t i,Byte=0x00;MyI2C_W_SDA(1);for(i=0;i<8;i++){ MyI2C_W_SCL(1);if(MyI2C_R_SDA()==1){Byte |= (0x80>>i);}//高位先行,所以右移MyI2C_W_SCL(0);}return Byte;
}

主机接收的数据要处理,所以要用变量存起来,发送的数据从机会自动处理
6.配置IIC发送应答

void MyI2C_SentAck(uint8_t AckBit)
{MyI2C_W_SDA(AckBit);//当发送完一个数据以后,SCL本身就是低的,所以前面不需要再给SCL低了MyI2C_W_SCL(1);MyI2C_W_SCL(0);
}

发送应答是主机接收了一个数据以后发送个主机的应答,SDA拉高,相当于主机发送1,为非应答,不需要再接收数据时就要发非应答,需要接收数据时,就在SDA拉低,为应答。从机发送完一个字节数据以后,会自动释放SDA,此时主机应占据SDA,从机便会去读取SDA的值,接收主机的应答(应答信号在第9个时钟周期出现,这时发送器必须在这一时钟位上释放数据线,由接收设备拉低SDA电平来产生应答信号或非应答信号)
7.配置IIC接收应答

uint8_t MyI2C_ReceiveAck(void)
{uint8_t AckBit;MyI2C_W_SDA(1);//主机主动空出SDA,从机会立刻占据,发送应答或者非应答信号MyI2C_W_SCL(1);//SCL拉高以后,主机便可以去读取从机给的信号AckBit=MyI2C_R_SDA();MyI2C_W_SCL(0);//此时从机放手SDAreturn AckBit;
}

在主机发送完数据以后,主机应空出SDA线,此时从机会产生应答或者非应答,因为是软件模拟IIC所以可以选择读取也可以不去读取,选择读取便可以根据读取的值判断下一步要不要再继续操作。因为一个时钟信号只进行一位传输,所以从机检测到电平变化以后如果接下来还是主机操作便不在占据SDA。

以上便是软件IIC的所有配置

以MPU6050为例,演示IIC的进行
MPU6050初始化即IIC初始化
如果要给MPU6050写一个字节的数据:

void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{MyI2C_Start();//打开IIC通信MyI2C_SentByte(0xD0);//选中 MPU6050,最后一位为0为写操作MyI2C_ReceiveAck();//从机发送应答,主机要接收应答MyI2C_SentByte(RegAddress);//主机继续发送要写的寄存器地址MyI2C_ReceiveAck();//主机接收从机的应答MyI2C_SentByte(Data);//主机发送要写的数据MyI2C_ReceiveAck();//主机接收从机的应答MyI2C_Stop();//停止IIC通信SDA与SCL都为高
}

IIC开始以后,第一次发送的是硬件的地址,每一个硬件都有一个地址,出厂的时候写好的,发送的数据前七位为地址,最后一位为读写位,0为写,1为读。
如果要读MPU6050一个字节的数据:

uint8_t MPU6050_ReadReg(uint8_t RegAddress)//读指定寄存器
{uint8_t Data;//接收读出数据的变量MyI2C_Start();MyI2C_SentByte(0xD0);MyI2C_ReceiveAck();MyI2C_SentByte(RegAddress);MyI2C_ReceiveAck();//前面几步确定地址MyI2C_Start();/*Start里面先SDA置1就是这里在上一步SCL为0的时候赶快为高然后重新开始,避免还没为高的时候SCL已经拉高了。如果SDA还没为高的时候SCL已经拉高了,这样再产生下降沿之前产生的就是上升沿了,就是停止的意思了。但是接收应答后,从机释放SDA,此时SDA就是高主机没有进行操作,SDA一直为高,所以个人感觉不重要*/MyI2C_SentByte(0xD1);//对指定地址进行读MyI2C_ReceiveAck();//从机要回应这个指令Data=MyI2C_ReceiveByte();//从机把指定地址的数据通过SDA线发出来MyI2C_SentAck(1);//主机回应1表示不给应答,从机便会结束发送MyI2C_Stop();//结束通信return Data;
}

因为无法直接指定寄存器读,但可以指定寄存器写,指定的地址指针在下一次操作前不变,所以指定地址写,然后什么都不写,重新开始读,便可以指定地址读。

再MPU5050手册中,刚上电时是睡眠模式,无法写入,只能读出。所有需要解除睡眠模式,此时就需要0x6B上写,0x6B地址是电源管理寄存器1,其中SLEEP位控制睡眠模式,在这个寄存器写入0x00,这样就能解除睡眠模式了。

在真正使用MPU6050之前还需要根据手册初始化一下,比如电源管理寄存器,时钟,陀螺仪,加速度计等各种寄存器。

#ifndef __MPU6050_REG_H
#define __MPU6050_REG_H#define SMPLRT_DIV         0x19
#define CONFIG             0x1A
#define GYRO_CONFIG        0x1B
#define ACCEL_CONFIG       0x1C
#define ACCEL_XOUT_H       0x3B
#define ACCEL_XOUT_L       0x3C
#define ACCEL_YOUT_H       0x3D
#define ACCEL_YOUT_L       0x3E
#define ACCEL_ZOUT_H       0x3F
#define ACCEL_ZOUT_L       0x40
#define TEMP_OUT_H         0x41
#define TEMP_OUT_L         0x42
#define GYRO_XOUT_H        0x43
#define GYRO_XOUT_L        0x44
#define GYRO_YOUT_H        0x45
#define GYRO_YOUT_L        0x46
#define GYRO_ZOUT_H        0x47
#define GYRO_ZOUT_L        0x48
#define PWR_MGMT_1         0x6B
#define PWR_MGMT_2         0x6C
#define WHO_AM_I           0x75
extern uint8_t AccX,AccY,AccZ,GyroX,GyroY,GyroZ;
#endif
void MPU6050_GetData(int16_t *AccX,int16_t *AccY,int16_t *AccZ,int16_t*GyroX,int16_t*GyroY,int16_t*GyroZ)
{uint8_t DataH,DataL;DataH=MPU6050_ReadReg(ACCEL_XOUT_H);DataL=MPU6050_ReadReg(ACCEL_XOUT_L);*AccX=(DataH<<8)|DataL;DataH=MPU6050_ReadReg(ACCEL_YOUT_H);DataL=MPU6050_ReadReg(ACCEL_YOUT_L);*AccY=(DataH<<8)|DataL;DataH=MPU6050_ReadReg(ACCEL_ZOUT_H);DataL=MPU6050_ReadReg(ACCEL_ZOUT_L);*AccZ=(DataH<<8)|DataL;DataH=MPU6050_ReadReg(GYRO_XOUT_H);DataL=MPU6050_ReadReg(GYRO_XOUT_L);*GyroX=(DataH<<8)|DataL;DataH=MPU6050_ReadReg(GYRO_YOUT_H);DataL=MPU6050_ReadReg(GYRO_YOUT_L);*GyroY=(DataH<<8)|DataL;DataH=MPU6050_ReadReg(GYRO_ZOUT_H);DataL=MPU6050_ReadReg(GYRO_ZOUT_L);*GyroZ=(DataH<<8)|DataL;
}
void MPU6050_Init(void)
{MyI2C_Init();MPU6050_WriteReg(PWR_MGMT_1,0x01);//电源管理1MPU6050_WriteReg(PWR_MGMT_2,0x00);//电源管理2MPU6050_WriteReg(SMPLRT_DIV,0x09);//采样率分频,10分频MPU6050_WriteReg(CONFIG,0x06);//外部同步(不需要)与低通滤波MPU6050_WriteReg(GYRO_CONFIG,0x18);//陀螺仪配置寄存器MPU6050_WriteReg(ACCEL_CONFIG,0x18);//加速度计
}

硬件IIC

由于IIC是同步时序,所以软件模拟II从时序,灵活且方便,用的范围比较广。
STM32内部集成了硬件IIC的电路,STM32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,用库函数封装好,直接读取寄存器即可。减轻CPU的负担。
比如:

支持多主机模型
支持7位/10位地址模式
支持不同的通讯速度,标准速度(高达100 kHz),快速(高达400 kHz)
支持DMA
兼容SMBus协议

STM32F103C8T6 硬件I2C资源:I2C1、I2C2

引脚映射:
C8T6的IIC2映射的PB10为SCL,PB11为SDA。IIC1的SCL为PB6,SDA为PB7。

内部电路

在这里插入图片描述

上半部分是SDA,数据控制部分。数据收发的核心部分是上面的数据寄存器和数据移位寄存器。当需要发送数据时,可以把一个字节数据写到数据寄存器DR。当移位寄存器没有数据移位时,DR中的值就会转到移位寄存器中。在移位的过程中,可以直接把下一个数据放到数据寄存器中等着。当数据由数据寄存器转到移位寄存器时就会置状态寄存器的TXE位为 1 ,表示发送寄存器为空。
接收的过程也是这样,输入的数据先放进移位寄存器,当一个字节后,数据从移位寄存器转入DR。同时置标志位RXNE,表示接收寄存器非空。此时就可以将数据从数据寄存器读出来了。
对于起始条件,终止条件,应答位什么的都由数据控制电路完成。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入解析 TypeScript 核心配置文件 tsconfig.json

什么是 tsconfig.json&#xff1f; tsconfig.json 是 TypeScript 项目的中枢神经系统&#xff0c;它是 TypeScript 编译器的配置文件&#xff0c;决定了整个项目的编译规则、模块解析方式和类型检查策略。这个 JSON 文件通常位于项目根目录&#xff0c;是 TypeScript 工程化开…

debug 笔记:llama 3.2 部署bug 之cutlassF: no kernel found to launch!

1 问题描述 按照官方的写法 import torch from transformers import pipeline import os os.environ["HF_TOKEN"] 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 model_id "meta-llama/Llama-3.2-3B"pipe pipeline("text-generation", modelmode…

使用ZYNQ芯片和LVGL框架实现用户高刷新UI设计系列教程(第五讲)

在上一讲我们讲解了按键回调函数的自定义函数的用法&#xff0c;这一讲继续讲解回调函数的另一种用法。 首先我们将上一讲做好的按键名称以及自定义回调事件中的按键名称修改&#xff0c;改为默认模式为“open”当点击按键时进入回调函数将按键名称改为“close”&#xff0c;具…

Hyperliquid 遇袭「拔网线」、Polymarket 遭治理攻击「不作为」,从双平台危机看去中心化治理的进化阵痛

作者&#xff1a;Techub 热点速递 撰文&#xff1a;Glendon&#xff0c;Techub News 继 3 月 12 日「Hyperliquid 50 倍杠杆巨鲸」引发的 Hyperliquid 清算事件之后&#xff0c;3 月 26 日 晚间&#xff0c;Hyperliquid 再次遭遇了一场针对其流动性和治理模式的「闪电狙击」。…

交换机与路由器的区别:深入解析

在构建和维护现代计算机网络的过程中&#xff0c;交换机和路由器无疑是两种不可或缺的设备。尽管它们都在数据的传输和转发中扮演着重要角色&#xff0c;但各自的工作原理、应用场景和功能特性却大相径庭。本文将从多个角度&#xff0c;结合最新的技术发展和实际应用&#xff0…

自顶向下学习K8S--部署Agones

本文在本人博客&#xff0c;原文地址&#xff1a;http://viogami.tech/index.php/blog/346/ 我是gopher&#xff0c;离不开云原生&#xff0c;自然也逃不了理解docker和K8S这俩。今天抽空想玩下agones&#xff0c;进而对K8S有实践性的理解。 学一个新事物从底层理论学肯定是最…

蓝桥杯省模拟赛 阶乘求值

问题描述 给定 n&#xff0c;求 n! 除以 1000000007的余数。 其中 n! 表示 n 的阶乘&#xff0c;值为从 1 连乘到 n 的积&#xff0c;即 n!123…n。 输入格式 输入一行包含一个整数 n。 输出格式 输出一行&#xff0c;包含一个整数&#xff0c;表示答案。 样例输入 3样…

如何在Webpack中配置别名路径?

如何在Webpack中配置别名路径&#xff1f; 文章目录 如何在Webpack中配置别名路径&#xff1f;1. 引言2. 配置别名路径的基本原理3. 如何配置别名路径3.1 基本配置3.2 结合Babel与TypeScript3.2.1 Babel配置3.2.2 TypeScript配置 3.3 适用场景与最佳实践 4. 调试与常见问题4.1 …

协作机械臂需要加安全墙吗? 安全墙 光栅 干涉区

安全墙是什么 文章目录 安全墙是什么简介1. 物理安全墙1.1 定义&#xff1a;1.2 作用机制&#xff1a;1.3 应用场景&#xff1a; 2. 虚拟安全墙2.2 定义&#xff1a;2.3 作用机制&#xff1a;2.3 应用场景&#xff1a; 3. 安全毛毯3.1 工作原理&#xff1a;3.2 特点3.3 应用场景…

Promise怎么使用,以及它解决了什么问题?

什么是 Promise&#xff1f; Promise 是一种用于处理异步操作的 JavaScript 对象&#xff0c;它代表了一个可能还未完成但将来会完成的操作的结果。Promise 的目的是解决回调函数&#xff08;callback&#xff09;带来的问题&#xff0c;比如回调地狱&#xff08;callback hel…

光谱范围与颜色感知的关系

光谱范围与颜色感知是光学、生理学及技术应用交叉的核心课题&#xff0c;两者通过波长分布、人眼响应及技术处理共同决定人类对色彩的认知。以下是其关系的系统解析&#xff1a; ‌1.基础原理&#xff1a;光谱范围与可见光‌ ‌光谱范围定义‌&#xff1a; 电磁波谱中能被特定…

如何让DeepSeek-R1在内网稳定运行并实现随时随地远程在线调用

前言&#xff1a;最近&#xff0c;国产AI圈里的新星——Deepseek&#xff0c;简直是火到不行。但是&#xff0c;你是不是已经对那些千篇一律的手机APP和网页版体验感到腻味了&#xff1f;别急&#xff0c;今天就带你解锁一个超炫的操作&#xff1a;在你的Windows电脑上本地部署…

leetcode33.搜索旋转排序数组

思路源于 【小白都能听懂的算法课】【力扣】【Leetcode33】搜索旋转排序数组 | 二分查找 | 数组 主要是数组旋转后分为左右两个升序区间 &#xff0c;如果mid落在左区间并且目标大小也在left-mid中&#xff0c;那么right右缩 class Solution {public int search(int[] nums, i…

《TypeScript 7天速成系列》第6天:TypeScript装饰器+混入:高级编程模式揭秘

装饰器是TypeScript中一项强大的元编程特性&#xff0c;被Angular和Vue3等主流框架广泛使用。今天我们将深入探讨这一高级特性。 装饰器基础 装饰器是一种特殊类型的声明&#xff0c;可以附加到类声明、方法、访问器、属性或参数上。装饰器使用expression形式&#xff0c;其中…

YOLO历代发展 图像增强方式 架构

YOLO1 YOLOV5 数据增强 mosaic 仿射变换(Affine)、透视变换(Perspective) 网络搭建

NX二次开发刻字功能——布尔运算

刻字功能在经历、创建文本、拉伸功能以后就剩下布尔运算了。布尔运算的目的就是实现文本时凸还是凹。这部分内容很简单。 1、首先识别布尔运算的类型&#xff0c;我这里用到一个枚举类型的选项&#xff0c;凸就是布尔求和&#xff0c;凹就是布尔求差。 2、其放置位置为创建拉伸…

【MySQL基础】数据库及表基本操作

作为运维工程师&#xff0c;掌握MySQL的基础操作是日常工作的重要技能之一。本文将介绍MySQL中数据库和表的基本操作&#xff0c;帮助您快速上手或复习这些核心概念。 1 数据库基本操作 1.1 创建数据库 create database db_name; -- 指定字符集和排序规则 create database d…

Python贝叶斯分层模型专题|对环境健康、医学心梗患者、体育赛事数据空间异质性实证分析合集|附数据代码

全文链接&#xff1a;https://tecdat.cn/?p41267 在大数据时代&#xff0c;多水平数据结构广泛存在于环境健康、医学研究和体育赛事等领域。本专题合集聚焦贝叶斯分层模型&#xff08;Hierarchical Bayesian Model&#xff09;的创新应用&#xff0c;通过氡气污染数据与 季后…

基于 Qt / HTTP/JSON 的智能天气预报系统测试报告

目录 一、项目概述 1.1项目背景 1.2项目目标 二、功能需求 2.1 用户界面功能 2.2 后台功能 三、技术选择 3.1 开发框架与工具 3.2 第三方 API 四、UI设计 4.1界面展示 4.2stylesheet样式 五、代码实现 1.构造函数 2.网络请求响应处理函数 3.处理json数据 4.更新…

GitLab 中文版17.10正式发布,27项重点功能解读【三】

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料&#xff1a; 极狐GitLab 官网极狐…