7、单片机与W25Q128(FLASH)的通讯(SPI)实验(STM32F407)
SPI接口简介
SPI 是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。
SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。
SPI接口框图
SPI内部结构简明图
SPI接口一般使用4条线通信:
MISO 主设备数据输入,从设备数据输出。
MOSI 主设备数据输出,从设备数据输入。
SCLK时钟信号,由主设备产生。
CS从设备片选信号,由主设备控制。
SPI工作原理总结
硬件上为4根线。
主机和从机都有一个串行移位寄存器,主机通过向它的SPI串行寄存器写入一个字节来发起一次传输。
串行移位寄存器通过MOSI信号线将字节传送给从机,从机也将自己的串行移位寄存器中的内容通过MISO信号线返回给主机。这样,两个移位寄存器中的内容就被交换。
外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的一个字节,就必须发送一个空字节来引发从机的传输。
STM32 SPI接口可配置为支持SPI协议或者支持I2S音频协议,默认是SPI模式。可以通过软件切换到I2S方式。
SPI引脚配置(3个SPI)
哪些引脚可以复用为SPIx的相应功能引脚,需要查数据手册。
常用寄存器
SPI控制寄存器1(SPI_CR1)
SPI控制寄存器2(SPI_CR2)
SPI状态寄存器(SPI_SR)
SPI数据寄存器(SPI_DR)
SPI_I2S配置寄存器(SPI_I2S_CFGR)
SPI_I2S预分频寄存器(SPI_I2SPR)
程序源码
w25qxx.h
#ifndef __W25QXX_H
#define __W25QXX_H
#include "sys.h"// W25X系列/Q系列芯片列表
// W25Q80 ID 0XEF13
// W25Q16 ID 0XEF14
// W25Q32 ID 0XEF15
// W25Q64 ID 0XEF16
// W25Q128 ID 0XEF17
#define W25Q80 0XEF13
#define W25Q16 0XEF14
#define W25Q32 0XEF15
#define W25Q64 0XEF16
#define W25Q128 0XEF17#define NM25Q80 0X5213
#define NM25Q16 0X5214
#define NM25Q32 0X5215
#define NM25Q64 0X5216
#define NM25Q128 0X5217
#define NM25Q256 0X5218extern u16 W25QXX_TYPE; // 定义W25QXX芯片型号#define W25QXX_CS PBout(14) // W25QXX的片选信号//
// 指令表
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
#define W25X_ReadStatusReg 0x05
#define W25X_WriteStatusReg 0x01
#define W25X_ReadData 0x03
#define W25X_FastReadData 0x0B
#define W25X_FastReadDual 0x3B
#define W25X_PageProgram 0x02
#define W25X_BlockErase 0xD8
#define W25X_SectorErase 0x20
#define W25X_ChipErase 0xC7
#define W25X_PowerDown 0xB9
#define W25X_ReleasePowerDown 0xAB
#define W25X_DeviceID 0xAB
#define W25X_ManufactDeviceID 0x90
#define W25X_JedecDeviceID 0x9Fvoid W25QXX_Init(void);
u16 W25QXX_ReadID(void); // 读取FLASH ID
u8 W25QXX_ReadSR(void); // 读取状态寄存器
void W25QXX_Write_SR(u8 sr); // 写状态寄存器
void W25QXX_Write_Enable(void); // 写使能
void W25QXX_Write_Disable(void); // 写保护
void W25QXX_Write_NoCheck(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite);
void W25QXX_Read(u8 *pBuffer, u32 ReadAddr, u16 NumByteToRead); // 读取flash
void W25QXX_Write(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite); // 写入flash
void W25QXX_Erase_Chip(void); // 整片擦除
void W25QXX_Erase_Sector(u32 Dst_Addr); // 扇区擦除
void W25QXX_Wait_Busy(void); // 等待空闲
void W25QXX_PowerDown(void); // 进入掉电模式
void W25QXX_WAKEUP(void); // 唤醒
#endif
w25qxx.c
#include "w25qxx.h"
#include "spi.h"
#include "delay.h"
#include "usart.h"u16 W25QXX_TYPE = W25Q128; // 默认是W25Q128// 4Kbytes为一个Sector
// 16个扇区为1个Block
// W25Q128
// 容量为16M字节,共有128个Block,4096个Sector// 初始化SPI FLASH的IO口
void W25QXX_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); // 使能GPIOB时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE); // 使能GPIOG时钟// GPIOB14GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; // PB14GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; // 输出GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; // 100MHzGPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // 上拉GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; // PG7GPIO_Init(GPIOG, &GPIO_InitStructure); // 初始化GPIO_SetBits(GPIOG, GPIO_Pin_7); // PG7输出1,防止NRF干扰SPI FLASH的通信W25QXX_CS = 1; // SPI FLASH不选中SPI1_Init(); // 初始化SPISPI1_SetSpeed(SPI_BaudRatePrescaler_4); // 设置为21M时钟W25QXX_TYPE = W25QXX_ReadID(); // 读取FLASH ID.
}// 读取W25QXX的状态寄存器
// BIT7 6 5 4 3 2 1 0
// SPR RV TB BP2 BP1 BP0 WEL BUSY
// SPR:默认0,状态寄存器保护位,配合WP使用
// TB,BP2,BP1,BP0:FLASH区域写保护设置
// WEL:写使能锁定
// BUSY:忙标记位(1,忙;0,空闲)
// 默认:0x00
u8 W25QXX_ReadSR(void)
{u8 byte = 0;W25QXX_CS = 0; // 使能器件SPI1_ReadWriteByte(W25X_ReadStatusReg); // 发送读取状态寄存器命令byte = SPI1_ReadWriteByte(0Xff); // 读取一个字节W25QXX_CS = 1; // 取消片选return byte;
}
// 写W25QXX状态寄存器
// 只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!
void W25QXX_Write_SR(u8 sr)
{W25QXX_CS = 0; // 使能器件SPI1_ReadWriteByte(W25X_WriteStatusReg); // 发送写取状态寄存器命令SPI1_ReadWriteByte(sr); // 写入一个字节W25QXX_CS = 1; // 取消片选
}
// W25QXX写使能
// 将WEL置位
void W25QXX_Write_Enable(void)
{W25QXX_CS = 0; // 使能器件SPI1_ReadWriteByte(W25X_WriteEnable); // 发送写使能W25QXX_CS = 1; // 取消片选
}
// W25QXX写禁止
// 将WEL清零
void W25QXX_Write_Disable(void)
{W25QXX_CS = 0; // 使能器件SPI1_ReadWriteByte(W25X_WriteDisable); // 发送写禁止指令W25QXX_CS = 1; // 取消片选
}
// 读取芯片ID
// 返回值如下:
// 0XEF13,表示芯片型号为W25Q80
// 0XEF14,表示芯片型号为W25Q16
// 0XEF15,表示芯片型号为W25Q32
// 0XEF16,表示芯片型号为W25Q64
// 0XEF17,表示芯片型号为W25Q128
u16 W25QXX_ReadID(void)
{u16 Temp = 0;W25QXX_CS = 0;SPI1_ReadWriteByte(0x90); // 发送读取ID命令SPI1_ReadWriteByte(0x00);SPI1_ReadWriteByte(0x00);SPI1_ReadWriteByte(0x00);Temp |= SPI1_ReadWriteByte(0xFF) << 8;Temp |= SPI1_ReadWriteByte(0xFF);W25QXX_CS = 1;return Temp;
}
// 读取SPI FLASH
// 在指定地址开始读取指定长度的数据
// pBuffer:数据存储区
// ReadAddr:开始读取的地址(24bit)
// NumByteToRead:要读取的字节数(最大65535)
void W25QXX_Read(u8 *pBuffer, u32 ReadAddr, u16 NumByteToRead)
{u16 i;W25QXX_CS = 0; // 使能器件SPI1_ReadWriteByte(W25X_ReadData); // 发送读取命令SPI1_ReadWriteByte((u8)((ReadAddr) >> 16)); // 发送24bit地址SPI1_ReadWriteByte((u8)((ReadAddr) >> 8));SPI1_ReadWriteByte((u8)ReadAddr);for (i = 0; i < NumByteToRead; i++){pBuffer[i] = SPI1_ReadWriteByte(0XFF); // 循环读数}W25QXX_CS = 1;
}
// SPI在一页(0~65535)内写入少于256个字节的数据
// 在指定地址开始写入最大256字节的数据
// pBuffer:数据存储区
// WriteAddr:开始写入的地址(24bit)
// NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!
void W25QXX_Write_Page(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{u16 i;W25QXX_Write_Enable(); // SET WELW25QXX_CS = 0; // 使能器件SPI1_ReadWriteByte(W25X_PageProgram); // 发送写页命令SPI1_ReadWriteByte((u8)((WriteAddr) >> 16)); // 发送24bit地址SPI1_ReadWriteByte((u8)((WriteAddr) >> 8));SPI1_ReadWriteByte((u8)WriteAddr);for (i = 0; i < NumByteToWrite; i++)SPI1_ReadWriteByte(pBuffer[i]); // 循环写数W25QXX_CS = 1; // 取消片选W25QXX_Wait_Busy(); // 等待写入结束
}
// 无检验写SPI FLASH
// 必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
// 具有自动换页功能
// 在指定地址开始写入指定长度的数据,但是要确保地址不越界!
// pBuffer:数据存储区
// WriteAddr:开始写入的地址(24bit)
// NumByteToWrite:要写入的字节数(最大65535)
// CHECK OK
void W25QXX_Write_NoCheck(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{u16 pageremain;pageremain = 256 - WriteAddr % 256; // 单页剩余的字节数if (NumByteToWrite <= pageremain)pageremain = NumByteToWrite; // 不大于256个字节while (1){W25QXX_Write_Page(pBuffer, WriteAddr, pageremain);if (NumByteToWrite == pageremain)break; // 写入结束了else // NumByteToWrite>pageremain{pBuffer += pageremain;WriteAddr += pageremain;NumByteToWrite -= pageremain; // 减去已经写入了的字节数if (NumByteToWrite > 256)pageremain = 256; // 一次可以写入256个字节elsepageremain = NumByteToWrite; // 不够256个字节了}};
}
// 写SPI FLASH
// 在指定地址开始写入指定长度的数据
// 该函数带擦除操作!
// pBuffer:数据存储区
// WriteAddr:开始写入的地址(24bit)
// NumByteToWrite:要写入的字节数(最大65535)
u8 W25QXX_BUFFER[4096];/*首先读取整个扇区的内容到W25QXX_BUF中。
接下来,使用一个for循环对读取的数据进行校验。循环从0到secremain(扇区剩余空间大小)遍历W25QXX_BUF数组。如果发现W25QXX_BUF[secoff+i]不等于0xFF,说明需要擦除这个扇区。
如果需要擦除扇区,则调用W25QXX_Erase_Sector函数擦除该扇区。然后,使用一个for循环将pBuffer中的数据复制到W25QXX_BUF中。
最后,调用W25QXX_Write_NoCheck函数将W25QXX_BUF中的数据写入整个扇区。如果不需要擦除扇区,则直接调用W25QXX_Write_NoCheck函数将pBuffer中的数据写入扇区剩余区间。
接下来,根据写入的情况进行一些处理。如果NumByteToWrite等于secremain,说明写入已经结束,此时跳出循环。否则,继续写入下一个扇区。
在写入下一个扇区之前,需要更新一些变量的值。secpos增加1,表示下一个扇区的地址。secoff重置为0,表示下一个扇区的偏移位置。
pBuffer和WriteAddr分别增加secremain,表示指针和写地址的偏移量。NumByteToWrite减去secremain,表示剩余要写入的字节数。
如果剩余要写入的字节数大于4096,说明下一个扇区还是写不完,所以secremain设置为4096。否则,secremain设置为剩余要写入的字节数。*/
void W25QXX_Write(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite) // pBuffer表示要写入的数据缓冲区,WriteAddr表示写入的起始地址,NumByteToWrite表示要写入的字节数
{u32 secpos; // 表示扇区地址u16 secoff; // 表示在扇区内的偏移u16 secremain; // 表示扇区剩余空间大小u16 i; // 表示循环计数器u8 *W25QXX_BUF; // W25QXX_BUF表示W25QXX缓冲区W25QXX_BUF = W25QXX_BUFFER; // 将W25QXX_BUF指向W25QXX_BUFFER。secpos = WriteAddr / 4096; // 扇区地址secoff = WriteAddr % 4096; // 在扇区内的偏移secremain = 4096 - secoff; // 扇区剩余空间大小// printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//测试用if (NumByteToWrite <= secremain)secremain = NumByteToWrite; // 不大于4096个字节while (1){W25QXX_Read(W25QXX_BUF, secpos * 4096, 4096); // 读出整个扇区的内容for (i = 0; i < secremain; i++) // 校验数据{if (W25QXX_BUF[secoff + i] != 0XFF)break; // 需要擦除}if (i < secremain) // 需要擦除,因为如果如果不需要擦除,i经过上面的校验应该大于secremain{W25QXX_Erase_Sector(secpos); // 擦除这个扇区for (i = 0; i < secremain; i++) // 复制{W25QXX_BUF[i + secoff] = pBuffer[i];}W25QXX_Write_NoCheck(W25QXX_BUF, secpos * 4096, 4096); // 写入整个扇区}elseW25QXX_Write_NoCheck(pBuffer, WriteAddr, secremain); // 写已经擦除了的,直接写入扇区剩余区间.if (NumByteToWrite == secremain)break; // 写入结束了else // 写入未结束{secpos++; // 扇区地址增1secoff = 0; // 偏移位置为0pBuffer += secremain; // 指针偏移WriteAddr += secremain; // 写地址偏移NumByteToWrite -= secremain; // 字节数递减if (NumByteToWrite > 4096)secremain = 4096; // 下一个扇区还是写不完elsesecremain = NumByteToWrite; // 下一个扇区可以写完了}};
}
// 擦除整个芯片
// 等待时间超长...
void W25QXX_Erase_Chip(void)
{W25QXX_Write_Enable(); // SET WELW25QXX_Wait_Busy();W25QXX_CS = 0; // 使能器件SPI1_ReadWriteByte(W25X_ChipErase); // 发送片擦除命令W25QXX_CS = 1; // 取消片选W25QXX_Wait_Busy(); // 等待芯片擦除结束
}
// 擦除一个扇区
// Dst_Addr:扇区地址 根据实际容量设置
// 擦除一个山区的最少时间:150ms
void W25QXX_Erase_Sector(u32 Dst_Addr)
{// 监视falsh擦除情况,测试用printf("fe:%x\r\n", Dst_Addr);Dst_Addr *= 4096;W25QXX_Write_Enable(); // SET WELW25QXX_Wait_Busy();W25QXX_CS = 0; // 使能器件SPI1_ReadWriteByte(W25X_SectorErase); // 发送扇区擦除指令SPI1_ReadWriteByte((u8)((Dst_Addr) >> 16)); // 发送24bit地址SPI1_ReadWriteByte((u8)((Dst_Addr) >> 8));SPI1_ReadWriteByte((u8)Dst_Addr);W25QXX_CS = 1; // 取消片选W25QXX_Wait_Busy(); // 等待擦除完成
}
// 等待空闲
void W25QXX_Wait_Busy(void)
{while ((W25QXX_ReadSR() & 0x01) == 0x01); // 等待BUSY位清空
}
// 进入掉电模式
void W25QXX_PowerDown(void)
{W25QXX_CS = 0; // 使能器件SPI1_ReadWriteByte(W25X_PowerDown); // 发送掉电命令W25QXX_CS = 1; // 取消片选delay_us(3); // 等待TPD
}
// 唤醒
void W25QXX_WAKEUP(void)
{W25QXX_CS = 0; // 使能器件SPI1_ReadWriteByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xABW25QXX_CS = 1; // 取消片选delay_us(3); // 等待TRES1
}
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "spi.h"
#include "w25qxx.h"
#include "key.h"// 要写入到W25Q16的字符串数组
const u8 TEXT_Buffer[] = {"Explorer STM32F4 SPI TEST"};
#define SIZE sizeof(TEXT_Buffer)int main(void)
{u8 key;u16 i = 0;u8 datatemp[SIZE];u32 FLASH_SIZE;u16 id = 0;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设置系统中断优先级分组2delay_init(168); // 初始化延时函数uart_init(115200); // 初始化串口波特率为115200LED_Init(); // 初始化LEDLCD_Init(); // LCD初始化KEY_Init(); // 按键初始化W25QXX_Init(); // W25QXX初始化POINT_COLOR = RED;LCD_ShowString(30, 50, 200, 16, 16, "Explorer STM32F4");LCD_ShowString(30, 70, 200, 16, 16, "SPI TEST");LCD_ShowString(30, 90, 200, 16, 16, "ATOM@ALIENTEK");LCD_ShowString(30, 110, 200, 16, 16, "2023/12/01");LCD_ShowString(30, 130, 200, 16, 16, "KEY1:Write KEY0:Read"); // 显示提示信息while (1){id = W25QXX_ReadID();if (id == W25Q128 || id == NM25Q128)break;LCD_ShowString(30, 150, 200, 16, 16, "W25Q128 Check Failed!");delay_ms(500);LCD_ShowString(30, 150, 200, 16, 16, "Please Check! ");delay_ms(500);LED0 = !LED0; // DS0闪烁}LCD_ShowString(30, 150, 200, 16, 16, "W25Q128 Ready!");FLASH_SIZE = 16 * 1024 * 1024; // FLASH 大小为16字节POINT_COLOR = BLUE; // 设置字体为蓝色while (1){key = KEY_Scan(0);if (key == KEY1_PRES) // KEY1按下,写入W25Q128{LCD_Fill(0, 170, 239, 319, WHITE); // 清除半屏LCD_ShowString(30, 170, 200, 16, 16, "Start Write W25Q128....");W25QXX_Write((u8 *)TEXT_Buffer, FLASH_SIZE - 100, SIZE); // 从倒数第100个地址处开始,写入SIZE长度的数据LCD_ShowString(30, 170, 200, 16, 16, "W25Q128 Write Finished!"); // 提示传送完成}if (key == KEY0_PRES) // KEY0按下,读取字符串并显示{LCD_ShowString(30, 170, 200, 16, 16, "Start Read W25Q128.... ");W25QXX_Read(datatemp, FLASH_SIZE - 100, SIZE); // 从倒数第100个地址处开始,读出SIZE个字节LCD_ShowString(30, 170, 200, 16, 16, "The Data Readed Is: "); // 提示传送完成LCD_ShowString(30, 190, 200, 16, 16, datatemp); // 显示读到的字符串}i++;delay_ms(10);if (i == 20){LED0 = !LED0; // 提示系统正在运行i = 0;}}
}
实验效果
SPI实验
相关文章:

7、单片机与W25Q128(FLASH)的通讯(SPI)实验(STM32F407)
SPI接口简介 SPI 是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。 SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根…...

stream流和方法引用
1.Stream流 1.1体验Stream流【理解】 案例需求 按照下面的要求完成集合的创建和遍历 创建一个集合,存储多个字符串元素把集合中所有以"张"开头的元素存储到一个新的集合把"张"开头的集合中的长度为3的元素存储到一个新的集合遍历上一步得到的集…...

Redis——某马点评day01——短信登录
项目介绍 导入黑马点评项目 项目架构 基于Session实现登录 基本流程 实现发送短信验证码功能 controller层中 /*** 发送手机验证码*/PostMapping("code")public Result sendCode(RequestParam("phone") String phone, HttpSession session) {// 发送短信…...

AES加密技术:原理与应用
一、引言 随着信息技术的飞速发展,数据安全已成为越来越受到重视的领域。加密技术作为保障数据安全的重要手段,在信息安全领域发挥着举足轻重的作用。AES(Advanced Encryption Standard)作为一种对称加密算法,自1990年…...

Unity中PlayerPrefs在PC上存储位置总结
编辑器下和EXE存储位置是不同的,这也不难理解,是为了避免存储位置相同导致开发和测试冲突。 编辑器下位置:HKEY_CURRENT_USER\Software\Unity\UnityEditor\ExampleCompanyName\ExampleProductName EXE位置:HKEY_CURRENT_USER\Sof…...

消融实验:深度学习的关键分析工具
消融实验:深度学习的关键分析工具 在深度学习和机器学习领域,消融实验(Ablation Study)是一种重要的实验方法,用于理解和评估模型的各个组成部分对其整体性能的贡献。通过这种方法,研究人员可以更深入地了…...

Redis缓存——Spring Cache入门学习
Spring Cache 介绍 Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。 Spring Cache 提供了一层抽象,底层可以切换不同的缓存实现,例如: EHCacheCaffeineR…...

Python标准库copy【侯小啾python领航班系列(十五)】
Python标准库copy【侯小啾python领航班系列(十五)】 大家好,我是博主侯小啾, 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹…...

Android--Jetpack--Lifecycle详解
富贵本无根,尽从勤里得 一,定义 Lifecycle 是一个具备宿主生命周期感知能力的组件。它持有组件(Activity/Fragment)生命周期状态信息,并且允许其观察者监听宿主生命周期状态变化。 顾名思义,Lifecycle的主…...

LeetCode105.从前序和中序遍历序列构造二叉树
这道题看完题想了几分钟就想到大概的思路了,但是在写的时候有很多细节没注意出了很多问题,然后写了1个多小时,其实这道题挺简单的。 首先,最基本的知识,先序遍历是根左右,中序遍历是左根右,那么…...

flutter-一个可以输入的数字增减器
效果 参考文章 代码 在参考文章上边,主要是改了一下样式,逻辑也比较清楚,对左右两边添加增减方法。 我在此基础上加了_numcontroller 输入框的监听。 加了数字输入框的控制 keyboardType: TextInputType.number, //设置键盘为数字 inputF…...

抑郁症中西医治疗对比?
抑郁症是一种常见的心理障碍,治疗方法包括中医和西医两种。下面就抑郁症中西医治疗进行对比: 治疗方法:中医治疗抑郁症强调整体观念和辨证论治,通过调理身体各部分的功能,达到治疗抑郁症的目的。中医治疗抑郁症多采用天…...

012 OpenCV sobel边缘检测
目录 一、环境 二、soble原理介绍 三、源码实验 一、环境 本文使用环境为: Windows10Python 3.9.17opencv-python 4.8.0.74 二、soble原理介绍 Sobel边缘检测是一种广泛应用于图像处理领域的边缘检测算法,它通过计算图像灰度函数在水平方向和垂直…...

【开源视频联动物联网平台】libmodbus 写一个modbus tcp客户端
libmodbus 是一个用于 Modbus 通信协议的 C 语言库,可以用来创建 Modbus TCP 客户端。以下是一个简单的示例代码,演示如何使用 libmodbus 创建一个 Modbus TCP 客户端。 首先,确保你已经安装了 libmodbus 库。你可以从 libmodbus 的官方网站…...

安装以及使用 stylepro_artistic 所遇问题解决
根据https://github.com/PaddlePaddle/PaddleHub/blob/develop/docs/docs_ch/get_start/windows_quickstart.md 安装 hub install stylepro_artistic1.0.1 出现ImportError: cannot import name ‘Constant’ from ‘paddle.fluid.initializer’,提示在File: "…...

【Rust】所有权的认识
所有权 所有权的认识移动,克隆,拷贝所有权与函数返回值与作用域 引用与借用可变引用悬垂引用(Dangling References) Slice类型 所有权的认识 所有程序都必须管理其运行时使用计算机内存的方式。一些语言中具有垃圾回收机制&#…...

中间件安全:Weblogic 漏洞.(使用工具可以利用多种类型漏洞)
中间件安全:Weblogic 漏洞.(使用工具可以利用多种类型漏洞) WebLogic 是美国 Oracle 公司出品的一个 application server,确切的说是一个基于 JAVA EE 架构的中间件,WebLogic 是用于开发、集成、部署和管理大型分布式…...

matlab操作方法(一)——向量及其操作
1.向量及其操作 matlab是英文Matrix Laboratory(矩阵实验室)的简称,是基于矩阵运算的操作环境。matlab中的所有数据都是以矩阵或多维数组的形式存储的。向量和标量是矩阵的两种特殊形式 向量是指单行或者单列的矩阵,它是构成矩阵…...

MicroPython标准库
MicroPython标准库 arraybinascii(二进制/ASCII转换)builtins – 内置函数和异常cmath – 复数的数学函数collections – 集合和容器类型errno – 系统错误代码gc – 控制垃圾收集器hashlib – 散列算法heapq – 堆队列算法io – 输入/输出流json – JSON 编码和解码math – 数…...

2023年产业数据价值化峰会暨数栖大会-核心PPT资料下载
一、峰会简介 本次大会由主论坛和3场分论坛组成,嘉宾阵容强大,内容丰富多彩。来自政企学界的百名专家从产学研用多种维度对企业数据管理、产业数据资源化建设等视角展开。大会围绕“产业数据价值化”为主题,秉持“让数据用起来”的使命&…...

深入理解 Vue 组件:构建优雅的前端应用
🍂引言: Vue.js 是一款流行的 JavaScript 框架,以其简单易用和高度灵活的特性而受到了广泛的欢迎。其中的一个重要概念就是组件,它使我们能够将用户界面划分为可重用的、独立的部分。本文将深入探讨 Vue 组件的概念、使用和最佳实…...

基于SpringBoot+Vue的前后端分离的房屋租赁系统2
✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取项目下载方式🍅 一、项目背景介绍: 开发过程中࿰…...

PHPExcel 导出Excel报错:PHPExcel_IOFactory::load()
背景 近期在做 excel文件数据导出时,遇到如下报错: iconv(): Detected an illegal character in input string场景:计划任务后台,分步导出 大数据 excel文件发现在加载文件时,会有报错 报错信息 如下: {&q…...

Jmeter-分布式压测(远程启动服务器,windows)
1 前提条件 JDK已部署,版本一致Jmeter已部署,版本一致多台服务器连接的同一网络(例如:同一wifi)防火墙处于关闭状态(或者对应默认端口处于开放状态)虚拟网络适配器都处于关闭状态查找到每一台服务器的IP 2 主服务器配…...

【C++】string类模拟实现过程中值得注意的点
👀樊梓慕:个人主页 🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》 🌝每一个不曾起舞的日子,都是对生命的辜负 目录 前言 1.有关const的使用 &#x…...

大数据湖项目建设方案:文档全文101页,附下载
关键词:大数据解决方案,数据湖解决方案,数据治理解决方案,数据中台解决方案 一、大数据湖建设思路 1、明确目标和定位:明确大数据湖的目标和定位是整个项目的基础,这可以帮助我们确定项目的内容、规模、所…...

通付盾Web3专题 | SharkTeam:起底朝鲜APT组织Lazarus Group,攻击手法及洗钱模式
国家级APT(Advanced Persistent Threat,高级持续性威胁)组织是有国家背景支持的顶尖黑客团伙,专门针对特定目标进行长期的持续性网络攻击。朝鲜APT组织Lazarus Group就是非常活跃的一个APT团伙,其攻击目的主要以窃取资…...

<蓝桥杯软件赛>零基础备赛20周--第8周第1讲--十大排序
报名明年4月蓝桥杯软件赛的同学们,如果你是大一零基础,目前懵懂中,不知该怎么办,可以看看本博客系列:备赛20周合集 20周的完整安排请点击:20周计划 每周发1个博客,共20周(读者可以按…...

数据增强让模型更健壮
在做一些图像分类训练任务时,我们经常会遇到一个很尴尬的情况,那就是: 明明训练数据集中有很多可爱猫咪的照片,但是当我们给训练好的模型输入一张戴着头盔的猫咪进行测试时,模型就不认识了,或者说识别精度很低。 很明显,模型的泛化能力太差,难道戴着头盔的猫咪就不是猫…...

Redis远程字典服务
1 介绍 Redis(Remote Dictionary Server)是一个开源的内存数据存储系统,可以用作数据库、缓存和消息中间件。它支持多种数据结构,包括字符串(strings)、哈希表(hashes)、列表&#…...