STC进阶开发(四)SPI协议、矩阵键盘、EEPROM

前言

        这一期我们简单介绍一下SPI协议,然后我们学习一下矩阵键盘,了解EEPROM是干什么用的,话不多说,开整!

SPI协议

SPI(Serial Peripheral Interface)是一种同步串行通信协议,用于在嵌入式系统中连接微控制器(MCU)和外围设备(如传感器、存储器、显示器等)。SPI协议需要4根线进行数据传输,分别是:

  • SCLK:时钟信号线,由主设备控制时序,用于同步数据传输。
  • MOSI:主设备输出从设备输入线,主设备通过该线向从设备发送数据。
  • MISO:主设备输入从设备输出线,从设备通过该线向主设备发送数据。
  • SS:从设备片选线,用于选择与主设备通信的从设备。(其他叫法CS)

SPI协议支持全双工通信,意味着主设备和从设备可以同时发送和接收数据。SPI协议传输数据时采用的是先进先出的方式。

标准的SPI总共有4根线,包括:SCLK(时钟线)、MOSI(主机输出从机输入线)、MISO(主机输入从机输出线)和SS(片选线)。但是在实际的应用中,可能会根据需要添加其他的辅助信号线,如数据就绪信号等。因此,SPI的具体实现方式可能会有所不同。

SPI协议中的DC线是指数据/命令线(Data/Command line),有时也称作RS线(Register Select line)。它是用来控制从主设备到从设备传输的数据是命令还是普通数据的信号线。在许多液晶显示屏、OLED屏幕、触摸屏等设备中,SPI总线上的DC线通常用于指示传输的数据是图像数据还是命令数据,以便设备能够正确地解析和处理数据

SPI通讯的时序是由主设备(Master)发起的,在数据传输的过程中,需要进行时序的协调,具体流程如下:

  • 主设备(Master)通过片选信号(Slave Select)选择通信的从设备(Slave)。
  • 主设备(Master)向从设备(Slave)发送时钟信号(SCLK),并将数据从输出口(MOSI)发送到从设备(Slave)的输入口(MISO)。
  • 从设备(Slave)在每个时钟脉冲的下降沿采样输入口(MISO)的数据,并将数据从输出口(MOSI)发送回主设备(Master)的输入口(MISO)。
  • 当传输完成后,主设备(Master)取消片选信号(Slave Select),从设备(Slave)被释放。

具体的通讯流程时序可以根据实际应用情况进行调整,例如可以调整时钟信号的极性和相位、选择合适的时钟频率等。

矩阵键盘

简介

        矩阵键盘是一种常见的数字输入设备,由多行多列的按键组成。每个按键都有一个唯一的行列坐标,通过行列坐标可以确定按键的编号,从而实现对数字或字母的输入。

原理图

矩阵键盘的基本结构包括按键、行引脚和列引脚。按键一般是机械按键或触摸按键,行引脚和列引脚分别与矩阵键盘的行和列相连,用于检测按键的输入状态。

代码

因为矩阵按键和之前学的独立按键很相似,所以代码不做过多解析,基本注释都在代码上标明,我们直接通过位运算来设定中间值从而捕获到每个按键的状态。

获取按键状态
#include "GPIO.h"
#include "NVIC.h"
#include "Delay.h"
#include "UART.h"
#include "Switch.h"#define COL1 P03
#define COL2 P06
#define COL3 P07
#define COL4 P17#define ROW1 P34
#define ROW2 P35
#define ROW3 P40
#define ROW4 P41//判断按键的状态
#define IS_KEY_DOWN(row , col)  ((states & (1 << (row * 4 + col))) == 0)
#define IS_KEY_UP(row,col) ((states  & (1 << (row * 4 + col))) > 0)//设置按键的状态
#define SET_KEY_DOWN(row, col)   (states &= ~(1 << (row * 4 + col)))
#define SET_KEY_UP(row, col)  (states  |=  (1 << (row * 4 + col)))//按键的状态
#define DOWN 0
#define UP 1void GPIO_config(void) {GPIO_InitTypeDef	GPIO_InitStructure;		//结构定义GPIO_InitStructure.Pin  = GPIO_Pin_3 | GPIO_Pin_6 | GPIO_Pin_7;		//指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_PullUp;	//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P0, &GPIO_InitStructure);//初始化GPIO_InitStructure.Pin  =  GPIO_Pin_7;		//指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_PullUp;	//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P1, &GPIO_InitStructure);//初始化GPIO_InitStructure.Pin  =  GPIO_Pin_4  | GPIO_Pin_5;		//指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_PullUp;	//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P3, &GPIO_InitStructure);//初始化GPIO_InitStructure.Pin  =  GPIO_Pin_0  | GPIO_Pin_1;		//指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_PullUp;	//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P4, &GPIO_InitStructure);//初始化
}void UART_config(void) {// >>> 记得添加 NVIC.c, UART.c, UART_Isr.c <<<COMx_InitDefine		COMx_InitStructure;					//结构定义COMx_InitStructure.UART_Mode      = UART_8bit_BRTx;	//模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTxCOMx_InitStructure.UART_BRT_Use   = BRT_Timer1;			//选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)COMx_InitStructure.UART_BaudRate  = 115200ul;			//波特率, 一般 110 ~ 115200COMx_InitStructure.UART_RxEnable  = ENABLE;				//接收允许,   ENABLE或DISABLECOMx_InitStructure.BaudRateDouble = DISABLE;			//波特率加倍, ENABLE或DISABLEUART_Configuration(UART1, &COMx_InitStructure);		//初始化串口1 UART1,UART2,UART3,UART4NVIC_UART1_Init(ENABLE,Priority_1);		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3UART1_SW(UART1_SW_P30_P31);		// 引脚选择, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}u8 get_col(u8 i){if(i==0) return COL1;if(i==1) return COL2;if(i==2) return COL3;if(i==3) return COL4;return COL1;
}// 根据遍历的索引下标来拉低对应行的电平状态
void pull_row(u8 i){ROW1 = i == 0 ? 0 : 1;ROW2 = i == 1 ? 0 : 1;ROW3 = i == 2 ? 0 : 1;ROW4 = i == 3 ? 0 : 1;
}u16 states = 0xFFFF;  //1111 1111 1111 1111void main(){int i , j;EA = 1 ;GPIO_config();UART_config();printf("start...\n");while(1){// 判定4行的状态//外层循环控制的是:行for(i  = 0 ; i < 4 ; i++){// 每遍历一次,就拉低这一行对应的电平状态,拉高其他行的电平状态pull_row(i);//里层循环控制的是: 列for(j = 0 ; j < 4  ; j++){/*第1行:0-0 :  字节的 第 0 位   0-1 :  字节的 第 1 位0-2 :  字节的 第 2 位0-3 :  字节的 第 3 位第2行:1-0 :  字节的 第 4 位1-1 :  字节的 第 5 位1-2 :  字节的 第 6 位1-3 :  字节的 第 7 位第3行:2-0 :  字节的 第 8 位2-1 :  字节的 第 9 位2-2 :  字节的 第 10 位2-3 :  字节的 第 11 位第4行:3-0 :  字节的 第 12 位3-1 :  字节的 第 13 位3-2 :  字节的 第 14 位3-3 :  字节的 第 15 位所以i行j列的键,对应的 位是: i * 4 + j我们要去操作对应的键和位。*/if(get_col(j) == UP && IS_KEY_DOWN(i, j)){printf("%d-%d::弹起\n" , i+1 , j+1);SET_KEY_UP(i, j);}else if(get_col(j) == DOWN && IS_KEY_UP(i,j) ){printf("%d-%d::按下\n" , i+1 , j+1);SET_KEY_DOWN(i,j);}}}delay_ms(10);}
}
获取按键状态(通过extern封装)
main.c
#include "GPIO.h"
#include "NVIC.h"
#include "Delay.h"
#include "UART.h"
#include "Switch.h"
#include "MatrixKey.h"void UART_config(void) {// >>> 记得添加 NVIC.c, UART.c, UART_Isr.c <<<COMx_InitDefine		COMx_InitStructure;					//结构定义COMx_InitStructure.UART_Mode      = UART_8bit_BRTx;	//模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTxCOMx_InitStructure.UART_BRT_Use   = BRT_Timer1;			//选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)COMx_InitStructure.UART_BaudRate  = 115200ul;			//波特率, 一般 110 ~ 115200COMx_InitStructure.UART_RxEnable  = ENABLE;				//接收允许,   ENABLE或DISABLECOMx_InitStructure.BaudRateDouble = DISABLE;			//波特率加倍, ENABLE或DISABLEUART_Configuration(UART1, &COMx_InitStructure);		//初始化串口1 UART1,UART2,UART3,UART4NVIC_UART1_Init(ENABLE,Priority_1);		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3UART1_SW(UART1_SW_P30_P31);		// 引脚选择, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}void MK_keydown(u8 row , u8 col){printf("%d-%d  按键按下了..\n" , (int)row , (int)col);
}void MK_keyup(u8 row , u8 col){printf("%d-%d  按键弹起了..\n" , (int)row , (int)col);
}void main(){EA = 1 ;//初始化矩阵键盘MK_init();UART_config();printf("start...\n");while(1){//扫描键盘MK_scan();delay_ms(10);}
}
MatrixKey.h
#ifndef	__MATRIXKEY_H
#define	__MATRIXKEY_H#include "GPIO.h"// 声明: 宏、结构体
#define COL1 P03
#define COL2 P06
#define COL3 P07
#define COL4 P17#define ROW1 P34
#define ROW2 P35
#define ROW3 P40
#define ROW4 P41//判断按键的状态
#define IS_KEY_DOWN(row , col)  ((states & (1 << (row * 4 + col))) == 0)
#define IS_KEY_UP(row,col) ((states  & (1 << (row * 4 + col))) > 0)//设置按键的状态
#define SET_KEY_DOWN(row, col)   (states &= ~(1 << (row * 4 + col)))
#define SET_KEY_UP(row, col)  (states  |=  (1 << (row * 4 + col)))//按键的状态
#define DOWN 0
#define UP 1// 函数具体功能
void MK_init();//扫描按键的状态的函数
void MK_scan();//既然封装了按键的扫描功能,但是以后按键按下了,或者弹起了,用户有自己的想法
//它们需求千变万化,所以特地声明了两个extern 标记的函数,谁要是使用我们的这一套代码
//就需要在自己的代码里面实现|定义这两个函数,这样就可以捕捉到是按下了按键还是弹起了按键。
//就可以针对性的去处理了。
extern void MK_keydown(u8 row , u8 col);extern void MK_keyup(u8 row , u8 col);#endif
MatrixKey.c
#include "MatrixKey.h"u16 states = 0xFFFF;  //1111 1111 1111 1111void MK_init(){GPIO_InitTypeDef	GPIO_InitStructure;		//结构定义GPIO_InitStructure.Pin  = GPIO_Pin_3 | GPIO_Pin_6 | GPIO_Pin_7;		//指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_PullUp;	//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P0, &GPIO_InitStructure);//初始化GPIO_InitStructure.Pin  =  GPIO_Pin_7;		//指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_PullUp;	//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P1, &GPIO_InitStructure);//初始化GPIO_InitStructure.Pin  =  GPIO_Pin_4  | GPIO_Pin_5;		//指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_PullUp;	//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P3, &GPIO_InitStructure);//初始化GPIO_InitStructure.Pin  =  GPIO_Pin_0  | GPIO_Pin_1;		//指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_PullUp;	//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P4, &GPIO_InitStructure);//初始化
}u8 get_col(u8 i){if(i==0) return COL1;if(i==1) return COL2;if(i==2) return COL3;if(i==3) return COL4;return COL1;
}// 根据遍历的索引下标来拉低对应行的电平状态
void pull_row(u8 i){ROW1 = i == 0 ? 0 : 1;ROW2 = i == 1 ? 0 : 1;ROW3 = i == 2 ? 0 : 1;ROW4 = i == 3 ? 0 : 1;
}void MK_scan(){u8 i , j;// 判定4行的状态//外层循环控制的是:行for(i  = 0 ; i < 4 ; i++){// 每遍历一次,就拉低这一行对应的电平状态,拉高其他行的电平状态pull_row(i);//里层循环控制的是: 列for(j = 0 ; j < 4  ; j++){if(get_col(j) == UP && IS_KEY_DOWN(i, j)){SET_KEY_UP(i, j);MK_keyup(i, j);}else if(get_col(j) == DOWN && IS_KEY_UP(i,j) ){SET_KEY_DOWN(i,j);MK_keydown(i ,j);}}}
}
获取按键状态(通过函数指针封装)
main.c
#include "Delay.h"
#include "NVIC.h"
#include "GPIO.h"
#include "UART.h"
#include "Switch.h"
#include "MKkey.h"void UART_config(void) {// >>> 记得添加 NVIC.c, UART.c, UART_Isr.c <<<COMx_InitDefine		COMx_InitStructure;					//结构定义COMx_InitStructure.UART_Mode      = UART_8bit_BRTx;	//模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTxCOMx_InitStructure.UART_BRT_Use   = BRT_Timer1;			//选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)COMx_InitStructure.UART_BaudRate  = 115200ul;			//波特率, 一般 110 ~ 115200COMx_InitStructure.UART_RxEnable  = ENABLE;				//接收允许,   ENABLE或DISABLECOMx_InitStructure.BaudRateDouble = DISABLE;			//波特率加倍, ENABLE或DISABLEUART_Configuration(UART1, &COMx_InitStructure);		//初始化串口1 UART1,UART2,UART3,UART4NVIC_UART1_Init(ENABLE,Priority_1);		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3UART1_SW(UART1_SW_P30_P31);		// 引脚选择, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}void keydown(u8 row,u8 col){printf("%d-%d:按下\n",(int)row+1,(int)col+1);
}void keyup(u8 row,u8 col){printf("%d-%d:弹起\n",(int)row+1,(int)col+1);
}void main(){EA = 1;KEY_init();UART_config();while(1){MK_GET_key(keydown,keyup);delay_ms(10);}
}
MKkey.h
#ifndef	__MKkey_H
#define	__MKkey_H#include "GPIO.h"#define COL1 P03
#define COL2 P06
#define COL3 P07
#define COL4 P17#define ROW1 P34
#define ROW2 P35
#define ROW3 P40
#define ROW4 P41#define IS_KEY_DOWN(row,col) ((states & (1<<(row * 4 + col))) == 0)
#define IS_KEY_UP(row,col) ((states & (1<<(row * 4 + col))) > 0)
#define SET_KEY_DOWN(row,col) (states &= ~((1<<(row * 4 + col))))
#define SET_KEY_UP(row,col) (states |= (1<<(row * 4 + col)))
#define DOWN 0
#define UP 1void KEY_init();void MK_GET_key(void(*keydown)(u8 row,u8 col),void(*keyup)(u8 row,u8 col));#endif
MKkey.c
#include "MKkey.h"u16 states = 0xffff;void KEY_init(){GPIO_InitTypeDef	GPIO_InitStructure;		//结构定义GPIO_InitStructure.Pin  = GPIO_Pin_3 | GPIO_Pin_6 | GPIO_Pin_7;		//指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_PullUp;	//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P0, &GPIO_InitStructure);//初始化GPIO_InitStructure.Pin  = GPIO_Pin_7;		//指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_PullUp;	//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P1, &GPIO_InitStructure);//初始化GPIO_InitStructure.Pin  = GPIO_Pin_4 | GPIO_Pin_5;		//指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_PullUp;	//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P3, &GPIO_InitStructure);//初始化GPIO_InitStructure.Pin  = GPIO_Pin_0 | GPIO_Pin_1;		//指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_PullUp;	//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P4, &GPIO_InitStructure);//初始化
}u8 get_key(u8 i){if(i==0) return COL1;if(i==1) return COL2;if(i==2) return COL3;if(i==3) return COL4;return COL1;}void key_down(u8 i){ROW1 = i == 0 ? 0 : 1;ROW2 = i == 1 ? 0 : 1;ROW3 = i == 2 ? 0 : 1;ROW4 = i == 3 ? 0 : 1;
}void MK_GET_key(void(*keydown)(u8 row,u8 col),void(*keyup)(u8 row,u8 col)){int i,j;for(i=0;i<4;i++){key_down(i);for(j=0;j<4;j++){if(get_key(j) == UP && IS_KEY_DOWN(i,j)){SET_KEY_UP(i,j);if(keyup!=NULL){keyup(i,j);}}else if(get_key(j) == DOWN && IS_KEY_UP(i,j)){SET_KEY_DOWN(i,j);if(keydown!=NULL){keydown(i,j);}}}}
}

EEPROM

简介

        EEPROM是一种可擦写可编程只读存储器(Electrically Erasable Programmable Read-Only Memory)的缩写。它是一种非易失性存储器,可以在不需要外部电源的情况下保持存储数据。与ROM不同,EEPROM可以通过电子擦除和编程来修改存储的数据,因此它是一种可重写的存储器。

        EEPROM通常用于存储需要频繁修改的数据,例如系统配置信息、用户设置、校准数据等。由于EEPROM可以在系统运行时进行读写操作,因此它在许多应用中都具有很高的实用价值。

设置EEPROM

TC8H8K64U的EEPROM可以在烧录的时候指定大小, 如下图

代码

#include "Delay.h"
#include "NVIC.h"
#include "UART.h"
#include "Switch.h"
#include "EEPROM.h"
#include "string.h"void UART_config(void) {// >>> 记得添加 NVIC.c, UART.c, UART_Isr.c <<<COMx_InitDefine		COMx_InitStructure;					//结构定义COMx_InitStructure.UART_Mode      = UART_8bit_BRTx;	//模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTxCOMx_InitStructure.UART_BRT_Use   = BRT_Timer1;			//选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)COMx_InitStructure.UART_BaudRate  = 115200ul;			//波特率, 一般 110 ~ 115200COMx_InitStructure.UART_RxEnable  = ENABLE;				//接收允许,   ENABLE或DISABLECOMx_InitStructure.BaudRateDouble = DISABLE;			//波特率加倍, ENABLE或DISABLEUART_Configuration(UART1, &COMx_InitStructure);		//初始化串口1 UART1,UART2,UART3,UART4NVIC_UART1_Init(ENABLE,Priority_1);		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3UART1_SW(UART1_SW_P30_P31);		// 引脚选择, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}u16 EE_address = 0x0000;
xdata	char  str2[100];void main(){char *  str = "helloworld";u16 len  =  strlen(str);EA = 1 ;UART_config();//=============================操作EEPROM==========================//1. 擦除EPPROM :: 擦除的起始地址EEPROM_SectorErase(EE_address);//2. 写数据参数一: 写入的起始地址 ,参数二: 写什么数据,参数三,写多少个长度EEPROM_write_n(EE_address,str,len);//3. 读数据参数一: 读取的起始地址 ,参数二: 读取到哪里,参数三,读多少个长度EEPROM_read_n(EE_address,str2,len);//因为使用的字符数组来接收数据,它的长度很长,我们需要去设置字符的截止符号str2[len] = '\0';printf("str2=%s\n" , str2);while(1){}
}

总结

        今天内容比较容易,但是小伙伴们也一定要多加练习,在验证eeprom时,可以通过以上代码将数据写入进去,然后进行断电重新上电,直接进行读的操作,就会发现我们之前写上的数据仍然可以读取出来,说明数据被我们写里面存储啦。下期再见!

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

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

相关文章

rtsp解析视频流

这里先说一下 播放rtsp 视频流&#xff0c;尽量让后端转换一下其他格式的流进行播放。因为rtsp的流需要flash支持&#xff0c;现在很多浏览器不支持flash。 先说一下这里我没有用video-player插件&#xff0c;因为它需要用flash ,在一个是我下载flash后&#xff0c;还是无法播放…

Pytorch的GPU版本安装,在安装anaconda的前提下安装pytorch

本文基于conda安装GPU版本的PyTorch 一、CUDA 1.下载CUDA 点击下载 找到对应的版本进行下载 &#xff08;1&#xff09;打开命令提示符查看自己的版本&#xff0c;输入 nvidia-smi 根据自己的版本进行下载 &#xff08;2&#xff09;点击适合自己的版本进行下载 &#…

【MLOps】使用Ray缩放AI

Ray正在人工智能工程领域崭露头角&#xff0c;对扩展LLM和RL至关重要 Spark在数据工程中几乎是必不可少的。Ray正在人工智能工程领域崭露头角。 雷是伦敦大学学院Spark的继任者。Spark和Ray有很多相似之处&#xff0c;例如用于计算的统一引擎。但Spark主要专注于大规模数据分析…

【Python机器学习】k近邻——模型复杂度与泛化能力的关系

以某数据进行研究&#xff0c;先将数据集分为训练集和测试集&#xff0c;然后用不同的邻居数对训练集合测试集的新能进行评估&#xff1a; from sklearn.datasets import load_breast_cancer from sklearn.model_selection import train_test_split from sklearn.neighbors imp…

go执行静态二进制文件和执行动态库文件

目的和需求&#xff1a;部分go的核心文件不开源&#xff0c;例如验证&#xff0c;主程序核心逻辑等等 第一个想法&#xff0c;把子程序代码打包成静态文件&#xff0c;然后主程序执行 子程序 package mainimport ("fmt""github.com/gogf/gf/v2/os/gfile"…

ReCAPTCHA 解决方案的自动识别和解决方法

ReCAPTCHA&#xff0c;作为广泛使用的安全措施&#xff0c;旨在区分人类和自动化机器人。然而&#xff0c;技术的进步导致了自动识别和解决 ReCAPTCHA 挑战的方法的发展。在本文中&#xff0c;我们将探讨自动 ReCAPTCHA 识别和解决技术的概念&#xff0c;以及创新解决方案 Caps…

Yapi部署指南:在 Linux 上 Yapi 教程

YApi YApi 是高效、易用、功能强大的 api 管理平台&#xff0c;旨在为开发、产品、测试人员提供更优雅的接口管理服务。可以帮助开发者轻松创建、发布、维护 API&#xff0c;YApi 还为用户提供了优秀的交互体验&#xff0c;开发人员只需利用平台提供的接口数据写入工具以及简单…

题目:最大数组和(蓝桥OJ 3260)

问题描述&#xff1a; 解题思路&#xff1a; 官方&#xff1a; 总结&#xff1a;使用模拟。排序数组&#xff0c;枚举删除最大个数并推出其删除最小个数 &#xff0c;即可枚举出每一种可能的区间和&#xff0c;依次比较找最大区间和&#xff08;使用前缀和求区间和O(1)…

MySQL数据管理(一)

一、列类型 列类型指规定数据库中该列存放的数据类型 列类型分类 数值类型字符串类型日期和时间型数值类型 数值类型 字符串类型 日期和时间类型 MySQL允许“不严格”语法&#xff0c;任何标点符号都可以作为日期部分之间的间隔符&#xff0c;如“24-01-03”、“24.01.03”…

SSM建材商城网站----计算机毕业设计

项目介绍 本项目分为前后台&#xff0c;前台为普通用户登录&#xff0c;后台为管理员登录&#xff1b; 管理员角色包含以下功能&#xff1a; 管理员登录,管理员管理,注册用户管理,新闻公告管理,建材类型管理,配货点管理,建材商品管理,建材订单管理,建材评价管理等功能。 用…

VCoder:大语言模型的眼睛

简介 VCoder的一个视觉编码器&#xff0c;能够帮助MLLM更好地理解和分析图像内容。提高模型在识别图像中的对象、理解图像场景方面的能力。它可以帮助模型显示图片中不同物体的轮廓或深度图&#xff08;显示物体距离相机的远近&#xff09;。还能更准确的理解图片中的物体是什…

C#如何将本地文件上传至阿里云OSS中

要想将文件上传至OSS&#xff0c;那么阿里云的AccessKeyId和AccessKeySecret必不可少 一.去哪找AccessKeyId和AccessKeySecret 进入阿里云工作台&#xff0c;点击右上角头像&#xff0c;选择AccessKey管理&#xff0c;就能看到ID了 但是Secret目前阿里云不支持查看了&#xf…

labelme读取文件顺序

labelme版本4.5.10 labelme的目录结构 labelme通过在__main__.py中调用app.py&#xff0c;启动程序读取文件列表的部分在app.py的imageList函数中 def imageList(self):lst []for i in range(self.fileListWidget.count()):item self.fileListWidget.item(i)lst.append(ite…

应用系统如何集成和扩展开源工作流引擎

目前主流的开源流程引擎有activiti、flowable、camunda等&#xff0c;这几个开源流程引擎的版本很多&#xff0c;哪个开源流程引擎哪个版本的功能更多、性能更好&#xff0c;该如何选择请参考&#xff1a;https://lowcode.blog.csdn.net/article/details/116405594 无论您选择…

AR技术改变汽车行业,AR看车、AR车书、AR售后维修震撼登场!

引言&#xff1a; 随着中国汽车市场步入存量发展阶段&#xff0c;车企正迎来新的机遇和挑战。这一发展意味着庞大的汽车后市场需求&#xff0c;同时也要求企业和经销商能够快速响应市场需求&#xff0c;提供高质量的服务。而培养具备全面技能的成熟售后服务人员需要企业投入大…

HubSpot电子邮件:数字化时代的营销利器

在当今数字化时代&#xff0c;电子邮件仍然是企业与客户之间沟通的重要手段之一。而HubSpot电子邮件作为HubSpot全方位解决方案的一部分&#xff0c;不仅简化了营销流程&#xff0c;更为企业提供了强大的工具&#xff0c;助力建立更紧密的客户关系。本文将深入探讨HubSpot电子邮…

深度学习在工地安全帽识别技术的应用与展望

当我们谈论“工地安全帽识别”时&#xff0c;实际上我们在探讨的是如何利用深度学习图像识别技术来提高建筑工地的安全性。这一技术的应用可以显著提高工地安全管理的效率和有效性&#xff0c;是现代建筑工程管理中不可或缺的一部分。以测评的北京富维图像的工地安全帽识别为例…

小兔鲜儿 uniapp - SKU 模块

目录 存货单位&#xff08;SKU&#xff09;​ 插件市场​ 下载 SKU 插件​ 使用 SKU 插件​ 插件类型问题​ 核心业务​ 渲染商品规格​ 打开弹窗交互​ 渲染被选中的值​ 存货单位&#xff08;SKU&#xff09;​ SKU 概念 存货单位&#xff08;Stock Keeping Unit&a…

BUUCTF--gyctf_2020_borrowstack1

这是一题栈迁移的题目&#xff0c;先看看保护&#xff1a; 黑盒测试&#xff1a; 用户可输入两次内容&#xff0c;接着看看IDA中具体程序流程&#xff1a; 我们看到溢出内容只有0x10的空间给我们布局&#xff0c;这显然是不足以我们布置rop的。因此肯定就是栈迁移了。迁到什么地…

Vue3地图选点组件

Vue3地图选点组件 <template><div style"width: 100%; height: 500px"><div class"search-container"><el-autocompletev-model"suggestionKeyWord"class"search-container__input"clearable:fetch-suggestion…