SPI 通信协议

news2024/11/19 9:31:21

1. SPI通信

1. 什么是SPI通信协议

2. SPI的通信过程  

在一开始会先把发送缓冲器的数据(8位)。一次性放到移位寄存器里。 移位寄存器会一位一位发送出去。但是要先放到锁存器里。然后从机来读取。从机的过程也一样。当移位寄存器的数据全部发送完。其实是主机与从机交换了数据。这时一次性把移位寄存器的数据放到接收缓冲器中。

 

3. SPI的几种模式 

CPOL时钟极性决定空闲时的高低电平。设置为1。空闲就是高电平。设置为0。空闲就是低电平。

CPHA时钟相位什么时候进行采样。设置为0。在第一个时钟边沿采集。所以在采集前要准备好数据。设置为1。在第二个时钟边沿采集。

 

 

 

 

具体采用那种模式。查看从机手册支持哪种SPI模式来进行选择。

4. SPI的具体连接模式。

一主一从

一主多从 (通过哪个从机的片选使能来选择。如果某个从机选中。其他的从机就不起作用)

SPI不支持多主机的。 

 

对从机比较多那么相应的片选引脚也需要更多。可以采用菊花链连接来减少I/o口。从而节省资源。

但这种连接对于SPI通信也会变的复杂。

 5. SPI于IIC的比较

 

1. W25Q32介绍

当MCU资源不够用就可以外接一个W25Qxx芯片。

1. W25Q32的命名。

 2. W25Q32的引脚。

 WP:写保护引脚  在进行写操作时先要取消写保护才能进行写操作。

 /HOLD or /RESET:如果这个引脚有效。即使片选有效。W25Q32也不会生效相当于高组态。

其他引脚:CS DO DI  CLK  GND  VCC。

3. 存储划分的方便管理

对SPI发送的指令然后驱动电路对存储数据进行操作。

 

 4. w25Q32具体硬件图。 

 

5. W25Q32的寄存器

 只看状态寄存器1的低两位其余的自行查手册。

 6. 指令操作。(具体看手册指令的作用以及指令发送怎么获取数据)

 

 1. 读指令

具体的伪代码 

 

2. 擦除

 

 

 

3. 写指令 

3.  dome 实现SPI读取W25Q32

1. 程序设计 

 

  

2. 写数据注意事项

 

 

 

 

3. 具体的接线 

因为是模拟SPI所以引脚可以任意设定。

这里选择是SCL = PA5 ,MOSI = PA7 ,MISO = PA6 ,CS = PA4。

 soft_spi.h

#ifndef _SOFT_SPI_H
#define _SOFT_SPI_H
/**
filename: soft_spi.h

**/
#include "gd32f10x.h"
#include "systick.h"

//定义表示具体IO口的资源宏(模拟SPI的选用的引脚)
#define SPI_PORT GPIOA
#define SPI_MOSI GPIO_PIN_7
#define SPI_MISO GPIO_PIN_6
#define SPI_SCK  GPIO_PIN_5
#define SPI_CS   GPIO_PIN_4

/* SPI的模式 */
#define SPI_MODE0 0
#define SPI_MODE1 1
#define SPI_MODE2 2
#define SPI_MODE3 3

void soft_spi_init(void);                  // spi通信准备,初始化
void soft_spi_init_io(void);               // 初始化spi通信用到的io口
void soft_spi_init_mode(uint8_t spi_mode); // 初始化spi通信模式,时钟相位和时钟极性

void soft_spi_begin(void);               // 开始spi通信
void soft_spi_w_cs(uint8_t bit_value);   // 写片选cs口

uint8_t soft_spi_swap(uint8_t byte_to_send); /* 交换数据 */

void soft_spi_w_sck(uint8_t bit_value);   // 写时钟口
void soft_spi_w_mosi(uint8_t bit_value);  // 写MOSI口
uint8_t soft_spi_r_miso(void);            // 读MISO口

void soft_spi_end(void);  // 结束spi通信

#endif

soft_spi.c

#include "soft_spi.h"

uint8_t clock_polar;
uint8_t clock_phase;

// spi通信准备,初始化
void soft_spi_init(void){
	soft_spi_init_io();
	soft_spi_init_mode(SPI_MODE0);
}

// 初始化spi通信用到的io口
void soft_spi_init_io(void){
	rcu_periph_clock_enable(RCU_GPIOA); /* 使能GPIOA时钟 */
	gpio_init(SPI_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, SPI_MOSI|SPI_SCK|SPI_CS); /* MOSI, SCK, CS 配置成推挽输出  */
	gpio_init(SPI_PORT, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, SPI_MISO); /* MISO 输入模式  */
}

// 初始化spi通信模式,时钟相位和时钟极性
void soft_spi_init_mode(uint8_t spi_mode){
	switch(spi_mode){
		case SPI_MODE0:
			clock_polar = 0;
			clock_phase = 0;
			break;
		case SPI_MODE1:
			clock_polar = 0;
			clock_phase = 1;
			break;
		case SPI_MODE2:
			clock_polar = 1;
			clock_phase = 0;
			break;
		case SPI_MODE3:
			clock_polar = 1;
			clock_phase = 1;
			break;
		default:
			break;
	}
}

// 开始spi通信
void soft_spi_begin(void){
	soft_spi_w_cs((bit_status)0);  /* 把从机的片选拉低 */
}

// 写片选cs口
void soft_spi_w_cs(uint8_t bit_value){
	gpio_bit_write(SPI_PORT, SPI_CS, (bit_status)bit_value);
}

/*
重要函数,spi主机的移位寄存器与spi从机移位寄存器交换数值
*/
uint8_t soft_spi_swap(uint8_t byte_to_send){
	uint8_t byte_receive = 0x00;
	uint8_t i;
	
	for(i = 0; i < 8; i++){
		soft_spi_w_sck(clock_polar ? 1:0); /* 先有一个SCLghh空闲 */ 
		delay_1us(1);
 
		if(clock_phase){
			if(soft_spi_r_miso() == 1)byte_receive |= (0x80 >> i); /* 采集数据 */
			soft_spi_w_sck(clock_phase ? 0 : 1);
			delay_1us(1);
			soft_spi_w_mosi(byte_to_send & (0x80 >> i)); /* 先写 */
			
		}else{
			soft_spi_w_mosi(byte_to_send & (0x80 >> i)); /* 先写 */
			soft_spi_w_sck(clock_phase ? 0 : 1); /* 产生沿 */
			delay_1us(1);
			if(soft_spi_r_miso() == 1)byte_receive |= (0x80 >> i); /* 采集数据 */
		}
		
	}
	
	return byte_receive;
}

// 写时钟口
void soft_spi_w_sck(uint8_t bit_value){
	gpio_bit_write(SPI_PORT, SPI_SCK, (bit_status)bit_value);
}

// 写MOSI口
void soft_spi_w_mosi(uint8_t bit_value){
	gpio_bit_write(SPI_PORT, SPI_MOSI, (bit_status)bit_value);
}

// 读MISO口
uint8_t soft_spi_r_miso(void){
	return gpio_input_bit_get(SPI_PORT, SPI_MISO);    
}

// 结束spi通信
void soft_spi_end(void){
	
	soft_spi_w_sck(clock_polar ? 1:0); /* 根据模式来选择空闲电平 */
	soft_spi_w_cs((bit_status)1); /* 片选拉高 */
}

 w25qxx_spi.h

#ifndef _W25QXX_SPI_H
#define _W25QXX_SPI_H

#include "gd32f10x.h"
#include "w25qxx_ins.h"
#include "soft_spi.h"

#define W25QXX_ID_1           1

#define W25QXX_SR_ID_1        1
#define W25QXX_SR_ID_2        2
#define W25QXX_SR_ID_3        3

void w25qxx_init(void);

void w25qxx_wait_busy(void);
uint8_t w25qxx_read_sr(uint8_t sregister_id);  // 读状态寄存器
	
void w25qxx_read(uint8_t *p_buffer, uint32_t read_addr, uint16_t num_read_bytes);

void w25qxx_write(uint8_t *p_buffer, uint32_t write_addr, uint16_t num_write_bytes);
void w25qxx_write_nocheck(uint8_t *p_buffer, uint32_t write_addr, uint16_t num_write_bytes);
void w25qxx_write_page(uint8_t *p_buffer, uint32_t write_addr, uint16_t num_write_bytes); 

void w25qxx_erase_sector(uint32_t sector_addr);
void w25qxx_erase_chip(void);

void w25qxx_write_enable(void);
void w25qxx_write_disable(void);

void w25qxx_power_down(void);
void w25qxx_wake_up(void);

void w25qxx_cs_enable(uint8_t cs_id);
void w25qxx_cs_disable(uint8_t cs_id);
uint8_t w25qxx_swap(uint8_t byte_to_send);


#endif

 w25qxx_spi.c

 

#include "w25qxx_spi.h"

/* w25Q的初始化 */
void w25qxx_init(void){
	soft_spi_init();
}

// 如果SR-1的BUSY位为1的话,一直等待,直到BUSY位为0,结束等待
// 判断是否在忙
void w25qxx_wait_busy(void){
	while((w25qxx_read_sr(W25QXX_SR_ID_1) & 0x01) == 0x01){
		;
	}
}

// 读状态寄存器
uint8_t w25qxx_read_sr(uint8_t sregister_id){
	uint8_t command, result;
	switch(sregister_id){
		case W25QXX_SR_ID_1:
			command = W25QXX_READ_STATUS_REGISTER_1;
		break;
		case W25QXX_SR_ID_2:
			command = W25QXX_READ_STATUS_REGISTER_2;
		break;
		case W25QXX_SR_ID_3:
			command = W25QXX_READ_STATUS_REGISTER_3;
		break;
		default:
			command = W25QXX_READ_STATUS_REGISTER_1;
		break;
	}
	
	w25qxx_cs_enable(W25QXX_ID_1);
	w25qxx_swap(command);
	result = w25qxx_swap(0xFF);
	w25qxx_cs_disable(W25QXX_ID_1);
	
	return result;
}

// 读flash的数据
// *p_buffer 读回的数据的存放位置
void w25qxx_read(uint8_t *p_buffer, uint32_t read_addr, uint16_t num_read_bytes){
	uint16_t i;
	
	w25qxx_cs_enable(W25QXX_ID_1);
	
	w25qxx_swap(W25QXX_READ_DATA); //发送读数据的指令
	w25qxx_swap(read_addr >> 16);  //发送24bit地址
	w25qxx_swap(read_addr >> 8);
	w25qxx_swap(read_addr);
	
	for(i=0; i < num_read_bytes; i++){
		p_buffer[i] = w25qxx_swap(0xFF);
	}
	
	w25qxx_cs_disable(W25QXX_ID_1);
}

// 
uint8_t W25QXX_Buffer[4096];  //用来存放从sector读出的bytes
void w25qxx_write(uint8_t *p_buffer, uint32_t write_addr, uint16_t num_write_bytes){
	uint32_t sec_num;
	uint16_t sec_remain;
	uint16_t sec_off;
	uint16_t i;
	
	sec_num	= write_addr / 4096;              //要写入的位置处在第sec_num个扇区上
	sec_off = write_addr % 4096;
	
	sec_remain = 4096 - sec_off;
	
	if(num_write_bytes <= sec_remain){
		w25qxx_read(W25QXX_Buffer, sec_num * 4096, 4096);  //扇区的数据读出来
		
		for(i = 0; i < sec_remain; i++){
			if(W25QXX_Buffer[i + sec_off] != 0xFF)  //说明这个扇区的第i+sec_off位没有擦除
				break;
		}
		
		if(i < sec_remain){ // 扇区没有擦除
			w25qxx_erase_sector(sec_num * 4096);
			for(i = 0; i < sec_remain; i++){
				W25QXX_Buffer[i + sec_off] = p_buffer[i];
			}
			w25qxx_write_nocheck(W25QXX_Buffer, sec_num * 4096, 4096);
		}else{              // 扇区sec_remain部分是擦除过的
			w25qxx_write_nocheck(p_buffer, write_addr, num_write_bytes);
		}
	}else{
		w25qxx_read(W25QXX_Buffer, sec_num * 4096, 4096);  //扇区的数据读出来
		
		for(i = 0; i < sec_remain; i++){
			if(W25QXX_Buffer[i + sec_off] != 0xFF)  //说明这个扇区的第i+sec_off位没有擦除
				break;
		}
		
		if(i < sec_remain){ // 扇区没有擦除
			w25qxx_erase_sector(sec_num * 4096);
			for(i = 0; i < sec_remain; i++){
				W25QXX_Buffer[i + sec_off] = p_buffer[i];
			}
			w25qxx_write_nocheck(W25QXX_Buffer, sec_num * 4096, 4096);
		}else{              // 扇区sec_remain部分是擦除过的
			w25qxx_write_nocheck(p_buffer, write_addr, sec_remain);
		}
		
		write_addr += sec_remain;
		p_buffer += sec_remain;
		num_write_bytes -= sec_remain;
		w25qxx_write(p_buffer, write_addr, num_write_bytes);
	}
		
	//判断读出来的数据是否都为0xFF
	//扇区是否删除
	//判断是否跨页
}

// 调用之前先确保扇区删除
void w25qxx_write_nocheck(uint8_t *p_buffer, uint32_t write_addr, uint16_t num_write_bytes){
	uint16_t page_remain = 256 - write_addr % 256;
	
	if(num_write_bytes <= page_remain){
		w25qxx_write_page(p_buffer, write_addr, num_write_bytes);
	}else{
		w25qxx_write_page(p_buffer, write_addr, page_remain);
		p_buffer += page_remain;
		write_addr += page_remain;
		num_write_bytes -= page_remain;
		w25qxx_write_nocheck(p_buffer, write_addr, num_write_bytes);
	}
}

// page program
// 保证没有跨页写的前提下调用此函数往某个页上写内容
void w25qxx_write_page(uint8_t *p_buffer, uint32_t write_addr, uint16_t num_write_bytes){
	uint16_t i;
	
	w25qxx_write_enable();
	
	w25qxx_cs_enable(W25QXX_ID_1);
	w25qxx_swap(W25QXX_PAGE_PROGRAM);
	w25qxx_swap(write_addr >> 16);  //发送24bit地址
	w25qxx_swap(write_addr >> 8);
	w25qxx_swap(write_addr);
	
	for(i = 0; i < num_write_bytes; i++){
		w25qxx_swap(p_buffer[i]);
	}
	w25qxx_cs_disable(W25QXX_ID_1);
	
	w25qxx_wait_busy();
}

/* 擦除一个扇区 */
void w25qxx_erase_sector(uint32_t sector_addr){
	w25qxx_write_enable();
	
	w25qxx_cs_enable(W25QXX_ID_1);
	w25qxx_swap(W25QXX_SECTOR_ERASE_4KB);
	w25qxx_swap(sector_addr >> 16);
	w25qxx_swap(sector_addr >> 8);
	w25qxx_swap(sector_addr);
	w25qxx_cs_disable(W25QXX_ID_1);
	
	w25qxx_wait_busy();
}

/* 擦除全部 */
void w25qxx_erase_chip(void){
	w25qxx_write_enable();
	
	w25qxx_cs_enable(W25QXX_ID_1);
	w25qxx_swap(W25QXX_CHIP_ERASE);
	w25qxx_cs_disable(W25QXX_ID_1);
	
	w25qxx_wait_busy();
}
/* 使能写保护 */
void w25qxx_write_enable(void){
	w25qxx_cs_enable(W25QXX_ID_1);
	w25qxx_swap(W25QXX_WRITE_ENABLE);
	w25qxx_cs_disable(W25QXX_ID_1);
}

/* 失能写保护 */
void w25qxx_write_disable(void){
	w25qxx_cs_enable(W25QXX_ID_1);
	w25qxx_swap(W25QXX_WRITE_DISABLE);
	w25qxx_cs_disable(W25QXX_ID_1);
}

// 低电量休眠
void w25qxx_power_down(void){
	w25qxx_cs_enable(W25QXX_ID_1);
	w25qxx_swap(W25QXX_POWER_DOWN);
	w25qxx_cs_disable(W25QXX_ID_1);
}

// 唤醒
void w25qxx_wake_up(void){
	w25qxx_cs_enable(W25QXX_ID_1);
	w25qxx_swap(W25QXX_RELEASE_POWER_DOWN_HPM_DEVICE_ID);
	w25qxx_cs_disable(W25QXX_ID_1);
}

/*
brief:使能片选引脚cs
cs_id: cs引脚的序号,即第几个w25qxx flash
*/
void w25qxx_cs_enable(uint8_t cs_id){
	switch(cs_id){
		case W25QXX_ID_1:
			soft_spi_begin();
		break;
		default:
			break;
	}
}

// brief:失能片选引脚cs
void w25qxx_cs_disable(uint8_t cs_id){
	switch(cs_id){
		case W25QXX_ID_1:
			soft_spi_end();
		break;
		default:
			break;
	}
}

/*
**** 交换数据
*/
uint8_t w25qxx_swap(uint8_t byte_to_send){
	return soft_spi_swap(byte_to_send);
}

 w25qxx_ins.h (w25Q32的指令集)

#ifndef _W25QXX_INS_H
#define _W25QXX_INS_H

#define W25QXX_WRITE_ENABLE							        0x06
#define W25QXX_WRITE_DISABLE						        0x04
#define W25QXX_READ_STATUS_REGISTER_1				        0x05
#define W25QXX_READ_STATUS_REGISTER_2				        0x35
#define W25QXX_READ_STATUS_REGISTER_3				        0x15
#define W25QXX_READ_DATA							        0x03
#define W25QXX_READ_UNIQUE_ID						        0x4B
#define W25QXX_WRITE_STATUS_REGISTER_1				        0x01
#define W25QXX_WRITE_STATUS_REGISTER_2                      0x31
#define W25QXX_WRITE_STATUS_REGISTER_3                      0x11 
#define W25QXX_PAGE_PROGRAM							        0x02
#define W25QXX_QUAD_PAGE_PROGRAM					        0x32
#define W25QXX_BLOCK_ERASE_64KB						        0xD8
#define W25QXX_BLOCK_ERASE_32KB						        0x52
#define W25QXX_SECTOR_ERASE_4KB						        0x20
#define W25QXX_CHIP_ERASE							        0xC7
#define W25QXX_ERASE_SUSPEND						        0x75
#define W25QXX_ERASE_RESUME							        0x7A
#define W25QXX_POWER_DOWN							        0xB9
#define W25QXX_HIGH_PERFORMANCE_MODE				        0xA3
#define W25QXX_CONTINUOUS_READ_MODE_RESET			        0xFF
#define W25QXX_RELEASE_POWER_DOWN_HPM_DEVICE_ID             0xAB
#define W25QXX_MANUFACTURER_DEVICE_ID				        0x90
#define W25QXX_JEDEC_ID								        0x9F
#define W25QXX_FAST_READ							        0x0B
#define W25QXX_FAST_READ_DUAL_OUTPUT				        0x3B
#define W25QXX_FAST_READ_DUAL_IO					        0xBB
#define W25QXX_FAST_READ_QUAD_OUTPUT				        0x6B
#define W25QXX_FAST_READ_QUAD_IO					        0xEB
#define W25QXX_OCTAL_WORD_READ_QUAD_IO				        0xE3
#define W25QXX_DUMMY_BYTE							        0xFF

#endif

 对于w25Q3的写操作是比较复杂的。比如要考虑写的大小是否大于一页.以及在写之前要判断是否擦除。因为要先擦除才能写入。

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

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

相关文章

【Unity3D编辑器开发】Unity3D编辑器开发基础性框架结构【全面总结】

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 嗨&#xff0c;大家好&#xff0c;我是恬静的小魔龙。 同学们…

open62541学习:文件传输

作为一种通信协议&#xff0c;文件传输是非常重要的。例如传输执行程序&#xff0c;图片&#xff0c;配置文件等等。文件传输的机制和类型在 OPC UA 中已经存在很长时间了。FileType &#xff08;作为ObjectType&#xff09;和ImageType长期以来一直是内置模型的一部分&#xf…

Linux:TCP三握四挥简析

文章目录 1. 前言2. 背景3. TCP连接的建立和断开3.1 TCP协议状态机3.2 TCP的三握四挥3.2.1 TCP 连接建立的三次握手过程分析3.2.1.1 服务端和客户端套接字的创建3.2.1.2 服务端进入 LISTEN 状态3.2.1.3 服务端在 LISTEN 状态等待客户端的 SYN 请求3.2.1.4 客户端向服务端发送 S…

【云笔记篇】Microsoft OneNote笔记分区数据删除方法

【云笔记篇】Microsoft OneNote笔记分区数据删除方法 Microsoft OneNote删除分区数据需要在网页端操作才能彻底删除—【蘇小沐】 1、实验 系统版本Windows 11 专业工作站版22H2&#xff08;22621.1485&#xff09;&#xff1b;OneNoteOneNote 2016(版本 2303 Build 16.0.162…

香橙派Zero3安装miniconda3(问题多多,已全部解决)

文章目录 前言一、miniconda3版本二、使用步骤1.安装2.添加环境变量3.更新源4.创建新环境 总结另外 前言 你会遇到很多问题&#xff0c;按照我说的基本没问题。 香橙派是zero3。 一、miniconda3版本 Miniconda3-py37_4.9.2-Linux-aarch64.sh这个版本是测试没问题的&#xff0…

HDLbits : Module addsub

module top_module(input [31:0] a,input [31:0] b,input sub,output [31:0] sum );wire w1;add16 add16_1(a[15:0],b[15:0]^{16{sub}},sub,sum[15:0],w1);add16 add16_2(a[31:16],b[31:16]^{16{sub}},w1,sum[31:16],);endmodule 注意&#xff1a;sub位扩展

latex方程组编写,一种可以保证方程编号自适应的方法

问题描述&#xff1a; 在利用latex编写方程组时&#xff0c;可以有很多种方法&#xff0c;但不总是编辑好的公式能够显示出编号&#xff0c;故提出一种有效的方程组编写方法 方法&#xff1a; \begin{equation}X_{ t1}\left \{ \begin{matrix}\frac{x_{i}}{a} \quad\quad 0&l…

数学建模预测模型MATLAB代码大合集及皮尔逊相关性分析(无需调试、开源)

已知2010-2020数据&#xff0c;预测2021-2060数据 一、Logistic预测人口 %%logistic预测2021-2060年结果 clear;clc; X[7869.34, 8022.99, 8119.81, 8192.44, 8281.09, 8315.11, 8381.47, 8423.50, 8446.19, 8469.09, 8477.26]; nlength(X)-1; for t1:nZ(t)(X(t1)-X(t))/X(t1…

redis高可用(主从复制,哨兵,集群)

目录 一、主从复制&#xff1a; 1.主从复制介绍&#xff1a; 2.主从复制的作用&#xff1a; 3.主从复制流程&#xff1a; 4.搭建Redis 主从复制&#xff1a; 4.1 环境准备&#xff1a; 4.2 安装redis&#xff1a; 4.3 master节点修改 Redis 配置文件&#xff1a; 4.4 slave节点…

判断三条边是否构成三角形(Python实现)

组成三角形的三条边a,b,c需满足条件: ab>c ac>b bc>a 已知&#xff1a;三角形任意三条边的长度之和大于第三条边。 解题&#xff1a;定义3个变量a、b、c&#xff0c;让用户输入任意三个数字赋值给三个变量。判断三个变量中是否任意两个之和大于第三个数值。 判断条件之…

Docker快速搭建漏洞靶场指南

user: admin passwrod&#xff1a;password 查看容器是否已开启&#xff1a; 最常见漏洞&#xff1a; 防护级别提高后&#xff1a; 更改防护级别&#xff1a; 复现vulhub漏洞靶场&#xff1a; 开启&#xff1a; 一个是漏洞类型一个是真实的漏洞靶场。

VS的调式技巧你真的掌握了吗?

目录 什么是bug? 调式是什么&#xff1f;有多重要&#xff1f; 调试是什么&#xff1f; 调试的基本步骤 debug和release的介绍 windows环境调试介绍 1.调试环境的准备 2.学会快捷键 F11 VS F10 F9 & F5 3.调试时查看程序当前信息 查看临时变量的值 查看内存信…

LLMs: 近端策略优化PPO Proximal policy optimization

Dr. Ehsan Kamalinejad&#xff0c;通常简称为EK&#xff0c;是一位机器学习应用科学家。他目前是亚马逊NLP开发中的精英科学家。以前&#xff0c;他共同创办了Visual One&#xff0c;一家Y Combinator计算机视觉初创公司。在此之前&#xff0c;他曾担任苹果的首席机器学习工程…

WPS/word 表格跨行如何续表、和表的名称

1&#xff1a;具体操作&#xff1a; 将光标定位在跨页部分的第一行任意位置&#xff0c;按下快捷键ctrlshiftenter&#xff0c;就可以在跨页的表格上方插入空行&#xff08;在空行可以写&#xff0c;表1-3 xxxx&#xff08;续&#xff09;&#xff09; 在空行中输入…

NUWA论文阅读

论文链接&#xff1a;NUWA: Visual Synthesis Pre-training for Neural visUal World creAtion 文章目录 摘要引言相关工作视觉自回归模型视觉稀疏自注意 方法3D数据表征3D Nearby Self-Attention3D编码器-解码器训练目标 实验实现细节与SOTA比较T2I微调T2V微调V2V微调Sketch-t…

高效的ProtoBuf

一、背景 Google ProtoBuf介绍 这篇文章我们讲了怎么使用ProtoBuf进行序列化&#xff0c;但ProtoBuf怎么做到最高效的&#xff0c;它的数据又是如何压缩的&#xff0c;下面先看一个例子&#xff0c;然后再讲ProtoBuf压缩机制。 二、案例 网上有各种序列化方式性能对比&#…

elment以及elementPlus选中组件出现黑框问题解决!!

目录 问题&#xff1a; 图示&#xff1a; 解决方案&#xff1a; 问题&#xff1a; 使用elementPlus的按钮组件&#xff0c;点击按钮后会出现黑框&#xff0c;除非点击其他地方才能取消掉&#xff08;之前使用elment-ui其它组件时也出现过&#xff09; 图示&#xff1a; 解决方案…

2023网络安全工程师可以考哪些证书?只学习不考证怎么行呢?

想入网安行业的小可爱们&#xff0c;如果你在疯狂学习知识技能的同时&#xff0c;也计划着考取一些证书当做入门的金钥匙&#x1f511;。 先别急&#xff0c;如果还没有进入网络安全工作岗位&#xff0c;那么&#xff0c;首要任务是打好基础&#xff0c;学好网络安全技术。若是…

docker容器启动成功外部访问不到

1.重启docker服务 systemctl restart docker

9张图深入剖析ConcurrentHashMap

前言 在日常的开发中&#xff0c;我们经常使用key-value键值对的HashMap&#xff0c;其使用哈希表实现&#xff0c;用空间换取时间&#xff0c;提升查询性能 但在多线程的并发场景中&#xff0c;HashMap并不是线程安全的 如果想使用线程安全的&#xff0c;可以使用Concurren…