STM32IIC与SPI详解
单片机里的通信协议其实蛮多的,IIC;SPI;MQTT;CAN;包括串口也是一种通信协议。而串口通信虽然实现了全双工,但需要至少三根线,为了节省这一根线的成本,于是IIC诞生了。
目录
一.IIC协议
1.IIC的结构
2.IIC的特点
3.IIC的通信时序
4.具体配置(32HAL库版)
二.SPI协议
1.SPI的结构
2.SPI的特点
3.具体配置
三:联合配置
1.OLED屏幕的配置
OLED的数据格式
OLED的写入模式
Oled的命令
代码:
W25Q128配置
W25Q128的命令
W25Q128的寄存器
代码:
最终配置:
祝你看完就会
一.IIC协议
IIC协议其实就是一种标准外设协议,其实所谓协议,本质上就是各种时序电路的组合。IIC也不例外,它的最大特点就是特别的轻量级。
1.IIC的结构
IIC的简便和轻量级就在于它只有两条线,一条是时钟线SCL,一条是数据线SDA。说白了,就是在SCL的控制下在SDA上传输命令/数据。
在这张图上可以看到同时有很多设备连接在这两条线上,它们之间的关系一般是一主多从。
2.IIC的特点
1.IIC是半双工通信,因为SCL不负责传输数据,只有一条SDA数据线,无法发的同时接收信息。
2.如果你使用的是STM32芯片,那么如果没有配置上拉电阻的话GPIO口必须配置为开漏输出。因为假设时序出现错误两个设备一个讲SDA拉低一个将SDA拉高,那么将导致短路。
3.同步传输:数据的传输是严格按照时钟线来进行的。
3.IIC的通信时序
IIC的通信主要依靠四个信号:起始信号,应答信号,停止信号;读写信号;
START:

STOP:

ASK:

读写:

其中ASK就是在在吧SCL拉高的期间读取SDA的的电平。读取完成后立即拉低。读取到的SDA假设为1则表示有应答,若为0则表示没有应答。
读写信号则是在起始信号后将SCL拉低的期间向SDA上放或者读取数据。
START和STOP比较简单不多赘述。
4.具体配置(32HAL库版)
头文件:
#ifndef __IIC_H__
#define __IIC_H__#include "sys.h"#define SDA_PULL_UP() HAL_GPIO_WritePin(GPIO_POTT, SDA, GPIO_PIN_SET)
#define SDA_PULL_DOWN() HAL_GPIO_WritePin(GPIO_POTT, SDA, GPIO_PIN_RESET)
#define SCL_PULL_UP() HAL_GPIO_WritePin(GPIO_POTT, SCL, GPIO_PIN_SET)
#define SCL_PULL_DOWN() HAL_GPIO_WritePin(GPIO_POTT, SCL, GPIO_PIN_RESET)void iic_Stop(GPIO_TypeDef *GPIO_POTT,uint16_t SDA,uint16_t SCL);
void iic_Start(GPIO_TypeDef *GPIO_POTT,uint16_t SDA,uint16_t SCL);
void iic_Ask(GPIO_TypeDef *GPIO_POTT,uint16_t SDA,uint16_t SCL);
void iic_Sendbyte(GPIO_TypeDef *GPIO_POTT,uint16_t SDA,uint16_t SCL,uint8_t DATA);#endif
首先我这里用了大量的宏定义了很多宏函数来方便控制对应线的电平高低。另外如果你看的细致的话会发现我这里宏函数中的参数也是宏,然而你却在这儿找不到这个宏。其实它并不是宏,我用了一种稍微怪的方式来简便我在IIC定义里的工作量,但加大了一点调用的工作量。
源文件:
#include "IIC.h"void iic_Stop(GPIO_TypeDef *GPIO_POTT,uint16_t SDA,uint16_t SCL){SCL_PULL_UP();SDA_PULL_DOWN(); //先拉高SCL再拉高SDASDA_PULL_UP();}void iic_Start(GPIO_TypeDef *GPIO_POTT,uint16_t SDA,uint16_t SCL){SCL_PULL_UP(); //SCL高电平期间SDA下降沿SDA_PULL_UP();SDA_PULL_DOWN();SCL_PULL_DOWN();
}void iic_Ask(GPIO_TypeDef *GPIO_POTT,uint16_t SDA,uint16_t SCL){SCL_PULL_UP(); SCL_PULL_DOWN();
}void iic_Sendbyte(GPIO_TypeDef *GPIO_POTT,uint16_t SDA,uint16_t SCL,uint8_t DATA){uint8_t i,tmp = DATA;//主机在SCL低电平期间在SDA上放数据for(i = 0; i<8; i++){if((tmp & 0x80) == 0x80) //DATA &= 1000 0000 SDA_PULL_UP();elseSDA_PULL_DOWN();SCL_PULL_UP(); //从机在SCL高电平期间读取这一位 SCL_PULL_DOWN();tmp = tmp << 1;}
}
想必如果你由上面的疑问看了源文件也就理解 ,我定义的宏函数里的参数并不是宏而是调用它的函数里的参数。所以我增加的调用方的工作量就是传参很多,IIC这里就非常简介易懂了。
另外一个点就是数据传输函数中是一位一位放的,不断地放不断地左移知道8次轮回完成一字节的传输则结束。
二.SPI协议
SPI的全称是Serial Peripheral Interface。有基础的人估计一眼就看见Serial(串口)了。没错,其实这东西它使用非常像串口。不仅如此,配置起来也非常像串口。
1.SPI的结构
SPI一共由四条线组成:SCK;MISO;MOSI;NSS(CS)
其中,MISO和MOSI分别是:Master Input Slave Output
这里某些同学不要想歪了哈,Master这里就是主机,Slave就是从机,所以这两根线就很好理解了,简单说就是RX和TX一样。
然而:虽然这里也是两条线也是全双工,但是SPI的传输数据方式却是非常的特殊的。

图中画圈的地方都是SPI的重点,其中特殊就在于它的位移寄存器 。
2.SPI的特点
1.SPI最大的特点就来自于它的位移寄存器,它每发送一字节的数据就必须收一字节的数据,同样的,它要收一字节的数据就必须发出一字节数据。
2.看了特点一你会认为SPI是强制全双工的,但其实不是,它完全可以配置为半双工或者只有一条数据线。
3.SPI的工作模式比较特别,它的工作模式取决于时钟极性和时钟相位
第三点展开来说:
时钟极性控制SPI数据线上没有数据时SCL的电平状态:
CPOL为0则空闲时为低电平,反之则为高电平。
CPHA为0则每一个奇数边缘采样数据(第一个),反之则为偶数边缘采样。
你要是看不懂也没关系,总之就是CPOL和CPHA排列组合一共有四种工作模式。
3.具体配置
SPI的配置一般是依靠板子上确定的外设的,因为它不像IIC那样的轻量级。它有很多的东西需要配,比如:分频数;时钟启动;工作模式;是否半双工等等。
#include "SPI.h"
SPI_HandleTypeDef spi_handle = {0};void SPI_INIT(void){spi_handle.Instance = SPI1;spi_handle.Init.Mode = SPI_MODE_MASTER; //配置主从模式spi_handle.Init.Direction = SPI_DIRECTION_2LINES; //半双工全双工选择spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW; //低电平有效spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE; //奇数取值spi_handle.Init.NSS = SPI_NSS_SOFT; //软件调控NSSspi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; //分频数选择spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB; spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;spi_handle.Init.CRCPolynomial = 7; HAL_SPI_Init(&spi_handle);}void HAL_SPI_MspInit(SPI_HandleTypeDef *spi_handle){if(spi_handle->Instance == SPI1){GPIO_InitTypeDef gpio_initstruct;__HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_SPI1_CLK_ENABLE();gpio_initstruct.Pin = GPIO_PIN_4; gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; gpio_initstruct.Pull = GPIO_PULLUP; gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &gpio_initstruct);gpio_initstruct.Pin = GPIO_PIN_5 | GPIO_PIN_7; gpio_initstruct.Mode = GPIO_MODE_AF_PP; HAL_GPIO_Init(GPIOA, &gpio_initstruct);gpio_initstruct.Pin = GPIO_PIN_6; gpio_initstruct.Mode = GPIO_MODE_INPUT; HAL_GPIO_Init(GPIOA, &gpio_initstruct);}}uint8_t SPI_swap_byte(uint8_t data){uint8_t rev_data = 0;HAL_SPI_TransmitReceive(&spi_handle,&data,&rev_data,1,1000);return rev_data;
}
这里对于Instance的配置还是挺繁琐的,但是也只是繁琐并没有难度。剩下的就是时钟;GPIO配置;然后可以看到在发送的部分它的函数叫HAL_SPI_TransmitReceive,对应上了我们说的接收的同时必须发送。
三:联合配置
两个协议都学会了,如何应用呢?IIC的入门外设还是非常经典的--OLED屏幕。那SPI呢?可以采用一块存储块进行配合读写。我这里就用W25Q128的存储模块。
1.OLED屏幕的配置
Oled的配置核心其实就是显示东西嘛,所以其实总结成一句话就是:
告诉屏幕在哪里显示什么东西。
OLED是只可以选择亮或者灭的,所以显示什么东西其实最终说白了是各种点阵,这个东西其实没啥技术含量。另外OLED模块的初始化也是不需要学的,你就照着把一堆命令直接复制过来用就行了。所以主要的配置重点在于:如何告诉他。
那么这个时候我们就需要读一下OLED的手册了。
OLED的数据格式

以上为手册的原图,可以看到它的发送全部都是 Control byte + Data byte。那么这是什么意思呢?
说白了,就是Control byte 用来让Oled判断接下来所接收的数据到底是命令还是显示数据。
可以看到,整个数据帧的格式就是:
Start信号--写入数据模式--ASK--Control byte--Data byte--ASK--Stop信号
那么此时的问题就变成了写入模式是什么?以及Control byte是什么?
Control byte看右下角,D/C的后一位写0则表示接下来的数据是Command,写1则表示接下来的数据是Data。
其实自己看手册可绝望了,不信? 给:
OLED的写入模式
一共有四种:



总而言之呢,其实你只记得住第一个就行,因为我们用哪一个都ok,第一个在不配置的情况下是被默认选定的。只需要知道它在写完后会自动向右偏移一位。当写道最右边后会返回来这一行的最左边。那么这里就需要稍微知道一下屏幕的大小了:
整个屏幕是128*64的,每一个字节的八位是竖着排列的,逻辑为1的就亮为0就灭。
64 / 8 = 8,这也是为什么是8个page。
Oled的命令


Oled其实内置的是一块芯片,所以它的命令其实还是蛮多的。但是可以看到这里我给你截下来的命令都是关于位置设定和写入模式的设定的。
其实这里主要的就是Page和Column 的设定,Page的很简单B0~B7分别表示Page0到Page7.
主要就是Column需要给两次,因为有 128位嘛,所以需要两个字节。这就在编程的方面稍微有点小麻烦。
代码:
#include "oled.h"
#include "delay.h"
#include "front.h"void OLED_INIT(){GPIO_INIT();delay_ms(100); Oled_Write_Cmd(0xAE); Oled_Write_Cmd(0xD5); Oled_Write_Cmd(0x80); Oled_Write_Cmd(0xA8); Oled_Write_Cmd(0x3F); Oled_Write_Cmd(0xD3); Oled_Write_Cmd(0x00); Oled_Write_Cmd(0x40); Oled_Write_Cmd(0xA1); Oled_Write_Cmd(0xC8); Oled_Write_Cmd(0xDA); Oled_Write_Cmd(0x12);Oled_Write_Cmd(0x81); Oled_Write_Cmd(0xCF); Oled_Write_Cmd(0xD9); Oled_Write_Cmd(0xF1);Oled_Write_Cmd(0xDB); Oled_Write_Cmd(0x30);Oled_Write_Cmd(0xA4); Oled_Write_Cmd(0xA6); Oled_Write_Cmd(0x8D); Oled_Write_Cmd(0x14);Oled_Write_Cmd(0xAF); }void GPIO_INIT(){GPIO_InitTypeDef gpio_init;gpio_init.Mode = GPIO_MODE_OUTPUT_PP;gpio_init.Pin = SDA_PIN|SCL_PIN;gpio_init.Pull = GPIO_PULLUP;gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;__HAL_RCC_GPIOB_CLK_ENABLE();HAL_GPIO_Init(GPIOB, &gpio_init);
}void Oled_Write_Cmd(uint8_t cmd){iic_Start(SDA_PORT,SDA_PIN,SCL_PIN);iic_Sendbyte(SDA_PORT,SDA_PIN,SCL_PIN,0x78);iic_Ask(SDA_PORT,SDA_PIN,SCL_PIN);iic_Sendbyte(SDA_PORT,SDA_PIN,SCL_PIN,0x00);iic_Ask(SDA_PORT,SDA_PIN,SCL_PIN);iic_Sendbyte(SDA_PORT,SDA_PIN,SCL_PIN,cmd);iic_Ask(SDA_PORT,SDA_PIN,SCL_PIN);iic_Stop(SDA_PORT,SDA_PIN,SCL_PIN);
}void Oled_Write_Data(uint8_t data){iic_Start(SDA_PORT,SDA_PIN,SCL_PIN);iic_Sendbyte(SDA_PORT,SDA_PIN,SCL_PIN,0x78);iic_Ask(SDA_PORT,SDA_PIN,SCL_PIN);iic_Sendbyte(SDA_PORT,SDA_PIN,SCL_PIN,0x40);iic_Ask(SDA_PORT,SDA_PIN,SCL_PIN);iic_Sendbyte(SDA_PORT,SDA_PIN,SCL_PIN,data);iic_Ask(SDA_PORT,SDA_PIN,SCL_PIN);iic_Stop(SDA_PORT,SDA_PIN,SCL_PIN);
}void Oled_Set_Position(uint8_t page,uint8_t column){Oled_Write_Cmd(0xB0 + page); //选择页数Oled_Write_Cmd(column & 0x0F); //低四位Oled_Write_Cmd(((column & 0xF0) >> 4) | 0x10); //高四位}void Oled_clear(void){uint8_t i,j; for(i = 0;i < 8;i++){ Oled_Set_Position(i,0);for(j = 0;j<128;j++){Oled_Write_Data(0);} }}void Oled_show_picture(uint8_t hight,uint8_t wide,uint8_t *picture){uint8_t page,i,j;page = hight / 8;for(i = 0; i<page; i++){Oled_Set_Position(i,0);for(j = 0; j<wide; j++){Oled_Write_Data(picture[wide * i + j]);}}}void Oled_show_char(uint8_t Ocolumn, uint8_t Opage, uint8_t num, uint8_t size)
{uint8_t i, j, page;num = num - ' ';page = size / 8;if(size % 8)page++;for(j = 0; j < page; j++){Oled_Set_Position(Opage + j,Ocolumn);for(i = size / 2 * j; i < size /2 * (j + 1); i++){if(size == 12)Oled_Write_Data(ascii_6X12[num][i]);else if(size == 16)Oled_Write_Data(ascii_8X16[num][i]);else if(size == 24)Oled_Write_Data(ascii_12X24[num][i]);}}
}void Oled_show_string(uint8_t column, uint8_t page, char *p, uint8_t size)
{while(*p != '\0'){Oled_show_char(column, page, *p, size);column += size/2;p++;}
}
W25Q128配置
对于它其实主要就是配置 读;写;等待空闲;这就是一个FLASH储存器。
FLASH的唯一特性就是:它只能写0不能写1.
并且该模块不需要初始化,命令同样很多但是我们用的很少。
W25Q128的命令
| 0x06 | 写使能 | 写入数据/擦除之前,必须先发送该指令 |
| 0x05 | 读 SR1 | 判定 FLASH 是否处于空闲状态,擦除用 |
| 0x03 | 读数据 | 读取数据 |
| 0x02 | 页写 | 写入数据,最多写256字节 |
| 0x20 | 扇区擦除 | 扇区擦除指令,最小擦除单位 |
这里主要讲一些要点:
1.在做任何通讯的操作之前,必须要拉低CS,也就是拉低片选。这也是它和IIC不同的地方,IIC是进行寻址,而它通过拉低片选。操作完成后必须再拉高。
2.在进行读/写操作是需要发送地址,这个地址是三字节的,而发送时每次发送的是一个字节,所以就需要位操作。
void send_addr(uint32_t address){SPI_swap_byte((uint8_t)address >> 16); //右移的同时进行强转,强转保留低位,所以这里是发送高位SPI_swap_byte((uint8_t)address >> 8); //中间8位SPI_swap_byte((uint8_t)address); //低8位
}
3.任何和写相关的操作比如:马上要写,刚刚写完;必须进行等待空闲。
W25Q128的寄存器

这里就介绍这个一个,就是为了等待空闲操作使用。
在编程过程中,步骤也很简单:
拉低片选----向芯片发送读取Busy的命令----发送的同时接收----while来阻塞知道接收到BusyFlag为0----拉高片选。
void wait_busy(void){W25Q128_CS(0);SPI_swap_byte(FLASH_ReadStatusReg1); //读取状态寄存器指令SPI_swap_byte(FLASH_DummyByte); //接收状态寄存器flag while((SPI_swap_byte(0xFF) & 0x01) == 1); //等待知道寄存器busy位变为0 W25Q128_CS(1);
}
代码:
#include "w25q128.h"uint16_t w25q128_config(void){uint16_t device_id = 0;W25Q128_CS(0);SPI_swap_byte(FLASH_ManufactDeviceID);SPI_swap_byte(0x00);SPI_swap_byte(0x00);SPI_swap_byte(0x00);device_id = SPI_swap_byte(FLASH_DummyByte) << 8;device_id |= SPI_swap_byte(FLASH_DummyByte);W25Q128_CS(1);return device_id;
}void wait_busy(void){W25Q128_CS(0);SPI_swap_byte(FLASH_ReadStatusReg1); //读取状态寄存器指令SPI_swap_byte(FLASH_DummyByte); //接收状态寄存器flag while((SPI_swap_byte(0xFF) & 0x01) == 1); //等待知道寄存器busy位变为0 W25Q128_CS(1);
}void send_addr(uint32_t address){SPI_swap_byte((uint8_t)address >> 16); //右移的同时进行强转,强转保留低位,所以这里是发送高位SPI_swap_byte((uint8_t)address >> 8); //中间8位SPI_swap_byte((uint8_t)address); //低8位
}void w25q128_writ_enable(void)
{W25Q128_CS(0);SPI_swap_byte(FLASH_WriteEnable);W25Q128_CS(1);
}void read_data(uint32_t address, uint8_t *rev_data, uint8_t size){W25Q128_CS(0);SPI_swap_byte(FLASH_ReadData);send_addr(address);uint8_t i = 0; for(i = 0; i < size; i++){rev_data[i] = SPI_swap_byte(0xFF); //直接根据指针写进去了所以不需要返回值}W25Q128_CS(1);
}void write_page_data(uint32_t address, uint8_t *write_data, uint8_t size){ w25q128_writ_enable();wait_busy();W25Q128_CS(0);SPI_swap_byte(FLASH_PageProgram);send_addr(address);uint16_t i = 0;for(i = 0; i< size; i++){SPI_swap_byte(write_data[i]);}W25Q128_CS(1);wait_busy();}void erase_page(uint32_t address){w25q128_writ_enable();wait_busy();W25Q128_CS(0);SPI_swap_byte(FLASH_SectorErase);send_addr(address);W25Q128_CS(1);wait_busy();}
最终配置:
把文件合并,接线合并,初始化后在Main函数更改写法让读写操作显示在屏幕上:
#include "sys.h"
#include "uart1.h"
#include "delay.h"
#include "led.h"
#include "SPI.h"
#include "w25q128.h"
#include "oled.h"
#include "IIC.h"
#include "string.h"uint8_t data_write[4] = {0xAA, 0xBB, 0xCC, 0xDD};
uint8_t data_read[4] = {0};
int main(void)
{HAL_Init(); stm32_clock_init(RCC_PLL_MUL9); SPI_INIT();uart1_init(115200); OLED_INIT();Oled_clear(); Oled_show_string(1,1,"HELLO WKX",24); delay_ms(1000); Oled_clear();char show[8];uint16_t number = w25q128_config();sprintf(show,"device id :%X",number);Oled_show_string(1,1,"Loading...",24); delay_ms(1000); Oled_clear();Oled_show_string(1,1,show,16);delay_ms(1000);Oled_clear(); write_page_data(0x000000, data_write, 4);Oled_show_string(1,1,"Writed succes",16);delay_ms(500);Oled_clear();Oled_show_string(1,1,"Reading data",16);delay_ms(500);Oled_clear();read_data(0x000000, data_read, 4);memset(show,0,8);sprintf(show,"%X",data_read[0]);Oled_show_string(1,1,show,16);sprintf(show,"%X",data_read[1]);Oled_show_string(40,1,show,16);sprintf(show,"%X",data_read[2]);Oled_show_string(80,1,show,16);while(1){ }
}
好了给看看效果:
OLED&W25&Q128
祝你看完就会
相关文章:
STM32IIC与SPI详解
单片机里的通信协议其实蛮多的,IIC;SPI;MQTT;CAN;包括串口也是一种通信协议。而串口通信虽然实现了全双工,但需要至少三根线,为了节省这一根线的成本,于是IIC诞生了。 目录 一.IIC…...
K8s第三节:k8s1.23.1升级为k8s1.30.0
上回书说到我们使用了kubeadm安装了k8s1.23.1,但是在k8s1.24之前还是使用docker作为容器运行时,所以这一节我打算将我安装的k8s集群升级为1.30.0版本; 1、修改containerd 配置 因为我们安装的docker自带containerd,所以我们不需要重新安装con…...
.gitignore不生效的解决方案
为什么会不生效 因为文件已经被git追踪(或者说被track 或者说被索引,都是一个意思)。 目前.gitignore面对已经被git追踪的文件是无法生效的。(这是现状,我们只能接收这个现状。不过个人觉得git官方可以对这方面进行优化调整,让其…...
脱胎于 S 语言的R语言,Ross Ihaka 和 Robert Gentleman 和社区的力量让 R 在学术界与研究机构放光彩
R语言从一门用于统计学教学的编程语言,发展成为全球数据科学领域的重要工具,离不开其强大的功能、丰富的社区资源和开源精神。这些都离不开Ross Ihaka 和 Robert Gentleman 和 社区的力量。 在1990年代初,新西兰奥克兰大学的统计学教授Ross I…...
JavaEE 第6节 内存可见性问题以及解决方法
目录 一、什么是内存可见性问题? 1、问题代码演示 2、基础知识铺垫 1)硬件层面 2)模型层面(JMM) 二、内存可见性问题的原因 三、volatile解决内存可见性问题 一、什么是内存可见性问题? 1、问题代码…...
es基本操作
以下是一些 Elasticsearch 常用的命令,涵盖了索引管理、数据操作和集群管理等方面: 基本操作 检查集群状态: curl -X GET "localhost:9200/_cluster/health?pretty"查看集群健康状态和基本信息。 查看所有索引: curl…...
开源 AI 智能名片 S2B2C 商城小程序赋能下的社区团购商业模式研究
摘要:本文深入探讨了社区团购商业模式的本质、特点及其优势,并详细分析了开源 AI 智能名片 S2B2C 商城小程序在社区团购中的应用与价值。通过对相关案例的研究和数据的分析,揭示了这一创新组合对社区商业生态的重要影响,为未来社区…...
AutoSar AP软件规范中CM介绍及功能概要
1. 前言 为了理解AutoSar AP中EM的概念,生搬硬套的翻译了《 AUTOSAR SWS CommunicationManagement.pdf》的介绍部分,并按照自己的理解进行了修改。如下 2. AUTOSAR_SWS_CommunicationManagement.pdf的介绍部分 本文件包含AUTOSAR AP通信管理的功能、A…...
【图形学】TA之路-向量
向量 向量 是一个有大小和方向的数学对象。在三维空间中,向量通常表示为 (v_x, v_y, v_z)。 基本操作 加法: a b (a_x b_x, a_y b_y, a_z b_z)减法: a - b (a_x - b_x, a_y - b_y, a_z - b_z)标量乘法: k * v (k * v_x, …...
[flink]部署模式
部署模式 在一些应用场景中,对于集群资源分配和占用的方式,可能会有特定的需求。 Flink为各种场景提供了不同的部署模式,主要有以下三种:会话模式(Session Mode)、单作业模式(Per-Job Mode&…...
为什么不用postman做自动化
面试的时候被问到:为什么不用postman做自动化 打开postman,看到用例集管理、API 管理、环境管理这三个功能,用户体验感算得上品牌等级了 为什么不用呢,文心一言给了一些答案 不适合大规模自动化测试:Postman 主要是为…...
一、Matlab基础
文章目录 一、Matlab界面二、Matlab窗口常用命令三、Matlab的数据类型3.1 数值类型3.2 字符和字符串3.3 逻辑类型3.4 函数句柄3.5 结构类型3.6 细胞数组 四、Matlab的运算符4.1 算术运算符4.2 关系运算符4.3 逻辑运算4.4 运算符优先级 五、Matlab的矩阵5.1 矩阵的建立5.2 矩阵的…...
执行java -jar命令,显示jar中没有主清单属性
在Java中,一个"主清单属性"(Main-Class attribute)是指定JAR文件中包含的应用程序入口点,即包含main方法的类的完全限定名。如果你尝试运行一个没有主清单属性的JAR文件,你可能会看到错误消息,如…...
【C++进阶】红黑树
目录 什么是红黑树?红黑树红黑树的性质 定义红黑树红黑树的操作insertinorderfindheightsize构造函数析构函数赋值拷贝判断红黑树 全部代码总结 什么是红黑树? 红黑树 红黑树(Red-Black Tree)是一种自平衡的二叉搜索树ÿ…...
linux使用ssh连接一直弹出密码框问题
1.查看ssh服务的状态 输入以下命令: sudo service sshd status 小编已经安装了。 如果出现 Loaded: error (Reason: No such file or directory) 提示的话,说名没有安装ssh服务,按照第二步:安装ssh服务。 如果出现 Active: in…...
Python 3 数据结构
Python 3 数据结构 引言 Python 是一种高级编程语言,因其简洁明了的语法和强大的功能而广受欢迎。在 Python 中,数据结构是组织和存储数据的方式,对于编写高效和可维护的代码至关重要。本文将深入探讨 Python 3 中的主要数据结构࿰…...
【开源社区】Elasticsearch(ES)中空值字段 null_value 及通过exists查找非空文档
文章目录 0、声明1、问题描述2、问题剖析2.1 NULL或者空值类型有哪些2.2 案例讲解:尝试检索值为 null 的字段2.3 解决思路 3、使用 null_value 的诸多坑(避免生产事故)3.1 null_value 替换的是索引,并不会直接替换源数据3.2 不支持…...
JavaDS —— 位图(BitSet)与 布隆过滤器
位图 引入问题:给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。 首先要注意 40 亿个数据如果使用 整型(int) 来存放的话,就是要 40 亿个整型,一个整型有…...
如何确保场外个股期权交易的安全?
如何确保场外个股期权交易的安全?投资者可以采取以下措施,以提高交易的安全性和减少风险: 增强知识储备:深入学习期权的基础知识,包括不同类型的期权、它们的权利和义务、定价方式以及风险特性,从而提升自…...
第2章:LabVIEW FPGA未来发展方向《LabVIEW ZYNQ FPGA宝典》
2.1:NI的LabVIEW FPGA未来战略部署 在展望NI公司的LabVIEW FPGA技术未来发展趋势之前,让我们先来回顾一下LabVIEW与FPGA的技术发展历程,如图2-1所示。可以看出,NI公司的LabVIEW FPGA软件一方面是跟随Xilinx最新的FPGA硬件可持续发…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...
