HAL库学习梳理——SPI(收发Flash数据实验)

news2024/9/20 9:56:51

实验现象:将LED灯的状态保存到Flash里,掉电读取Flash并设置LED。

1,STM32CubeMx 配置

1.1 SPI引脚说明

外设连接

 1.2 参数配置

配置工作模式
主机工作模式
SPI 工作参数设置

1.3 GPIO配置 

SPI接线配置
SPI引脚的GPIO配置

2,程序

2.1 保存LED状态到Flash

发送数据流程为:Flash写使能——擦除扇区——延迟100ms——写使能——页编程——延迟10ms

需要注意的是每一次对Flash进行操作的时候都需要:开启片选NSS——Flash操作——关闭片选NSS

开启或关闭片选NSS:就是对NSS的GPIO引脚输入相应的高低电平。笔者这里NSS的GPIO引脚是PA4。

// 开启片选NSS
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);

// 关闭片选NSS
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);

(1) Flash写使能:从器件工作手册上可以看到,Flash的写使能指令是0x06

写使能操作
uint8_t WriteEnableCmd[] = {0x06};                         // 写使能命令

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);      // 开启片选
  
HAL_SPI_Transmit(&hspi1,WriteEnableCmd,1,HAL_MAX_DELAY);   // 发送命令

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);        // 关闭片选

(2) 擦除扇区:擦除扇区指令为0x20。

擦除扇区
uint8_t sectorEraseCmd[] = {0x20,0x00,0x00,0x00};          // 擦除命令和24位擦除地址

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);      // 开启片选
  
HAL_SPI_Transmit(&hspi1,sectorEraseCmd,4,HAL_MAX_DELAY);   // 发送擦除命令

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);        // 关闭片选

(3) 延时100ms: 

  // 延迟100ms
  HAL_Delay(100);

(4) Flash写使能:与上面的一样,写使能指令是0x06

(5)页编程写入数据: 注意页编程的指令是 0x02擦除扇区的指令是 0x20

页编程操作
uint8_t pageProgCmd[5];     // 存放页编程命令、24位写入地址、以及写入的数据

pageProgCmd[0]=0x02;        // 页编程命令

pageProgCmd[1]=0x00;        // 页编程地址
pageProgCmd[2]=0x00;
pageProgCmd[3]=0x00;

pageProgCmd[4]=led_state;   // 存放数据——LED状态

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);      // 开启片选
  
HAL_SPI_Transmit(&hspi1,pageProgCmd,5,HAL_MAX_DELAY);      // 页编程

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);        // 关闭片选

(6) 延时10ms: 

  // 延迟10ms
  HAL_Delay(10);

2.2 从Flash读取数据

读取数据流程为:开启片选——Flash发送读命令——读取数据赋值——关闭片选

uint8_t LoadLEDstate(void)
{
  uint8_t readEnableCmd[] = {0x03,0x00,0x00,0x00};            // 读命令(0x03)和地址
  uint8_t ledState = 0xff;                                    // 存放读取的数据

  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);       // 开启片选

  HAL_SPI_Transmit(&hspi1,readEnableCmd,4,HAL_MAX_DELAY);     // 发送读命令

  HAL_SPI_Receive(&hspi1,&ledState,1,HAL_MAX_DELAY);          // 接收数据并保存

  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);         // 关闭片选

  return ledState;
}

2.3 总程序

#include "main.h"

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
/* USER CODE BEGIN PFP */
static void SaveLEDstate(uint8_t led_state);        // 保存LED状态函数声明
static uint8_t LoadLEDstate(void);                  // 读取LED状态函数声明
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
static void SaveLEDstate(uint8_t led_state)         // 保存LED状态函数
{

  // 写使能
  uint8_t WriteEnableCmd[] = {0x06};
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
  HAL_SPI_Transmit(&hspi1,WriteEnableCmd,1,HAL_MAX_DELAY); 
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);  
  // 擦除扇区
  uint8_t sectorEraseCmd[] = {0x20,0x00,0x00,0x00};
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
  HAL_SPI_Transmit(&hspi1,sectorEraseCmd,4,HAL_MAX_DELAY); 
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
  // 延迟100ms
  HAL_Delay(100);
  // 写使能
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
  HAL_SPI_Transmit(&hspi1,WriteEnableCmd,1,HAL_MAX_DELAY); 
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); 
  // 页编程
  uint8_t pageProgCmd[5];
  pageProgCmd[0]=0x02;
  pageProgCmd[1]=0x00;
  pageProgCmd[2]=0x00;
  pageProgCmd[3]=0x00;
  pageProgCmd[4]=led_state;
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
  HAL_SPI_Transmit(&hspi1,pageProgCmd,5,HAL_MAX_DELAY); 
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
  // 延迟10ms
  HAL_Delay(10);

}

uint8_t LoadLEDstate(void)                        // 读取LED状态函数
{
  uint8_t readEnableCmd[] = {0x03,0x00,0x00,0x00};
  uint8_t ledState = 0xff;

  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
  HAL_SPI_Transmit(&hspi1,readEnableCmd,4,HAL_MAX_DELAY); 
  HAL_SPI_Receive(&hspi1,&ledState,1,HAL_MAX_DELAY); 
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
  return ledState;
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)                                // 主函数
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */                        
  uint8_t pre = 1;
  uint8_t cur = 1;
  uint8_t led_state = 0;
  
  led_state=LoadLEDstate();                            // while之前读取Flash
  if(led_state == 1)
  {
      HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
  }
  else
  {
      HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
  }
  while (1)
  {
    pre = cur;
    if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_SET)   // 按钮翻转LED
    {
      cur=0; 
    }
    else
    { 
      cur=1;
    }
    if(pre!=cur)
    {
      if(cur==0){}
      else
      {
        if(led_state == 0)
        {
            HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
            led_state = 1;
        }
        else
        {
            HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
            led_state = 0;  
        }
        SaveLEDstate(led_state);                            // 保存LED状态
      }   
    }
    
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}


 

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

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

相关文章

大模型开源:ChatGLM-6B (介绍以及本地部署)

简介 ChatGLM-6B 是一个开源的、支持中英双语问答的对话语言模型,基于 General Language Model (GLM) 架构,具有 62 亿参数。结合模型量化技术,用户可以在消费级的显卡上进行本地部署(INT4 量化级别下最低只需 6GB 显存&#xff…

水位雨量自动监测站的工作原理

水位雨量自动监测站是一种集自动化、智能化于一体的水文监测设施,主要用于实时监测和记录水位及降雨量的变化,为水文预报、水资源管理、防洪减灾等提供科学依据。水位雨量自动监测站主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构…

js读取文件,生成随机题目,多项选择题则提供随机答案供选择

一.第一个要求 根据模板生成随机题目可以将 --- 内的内容 ---变成JSON然后根据参数的限制条件来生成随机参数,再替换到题目中example.md --- Type: Quiz Template Domain: - Geometry Knowledge:- - 數學- 度量、圖形與空間範疇- 弧長和扇形面積- 理解圓的弧長公…

掌握项目全流程:10个项目管理烫知识

一、启动阶段 1、一个清晰且有吸引力的项目愿景对于项目的成功启动至关重要。它能够让所有项目成员以及相关干系人明白项目的最终目标和意义。 在这个阶段,我们可以利用项目管理工具进度猫来可视化地呈现项目的整体愿景,将大的目标拆分成初步的任务板…

RT-DETR训练自己的数据集(从代码下载到实例测试)

文章目录 前言一、RT-DETR简介二、环境搭建三、构建数据集四、修改配置文件①数据集文件配置②模型文件配置③训练文件配置 五、模型训练和测试模型训练模型测试 总结 前言 提示:本文是RT-DETR训练自己数据集的记录教程,需要大家在本地已配置好CUDA,cuD…

302状态如何进行重定向

文章目录 一、302状态是什么意思二、遇到的使用场景三、如何处理customservice.wxmlcustomservice.js 一、302状态是什么意思 302状态码是临时重定向(Move Temporarily),表示所请求的资源临时地转移到新的位置。此外还有一个301永久重定向&a…

【spring】maven引入okhttp的日志拦截器打开增量注解进程

HttpLoggingInterceptor 是在logging-interceptor库中的:这个logging库老找不到 import okhttp3.OkHttpClient; import okhttp3.logging.HttpLoggingInterceptor;发现这仨是独立的库 pom中三个依赖 <!-- OKHTTP3 --><

在group by分组的时候,某个key过多导致数据倾斜

解决方案&#xff1a;将 key 打散&#xff0c;给 key 增加随机前缀 在进行 group by 之前&#xff0c;先给每个 user_id 增加一个随机前缀&#xff0c;使得原本相同的 user_id 被打散到不同的分组中。 按带前缀的 key 进行分组 对带有随机前缀的 user_id 进行分组和聚合。 …

重要涉密文件如何防窃取?四个方法有效防止文件泄密【文件保密管理】

随着信息化时代的发展&#xff0c;数据安全问题变得日益突出&#xff0c;特别是对于一些重要的涉密文件&#xff0c;其泄密将带来严重后果。因此&#xff0c;企业和个人在处理机密文件时&#xff0c;必须采取有效的措施来防止文件被窃取。 小编在本文将介绍四个有效的方法&…

三招教你搞定GPU服务器配置→收藏推荐配置

在AI人工智能应用日益渗透各行各业的今天&#xff0c;图形处理器&#xff08;GPU&#xff09;市场呈现出蓬勃发展的态势&#xff0c;其中GPU服务器市场更是炙手可热&#xff0c;其热度始终居高不下。随着人工智能、深度学习、大数据分析等前沿领域的不断拓展与深化&#xff0c;…

python+matplotlib 画一个漂亮的折线统计图

pythonmatplotlib 画一个漂亮的折线统计图 有详细的注释说明…… import matplotlib.pyplot as plt import numpy as np import mathdef draw_line_chart(Line_data_list,title,pic_name)::param Line_data_list: 折线数据源:param title: 图表名称:param pic_name: 保存图片名…

免费!OpenAI发布最新模型GPT-4o mini,取代GPT3.5,GPT3.5退出历史舞台?

有个小伙伴问我&#xff0c;GPT-4O mini是什么&#xff0c;当时我还一脸懵逼&#xff0c;便做了一波猜测&#xff1a; 我猜测哈&#xff0c;这个可能是ChatGPT4o的前提下&#xff0c;只支持文本功能的版本&#xff0c;速度更快 结果&#xff0c;大错特错。 让我们一起看看Open…

理解高并发

文章目录 1、如何理解高并发2、高并发的关键指标3、高并发系统设计的目标是什么&#xff1f;1_宏观目标2_微观目标1.性能指标2.可用性指标3.可扩展性指标 4、高并发的实践方案有哪些&#xff1f;1_通用的设计方法1.纵向扩展&#xff08;scale-up&#xff09;2.横向扩展&#xf…

【隐私计算】Cheetah安全多方计算协议-阿里安全双子座实验室

2PC-NN安全推理与实际应用之间仍存在较大性能差距&#xff0c;因此只适用于小数据集或简单模型。Cheetah仔细设计DNN&#xff0c;基于格的同态加密、VOLE类型的不经意传输和秘密共享&#xff0c;提出了一个2PC-NN推理系统Cheetah&#xff0c;比CCS20的CrypTFlow2开销小的多&…

数据结构—线性表和顺序表

线性表&#xff1a; 线性表是一个由n个具有相同特性的数据元素构成的有限序列。常用到的线性表都有&#xff1a;链表、队列、栈、顺序表.... 顺序表&#xff1a; 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构&#xff08;顺序表的元素类型是包装类&#x…

[苍穹外卖]-10WebSocket入门与实战

WebSocket WebSocket是基于TCP的一种新的网络协议, 实现了浏览器与服务器的全双工通信, 即一次握手,建立持久连接,双向数据传输 区别 HTTP是短连接, WebSocket是长连接HTTP单向通信, 基于请求响应模型WebSocket支持双向通信 相同 HTTP和WebSocket底层都是TCP连接 应用场景…

Android 通过相机和系统相册获取图片,压缩,结果回调

一、需求背景 在常规的App开发中&#xff0c;很多时候需要用户上传图片来进行一些业务上的实现&#xff0c;例如用户反馈&#xff0c;图片凭证等。 二、实现功能 1.选择弹窗&#xff08;即选择拍照或者相册&#xff09; 2.申请权限&#xff08;相机权限&#xff09; 3.相机…

油耳用什么掏耳朵比较好?可视挖耳勺推荐平价

掏耳朵是一个轻松又舒服的感觉&#xff0c;很多人就会用棉签和普通耳勺越掏越进&#xff0c;在盲掏的过程中容易弄伤耳膜。所以我们在掏耳时要选好工具。市面上的智能可视挖耳勺&#xff0c;顶端带有摄像头&#xff0c;可以通过清楚的观察到耳道中的情况。但现在市面上关于可视…

【Unity学习心得】如何使用Unity制作“饥荒”风格的俯视角2.5D游戏

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、需要导入的素材二、要实现的步骤 俯视角2D人物移动控制2.5D风格的实现使用协程实现相机绕玩家旋转效果总结 前言 由于要找工作开始重新拾起学习Unity&#…

系统资源智能管理:zTasker软件的监控与优化

在创新的引领下&#xff0c;科技不断迭代升级&#xff0c;为我们应对快节奏生活的挑战提供了强大的工具。它让我们在协调工作与家庭的同时&#xff0c;也能保持内心的宁静与平衡——而自动化工具的出现&#xff0c;正是科技力量在提升工作效率和生活质量方面的体现。zTasker&am…