当前位置:   article > 正文

【正点原子STM32连载】 第四十一章 SPI实验 摘自【正点原子】APM32E103最小系统板使用指南

【正点原子】apm32e103最小系统板使用指南

1)实验平台:正点原子APM32E103最小系统
2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/docs/boards/xiaoxitongban

第四十一章 SPI实验

本章将介绍使用APM32E103驱动板载的NOR Flash进行读写操作。通过本章的学习,读者将学习到使用SPI驱动NOR Flash的使用。
本章分为如下几个小节:
41.1 硬件设计
41.2 程序设计
41.3 下载验证

41.1 硬件设计
41.1.1 例程功能

  1. 按下KEY_UP和KEY0按键,分别对25Q128进行数据的写入和读取操作,读取到的数据会显示至LCD
  2. 可通过USMART对25Q128进行读ID和芯片/扇区擦除的操作
  3. LED0闪烁,指示程序正在运行
    41.1.2 硬件资源
  4. LED
    LED0 - PB5
  5. 按键
    KEY0 - PE4
    KEY_UP - PA0
  6. USART1(PA9、PA10连接至板载USB转串口芯片上)
  7. 正点原子 2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动)
  8. SPI2
    SPI2_SCK - PB13
    SPI2_MISO - PB14
    SPI2_MOSI - PB15
  9. 25Q128
    F_CS - PB12
    41.1.3 原理图
    本章实验使用了板载的25Q128芯片,该芯片是一个NOR Flash,MCU是通过SPI与该NOR Flash进行连接与通信的,该NOR Flash与MCU的连接原理图,如下如图所示:
    在这里插入图片描述

图41.1.3.1 NOR Flash与MCU的连接原理图
41.2 程序设计
41.2.1 Geehy标准库的SPI驱动
本章实验通过SPI2驱动NOR Flash,因此需要对SPI2进行相应的配置,并使用SPI2与NOR Flash进行通信,其具体的步骤如下所示:
①:配置SPI2
②:使能SPI2
③:使用SPI2发送数据(接收数据)前,等待SPI2发送缓冲区为空(接收缓冲区非空)
④:使用SPI2发送一字节数据
⑤:使用SPI2接收一字节数据
在Geehy标准库中对应的驱动函数如下:
①:配置SPI
该函数用于配置SPI,其函数原型如下所示:
void SPI_Config(SPI_T* spi, SPI_Config_T* spiConfig);
该函数的形参描述,如下表所示:
形参 描述
spi 指向SPI外设结构体的指针
例如:SPI1、SPI2等(在apm32e10x.h文件中有定义)
spiConfig 指向SPI配置结构体的指针
需自行定义,并根据SPI的配置参数填充结构体中的成员变量
表41.2.1.1 函数SPI_Config()形参描述
该函数的返回值描述,如下表所示:
返回值 描述
无 无
表41.2.1.2 函数SPI_Config()返回值描述
该函数使用SPI_Config_T类型的结构体变量传入SPI的配置参数,该结构体的定义如下所示:

typedef enum
{
    SPI_MODE_MASTER = 0x0104,                  /* 主机模式 */
    SPI_MODE_SLAVE  = 0x0000                   /* 从机模式 */
}SPI_MODE_T;

typedef enum
{
    SPI_DATA_LENGTH_16B = 0x0800,              /* 8位数据格式 */
    SPI_DATA_LENGTH_8B  = 0x0000               /* 8位数据格式 */
}SPI_DATA_LENGTH_T;

typedef enum
{
    SPI_CLKPHA_1EDGE = 0x0000,                 /* 在第一个时钟边沿进行采样 */
    SPI_CLKPHA_2EDGE = 0x0001                  /* 在第二个时钟边沿进行采样 */
}SPI_CLKPHA_T;

typedef enum
{
    SPI_CLKPOL_LOW   = 0x0000,                 /* 时钟信号空闲时为低电平 */
    SPI_CLKPOL_HIGH  = 0x0002                  /* 时钟信号空闲时为高电平 */
}SPI_CLKPOL_T;

typedef enum
{
    SPI_NSS_SOFT = 0x0200,                     /* 软件片选 */
    SPI_NSS_HARD = 0x0000                      /* 硬件片选 */
}SPI_NSS_T;

typedef enum
{
    SPI_FIRSTBIT_MSB = 0x0000,                 /* MSB */
    SPI_FIRSTBIT_LSB = 0x0080                  /* LSB */
}SPI_FIRSTBIT_T;

typedef enum
{
    SPI_DIRECTION_2LINES_FULLDUPLEX = 0x0000,  /* 双线全双工 */
    SPI_DIRECTION_2LINES_RXONLY     = 0x0400,  /* 双线仅接收 */
    SPI_DIRECTION_1LINE_RX          = 0x8000,  /* 单线仅接受 */
    SPI_DIRECTION_1LINE_TX          = 0xC000   /* 单线仅发送 */
}SPI_DIRECTION_T;

typedef enum
{
    SPI_BAUDRATE_DIV_2   = 0x0000,             /*波特率2分频 */
    SPI_BAUDRATE_DIV_4   = 0x0008,	            /*波特率4分频 */
    SPI_BAUDRATE_DIV_8   = 0x0010,	            /*波特率8分频 */
    SPI_BAUDRATE_DIV_16  = 0x0018,	            /*波特率16分频 */
    SPI_BAUDRATE_DIV_32  = 0x0020,	            /*波特率32分频 */
    SPI_BAUDRATE_DIV_64  = 0x0028,	            /*波特率64分频 */
    SPI_BAUDRATE_DIV_128 = 0x0030,	            /*波特率128分频 */
    SPI_BAUDRATE_DIV_256 = 0x0038,	            /*波特率256分频 */
}SPI_BAUDRATE_DIV_T;

typedef struct
{
    SPI_MODE_T			mode;			        /* 模式 */
    SPI_DATA_LENGTH_T	length;			        /* 数据位长度 */
    SPI_CLKPHA_T		phase;			        /* 采样阶段 */
    SPI_CLKPOL_T		polarity;		        /* 时钟线空闲极性 */
    SPI_NSS_T			nss;			        /* 片选信号 */
    SPI_FIRSTBIT_T		firstBit;		        /* 数据第一比特 */
    SPI_DIRECTION_T		direction;		        /* 方向 */
    SPI_BAUDRATE_DIV_T	baudrateDiv;	        /* 波特率分频 */
    uint16_t			crcPolynomial;	        /* CRC校验值 */
} SPI_Config_T;

该函数的使用示例,如下所示:
#include "apm32e10x.h"
#include "apm32e10x_spi.h"

void example_fun(void)
{
    SPI_Config_T spi_init_struct;

    /* 配置SPI1 */
    spi_init_struct.mode			= SPI_MODE_MASTER;
    spi_init_struct.length			= SPI_DATA_LENGTH_8B;
    spi_init_struct.phase			= SPI_CLKPHA_2EDGE;
    spi_init_struct.polarity		= SPI_CLKPOL_HIGH;
    spi_init_struct.nss				= SPI_NSS_SOFT;
    spi_init_struct.firstBit		= SPI_FIRSTBIT_MSB;
    spi_init_struct.direction		= SPI_DIRECTION_2LINES_FULLDUPLEX;
    spi_init_struct.baudrateDiv		= SPI_BAUDRATE_DIV_256;
    spi_init_struct.crcPolynomial	= 7;
    SPI_Config(SPI1_SPI, &spi_init_struct);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

②:使能SPI
该函数用于使能SPI,其函数原型如下所示:
void SPI_Enable(SPI_T* spi);
该函数的形参描述,如下表所示:
形参 描述
spi 指向SPI外设结构体的指针
例如:SPI1、SPI2等(在apm32e10x.h文件中有定义)
表41.2.1.3 函数SPI_Enable()形参描述
该函数的返回值描述,如下表所示:
返回值 描述
无 无
表41.2.1.4 函数SPI_Enable()返回值描述
该函数的使用示例,如下所示:

#include "apm32e10x.h"
#include "apm32e10x_spi.h"

void example_fun(void)
{
    /* 使能SPI2 */
    SPI_Enable(SPI2);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

③:读取SPI的状态标志
该函数用于读取SPI的状态标志,其函数原型如下所示:
uint8_t SPI_I2S_ReadStatusFlag(SPI_T* spi, SPI_FLAG_T flag);
该函数的形参描述,如下表所示:
形参 描述
spi 指向SPI外设结构体的指针
例如:SPI1、SPI2等(在apm32e10x.h文件中有定义)
flag 指定的SPI状态标志
例如:SPI_FLAG_RXBNE、SPI_FLAG_TXBE等(在apm32e10x_spi.h文件中有定义)
表41.2.1.5 函数SPI_I2S_ReadStatusFlag()形参描述
该函数的返回值描述,如下表所示:
返回值 描述
SET 事件标志发生
RESET 事件标志未发生
表41.2.1.6 函数SPI_I2S_ReadStatusFlag()返回值描述
该函数的使用示例,如下所示:

#include "apm32e10x.h"
#include "apm32e10x_spi.h"

void example_fun(void)
{
    uint8_t flag;

    /* 读取SPI2的接收缓冲区非空标志 */
    flag = SPI_I2S_ReadStatusFlag(SPI2, SPI_FLAG_RXBNE);
    if (flag == SET)
    {
        /* Do something. */
    }
    else
    {
        /* Do something. */
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

④:SPI发送数据
该函数用于使用SPI发送数据,其函数原型如下所示:
void SPI_I2S_TxData(SPI_T* spi, uint16_t data);
该函数的形参描述,如下表所示:
形参 描述
spi 指向SPI外设结构体的指针
例如:SPI1、SPI2等(在apm32e10x.h文件中有定义)
data 待发送的数据
表41.2.1.7 函数SPI_I2S_TxData()形参描述
该函数的返回值描述,如下表所示:
返回值 描述
无 无
表41.2.1.8 函数SPI_I2S_TxData()返回值描述
该函数的使用示例,如下所示:

#include "apm32e10x.h"
#include "apm32e10x_spi.h"

void example_fun(void)
{
    uint8_t data;
    
    data = 0x55;
    
    /* 使用SPI2发送1字节数据 */
    SPI_I2S_TxData(SPI2, (uint16_t)data);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

⑤:SPI接收数据
该函数用于接收SPI接收的数据,其函数原型如下所示:
uint16_t SPI_I2S_RxData(SPI_T* spi);
该函数的形参描述,如下表所示:
形参 描述
spi 指向SPI外设结构体的指针
例如:SPI1、SPI2等(在apm32e10x.h文件中有定义)
表41.2.1.9 函数SPI_I2S_RxData()形参描述
该函数的返回值描述,如下表所示:
返回值 描述
uint16_t类型数据 SPI接收的数据
表41.2.1.10 函数SPI_I2S_TxData()返回值描述
该函数的使用示例,如下所示:

#include "apm32e10x.h"
#include "apm32e10x_spi.h"

void example_fun(void)
{
    uint8_t data;
    
    /* 接收SPI2接收到的1字节数据 */
    data = (uint8_t)SPI_I2S_RxData(SPI2);
    
    /* Do something. */
}
41.2.2 SPI驱动
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

本章实验的SPI驱动主要负责向NOR Flash驱动提供SPI的各种操作函数,例如:SPI初始化、SPI读写等。本章实验中,SPI的驱动代码包括spi.c和spi.h两个文件。
SPI驱动中,对SPI、GPIO相关的宏定义,如下所示:

/* SPI2相关定义 */
#define SPI2_SPI                    SPI2
#define SPI2_SPI_CLK_ENABLE()       do{ RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_SPI2); }while(0)

/* SPI2引脚定义 */
#define SPI2_SCK_GPIO_PORT          GPIOB
#define SPI2_SCK_GPIO_PIN           GPIO_PIN_13
#define SPI2_SCK_GPIO_CLK_ENABLE()  do{ RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOB); }while(0)

#define SPI2_MISO_GPIO_PORT         GPIOB
#define SPI2_MISO_GPIO_PIN          GPIO_PIN_14
#define SPI2_MISO_GPIO_CLK_ENABLE() do{ RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOB); }while(0)

#define SPI2_MOSI_GPIO_PORT         GPIOB
#define SPI2_MOSI_GPIO_PIN          GPIO_PIN_15
#define SPI2_MOSI_GPIO_CLK_ENABLE() do{ RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOB); }while(0)
SPI驱动中,SPI的初始化函数,如下所示:
/**
 * @brief       初始化SPI2
 * @param       无
 * @retval      无
 */
void spi2_init(void)
{
    GPIO_Config_T gpio_init_struct;
    SPI_Config_T spi_init_struct;
    
    /* 使能时钟 */
    SPI2_SPI_CLK_ENABLE();                         /* 使能SPI2时钟 */
    SPI2_SCK_GPIO_CLK_ENABLE();                    /* 使能SPI2 SCK引脚端口时钟 */
    SPI2_MISO_GPIO_CLK_ENABLE();                   /* 使能SPI2 MISO引脚端口时钟 */
    SPI2_MOSI_GPIO_CLK_ENABLE();                   /* 使能SPI2 MOSI引脚端口时钟 */
    
    /* 配置SPI2 SCK引脚 */
    gpio_init_struct.pin = SPI2_SCK_GPIO_PIN;      /* SPI2 SCK引脚 */
    gpio_init_struct.speed = GPIO_SPEED_50MHz;     /* 高速 */
    gpio_init_struct.mode = GPIO_MODE_AF_PP;       /* 复用功能推挽输出模式 */
GPIO_Config(SPI2_SCK_GPIO_PORT, &gpio_init_struct); 

    /* 配置SPI2 MISO引脚 */
    gpio_init_struct.pin = SPI2_MISO_GPIO_PIN;     /* SPI2 MISO引脚 */
    gpio_init_struct.speed = GPIO_SPEED_50MHz;     /* 高速 */
    gpio_init_struct.mode = GPIO_MODE_AF_PP;       /* 复用功能推挽输出模式 */
    GPIO_Config(SPI2_MISO_GPIO_PORT, &gpio_init_struct);
    
    /* 配置SPI2 MOSI引脚 */
    gpio_init_struct.pin = SPI2_MOSI_GPIO_PIN;     /* SPI2 MOSI引脚 */
    gpio_init_struct.speed = GPIO_SPEED_50MHz;     /* 高速 */
    gpio_init_struct.mode = GPIO_MODE_AF_PP;       /* 复用功能推挽输出模式 */
    GPIO_Config(SPI2_MOSI_GPIO_PORT, &gpio_init_struct);
    
    /* 配置SPI2 */
    spi_init_struct.mode = SPI_MODE_MASTER;        /* 主模式 */
    spi_init_struct.length = SPI_DATA_LENGTH_8B;   /* 8位数据帧格式 */
spi_init_struct.phase = SPI_CLKPHA_2EDGE;      /* 在第2个时钟边沿采样 */
/* SPI处于空闲状态时,SCK保持高电平状态 */
    spi_init_struct.polarity = SPI_CLKPOL_HIGH;
    spi_init_struct.nss = SPI_NSS_SOFT;            /* 启用软件NSS模式 */
spi_init_struct.firstBit = SPI_FIRSTBIT_MSB;   /* 先发送最高有效位(MSB) */
/* 双线单向、同时发送和接收 */
spi_init_struct.direction = SPI_DIRECTION_2LINES_FULLDUPLEX;
/* 波特率分频系数 */
    spi_init_struct.baudrateDiv = SPI_BAUDRATE_DIV_256;
    spi_init_struct.crcPolynomial = 7;             /* CRC多项式数值 */
    SPI_Config(SPI2_SPI, &spi_init_struct);        /* 配置SPI2 */
    SPI_DisableCRC(SPI2_SPI);                      /* 禁止CRC */
    SPI_Enable(SPI2_SPI);                          /* 使能SPI2 */
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

可以看到,该函数会配置并使能SPI1,同时也配置SPI使用的GPIO引脚的复用功能。
SPI驱动中,使用SPI传输1字节数据的函数,如下所示:

/**
 * @brief       SPI2读写一个字节数据
 * @param       txdata: 待发送的一字节数据
 * @retval      接收到的一字节数据
 */
uint8_t spi2_read_write_byte(uint8_t txdata)
{
    uint8_t rxdata;
    /* 等待发送缓冲器为空 */
while (SPI_I2S_ReadStatusFlag(SPI2_SPI, SPI_FLAG_TXBE) != SET);
/* 发送一字节数据 */
    SPI_I2S_TxData(SPI2_SPI, txdata);
    /* 等待接收缓冲非空 */
while (SPI_I2S_ReadStatusFlag(SPI2_SPI, SPI_FLAG_RXBNE) != SET);
/* 接收一字节数据 */
    rxdata = SPI_I2S_RxData(SPI2_SPI);
    
    return rxdata;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

使用SPI传输1字节数据就是先后发送并接收1字节数据。
41.2.3 NOR Flash驱动
本章实验的NOR Flash驱动主要负责向应用层提供NOR Flash的初始化和读写操作等函数。本章实验中,NOR Flash的驱动代码包括norflash.c和norflash.h两个文件。
NOR Flash驱动中,对GPIO的相关宏定义,如下所示:

/* NOR Flash片选引脚定义 */
#define NORFLASH_CS_GPIO_PORT           GPIOB
#define NORFLASH_CS_GPIO_PIN            GPIO_PIN_12
#define NORFLASH_CS_GPIO_CLK_ENABLE()   do{ RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOB); }while(0)

/* NOR Flash片选引脚IO操作 */
#define NORFLASH_CS(x)                  do{ x ?                                \
                                            GPIO_SetBit(NORFLASH_CS_GPIO_PORT, NORFLASH_CS_GPIO_PIN) :            \
                                            GPIO_ResetBit(NORFLASH_CS_GPIO_PORT, NORFLASH_CS_GPIO_PIN);             \
                                        }while(0)
NOR Flash驱动中,初始化NOR Flash的函数,如下所示:
/**
 * @brief       初始化NOR Flash
 * @param       无
 * @retval      无
 */
void norflash_init(void)
{
    GPIO_Config_T gpio_init_struct;
    uint8_t temp;
    /* 使能NOR Flash片选引脚端口时钟 */
    NORFLASH_CS_GPIO_CLK_ENABLE();
    
    /* NOR Flash片选引脚 */
    gpio_init_struct.pin = NORFLASH_CS_GPIO_PIN;
    gpio_init_struct.speed = GPIO_SPEED_50MHz;           /* 高速 */
    gpio_init_struct.mode = GPIO_MODE_OUT_PP;            /* 推挽输出模式 */
    GPIO_Config(NORFLASH_CS_GPIO_PORT, &gpio_init_struct);
    NORFLASH_CS(1);                                      /* 失能NOR Flash片选 */
    
/* 配置SPI2接口 */
spi2_init();                                         /* 初始化SPI2 */
/* 设置SPI2速度,60MHz/2=30MHz */
    spi2_set_speed(SPI_SPEED_2);
/* 读取NOR Flash芯片ID */
g_norflash_type = norflash_read_id();
/* W25Q256需使能4字节地址模式 */
    if (g_norflash_type == W25Q256)
{
/* 读状态寄存器3,判断地址模式 */
        temp = norflash_read_sr(3);
/* 如果不是4字节地址模式,则需进行相应配置 */
        if ((temp & 0x01) == 0)
        {
            norflash_write_enable();                     /* NOR Flash写使能 */
/* ADP=1,配置上电4字节地址模式 */
            temp |= (1 << 1);
            norflash_write_sr(3, temp);                  /* 写状态寄存器3 */
            NORFLASH_CS(0);                              /* 使能NOR Flash片选 */
/* 使能4字节地址模式 */
            spi2_read_write_byte(NORFLASH_Enable4ByteAddr);
            NORFLASH_CS(1);                              /* 失能NOR Flash片选 */
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

可以看到,在NOR Flash的初始化函数中,先初始化了控制NOR Flash片选的GPIO引脚,然后再是初始化与NOR Flash通讯的SPI并配置其通讯波特率,最后还会根据不同容量的NOR Flash做相应的配置操作。
NOR Flash驱动中其他对NOR Flash的操作函数,例如,NOR Flash的读写函数、擦除函数等,请读者结合25Q128 NOR Flash芯片的数据手册查看本实验的配套实验源码。
41.2.4 实验应用代码
本章实验的应用代码,如下所示:

/* 待写入NOR Flash的数据 */
static const uint8_t g_text_buf[] = {"APM32 SPI TEST"};

/* 待写入NOR Flash数据的长度 */
#define TEXT_SIZE sizeof(g_text_buf)

int main(void)
{
    uint16_t id;
    uint8_t t = 0;
    uint8_t key;
    uint8_t data[TEXT_SIZE];
    uint32_t flashsize;
    
    NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4);  /* 设置中断优先级分组为组4 */
    sys_apm32_clock_init(15);                         /* 配置系统时钟 */
    delay_init(120);                                  /* 初始化延时功能 */
    usart_init(115200);                               /* 初始化串口 */
    usmart_dev.init(120);                             /* 初始化USMART */
    led_init();                                       /* 初始化LED */
    lcd_init();                                       /* 初始化LCD */
    norflash_init();                                  /* 初始化NOR Flash */
    
    lcd_show_string(30, 50, 200, 16, 16, "APM32", RED);
    lcd_show_string(30, 70, 200, 16, 16, "SPI TEST", RED);
    lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
    lcd_show_string(30, 110, 200, 16, 16, "KEY_UP:Write  KEY0:Read", RED);
    
    id = norflash_read_id();                          /* 读NOR Flash芯片ID */
    while ((id == 0) || (id == 0xFFFF))               /* 检测不到NOR Flash芯片 */
    {
        lcd_show_string(30, 130, 200, 16, 16, "NOR Flash Check Failed!", RED);
        delay_ms(500);
        lcd_show_string(30, 130, 200, 16, 16, "Please Check!          ", RED);
        delay_ms(500);
        LED0_TOGGLE();
}
/* NOR Flash检测正常 */
lcd_show_string(30, 130, 200, 16, 16, "NOR FLASH Ready!", BLUE);
/* NOR Flash容量为16MB */
    flashsize = 16 * 1024 * 1204;
    
    while (1)
    {
        t++;
        key = key_scan(0);
        
        if (key == WKUP_PRES)                         /* 写入数据 */
        {
            lcd_fill(0, 150, 239, 319, WHITE);
            lcd_show_string(30, 150, 200, 16, 16,
"Start Write Flash....", BLUE);
            sprintf((char *)data, "%s%d", (char *)g_text_buf, t);
/* 从倒数第100个地址处开始写入TEXT_SIZE个字节的数据 */
            norflash_write((uint8_t *)data, flashsize - 100, TEXT_SIZE);
            lcd_show_string(30, 150, 200, 16, 16, 
"Flash Write Finished!", BLUE);
        }
        else if (key == KEY0_PRES)                    /* 读取数据 */
        {
            lcd_show_string(30, 150, 200, 16, 16,
"Start Read FLASH... . ", BLUE);
/* 从倒数第100个地址处开始读出TEXT_SIZE个字节的数据 */
            norflash_read(data, flashsize - 100, TEXT_SIZE);
            lcd_show_string(30, 150, 200, 16, 16,
"The Data Readed Is:   ", BLUE);
            lcd_show_string(30, 170, 200, 16, 16, (char *)data, BLUE);
        }
        
        if (t == 20)
        {
            LED0_TOGGLE();
            t = 0;
        }
        delay_ms(10);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77

从本章实验的应用代码中可以看到,在初始化完NOR Flash后,会检测与NOR Flash的连接是否正常,若与NOR Flash的连接正常,则会不断地等待按键输入,若检测到KEY_UP按键被按下,则会往NOR Flash的指定地址中写入指定的数据,若检测KEY0按键被按下,则会从NOR Flash的指定地址中读取数据,并在LCD上进行显示。
41.3 下载验证
在完成编译和烧录操作后,若MCU与NOR Flash的连接无误,则可以在LCD上看到“NOR Flash Ready!”的提示信息,此时可以按下KEY_UP按键往NOR Flash的指定地址写入指定的数据,然后再按下KEY_0按键从NOR Flash的指定地址将写入的数据读回来在LCD上进行显示,此时便可以看到LCD上显示“APM32 SPI TESTn”的提示信息,该提示信息就是从NOR Flash中读回的数据。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号