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

STM32F407寄存器操作(DMA+SPI)

1.前言

前面看B站中有些小伙伴吐槽F4的SPI+DMA没有硬件可控的CS引脚,那么今天我就来攻破这个问题

我这边暂时没有SPI的从机芯片,并且接收的过程与发送的过程类似,所以这里我就以发送的过程为例了。

2.理论

手册上给出了如下的描述

我们关注一下黑点的两行,这是DMA操作的核心,我们可以理解为TXE与DMA的触发挂钩,这样理解上与程序上都比较好写。

手册上还给出了DMA的触发流程,如下。

我们详细剖析一下TXE与DMA操作关联,可以看到每一次TXE变高,DMA就会进行一次搬运,直到通讯结束,这样一来我们就可以通过等待TXE置位来联动DMA。

除此之外,我们还需监控BSY位,等待TXE=1然后BSY=0后再关闭SPI,进而完成通讯

然后是DMA通道,本次实验我用的是DMA2的数据流3的通道3

3.程序

3.1 SPI初始化

void init_spi1(void)
{RCC->AHB1ENR|=1<<1;		//开启PB时钟RCC->AHB1ENR|=1<<0;		//开启PA时钟RCC->APB2ENR|=1<<12;	//开启SPI1时钟#if	SPI1_NSSMODE==0init_spi1_nss1();#elseGPIOA->MODER|=2<<8;		//PA4功能复用GPIOA->OSPEEDR|=2<<8;	//端口速度50MHZGPIOA->PUPDR|=1<<8;		//PA4上拉输出GPIOA->AFR[0]|=5<<16;			//功能复用到SPI1#endifGPIOA->MODER|=2<<10;		//PA5功能复用GPIOA->OSPEEDR|=2<<10;	//端口速度50MHZGPIOA->PUPDR|=1<<10;		//PA3上拉输出GPIOA->AFR[0]|=5<<20;			//功能复用到SPI1GPIOA->MODER|=2<<12;		//PA6功能复用GPIOA->OSPEEDR|=2<<12;	//端口速度50MHZGPIOA->PUPDR|=1<<12;		//PA6上拉输出GPIOA->AFR[0]|=5<<24;			//功能复用到SPI1GPIOA->MODER|=2<<14;		//PA7功能复用GPIOA->OSPEEDR|=2<<14;	//端口速度50MHZGPIOA->PUPDR|=1<<14;		//PA7上拉输出GPIOA->AFR[0]|=5<<28;			//功能复用到SPI1SPI1->CR1&=~(1<<10);		//全双工模式#if	SPI1_NSSMODE==0SPI2->CR1|=1<<9;	//软件控制nssSPI2->CR1|=1<<8;	//选择芯片上的引脚#elseSPI1->CR2|=1<<2;		//硬件控制NSS引脚#endifSPI1->CR1|=1<<2;	//作为SPI主机#if	SPI1_DATALENGTH==8SPI1->CR1&=~(1<<11);	//数据长度为8位#elseSPI1->CR1|=(1<<11);		//数据长度为16位#endif#if SPI1_DMA_TX_EN==1SPI1->CR2|=1<<1;	//开启DMA传输#elseSPI1->CR2&=~(1<<1);	//开启DMA传输#endifSPI1->CR1|=1<<0;	//从第二位开始采集数据SPI1->CR1|=1<<1;	//空闲状态下时钟保持高电平SPI1->CR1|=SPI_SPEED_8<<3;		//APB2上84MHz,8分频SPI1->CR1&=~(1<<7);	//先发送MSB,高位先发送SPI1->I2SCFGR&=~(1<<11);	//关闭I2S功能,使用SPI
}

说一下区别吧,很少,就一句话

SPI的CR2的第一位,解释如下

这里注意一下SPI的发送与接收是分开的,我们可以根据需要开启其中的DMA。

3.2 DMA初始化

//初始化DMA2 组3 通道3
//SPI1_TX
void init_DMA2_S3C3(unsigned char *SPIData,unsigned short SPIWEI)
{	DMA2_Stream3 ->CR   = 0;//禁止数据流 ,才能写寄存器 //外设地址寄存器//将所需寄存器的地址放入PAR寄存器DMA2_Stream3 ->PAR  = (unsigned int)(&SPI1->DR);//数据流地址寄存器//M1AR仅在双通道模式下有用//将数据所在地址给M0AR寄存器DMA2_Stream3 ->M0AR = (unsigned int)(SPIData);DMA2_Stream3 ->NDTR = SPIWEI;			// 一次传输数量DMA2_Stream3 ->FCR  = 0x21;		//FIFO所有配置失效DMA2_Stream3 ->CR |= 1<< 6;		//储存器到外设模式//循环模式://当NDTR寄存器减到0时自动重装//单次模式(普通模式)://NDTR减到0后停止DMADMA2_Stream3 ->CR &=~(1<<8);	//非循环模式DMA2_Stream3 ->CR &=~(3<<11);	//外设数据长度:8位DMA2_Stream3 ->CR &=~(3<<13);	//存储器数据长度:8位DMA2_Stream3 ->CR &= ~(1<<9); //外设非增量模式DMA2_Stream3 ->CR |= 1<<10;   //存储器增量模式,指针增加,可用于传输数组DMA2_Stream3 ->CR |= 1<<16;   //中等优先级//突发传输//DMA占用CPU总线时间,此时CPU无法工作//一个节拍:传输多少次32位变量//应用场景:从ram里读出字节DMA2_Stream3 ->CR &= ~(3<<21);   //外设突发单次传输DMA2_Stream3 ->CR &= ~(3<23);   //存储器突发单次传输DMA2_Stream3 ->CR |= 3<<25;   //通道3DMA2_Stream3 ->CR |= 1<<0;    //使能数据流
}

没有什么特别的地方,和存储器去寄存器的操作方式一致。

3.3 发送

unsigned char SPI1_WR(unsigned char SPI1MODE,unsigned char SPI1Data)
{unsigned char temp=0;switch(SPI1MODE){case SPI1_WRMODE://清除全部设置SPI1->CR1&=~(1<<15);	SPI1->CR1&=~(1<<10);#if SPI1_NSSMODE==0#elseSPI1->CR1|=(1<<6);	//开启SPI#endifwhile((SPI1->SR&1<<1)==0);	//等待发送缓冲为空SPI1->DR=SPI1Data;	//发送数据while((SPI1->SR&1<<0)==0);	//等待接受缓冲为空temp=SPI1->DR;		//接受数据while((SPI1->SR&1<<7)==1);	//等待发送缓冲为空#if SPI1_NSSMODE==0;#elseSPI1->CR1&=~(1<<6);	//关闭SPI#endifbreak;case SPI1_WOMODE:#if SPI1_NSSMODE==0#elseSPI1->CR1|=(1<<6);	//开启SPI#endifSPI1->CR1&=~(1<<15);	//清除模式设置SPI1->CR1&=~(1<<10);	//清除模式设置while((SPI1->SR&1<<1)==0);	//等待发送缓冲为空#if SPI1_DMA_TX_EN==1while((SPI1->SR&1<<1)==0);	//等待发送缓冲为空#elsewhile((SPI1->SR&1<<1)==0);	//等待发送缓冲为空SPI1->DR=SPI1Data;	//发送数据while((SPI1->SR&1<<1)==0);	//等待发送缓冲为空#endif#if SPI1_NSSMODE==0#else#endifwhile((SPI1->SR&1<<7)==1);	//等待总线空闲SPI1->CR1&=~(1<<6);	//关闭SPIbreak;case SPI1_ROMODE:SPI1->CR1&=~(1<<10);//清除模式设置SPI1->CR1|=1<<10;	//半双工模式只读temp=SPI1->DR;		//接受数据break;}return temp;
}

这里稍微说说区别

核心在于两个TXE的判断

第一个TXE就是手册上的第一个判断

第二个也就是后面的,但是由于DMA的存在,所以下面无需我们再判断,当一个数据搬运完成,就会重新再次搬运直达搬运完所有数据TXE才会拉高,所以这里我们无需进行循环判断

4.测试

最终程序

spi.c

#include "spi.h"void init_spi1(void)
{RCC->AHB1ENR|=1<<1;		//开启PB时钟RCC->AHB1ENR|=1<<0;		//开启PA时钟RCC->APB2ENR|=1<<12;	//开启SPI1时钟#if	SPI1_NSSMODE==0init_spi1_nss1();#elseGPIOA->MODER|=2<<8;		//PA4功能复用GPIOA->OSPEEDR|=2<<8;	//端口速度50MHZGPIOA->PUPDR|=1<<8;		//PA4上拉输出GPIOA->AFR[0]|=5<<16;			//功能复用到SPI1#endifGPIOA->MODER|=2<<10;		//PA5功能复用GPIOA->OSPEEDR|=2<<10;	//端口速度50MHZGPIOA->PUPDR|=1<<10;		//PA3上拉输出GPIOA->AFR[0]|=5<<20;			//功能复用到SPI1GPIOA->MODER|=2<<12;		//PA6功能复用GPIOA->OSPEEDR|=2<<12;	//端口速度50MHZGPIOA->PUPDR|=1<<12;		//PA6上拉输出GPIOA->AFR[0]|=5<<24;			//功能复用到SPI1GPIOA->MODER|=2<<14;		//PA7功能复用GPIOA->OSPEEDR|=2<<14;	//端口速度50MHZGPIOA->PUPDR|=1<<14;		//PA7上拉输出GPIOA->AFR[0]|=5<<28;			//功能复用到SPI1SPI1->CR1&=~(1<<10);		//全双工模式#if	SPI1_NSSMODE==0SPI2->CR1|=1<<9;	//软件控制nssSPI2->CR1|=1<<8;	//选择芯片上的引脚#elseSPI1->CR2|=1<<2;		//硬件控制NSS引脚#endifSPI1->CR1|=1<<2;	//作为SPI主机#if	SPI1_DATALENGTH==8SPI1->CR1&=~(1<<11);	//数据长度为8位#elseSPI1->CR1|=(1<<11);		//数据长度为16位#endif#if SPI1_DMA_TX_EN==1SPI1->CR2|=1<<1;	//开启DMA传输#elseSPI1->CR2&=~(1<<1);	//开启DMA传输#endifSPI1->CR1|=1<<0;	//从第二位开始采集数据SPI1->CR1|=1<<1;	//空闲状态下时钟保持高电平SPI1->CR1|=SPI_SPEED_256<<3;		//APB2上84MHz,8分频SPI1->CR1&=~(1<<7);	//先发送MSB,高位先发送SPI1->I2SCFGR&=~(1<<11);	//关闭I2S功能,使用SPI
}unsigned char SPI1_WR(unsigned char SPI1MODE,unsigned char SPI1Data)
{unsigned char temp=0;switch(SPI1MODE){case SPI1_WRMODE://清除全部设置SPI1->CR1&=~(1<<15);	SPI1->CR1&=~(1<<10);#if SPI1_NSSMODE==0#elseSPI1->CR1|=(1<<6);	//开启SPI#endifwhile((SPI1->SR&1<<1)==0);	//等待发送缓冲为空SPI1->DR=SPI1Data;	//发送数据while((SPI1->SR&1<<0)==0);	//等待接受缓冲为空temp=SPI1->DR;		//接受数据while((SPI1->SR&1<<7)==1);	//等待发送缓冲为空#if SPI1_NSSMODE==0;#elseSPI1->CR1&=~(1<<6);	//关闭SPI#endifbreak;case SPI1_WOMODE:#if SPI1_NSSMODE==0#elseSPI1->CR1|=(1<<6);	//开启SPI#endifSPI1->CR1&=~(1<<15);	//清除模式设置SPI1->CR1&=~(1<<10);	//清除模式设置while((SPI1->SR&1<<1)==0);	//等待发送缓冲为空#if SPI1_DMA_TX_EN==1while((SPI1->SR&1<<1)==0);	//等待发送缓冲为空#elsewhile((SPI1->SR&1<<1)==0);	//等待发送缓冲为空SPI1->DR=SPI1Data;	//发送数据while((SPI1->SR&1<<1)==0);	//等待发送缓冲为空#endif#if SPI1_NSSMODE==0#else#endifwhile((SPI1->SR&1<<7)==1);	//等待总线空闲SPI1->CR1&=~(1<<6);	//关闭SPIbreak;case SPI1_ROMODE:SPI1->CR1&=~(1<<10);//清除模式设置SPI1->CR1|=1<<10;	//半双工模式只读temp=SPI1->DR;		//接受数据break;}return temp;
}

spi.h

#ifndef SPI_H__
#define SPI_H__#include "stm32f4xx.h"#define SPI_SPEED_2 	0
#define SPI_SPEED_4 	1
#define SPI_SPEED_8 	2
#define SPI_SPEED_16 	3
#define SPI_SPEED_32 	4
#define SPI_SPEED_64 	5
#define SPI_SPEED_128 6
#define SPI_SPEED_256 7//定义空闲状态下的时钟状态,为1则是高电平,否则是低电平
#define SPI1_CPOL	1
//定义数据长度
#define SPI1_DATALENGTH	8#define SPI1_NSS1UP			do{GPIOB->ODR|=1<<12;}while(0)
#define SPI1_NSS1DOWN		do{GPIOB->ODR&=~(1<<12);}while(0)//是否软件管理NSS引脚
//0	软件管理
//1	硬件管理
#define SPI1_NSSMODE	1//是否开启SPI1发送的DMA功能
//0 关闭
//1 开启
#define SPI1_DMA_TX_EN	1
//是否开启SPI1接收的DMA功能
//0 关闭
//1 开启
#define SPI1_DMA_RX_EN	0//SPI2通信模式
//0	全双工通信
//1	只发送
//2	只接收
#define SPI1_WRMODE	0
#define SPI1_WOMODE	1
#define SPI1_ROMODE	2#endif

DMA

//初始化DMA2 组3 通道3
//SPI1_TX
void init_DMA2_S3C3(unsigned char *SPIData,unsigned short SPIWEI)
{	DMA2_Stream3 ->CR   = 0;//禁止数据流 ,才能写寄存器 //外设地址寄存器//将所需寄存器的地址放入PAR寄存器DMA2_Stream3 ->PAR  = (unsigned int)(&SPI1->DR);//数据流地址寄存器//M1AR仅在双通道模式下有用//将数据所在地址给M0AR寄存器DMA2_Stream3 ->M0AR = (unsigned int)(SPIData);DMA2_Stream3 ->NDTR = SPIWEI;			// 一次传输数量DMA2_Stream3 ->FCR  = 0x21;		//FIFO所有配置失效DMA2_Stream3 ->CR |= 1<< 6;		//储存器到外设模式//循环模式://当NDTR寄存器减到0时自动重装//单次模式(普通模式)://NDTR减到0后停止DMADMA2_Stream3 ->CR &=~(1<<8);	//非循环模式DMA2_Stream3 ->CR &=~(3<<11);	//外设数据长度:8位DMA2_Stream3 ->CR &=~(3<<13);	//存储器数据长度:8位DMA2_Stream3 ->CR &= ~(1<<9); //外设非增量模式DMA2_Stream3 ->CR |= 1<<10;   //存储器增量模式,指针增加,可用于传输数组DMA2_Stream3 ->CR |= 1<<16;   //中等优先级//突发传输//DMA占用CPU总线时间,此时CPU无法工作//一个节拍:传输多少次32位变量//应用场景:从ram里读出字节DMA2_Stream3 ->CR &= ~(3<<21);   //外设突发单次传输DMA2_Stream3 ->CR &= ~(3<23);   //存储器突发单次传输DMA2_Stream3 ->CR |= 3<<25;   //通道3DMA2_Stream3 ->CR |= 1<<0;    //使能数据流
}

我们在主程序里如何使用呢?首先初始化SPI,然后是DMA,最后触发传输即可。这里我传输5个数据0x01,0x02,0x04,0x01最后一位应该是00

unsigned char spi_test_data[5]={0x01,0x02,0x04,0x01};
init_spi1();//初始化SPI1
init_DMA2_S3C3(spi_test_data,5);//初始化DMA
SPI1_WR(SPI1_WOMODE,5);//发送

可以看到效果拔群啊,CS管脚也没问题。

5.结语

至此完整的SPI完全出来了,手册上说这样的效果可以实现SPI的最高速率,但是我没有测试过。刚刚看手册的时候发现DMA有乒乓功能,嗯?难道这样一来速率还能在高?那么还是老样子有问题评论区见,我们下篇文章见。

相关文章:

STM32F407寄存器操作(DMA+SPI)

1.前言 前面看B站中有些小伙伴吐槽F4的SPIDMA没有硬件可控的CS引脚&#xff0c;那么今天我就来攻破这个问题 我这边暂时没有SPI的从机芯片&#xff0c;并且接收的过程与发送的过程类似&#xff0c;所以这里我就以发送的过程为例了。 2.理论 手册上给出了如下的描述 我们关注…...

Oracle 的 OCP 与 MySQL 的 OCP 的区别

事务开始与提交&#xff08;以 Java 代码中的事务操作为例&#xff09; Oracle&#xff08;在 Java 中使用 JDBC 进行事务操作&#xff09; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement;public cla…...

数据治理、数据清洗定义、区别以及数据清洗常用方法

一、数据治理定义 数据治理是一种组织数据管理的方法&#xff0c;涉及数据的收集、存储、处理、分析和共享等方面&#xff0c;旨在最大程度地利用数据资产并降低数据相关的风险。‌ 数据治理确保数据的质量、安全性、合规性和可用性&#xff0c;以支持组织的决策和运营活动。‌…...

web基础-攻防世界

get-post 一、WP &#xff08;题目本质&#xff1a;get与post传参方法&#xff09; 用 GET 给后端传参的方法是&#xff1a;在?后跟变量名字&#xff0c;不同的变量之间用&隔开。例如&#xff0c;在 url 后添加/&#xff1f;a1 即可发送 get 请求。 利用 hackbar 进行…...

Java基础-String Class(字符串类)

String Java String 类概览 String 类是 Java 中最常用的类之一&#xff0c;用于处理字符串。以下是 String 类的主要特性和操作&#xff1a; 特性/操作描述不可变性String 对象一旦创建就不能被修改创建方式使用双引号 “” 或 String 构造函数字符串池Java 维护字符串常量池…...

《Linux服务与安全管理》| 服务进程与网络配置

《Linux服务与安全管理》| 服务进程与网络配置 目录 《Linux服务与安全管理》| 服务进程与网络配置 &#xff08;1&#xff09; 写出查看NetworkManager服务状态的命令。 &#xff08;2&#xff09; 写出查看NetworkManager服务自启动状态的命令。 &#xff08;3&#xff0…...

No.15 笔记 | CSRF 跨站请求伪造

目录 一、基础知识 &#xff08;一&#xff09;cookie 和 session、同源策略 &#xff08;二&#xff09;CSRF 原理 二、CSRF 类型 &#xff08;一&#xff09;GET 类型 &#xff08;二&#xff09;POST 类型 三、CSRF 实例讲解 &#xff08;一&#xff09;真实案例 &am…...

解决linux中pip速度过慢问题

在 Linux 系统下&#xff0c;如果你发现使用 pip 下载 Python 库时速度非常慢&#xff0c;可以考虑以下几种方法来加速下载&#xff1a; 使用 pip 的 -i 选项&#xff1a; 如果你只想临时使用其他镜像&#xff0c;可以在安装时加上 -i 选项&#xff1a; pip install package_n…...

FlinkSQL中 的 双流JOIN

在 Flink SQL 中&#xff0c;流与流的 JOIN 是一种复杂的操作&#xff0c;因为它涉及到实时数据的无界处理。理解 Flink SQL 流与流 JOIN 的底层原理和实现需要从多个角度来分析&#xff0c;包括 状态管理、事件时间处理、窗口机制 以及 内部数据流处理模型 等。下面将从这些角…...

Mysql(五) --- 数据库设计

文章目录 前言1.范式1.1.第一范式1.1.1 定义1.1.2.例子 1.2.第二范式1.2.1 定义1.2.2 例子1.2.3.不满足第二范式可能会出现的问题 1.3.第三范式1.3.1 定义2.3.2 示例 2. 设计过程3. 实体-关系图3.1 E-R图的基本组成3.2 关系的类型3.2.1 一对一关系(1:1)3.2.2 ⼀对多关系(1:N)3.…...

po框架的了解和应用

https://www.cnblogs.com/xiaolehong/p/18458470 笔记 任务:1、通过po框架输入测试报告 2、编写自动化测试框架 3、总结测试讲解稿 自动化测试框架概念: 自动化测试框架是一个集成体系,这个体系中包含测试功能的函数、测试数据源、测试对以及重要的模块。 作用:用于解决或…...

Linux云计算 |【第四阶段】RDBMS2-DAY5

主要内容&#xff1a; PXC概述、部署PXC&#xff08;自动故障恢复测试&#xff09;、存储引擎、读锁/写锁、表锁/行锁、常用的存储引擎介绍 一、PXC概述 PXC&#xff08;Percona XtraDB Cluster&#xff0c;简称PXC集群&#xff09;&#xff0c;是基于Galera的MySQL高可用集群…...

从0开始深度学习(9)——softmax回归的逐步实现

文章使用Fashion-MNIST数据集&#xff0c;做一次分类识别任务 Fashion-MNIST中包含的10个类别&#xff0c;分别为&#xff1a; t-shirt&#xff08;T恤&#xff09;、trouser&#xff08;裤子&#xff09;、pullover&#xff08;套衫&#xff09;、dress&#xff08;连衣裙&…...

Cannot inspect org.apache.hadoop.hive.serde2.io.HiveDecimalWritable 问题分析处理

报错; org.apache.hadoop.hive.ql.metadata.HiveException: java.lang.UnsupportedOperationException: Cannot inspect org.apache.hadoop.hive.serde2.io.HiveDecimalWritable 该问题常见于parquet格式hive表查询时&#xff0c;一般原因为hive表对应数据文件元数据对应格式与…...

电子取证新视角:USB键盘流量提取密码方法研究与实现

0x01 引言 在当今数字化时代&#xff0c;USB设备的广泛使用使得信息安全和电子取证领域面临着新的挑战与机遇。特别是USB键盘&#xff0c;作为一种常见的输入设备&#xff0c;其流量中可能包含用户输入的敏感信息&#xff0c;如密码和其他私人数据。因此&#xff0c;研究USB键…...

Tongweb7049m4+THS6010-6012配置故障轉移+重試机制(by lqw)

使用场景 1.ths代理tongweb多套后端&#xff0c;假如有其中一套tongweb因为服务器重启或者宕机后没有及时启动&#xff0c;导致ths一直轮询在这个出故障的节点上。 2.即使在tongweb重启了&#xff0c;有的应用启动也需要一定的时间&#xff0c;这个时候只是启动了应用端口&…...

在线客服系统网站源码-网页聊天客服实现代码

源码简介 在线客服系统 – 网上客服系统&#xff0c;在线客服系统网站源码。 消息预知功能就是别人在聊天框打字你都能看到 1.新增客服坐席消息互动&#xff0c;客服之间可以互相接收消息&#xff0c;可以智能分配 2.新增消息预知功能&#xff0c;可提前预知访客已输入未发…...

JioNLP:一款实用的中文NLP预处理工具包

一、什么是 JioNLP? JioNLP是一个面向NLP开发者的工具包,提供了常见的中文文本预处理、解析等功能,使用简单、高效准确、无需配置,可极大加快NLP项目的开发进度。 主要特点包括: 代码开源,使用MIT协议功能丰富,涵盖多个NLP预处理需求使用简单,无需复杂配置即可调用准确高效…...

GR-ConvNet论文 学习笔记

GR-ConvNet 文章目录 GR-ConvNet前言一、引言二、相关研究三、问题阐述四、方法A.推理模块B.控制模块C.模型结构D.训练方法E.损失函数 五、评估A.数据集B.抓取评判标准 六、实验A.设置B.家庭测试物体C.对抗性测试物体D.混合物体 七、结果A.康奈尔数据集B.Jacquard数据集C.抓取新…...

windows环境批量删除指定目录下的全部指定文件

写在开头&#xff1a; 1. 涉及文件删除&#xff0c;先在小范围内测试&#xff08;更改D:\扫描文件路径&#xff09; 2. 命令会递归该目录下的所有文件 命令&#xff1a; forfiles /p D:\ /s /m _maven.repositories /c "cmd /c del path"解释&#xff1a; /p D:\ …...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

vulnyx Blogger writeup

信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面&#xff0c;gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress&#xff0c;说明目标所使用的cms是wordpress&#xff0c;访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...

华为OD机试-最短木板长度-二分法(A卷,100分)

此题是一个最大化最小值的典型例题&#xff0c; 因为搜索范围是有界的&#xff0c;上界最大木板长度补充的全部木料长度&#xff0c;下界最小木板长度&#xff1b; 即left0,right10^6; 我们可以设置一个候选值x(mid)&#xff0c;将木板的长度全部都补充到x&#xff0c;如果成功…...