W25Qxx------------(硬件SPI)

一、软件SPI和硬件SPI的区别

🍏软件SPI:用IO模拟SPI时序,这个模拟过程全部是CPU在负责执行,为了其稳定的存取数据,你可能会插入软件延时,这个时间在读取数据量不大的情况下并不明显,但是基本上你在读取过程中,其他非中断非异常程序是无法得到执行。


🍎硬件SPI:首先这个数据存道储的过程是不需要CPU参与得,程序中配置好SPI的访问时序,开启中断,CPU就可以在中断函数中搬移数据,省下了软件模拟IO得存取时间。
仔细研究就会发现,CPU在进行SPI中断服务程序还版是需要耽误时间得,这个过程在大数据量传输中还是很耗时,

        ARM中Cortex-M3内核得处理器在硬件SPI上加入了DMA,这个DMA直接从SPI的数据寄存器,软件配置好DMA之后,基本上整个传输都不要权CPU参与,软件设计得好的话,整个数据传输都不要CPU参与,此时CPU就可以做更多其他有意义的事了。

🀄上文介绍过软件SPI的收发,这次来看下硬件SPI的收发 

这个是字节的发送和读取,所以不需要像软件SPI那样循环发送8个位

//SPIx 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
u8 SPI1_ReadWriteByte(u8 TxData)
{		
	u8 retry=0;				 	
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
		{
		retry++;
		if(retry>200)return 0;
		}			  
	SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个数据
	retry=0;

	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET) //检查指定的SPI标志位设置与否:接受缓存非空标志位
		{
		retry++;
		if(retry>200)return 0;
		}	  						    
	return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据					    
}

二、 W25Q64简介

🍉   W25Q64(64Mbit)是为系统提供一个最小的空间、引脚和功耗的存储器解决方案的串行FLASH存储器。25Q系列比普通的串行FLASH存储器更灵活,性能更优越。基于双倍/四倍的SPI,它们能够可以立即完成提供数据给RAM,包括声音、文本和数据。

🍇     W25Q64由每页256字节组成,每页的256字节用一次页编程指令即可完成。每次可以擦除16页(一个扇区),128页(32KB块),256页(64KB块)和全片擦除。

 🍓    W25Q64的内存空间结构:一页256字节,4k(4096字节)为一个扇区,16个扇区为一块,总容量为8M字节,共有128个块即2048个扇区。SPI最高支持80MHZ,当使用快读双倍/四倍指令时,相当于双倍输出时最高速率160MHZ,四倍输出时最高速率320MHZ。

 

🔔特点:

  • 标准、双倍和四倍SPI​​​​​​
  • 高性能串行FLASH存储器
  • 灵活的4KB扇区结构

       统一的扇区擦除和块擦除, 一次编程256字节,至少100000写/擦除周期,数据保存20年。

  • 高级的安全特点
  • 低功耗、宽温度范围

        单电源2.7~3.6V,工作电流4mA,-40℃~85℃工作。

💢封装 

 🌀引脚描述 

引脚编号引脚名称I/O功能
1/CSI片选端输入
2DO(IO1)I/O数据输出
3/WP(IO2)I/O写保护输入
4GND
5DI(IO0)I/O数据输入
6CLKI串行时钟输入
7/HOLD(IO3)I/O保持端输入
8VCC电源

1.1 片选端(/CS)

        SPI片选(/CS)引脚使能和禁止芯片操作。当/CS为高电平时,芯片未被选择,串行数据输出(IOx)引脚为高阻态,芯片处于待机状态下的低功耗,除非芯片内部在擦除。当/CS变成低电平,芯片功耗将增长到正常工作,能够从芯片上读写数据。上电后,在接收新的指令前,/CS必须由高电平变成低电平。

1.2 串行数据输入输出(DI、DO)

       标准的 SPI 传输用单向的 DI(输入)引脚连续的写命令、地址或者数据在串行时钟(CLK)的上升沿时写入到芯片内。标准的SPI 用单向的 DO(输出)在 CLK 的下降沿从芯片内读出数据或状态。

1.3 写保护(/WP)

        写保护引脚(/WP)用来保护状态寄存器。和状态寄存器的块保护位(SEC、TB、BP2、BP1 和BP0)和状态寄存器保护位(SRP)对存储器进行一部分或者全部的硬件保护。/WP 引脚低电平有效。当状态寄存器 2 的 QE 位被置位了,/WP 引脚(硬件写保护)的功能不可用,被用作了 IO2。

1.4 保持端(/HOLD)

        当/HOLD 引脚是有效时,允许芯片暂停工作。在/CS 为低电平时,当/HOLD 变为低电平,DO 引脚将变为高阻态,在 DI 和 CLK 引脚上的信号将无效。当/HOLD 变为高电平,芯片恢复工作。/HOLD功能用在当有多个设备共享同一 SPI 总线时。/HOLD 引脚低电平有效。当状态寄存器 2 的 QE 位被置位了,/ HOLD 引脚的功能不可用,被用作了 IO3。

1.5 串行时钟(CLK)

        串行时钟输入引脚为串行输入和输出操作提供时序。设备数据传输是从高位开始,数据传输的格式为 8bit,数据采样从上升沿开始。

 1.6  结构框图

三、SPI 通信

有关SPI的介绍已经在上两篇文章介绍了,我这就不说了,直接上配置代码

1.配置SPI初始化

  • IO,SPI结构体变量定义
  • 使能IO、SPI时钟
  • 映射SPI引脚,CS不用
  • IO参数配置,初始化
  • SPI参数配置,初始化
  • SPI使能
  • 拉高CS
/*******************************************
*@函数名    : W25Q64_Init
*@函数功能  : W25Q64初始化---SPI1
*@函数参数  :  None
*@Data    2023-09-11
*@函数返回值: None
*@函数描述  : PA4--CS  PA5--SCK  PA6--MISO  PA7--MOSI
*********************************************/
void W25Q64_Init(void)
{
	//结构体变量创建
	GPIO_InitTypeDef GPIO_InitStructure;
	SPI_InitTypeDef SPI_InitStructure;
	//使能GPIO时钟
	RCC_AHB1PeriphClockLPModeCmd(RCC_AHB1Periph_GPIOA,ENABLE);
	//使能SPI时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
	//映射SPI1引脚 PA7   PA5   PA6
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_SPI1);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_SPI1);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_SPI1);
	//GPIO参数配置--配置 SPI引脚: SCK、MISO、MOSI
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;       //复用模式
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;     //推挽输出
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5 | GPIO_Pin_6 |GPIO_Pin_7;
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;       //上拉
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	//CS 片选---PC7
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;		//普通模式
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;	//推挽输出
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;		//上拉
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
	GPIO_Init(GPIOC,&GPIO_InitStructure);
	W25Q64_CS_HIGH;                                 // CS引脚拉高:停止信号 
	//SPI1参数配置
	SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_2;//波特率预分频值
	SPI_InitStructure.SPI_CPHA=SPI_CPHA_2Edge;//串行时钟进行偶次采样
	SPI_InitStructure.SPI_CPOL=SPI_CPOL_High;//时钟空闲为高电平---模式3-上升沿采集数据
	SPI_InitStructure.SPI_CRCPolynomial=7;//CRC值计算多项式--7--复位值
	SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;//SPI双向全双工
	SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;//8位数据帧
	SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;//数据高位在前
	SPI_InitStructure.SPI_Mode=SPI_Mode_Master;// 主从模式:  1 = 主配置
	SPI_InitStructure.SPI_NSS=SPI_NSS_Soft; // 软件从器件管理 :  1 = 使能软件从器件管理(软件NSS)
	SPI_Init(SPI1,&SPI_InitStructure);
	SPI_Cmd(SPI1,ENABLE);// SPI使能  1 = 使能外设
	
	readID();//读取芯片
}

2.读写数据

通过接收完成和发送完成两个标志位实现一个字节的发送

*******************************************
*@函数名    : sendByte
*@函数功能  : 发送1字节,返回1字节
*@函数参数  :  data: 数据
*@Data    2023-09-11
*@函数返回值: 返回接收到的字节
*@函数描述  : SPI通信,只一个动作:向DR写入从设命令值,同步读出数据!
写读组合,按从设时序图来. 作为主设,因为收发同步,连接收发送中断也不用开,
*********************************************/
uint8_t sendByte(uint8_t data)
{
    uint16_t retry = 0;

    while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET)      // 等待发送区为空
    {
        retry++;
        if (retry > 1000)    return 0;
    }
    SPI_I2S_SendData(SPI1,data);

    retry = 0;
    while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) == RESET)//等待接收缓存区非空
    {
        retry++;
        if (retry > 1000)    return 0;
    }
    return SPI_I2S_ReceiveData(SPI1);
}

 W25Q的指令

👉写使能:0x06

👉禁使能:0x04

👉读状态寄存器指令:0x05

       1.CS片选拉低发送指令,CS片选拉高结束读指令结束

2.读状态寄存器指令任何时候都能用

3.高位数据在前,先发送指令,再读取数据

4.时钟有主控控制,读取数据同时,要发送任意得数据给从机。

👉写状态寄存器指令:0x01

  1. CS片选拉低发送指令,CS片选拉高结束写指令结束,片选拉晚或者没有拉高,写入的值将无效
  2. 先写使能(0x06)
  3. 只有SRP TB BP2 BP1 BP0 可以被写入
  4. TB BP2 BP1 BP0写1的时候只能读,写0才能对块区进行操作

👉读数据命令:0x03

  1. CS片选拉低发送指令,CS片选拉高结束读指令结束
  2. 先发送0x03指令,后面跟24位的起始数据地址
  3. 只要片选不拉高,就会一直去读取芯片的数据,指导整个芯片数据读取完成

页编程指令:0x02  256字节

  1. CS片选拉低发送指令,CS片选拉高结束读指令结束
  2. 先写使能(0x02)
  3. 写入之前先把写入的扇区擦除,擦除写0xff
  1. 先发送0x02指令,后面跟24位的起始数据地址
  2. 注意不要超出一个页的范围(256)个字节,除非写完一个页后把地址改为0
  3. 页写指令不能跨页,所以写数据地址要保持256的倍数

👉扇区擦除指令:0x20  擦除4K

  1. CS片选拉低发送指令,CS片选拉高结束读指令结束
  2. 先写使能(0x02)
  3. 先发送0x20指令,后面跟24位的起始数据地址
  4. CS片选拉高结束写指令,片选拉晚或者没有拉高,写入的值将无效

👉块区擦除指令:0xD8  擦除64K

  1. CS片选拉低发送指令,CS片选拉高结束读指令结束
  2. 先写使能(0x02)
  3. 先发送0xD8指令,后面跟24位的起始数据地址
  4. CS片选拉高结束写指令,片选拉晚或者没有拉高,写入的值将无效

👉芯片擦除指令:0xC7  擦除8M

  1. CS片选拉低发送指令,CS片选拉高结束读指令结束
  2. 先写使能(0x02)
  3. 先发送0xC7指令
  4. CS片选拉高结束写指令,片选拉晚或者没有拉高,写入的值将无效

👉读取/制造器件号指令:0x90

  1. CS片选拉低发送指令,CS片选拉高结束读指令结束
  1. 先发送0x90指令
  1. 发送24位0地址(0x0)
  2. 发送8位任意数据产生时钟,接收8位返回ID,高位在前

3.指令发送

👽写使能

void W25QXX_WriteEnable(void)
{
	W25Q64_CS_LOW;
	sendByte(0x06);                  // 命令: Write Enable : 06h
	W25Q64_CS_HIGH;
}

👹写禁能

void W25QXX_WriteDisable(void)
{
	W25Q64_CS_LOW;
	sendByte(0x04);                  // 命令: Write Disable : 04h
	W25Q64_CS_HIGH;	
}

👻读状态寄存器,空闲状态

void W25QXX_WaitBusy(void)   
{   
	W25Q64_CS_LOW ;
    sendByte(0x05);  
    while (sendByte(0xFF) & 1) {}
    W25Q64_CS_HIGH ;
}

👦擦除扇区

void W25QXX_EraseSector(uint32_t addr)   
{  
	 addr = addr * 4096;        // 从第几扇区开始
	 W25QXX_WriteEnable();		//写使能
	 W25QXX_WaitBusy();			//等待空闲
	 W25Q64_CS_LOW;				//拉低
	 sendByte(0x20);			//发送扇区擦除指令
	 sendByte((uint8_t)(addr >> 16));//发送24位地址的最高8位
     sendByte((uint8_t)(addr >> 8));//发送24位地址的中间8位
     sendByte((uint8_t)addr);//发送24位地址的最低8位				    
	 W25Q64_CS_HIGH;				//拉高
	 W25QXX_WaitBusy();			//等待空闲
     printf("\r\n擦除完成!\r\n");
}

👧页写

//SPI在一页(0~65535)内写入少于256个字节的数据--分扇区写进去
//在指定地址开始写入最大256字节的数据
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!	
void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
 	u16 i;  
    W25QXX_WriteEnable();                  		//SET WEL
	W25QXX_WaitBusy();	
	W25Q64_CS_LOW ;                            	//使能器件   
    sendByte(0x02);      						//发送写页命令   
    sendByte((u8)((WriteAddr)>>16)); 	//发送24bit地址    
    sendByte((u8)((WriteAddr)>>8));   
    sendByte((u8)WriteAddr);   
    for(i=0;i<NumByteToWrite;i++)sendByte(pBuffer[i]);//循环写数  
	W25Q64_CS_HIGH ;                            	//取消片选 
	W25QXX_WaitBusy();					   		//等待写入结束
} 

🙅无校验写

/***********************************函数5.7****************************************************/
//无检验写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个字节
			else pageremain=NumByteToWrite; 	  //不够256个字节了
		}
	};	    
} 

💁读取数据

/************************************函数5.10**************************************************************
* 函 数 名 : W25QXX_ReadDatas
* 功能说明 : 读取数据
* 形    参 : buffer:数据缓存区,addr:开始读取的地址(24bit),num_data:要读取的字节数(最大32768)
* 返 回 值 : 无
* 备    注 : 无   指令---03H
*********************************************************************************************************/
void W25QXX_ReadDatas(uint8_t *buffer,uint32_t addr, uint16_t num)   
{ 
	W25Q64_CS_LOW ;
    sendByte(0x03);                     // 发送读取命令 03h
    sendByte((uint8_t)(addr >> 16));
    sendByte((uint8_t)(addr >> 8));
    sendByte((uint8_t)addr);
    for (uint32_t i = 0; i < num; i++)
    {
        buffer[i] = sendByte(0xFF);
    }
    W25Q64_CS_HIGH ;
}

👮读取设备ID

/****************************************函数5.11***********************************************************
* 函 数 名 : W25QXX_ReadID
* 功能说明 : 读器件ID号
* 形    参 : 0XEF17,表示芯片型号为W25Q128 
* 返 回 值 : 0XEF13,表示芯片型号为W25Q08  0XEF14,表示芯片型号为W25Q16  
* 备    注 : 0XEF15,表示芯片型号为W25Q32  0XEF16,表示芯片型号为W25Q64 
*********************************************************************************************************/ 
uint32_t readID(void)
{
    uint16_t Temp = 0;
    W25Q64_CS_LOW;
    sendByte(0x90);//发送读取ID命令
    sendByte(0x00);
    sendByte(0x00);
    sendByte(0x00);
    Temp |= sendByte(0xFF) << 8;
    Temp |= sendByte(0xFF);
    W25Q64_CS_HIGH;

    xW25Q64.FlagInit  = 1; //字库判断,防止被擦除
	if(Temp==W25Q64)  //0XEF16
	{
		sprintf((char *)xW25Q64.type, "%s", "W25Q64");
	}
	else
	{
		sprintf((char *)xW25Q64.type, "%s", "Flash设备失败 !!!");
        xW25Q64.FlagInit = 0;
		printf("读取到的错误型号数据:%x\r\n", Temp);
	}
    if (xW25Q64.FlagInit == 1)  
        printf("Flash存储 检测...  ID为:0x%x      型号:%s\r\n",Temp ,xW25Q64.type);  
    else
        printf("数据存储检测:           型号读取错误,设备不可用!\r\n");        
    return Temp;
}

四、字库烧写 

/*********************************************************************************************************
* 函 数 名 : USART1_W25QXX
* 功能说明 : 通过串口往W25Q烧写数据 
* 形    参 : sector:起止扇区编号,n:准备写入的数据占据的扇区个数
* 返 回 值 : 无
* 备    注 : 无
*********************************************************************************************************/ 
void USART1_W25QXX(uint16_t sector,uint16_t n)
{
	uint8_t buf;//缓冲区
	uint16_t i;
	uint32_t addr = sector * 4096;
	  //擦除数据
    for(i=0;i<n;i++)
    {
        W25QXX_EraseSector(sector+i); //删除扇区数据
    }
	USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);//关闭串口中断
	USART_ITConfig(USART1,USART_IT_IDLE,DISABLE);//关闭空闲中断
	while(1)
	{
		 if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE))
		 {
			 buf=USART_ReceiveData(USART1);
			 W25QXX_Write_shaoxie(&buf,addr++,1);
			 printf("写入成功\r\n");
		 }	
	}	
}

根据字库的大小,计算需要写的扇区,一个扇区占4K的数据,256K的字库,需要64个扇区的空间,所以需要写64个扇区。,烧写之前先擦除数据

烧写二进制文件,bin为后缀的

读取字库的字

W25QXX_ReadDatas(New_Ch,((buf[j]-0xA1)*94+(*(&buf[j]+1)-0xA1))*32+(num*4096),32);

buf:表示你要读取的字

num:你烧写的字库的扇区起始位置

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
作者:杨红超 绪论 本章主要阐述多功能气压计的应用背景,包括根据大气压强判断和确定建筑工人的楼层位置、帮助建筑工人感知周围环境温度变化等,同时也可根据大气压强判断无人机的GPS定位。其次着重介绍气压计的具体功能,如可以通过对工人周围的气压和温度的采集计算出当前所在的楼层位置,并将数据信息通过ONENET上传到云服务器上,通过语音识别实现设备在线升级功能。最后对本次设计的组织结构进行介绍,以表明每章节的主要内容和作用。 1.1应用背景 为确保建筑工人在工地施工时的人身安全,故此设计一款工人们的“运行手环”——多功能气压计。它内置气体压强检测装置可实时检测建筑工人身处的大气压强和周围的环境温度,进而根据采集的数据推算出工人所在的楼层高度,并将数据实时上传到云服务器上通过管理者对数据的检测给建筑工人提供一份双保险。 此外,该多功能气压计还具有无人机GPS定位和判断吸尘器吸力大小等应用于多对象、多环境的特点。 1.2实现功能 本次多功能气压计的设计硬件采用ART-Pi开发板、LPS22HH气压传感器和LD3320语音识别模块,操作系统使用RT-Thread 4.0.3,软件使用RT-Thread Studio 1.1.5开发平台和使用C语言实现软件编程,具有如下功能: (1)利用LPS22HH气压传感器实时对大气压的压强进行采集,并通过SPI4接口将采集的数据传给单片机。 (2)利用AP6212 WIFI模块实时将经过处理后的数据,如温度值和楼层信息等上传到云服务器;同时通过WIFI模块实现在线升级用户程序。 (3)语音识别模块通过SPI2实现与开发板的数据交互,完成语音重启设备和语音在线升级功能。 1.3设计组织结构 本次基于ART-Pi开发板的多功能气压计设计,主要分为五个章节其具体设计组织结构如下: 第一章绪论,主要介绍多功能气压计的实际应用背景和具有的具体功能,以及设计组织结构的规划。 第二章RT-Thread概述,主要对在本设计中涉及的RT-Thread内核、及其组件和软件包进行阐述,欲以说明对RT-Thread操作系统的使用情况和了解程度,同时对其内容作些简单的介绍。 第三章硬件设计,主要阐述硬件模块的电气连接和本次设计使用的硬件电路,如LPS22HH气压传感器、ART-Pi开发板和语音识别模块等。 第四章软件设计,主要阐述软件实现的设计流程和各个软件模块设计的框架,以及模块之间的通讯方式。 第五章总结与展望,主要阐述对本次设计的评估,即软件设计存在的不足和功能与性能存在的不足,以及针对不足之处提出的具体改进措施和方案、参加比赛的感悟和心得。 1.4本章小节 本章主要介绍多功能气压计的应用背景和具体的应用功能,以及对软硬件开发环境和该设计文档的组织结构进行阐述。 RT-Thread概述 本章主要阐述在软件设计中关于RT-Thread操作系统的应用情况,如与线程运行有关的采用动态方式创建线程,与线程同步有关的信号量的动态创建、释放和获取,以及与网络有关的SAL组件、OneNET软件包等。 2.1内核 为了提高软件运行的并发性和数据采集的实时性,故使用内核中的核心部分——线程,使其维护和管理每个任务的运行,同时以使用信号量和事件集等的同步方式,以及使用邮箱和消息队列等的通信方式来确保每个任务在运行过程中能“自由飞翔”。 不仅如此,为增加任务在运行状态中的时间和提高每个任务响应的快慢速度,故使用线程中重要的两个属性即线程优先级和时间片,并根据应用的具体环境和软实时性的要求将每个任务赋予各自该具有的任务优先级和时间片。同时,使用rt_thread_mdelay延迟函数来定时释放线程(任务)确保在其处于非运行态时可以退出时间片以让其它任务能及时运行。 2.2驱动 在bootloader程序中主要初始化SPI和SFUD驱动实现对外部SPI FLASH的读写操作,同时结合使用FAL软件包将操作FLASH的函数进行分层,进而实现在bootloader程序中读取“download”分区的升级固件,以及使用ota_downloader软件包完成升级固件的下载,最后使用出厂W25QXX函数实现固件搬运工作进而完成在线升级应用。 2.3组件 SAL组件完成并提供了基于RT-Thread操作系统的对不同网络协议栈或网络实现接口的抽象和与上层应用有关的一组标准BSD Socket API,在网络开发设计时可只需关心和使用网络应用层提供的网络接口,而无需关心底层具体网络协议栈类型和具体实现,如TCP/IP协议栈、LWIP和AT Socket网络。SAL组件不仅提高了软件系统对底层驱动的兼容性,而且缩短了网络开发周期。此外,SAL组件还具有一下功能特点[1]: 抽象、统一多种网络协议栈接口; 提供Socket层面的TLS加密传输特性; 支持标准BSP S

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值