虎年马上就要到了,放假在家闲来无事开始学习单片机。我使用的单片机是洋桃电子1号开发板,目前学到第30步读写FLASH。洋桃电子使用的是库函数,我就对其代码做了一点点小改动,使用的是HAL库,记录一下以免今后忘记。
STM32CubeMX配置过程,将PB0,PB1设置为推挽输出模式。开发板的电路原理图为:按下开关,PA0接地;PB0,PB1输出高电平可分别点亮led1,led2。
1、定义按键头文件和函数
#ifndef _KEY_H_
#define _KEY_H_
#include "stm32f1xx.h"
#define k2 GPIO_PIN_0 //定义PA0为k2
void Key_Init(void); //端口初始化
void key_scan2led(void); //按键控制函数
#endif
#include "key.h"
#include "flash.h"
void Key_Init(void)
{
/* 开启GPIOA时钟 */
__HAL_RCC_GPIOA_CLK_ENABLE();
/* 定义按键初始化结构体,模式为输入,端口为k2,上拉 */
GPIO_InitTypeDef Key;
Key.Mode = GPIO_MODE_INPUT;
Key.Pin = k2;
Key.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA,&Key);
}
/* 采用软件消抖,延时20毫秒。
操作端口输出数据寄存器(GPIOx_ODR)进行整组写入。
当flash_data为0时,led1灭,led2灭;
当flash_data为1时,led1亮,led2灭;
当flash_data为2时,led1灭,led2亮;
当flash_data为3时,led1亮,led2亮;
当flash_data大于3时,置0。 */
void key_scan2led(void)
{
extern uint16_t flash_data;
if(HAL_GPIO_ReadPin(GPIOA,k2)==GPIO_PIN_RESET)
{
HAL_Delay(20);
if(HAL_GPIO_ReadPin(GPIOA,k2)==GPIO_PIN_RESET)
{
flash_data++;
if(flash_data>3)
{
flash_data=0;
}
GPIOB->ODR = flash_data;
write_flash(flash_start,flash_data);
}
while(HAL_GPIO_ReadPin(GPIOA,k2) == GPIO_PIN_RESET);
}
}
?2、定义FLASH头文件和函数
#ifndef _FLASH_H_
#define _FLASH_H_
#include "stm32f1xx.h"
#define flash_start 0x0801f000 //对0x0801f000地址所在页进行写入
void write_flash(uint32_t add,uint16_t dat);
uint16_t read_flash(uint32_t add);
#endif
#include "flash.h"
/* 写FLASH
1、解锁;
2、清除标志位;
3、擦除FLASH,以页为单位;首先定义擦除初始化结构体,分别设置页擦除、擦除地址、擦除页数;定义一个错误变量,若在擦除过程中出现错误,函数会将错误代码写入变量所在地址;
4、以半字(16bit)写入
5、清除标志位;
6、上锁 */
void write_flash(uint32_t add,uint16_t dat)
{
uint32_t flash_error=0;
FLASH_EraseInitTypeDef flash_set;
flash_set.TypeErase = FLASH_TYPEERASE_PAGES;
flash_set.PageAddress = flash_start;
flash_set.NbPages = 1;
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP|FLASH_FLAG_WRPERR|FLASH_FLAG_PGERR|FLASH_FLAG_OPTVERR);
HAL_FLASHEx_Erase(&flash_set,&flash_error);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,add,dat);
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP|FLASH_FLAG_WRPERR|FLASH_FLAG_PGERR|FLASH_FLAG_OPTVERR);
HAL_FLASH_Lock();
}
/* 读FLASH */
uint16_t read_flash(uint32_t add)
{
uint16_t a=*(uint16_t *)(add);
return a;
}
3、main函数
?如图,在main函数外定义一个全局变量flash_data,并在主函数内依次调用初始化函数和按键函数
/* USER CODE BEGIN 0 */
uint16_t flash_data=0;
/* 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();
/* USER CODE BEGIN 2 */
// LED_Init();
Key_Init();
flash_data=read_flash(flash_start);
GPIOB->ODR = flash_data;
// TIM4_Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
key_scan2led();
/* USER CODE BEGIN 3 */
}
/* USER CODE END
|