赞
踩
在嵌入式系统开发中,掌握各种外设接口的使用是关键技能之一。UART(通用异步收发传输器)和SPI(串行外围接口)是常见的通信接口,通过它们可以实现微控制器与外部设备之间的数据交换。本实验的目的是通过实际操作,熟悉STM32F103微控制器上UART1和SPI接口的配置与使用方法。
1.掌握STM32F103的UART1的使用
2.掌握STM32F103的SPI读写的使用
单片机为了拓展硬件资源需要和各种外设通信,有的传输距离远、有的需要传输速度快,有的需要抗干扰强,这就需要不同的通信方式。UART(通用异步收发传输器)和SPI(串行外围接口)是两种常用的通信接口。
UART接口因其简单易用和稳定性高,被广泛应用于短距离、低速的通信场合。
而SPI接口则因其高速和全双工通信特点,常用于需要快速数据传输的场合,如存储器读写、传感器数据采集等。
串行通讯 USART /SPI:
1.设备之间通过少量数据信号线(一般是 8 根以下),地线以及控制信号线
2.按数据位形式一位一位地传输数据的通讯方式
并行通讯:
1.使用多个数据线进行传输
2.像多个车道的公路,可以同时传输多个数据位的数据
图1 特性分析
根据数据通讯的方向,通讯又分为全双工、半双工及单工通讯:
1.全双工的通讯就是一个双向车道,两个方向上的车流互不相干;
2.半双工则像乡间小道那样,同一时刻只能让一辆小车通过,另一方向的来车只能等待道路 空出来时才能经过;
3.单工则像单行道,另一方向的车辆完全禁止通行。
同步通讯:收发设备双方会使用一根信号线表示时钟信号,在时钟信号的驱动下 双方进行协调,同步数据
异步通讯:不使用时钟信号进行数据同步,它们直接在数据信号中穿插一些同步用的信号位,或者把主体数据进行打包,以数据帧的格式传输数据
串口通讯(Serial Communication)是一种设备间非常有用的串行通讯方式
1.简单双向串口通信有两根通信线(发送端TX和接收端RX)
2.TX与RX要交叉连接
3.当只需单向的数据传输时,可以只接一根通信线
4.当电平标准不一致时,需要加电平转换芯片
图2 串口通讯接线图
图3 各通信接口的通信协议
波特率:串口通信的速率, 如4800、9600、115200
起始位:标志一个数据帧的开始,固定为低电平
数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行
校验位:用于数据验证,根据数据位计算得来
停止位:用于数据帧间隔,固定为高电平
图4 串口协议时序
传输一帧数据示例
假设传输一帧包含8个数据位、1个校验位和1个停止位的数据帧,总长度为11位。
起始位:固定为0。
数据位:假设数据为 0b10101010(即十进制的170)。
校验位:根据奇偶校验规则计算(假设为偶校验)。
停止位:固定为1。
USART:通用同步异步收发器 (Universal Synchronous Asynchronous Receiver and Transmitter)
串行通信设备,可以灵活地与外部设备进行全双工数据交换。
UART(Universal Asynchronous Receiver and Transmitter):它是在 USART 基础上裁剪掉了同步通信功能,只有异步通信。
简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是UART。
TX:发送数据输出引脚。
RX:接收数据输入引脚。
nRTS: 将被设置为高电平。该引脚只适用于硬件流控制。
nCTS:清除以发送(Clear To Send),n 表示低电平有效。如果使能CTS流控制,发送器在发送下一帧数据之前会检测nCTS引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前数据帧之后停止发送。该引脚只适用于硬件流控制。
SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。
图5 配置引脚图
图6 USART-发送和接收控制器
(1) 使能 RX 和 TX 引脚 GPIO 时钟和 USART 时钟;
(2) 初始化 GPIO,并将 GPIO 复用到 USART 上;
(3) 配置 USART 参数;
(4) 配置中断控制器并使能 USART 接收中断;
(5) 使能 USART;
(6) 在 USART 接收中断服务函数实现数据接收和发送。
硬件准备
开发板:确保开发板具有USART接口,并连接好所需的电缆。
电脑:配置好终端软件,如Tera Term、PuTTY或其他串行终端软件。
串口线:用于连接开发板和电脑的串口线。
通过USART进行串行通信,开发板发送字符串到电脑,并进入中断接收等待状态。电脑发送数据后,开发板产生中断并将接收到的数据返回发送给电脑
SPI(Serial Peripheral Interface)是一种同步,全双工支持总线挂载多设备(一主多从)的串行通信协议,通常用于短距离通信。它包含四条主要信号线:
NSS(Slave Select):选择从设备。
SCK(Serial Clock):时钟信号。
MOSI(Master Out Slave In):主机输出从机输入。
MISO(Master In Slave Out):主机输入从机输出。
在 SPI 通信中,NSS、SCK、MOSI 信号都由主机控制产生,而 MISO 信号由从机产生,主机通过该信号线读取从机的数据。MOSI 与 MISO 的信号只在 NSS 为低电平的时候才有效,在SCK 的每个时钟周期 MOSI 和 MISO 传输一位数据。
图7 SPI时序图
时序图说明
NSS 低电平:当 NSS 线为低电平时,SPI 通信开始,主机选择从机进行通信。在整个低电平期间,主机和从机之间的通信有效。
SCK 时钟信号:SCK 信号由主机产生,每一个时钟周期(即一个上升沿到下一个上升沿)代表一位数据的传输。在 SCK 的上升沿或下降沿(取决于 SPI 模式),MOSI 和 MISO 线上分别传输和接收数据位。
MOSI 数据传输:MOSI 线上,数据在 SCK 时钟信号的每个有效沿传输。
MISO 数据接收:MISO 线上,数据在 SCK 时钟信号的每个有效沿传输。
关键点
数据同步:SPI 是一种同步通信协议,数据传输和接收都由时钟信号(SCK)同步进行。
时钟极性和相位(SPI 模式):SCK 的上升沿或下降沿决定了数据的采样时间,这由 SPI 模式决定。常见的四种模式分别为:
模式0:CPOL = 0, CPHA = 0(时钟空闲状态为低电平,数据在上升沿采样)
模式1:CPOL = 0, CPHA = 1(时钟空闲状态为低电平,数据在下降沿采样)
模式2:CPOL = 1, CPHA = 0(时钟空闲状态为高电平,数据在下降沿采样)
模式3:CPOL = 1, CPHA = 1(时钟空闲状态为高电平,数据在上升沿采样)
SPI 的所有硬件架构都从 MOSI、MISO、SCK 及 NSS 线展开的。
STM32 芯片有多个 SPI 外设,它们的 SPI 通讯信号引出到不同的 GPIO 引脚上,使用时必须配置到这些指定的引脚
图8 SPI引脚图
(1) 初始化通讯使用的目标引脚及端口时钟;
(2) 使能 SPI 外设的时钟;
(3) 配置 SPI 外设的模式、地址、速率等参数并使能 SPI 外设;
(4) 编写基本 SPI 按字节收发的函数;
(5) 编写对 FLASH 擦除及读写操作的的函数;
(6) 编写测试程序,对读写数据进行校验。
本实验是一种使用 SPI 通讯的串行 FLASH 存储芯片的读写实验为大家讲解 STM32 的SPI 使用方法。 实验中 STM32 的 SPI 外设采用主模式,通过查询事件的方式来确保正常通讯。
本实验板中的 FLASH 芯片(型号:W25Q64)是一种使用 SPI 通讯协议的 NOR FLASH 存储器,它的 CS/CLK/DIO/DO 引 脚分别连接到了STM32 对应的NSS/SCK/MOSI/MISO 的 SPI 引脚上
SPI 的基本收发单元定义好,还需要了解如何对 FLASH 芯片进行读写。
FLASH 芯片自定义了很多指令,我们通过控制 STM32 利用 SPI 总线向 FLASH 芯片发送指令,FLASH芯片收到后就会执行相应的操作。
实验例程提供的串口波特率是115200,数据位8,无校验位,1位停止位。设计程序,将上位机电脑端的波特率为9600实现单片机发送“Welcome to SZTU”;设计程序将上位机数据位设为7,校验位为Odd, 停止位为2,实现“THIS IS SGIM”。在单片机中通过寄存器进行初始化,改变波特率、奇偶校验、停止位等参数,如何设置串口助手参数实现信号的正确发送和接收?
图9 修改波特率
图10发送“Welcome to SZTU”
图11 usart配置修改
图12 发送“THIS IS SGIM”
图13 设置串口助手参数
- #include "stm32f10x.h"
- #include "bsp_usart.h"
-
-
- /**
- * @brief 主函数
- * @param 无
- * @retval 无
- */
- int main(void)
- {
- /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
- USART_Config();
-
- /* 发送一个字符串 */
- Usart_SendString( DEBUG_USARTx,"THIS IS EAT\n");
- printf("吃货吃吃吃吃吃吃\n\n\n\n");
-
- while(1)
- {
-
- }
- }
- /*********************************************END OF FILE**********************/
- #include "bsp_usart.h"
-
- /**
- * @brief 配置嵌套向量中断控制器NVIC
- * @param 无
- * @retval 无
- */
- static void NVIC_Configuration(void)
- {
- NVIC_InitTypeDef NVIC_InitStructure;
-
- /* 嵌套向量中断控制器组选择 */
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
-
- /* 配置USART为中断源 */
- NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
- /* 抢断优先级*/
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
- /* 子优先级 */
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
- /* 使能中断 */
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- /* 初始化配置NVIC */
- NVIC_Init(&NVIC_InitStructure);
- }
-
- /**
- * @brief USART GPIO 配置,工作参数配置
- * @param 无
- * @retval 无
- */
- void USART_Config(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- USART_InitTypeDef USART_InitStructure;
-
- // 打开串口GPIO的时钟
- DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
-
- // 打开串口外设的时钟
- DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
-
- // 将USART Tx的GPIO配置为推挽复用模式
- GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
-
- // 将USART Rx的GPIO配置为浮空输入模式
- GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
-
- // 配置串口的工作参数
- // 配置波特率
- USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
- // 配置 针数据字长
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;
- // 配置停止位
- USART_InitStructure.USART_StopBits = USART_StopBits_2;
- // 配置校验位
- USART_InitStructure.USART_Parity = USART_Parity_Odd;
- // 配置硬件流控制
- USART_InitStructure.USART_HardwareFlowControl =
- USART_HardwareFlowControl_None;
- // 配置工作模式,收发一起
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
- // 完成串口的初始化配置
- USART_Init(DEBUG_USARTx, &USART_InitStructure);
-
- // 串口中断优先级配置
- NVIC_Configuration();
-
- // 使能串口接收中断
- USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
-
- // 使能串口
- USART_Cmd(DEBUG_USARTx, ENABLE);
- }
-
- /***************** 发送一个字节 **********************/
- void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
- {
- /* 发送一个字节数据到USART */
- USART_SendData(pUSARTx,ch);
-
- /* 等待发送数据寄存器为空 */
- while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
- }
-
- /****************** 发送8位的数组 ************************/
- void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
- {
- uint8_t i;
-
- for(i=0; i<num; i++)
- {
- /* 发送一个字节数据到USART */
- Usart_SendByte(pUSARTx,array[i]);
-
- }
- /* 等待发送完成 */
- while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
- }
-
- /***************** 发送字符串 **********************/
- void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
- {
- unsigned int k=0;
- do
- {
- Usart_SendByte( pUSARTx, *(str + k) );
- k++;
- } while(*(str + k)!='\0');
-
- /* 等待发送完成 */
- while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
- {}
- }
-
- /***************** 发送一个16位数 **********************/
- void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
- {
- uint8_t temp_h, temp_l;
-
- /* 取出高八位 */
- temp_h = (ch&0XFF00)>>8;
- /* 取出低八位 */
- temp_l = ch&0XFF;
-
- /* 发送高八位 */
- USART_SendData(pUSARTx,temp_h);
- while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
-
- /* 发送低八位 */
- USART_SendData(pUSARTx,temp_l);
- while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
- }
-
- ///重定向c库函数printf到串口,重定向后可使用printf函数
- int fputc(int ch, FILE *f)
- {
- /* 发送一个字节数据到串口 */
- USART_SendData(DEBUG_USARTx, (uint8_t) ch);
-
- /* 等待发送完毕 */
- while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
-
- return (ch);
- }
-
- ///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
- int fgetc(FILE *f)
- {
- /* 等待串口输入数据 */
- while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
-
- return (int)USART_ReceiveData(DEBUG_USARTx);
- }
-
- #ifndef __USART_H
- #define __USART_H
-
-
- #include "stm32f10x.h"
- #include <stdio.h>
-
- /**
- * 串口宏定义,不同的串口挂载的总线和IO不一样,移植时需要修改这几个宏
- * 1-修改总线时钟的宏,uart1挂载到apb2总线,其他uart挂载到apb1总线
- * 2-修改GPIO的宏
- */
-
- // 串口1-USART1
- #define DEBUG_USARTx USART1
- #define DEBUG_USART_CLK RCC_APB2Periph_USART1
- #define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
- #define DEBUG_USART_BAUDRATE 115200
-
- // USART GPIO 引脚宏定义
- #define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
- #define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
-
- #define DEBUG_USART_TX_GPIO_PORT GPIOA
- #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
- #define DEBUG_USART_RX_GPIO_PORT GPIOA
- #define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
-
- #define DEBUG_USART_IRQ USART1_IRQn
- #define DEBUG_USART_IRQHandler USART1_IRQHandler
-
-
- // 串口2-USART2
- //#define DEBUG_USARTx USART2
- //#define DEBUG_USART_CLK RCC_APB1Periph_USART2
- //#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
- //#define DEBUG_USART_BAUDRATE 115200
-
- USART GPIO 引脚宏定义
- //#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
- //#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
- //
- //#define DEBUG_USART_TX_GPIO_PORT GPIOA
- //#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_2
- //#define DEBUG_USART_RX_GPIO_PORT GPIOA
- //#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_3
-
- //#define DEBUG_USART_IRQ USART2_IRQn
- //#define DEBUG_USART_IRQHandler USART2_IRQHandler
-
- // 串口3-USART3
- //#define DEBUG_USARTx USART3
- //#define DEBUG_USART_CLK RCC_APB1Periph_USART3
- //#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
- //#define DEBUG_USART_BAUDRATE 115200
-
- USART GPIO 引脚宏定义
- //#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOB)
- //#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
- //
- //#define DEBUG_USART_TX_GPIO_PORT GPIOB
- //#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
- //#define DEBUG_USART_RX_GPIO_PORT GPIOB
- //#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
-
- //#define DEBUG_USART_IRQ USART3_IRQn
- //#define DEBUG_USART_IRQHandler USART3_IRQHandler
-
- // 串口4-UART4
- //#define DEBUG_USARTx UART4
- //#define DEBUG_USART_CLK RCC_APB1Periph_UART4
- //#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
- //#define DEBUG_USART_BAUDRATE 115200
-
- USART GPIO 引脚宏定义
- //#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC)
- //#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
- //
- //#define DEBUG_USART_TX_GPIO_PORT GPIOC
- //#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
- //#define DEBUG_USART_RX_GPIO_PORT GPIOC
- //#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
-
- //#define DEBUG_USART_IRQ UART4_IRQn
- //#define DEBUG_USART_IRQHandler UART4_IRQHandler
-
-
- // 串口5-UART5
- //#define DEBUG_USARTx UART5
- //#define DEBUG_USART_CLK RCC_APB1Periph_UART5
- //#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
- //#define DEBUG_USART_BAUDRATE 115200
-
- USART GPIO 引脚宏定义
- //#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD)
- //#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
- //
- //#define DEBUG_USART_TX_GPIO_PORT GPIOC
- //#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_12
- //#define DEBUG_USART_RX_GPIO_PORT GPIOD
- //#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_2
-
- //#define DEBUG_USART_IRQ UART5_IRQn
- //#define DEBUG_USART_IRQHandler UART5_IRQHandler
-
-
- void USART_Config(void);
- void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
- void Usart_SendString( USART_TypeDef * pUSARTx, char *str);
- void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch);
-
- #endif /* __USART_H */
为了确保通信的正确,降低误码率,工业使用异步串口通信通常需要设计一个协议标准,比如以“AA”表示开始,增加CRC校验作为结尾。设计程序实现“地址码 功能码 校验码”的数据发送。比如“AA 33 XX”,其中AA为地址码,33为发送的数据,XX是计算的CRC校验码(CRC校验可以参考网络CRC计算程序CRC(循环冗余校验)在线计算_ip33.com)。
图14 CRC计算代码
图15 实现“地址码 功能码 数据 校验码”发送的函数
图16 主函数
在bsp_usart.c中添加
- #define POLY 0x1021
-
- uint16_t calculate_crc(uint8_t *data, uint16_t length) {
- uint16_t crc = 0xFFFF;
- for (uint16_t i = 0; i < length; i++) {
- crc ^= (uint16_t)data[i] << 8;
- for (uint8_t j = 0; j < 8; j++) {
- if (crc & 0x8000) {
- crc = (crc << 1) ^ POLY;
- } else {
- crc = crc << 1;
- }
- }
- }
- return crc;
- }
-
- void send_packet(uint8_t address, uint8_t function, uint8_t data) {
- uint8_t packet[6];
- packet[0] = 0xAA; // 起始符
- packet[1] = address;
- packet[2] = function;
- packet[3] = data;
-
- uint16_t crc = calculate_crc(packet, 4);
- packet[4] = crc & 0xFF; // CRC低字节
- packet[5] = (crc >> 8) & 0xFF; // CRC高字节
- // 通过串口发送数据包
- for (int i = 0; i < 6; i++) {
- USART_SendData(DEBUG_USARTx, packet[i]);
- while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
- }
- }
画出SPI_FLASH_BufferWrite和SPI_FLASH_BufferRead的流程图,具体到CS, MOSI,MISO,CLK信号值。基于例 程,设计程序实现将“SZTU”存入SPI Flash, 并通过读出值判读存入数据是否正确。
SPI_FLASH_BufferWrite 流程图
启动信号传输:拉低CS(Chip Select)使设备处于选中状态。
发送写入命令:通过MOSI(Master Out Slave In)发送写入命令。
发送地址:通过MOSI发送数据要写入的起始地址。
写入数据:通过MOSI发送数据。
停止信号传输:拉高CS结束写入过程。
SPI_FLASH_BufferRead 流程图
启动信号传输:拉低CS。
发送读取命令:通过MOSI发送读取命令。
发送地址:通过MOSI发送要读取数据的起始地址。
读取数据:通过MISO(Master In Slave Out)接收数据。
停止信号传输:拉高CS结束读取过程。
图17 SPI_FLASH_BufferWrite流程图
图18 SPI_FLASH_BufferRead流程图
图19 读写页面流程图
图20 发送缓冲区写入SZTU
图21 将“SZTU”存入SPI Flash, 并通过读出值判读存入数据是否正确
- #include "./flash/bsp_spi_flash.h"
-
- static __IO uint32_t SPITimeout = SPIT_LONG_TIMEOUT;
- static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);
-
- /**
- * @brief SPI_FLASH初始化
- * @param 无
- * @retval 无
- */
- void SPI_FLASH_Init(void)
- {
- SPI_InitTypeDef SPI_InitStructure;
- GPIO_InitTypeDef GPIO_InitStructure;
-
- /* 使能SPI时钟 */
- FLASH_SPI_APBxClock_FUN ( FLASH_SPI_CLK, ENABLE );
-
- /* 使能SPI引脚相关的时钟 */
- FLASH_SPI_CS_APBxClock_FUN ( FLASH_SPI_CS_CLK|FLASH_SPI_SCK_CLK|
- FLASH_SPI_MISO_PIN|FLASH_SPI_MOSI_PIN, ENABLE );
-
- /* 配置SPI的 CS引脚,普通IO即可 */
- GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_PIN;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_Init(FLASH_SPI_CS_PORT, &GPIO_InitStructure);
-
- /* 配置SPI的 SCK引脚*/
- GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_Init(FLASH_SPI_SCK_PORT, &GPIO_InitStructure);
-
- /* 配置SPI的 MISO引脚*/
- GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;
- GPIO_Init(FLASH_SPI_MISO_PORT, &GPIO_InitStructure);
-
- /* 配置SPI的 MOSI引脚*/
- GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;
- GPIO_Init(FLASH_SPI_MOSI_PORT, &GPIO_InitStructure);
-
- /* 停止信号 FLASH: CS引脚高电平*/
- SPI_FLASH_CS_HIGH();
-
- /* SPI 模式配置 */
- // FLASH芯片 支持SPI模式0及模式3,据此设置CPOL CPHA
- SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
- SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
- SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
- SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
- SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
- SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
- SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
- SPI_InitStructure.SPI_CRCPolynomial = 7;
- SPI_Init(FLASH_SPIx , &SPI_InitStructure);
-
- /* 使能 SPI */
- SPI_Cmd(FLASH_SPIx , ENABLE);
-
- }
- /**
- * @brief 擦除FLASH扇区
- * @param SectorAddr:要擦除的扇区地址
- * @retval 无
- */
- void SPI_FLASH_SectorErase(u32 SectorAddr)
- {
- /* 发送FLASH写使能命令 */
- SPI_FLASH_WriteEnable();
- SPI_FLASH_WaitForWriteEnd();
- /* 擦除扇区 */
- /* 选择FLASH: CS低电平 */
- SPI_FLASH_CS_LOW();
- /* 发送扇区擦除指令*/
- SPI_FLASH_SendByte(W25X_SectorErase);
- /*发送擦除扇区地址的高位*/
- SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);
- /* 发送擦除扇区地址的中位 */
- SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);
- /* 发送擦除扇区地址的低位 */
- SPI_FLASH_SendByte(SectorAddr & 0xFF);
- /* 停止信号 FLASH: CS 高电平 */
- SPI_FLASH_CS_HIGH();
- /* 等待擦除完毕*/
- SPI_FLASH_WaitForWriteEnd();
- }
-
- /**
- * @brief 擦除FLASH扇区,整片擦除
- * @param 无
- * @retval 无
- */
- void SPI_FLASH_BulkErase(void)
- {
- /* 发送FLASH写使能命令 */
- SPI_FLASH_WriteEnable();
-
- /* 整块 Erase */
- /* 选择FLASH: CS低电平 */
- SPI_FLASH_CS_LOW();
- /* 发送整块擦除指令*/
- SPI_FLASH_SendByte(W25X_ChipErase);
- /* 停止信号 FLASH: CS 高电平 */
- SPI_FLASH_CS_HIGH();
-
- /* 等待擦除完毕*/
- SPI_FLASH_WaitForWriteEnd();
- }
-
- /**
- * @brief 对FLASH按页写入数据,调用本函数写入数据前需要先擦除扇区
- * @param pBuffer,要写入数据的指针
- * @param WriteAddr,写入地址
- * @param NumByteToWrite,写入数据长度,必须小于等于SPI_FLASH_PerWritePageSize
- * @retval 无
- */
- void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
- {
- /* 发送FLASH写使能命令 */
- SPI_FLASH_WriteEnable();
-
- /* 选择FLASH: CS低电平 */
- SPI_FLASH_CS_LOW();
- /* 写页写指令*/
- SPI_FLASH_SendByte(W25X_PageProgram);
- /*发送写地址的高位*/
- SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);
- /*发送写地址的中位*/
- SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);
- /*发送写地址的低位*/
- SPI_FLASH_SendByte(WriteAddr & 0xFF);
-
- if(NumByteToWrite > SPI_FLASH_PerWritePageSize)
- {
- NumByteToWrite = SPI_FLASH_PerWritePageSize;
- FLASH_ERROR("SPI_FLASH_PageWrite too large!");
- }
-
- /* 写入数据*/
- while (NumByteToWrite--)
- {
- /* 发送当前要写入的字节数据 */
- SPI_FLASH_SendByte(*pBuffer);
- /* 指向下一字节数据 */
- pBuffer++;
- }
-
- /* 停止信号 FLASH: CS 高电平 */
- SPI_FLASH_CS_HIGH();
-
- /* 等待写入完毕*/
- SPI_FLASH_WaitForWriteEnd();
- }
-
- /**
- * @brief 对FLASH写入数据,调用本函数写入数据前需要先擦除扇区
- * @param pBuffer,要写入数据的指针
- * @param WriteAddr,写入地址
- * @param NumByteToWrite,写入数据长度
- * @retval 无
- */
- void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
- {
- u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
-
- /*mod运算求余,若writeAddr是SPI_FLASH_PageSize整数倍,运算结果Addr值为0*/
- Addr = WriteAddr % SPI_FLASH_PageSize;
-
- /*差count个数据值,刚好可以对齐到页地址*/
- count = SPI_FLASH_PageSize - Addr;
- /*计算出要写多少整数页*/
- NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
- /*mod运算求余,计算出剩余不满一页的字节数*/
- NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
-
- /* Addr=0,则WriteAddr 刚好按页对齐 aligned */
- if (Addr == 0)
- {
- /* NumByteToWrite < SPI_FLASH_PageSize */
- if (NumOfPage == 0)
- {
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
- }
- else /* NumByteToWrite > SPI_FLASH_PageSize */
- {
- /*先把整数页都写了*/
- while (NumOfPage--)
- {
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
- WriteAddr += SPI_FLASH_PageSize;
- pBuffer += SPI_FLASH_PageSize;
- }
- /*若有多余的不满一页的数据,把它写完*/
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
- }
- }
- /* 若地址与 SPI_FLASH_PageSize 不对齐 */
- else
- {
- /* NumByteToWrite < SPI_FLASH_PageSize */
- if (NumOfPage == 0)
- {
- /*当前页剩余的count个位置比NumOfSingle小,一页写不完*/
- if (NumOfSingle > count)
- {
- temp = NumOfSingle - count;
- /*先写满当前页*/
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
-
- WriteAddr += count;
- pBuffer += count;
- /*再写剩余的数据*/
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
- }
- else /*当前页剩余的count个位置能写完NumOfSingle个数据*/
- {
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
- }
- }
- else /* NumByteToWrite > SPI_FLASH_PageSize */
- {
- /*地址不对齐多出的count分开处理,不加入这个运算*/
- NumByteToWrite -= count;
- NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
- NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
-
- /* 先写完count个数据,为的是让下一次要写的地址对齐 */
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
-
- /* 接下来就重复地址对齐的情况 */
- WriteAddr += count;
- pBuffer += count;
- /*把整数页都写了*/
- while (NumOfPage--)
- {
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
- WriteAddr += SPI_FLASH_PageSize;
- pBuffer += SPI_FLASH_PageSize;
- }
- /*若有多余的不满一页的数据,把它写完*/
- if (NumOfSingle != 0)
- {
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
- }
- }
- }
- }
-
- /**
- * @brief 读取FLASH数据
- * @param pBuffer,存储读出数据的指针
- * @param ReadAddr,读取地址
- * @param NumByteToRead,读取数据长度
- * @retval 无
- */
- void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
- {
- /* 选择FLASH: CS低电平 */
- SPI_FLASH_CS_LOW();
-
- /* 发送 读 指令 */
- SPI_FLASH_SendByte(W25X_ReadData);
-
- /* 发送 读 地址高位 */
- SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
- /* 发送 读 地址中位 */
- SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
- /* 发送 读 地址低位 */
- SPI_FLASH_SendByte(ReadAddr & 0xFF);
-
- /* 读取数据 */
- while (NumByteToRead--) /* while there is data to be read */
- {
- /* 读取一个字节*/
- *pBuffer = SPI_FLASH_SendByte(Dummy_Byte);
- /* 指向下一个字节缓冲区 */
- pBuffer++;
- }
-
- /* 停止信号 FLASH: CS 高电平 */
- SPI_FLASH_CS_HIGH();
- }
-
- /**
- * @brief 读取FLASH ID
- * @param 无
- * @retval FLASH ID
- */
- u32 SPI_FLASH_ReadID(void)
- {
- u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
-
- /* 开始通讯:CS低电平 */
- SPI_FLASH_CS_LOW();
-
- /* 发送JEDEC指令,读取ID */
- SPI_FLASH_SendByte(W25X_JedecDeviceID);
-
- /* 读取一个字节数据 */
- Temp0 = SPI_FLASH_SendByte(Dummy_Byte);
-
- /* 读取一个字节数据 */
- Temp1 = SPI_FLASH_SendByte(Dummy_Byte);
-
- /* 读取一个字节数据 */
- Temp2 = SPI_FLASH_SendByte(Dummy_Byte);
-
- /* 停止通讯:CS高电平 */
- SPI_FLASH_CS_HIGH();
-
- /*把数据组合起来,作为函数的返回值*/
- Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
-
- return Temp;
- }
- /**
- * @brief 读取FLASH Device ID
- * @param 无
- * @retval FLASH Device ID
- */
- u32 SPI_FLASH_ReadDeviceID(void)
- {
- u32 Temp = 0;
-
- /* Select the FLASH: Chip Select low */
- SPI_FLASH_CS_LOW();
-
- /* Send "RDID " instruction */
- SPI_FLASH_SendByte(W25X_DeviceID);
- SPI_FLASH_SendByte(Dummy_Byte);
- SPI_FLASH_SendByte(Dummy_Byte);
- SPI_FLASH_SendByte(Dummy_Byte);
-
- /* Read a byte from the FLASH */
- Temp = SPI_FLASH_SendByte(Dummy_Byte);
-
- /* Deselect the FLASH: Chip Select high */
- SPI_FLASH_CS_HIGH();
-
- return Temp;
- }
- /*******************************************************************************
- * Function Name : SPI_FLASH_StartReadSequence
- * Description : Initiates a read data byte (READ) sequence from the Flash.
- * This is done by driving the /CS line low to select the device,
- * then the READ instruction is transmitted followed by 3 bytes
- * address. This function exit and keep the /CS line low, so the
- * Flash still being selected. With this technique the whole
- * content of the Flash is read with a single READ instruction.
- * Input : - ReadAddr : FLASH's internal address to read from.
- * Output : None
- * Return : None
- *******************************************************************************/
- void SPI_FLASH_StartReadSequence(u32 ReadAddr)
- {
- /* Select the FLASH: Chip Select low */
- SPI_FLASH_CS_LOW();
- /* Send "Read from Memory " instruction */
- SPI_FLASH_SendByte(W25X_ReadData);
- /* Send the 24-bit address of the address to read from -----------------------*/
- /* Send ReadAddr high nibble address byte */
- SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
- /* Send ReadAddr medium nibble address byte */
- SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
- /* Send ReadAddr low nibble address byte */
- SPI_FLASH_SendByte(ReadAddr & 0xFF);
- }
- /**
- * @brief 使用SPI读取一个字节的数据
- * @param 无
- * @retval 返回接收到的数据
- */
- u8 SPI_FLASH_ReadByte(void)
- {
- return (SPI_FLASH_SendByte(Dummy_Byte));
- }
- /**
- * @brief 使用SPI发送一个字节的数据
- * @param byte:要发送的数据
- * @retval 返回接收到的数据
- */
- u8 SPI_FLASH_SendByte(u8 byte)
- {
- SPITimeout = SPIT_FLAG_TIMEOUT;
- /* 等待发送缓冲区为空,TXE事件 */
- while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_TXE) == RESET)
- {
- if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(0);
- }
- /* 写入数据寄存器,把要写入的数据写入发送缓冲区 */
- SPI_I2S_SendData(FLASH_SPIx , byte);
- SPITimeout = SPIT_FLAG_TIMEOUT;
- /* 等待接收缓冲区非空,RXNE事件 */
- while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_RXNE) == RESET)
- {
- if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(1);
- }
- /* 读取数据寄存器,获取接收缓冲区数据 */
- return SPI_I2S_ReceiveData(FLASH_SPIx );
- }
- /**
- * @brief 使用SPI发送两个字节的数据
- * @param byte:要发送的数据
- * @retval 返回接收到的数据
- */
- u16 SPI_FLASH_SendHalfWord(u16 HalfWord)
- {
- SPITimeout = SPIT_FLAG_TIMEOUT;
- /* 等待发送缓冲区为空,TXE事件 */
- while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_TXE) == RESET)
- {
- if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(2);
- }
-
- /* 写入数据寄存器,把要写入的数据写入发送缓冲区 */
- SPI_I2S_SendData(FLASH_SPIx , HalfWord);
- SPITimeout = SPIT_FLAG_TIMEOUT;
- /* 等待接收缓冲区非空,RXNE事件 */
- while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_RXNE) == RESET)
- {
- if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(3);
- }
- /* 读取数据寄存器,获取接收缓冲区数据 */
- return SPI_I2S_ReceiveData(FLASH_SPIx );
- }
- /**
- * @brief 向FLASH发送 写使能 命令
- * @param none
- * @retval none
- */
- void SPI_FLASH_WriteEnable(void)
- {
- /* 通讯开始:CS低 */
- SPI_FLASH_CS_LOW();
- /* 发送写使能命令*/
- SPI_FLASH_SendByte(W25X_WriteEnable);
- /*通讯结束:CS高 */
- SPI_FLASH_CS_HIGH();
- }
- /* WIP(busy)标志,FLASH内部正在写入 */
- #define WIP_Flag 0x01
- /**
- * @brief 等待WIP(BUSY)标志被置0,即等待到FLASH内部数据写入完毕
- * @param none
- * @retval none
- */
- void SPI_FLASH_WaitForWriteEnd(void)
- {
- u8 FLASH_Status = 0;
- /* 选择 FLASH: CS 低 */
- SPI_FLASH_CS_LOW();
- /* 发送 读状态寄存器 命令 */
- SPI_FLASH_SendByte(W25X_ReadStatusReg);
- /* 若FLASH忙碌,则等待 */
- do
- {
- /* 读取FLASH芯片的状态寄存器 */
- FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);
- }
- while ((FLASH_Status & WIP_Flag) == SET); /* 正在写入标志 */
- /* 停止信号 FLASH: CS 高 */
- SPI_FLASH_CS_HIGH();
- }
- //进入掉电模式
- void SPI_Flash_PowerDown(void)
- {
- /* 通讯开始:CS低 */
- SPI_FLASH_CS_LOW();
- /* 发送 掉电 命令 */
- SPI_FLASH_SendByte(W25X_PowerDown);
- /*通讯结束:CS高 */
- SPI_FLASH_CS_HIGH();
- }
- //唤醒
- void SPI_Flash_WAKEUP(void)
- {
- /*选择 FLASH: CS 低 */
- SPI_FLASH_CS_LOW();
- /* 发送 上电 命令 */
- SPI_FLASH_SendByte(W25X_ReleasePowerDown);
- /* 停止信号 FLASH: CS 高 */
- SPI_FLASH_CS_HIGH();
- }
-
- /**
- * @brief 等待超时回调函数
- * @param None.
- * @retval None.
- */
- static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)
- {
- /* 等待超时后的处理,输出错误信息 */
- FLASH_ERROR("SPI 等待超时!errorCode = %d",errorCode);
- return 0;
- }
-
- /*********************************************END OF FILE**********************/
- #ifndef __SPI_FLASH_H
- #define __SPI_FLASH_H
-
- #include "stm32f10x.h"
- #include <stdio.h>
-
- //#define sFLASH_ID 0xEF3015 //W25X16
- //#define sFLASH_ID 0xEF4015 //W25Q16
- //#define sFLASH_ID 0XEF4018 //W25Q128
- #define sFLASH_ID 0XEF4017 //W25Q64
-
- #define SPI_FLASH_PageSize 256
- #define SPI_FLASH_PerWritePageSize 256
-
- /*命令定义-开头*******************************/
- #define W25X_WriteEnable 0x06
- #define W25X_WriteDisable 0x04
- #define W25X_ReadStatusReg 0x05
- #define W25X_WriteStatusReg 0x01
- #define W25X_ReadData 0x03
- #define W25X_FastReadData 0x0B
- #define W25X_FastReadDual 0x3B
- #define W25X_PageProgram 0x02
- #define W25X_BlockErase 0xD8
- #define W25X_SectorErase 0x20
- #define W25X_ChipErase 0xC7
- #define W25X_PowerDown 0xB9
- #define W25X_ReleasePowerDown 0xAB
- #define W25X_DeviceID 0xAB
- #define W25X_ManufactDeviceID 0x90
- #define W25X_JedecDeviceID 0x9F
-
- /* WIP(busy)标志,FLASH内部正在写入 */
- #define WIP_Flag 0x01
- #define Dummy_Byte 0xFF
- /*命令定义-结尾*******************************/
-
-
- /*SPI接口定义-开头****************************/
- #define FLASH_SPIx SPI1
- #define FLASH_SPI_APBxClock_FUN RCC_APB2PeriphClockCmd
- #define FLASH_SPI_CLK RCC_APB2Periph_SPI1
-
- //CS(NSS)引脚 片选选普通GPIO即可
- #define FLASH_SPI_CS_APBxClock_FUN RCC_APB2PeriphClockCmd
- #define FLASH_SPI_CS_CLK RCC_APB2Periph_GPIOA
- #define FLASH_SPI_CS_PORT GPIOA
- #define FLASH_SPI_CS_PIN GPIO_Pin_4
-
- //SCK引脚
- #define FLASH_SPI_SCK_APBxClock_FUN RCC_APB2PeriphClockCmd
- #define FLASH_SPI_SCK_CLK RCC_APB2Periph_GPIOA
- #define FLASH_SPI_SCK_PORT GPIOA
- #define FLASH_SPI_SCK_PIN GPIO_Pin_5
- //MISO引脚
- #define FLASH_SPI_MISO_APBxClock_FUN RCC_APB2PeriphClockCmd
- #define FLASH_SPI_MISO_CLK RCC_APB2Periph_GPIOA
- #define FLASH_SPI_MISO_PORT GPIOA
- #define FLASH_SPI_MISO_PIN GPIO_Pin_6
- //MOSI引脚
- #define FLASH_SPI_MOSI_APBxClock_FUN RCC_APB2PeriphClockCmd
- #define FLASH_SPI_MOSI_CLK RCC_APB2Periph_GPIOA
- #define FLASH_SPI_MOSI_PORT GPIOA
- #define FLASH_SPI_MOSI_PIN GPIO_Pin_7
-
- #define SPI_FLASH_CS_LOW() GPIO_ResetBits( FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN )
- #define SPI_FLASH_CS_HIGH() GPIO_SetBits( FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN )
-
- /*SPI接口定义-结尾****************************/
-
- /*等待超时时间*/
- #define SPIT_FLAG_TIMEOUT ((uint32_t)0x1000)
- #define SPIT_LONG_TIMEOUT ((uint32_t)(10 * SPIT_FLAG_TIMEOUT))
-
- /*信息输出*/
- #define FLASH_DEBUG_ON 1
-
- #define FLASH_INFO(fmt,arg...) printf("<<-FLASH-INFO->> "fmt"\n",##arg)
- #define FLASH_ERROR(fmt,arg...) printf("<<-FLASH-ERROR->> "fmt"\n",##arg)
- #define FLASH_DEBUG(fmt,arg...) do{\
- if(FLASH_DEBUG_ON)\
- printf("<<-FLASH-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
- }while(0)
-
- void SPI_FLASH_Init(void);
- void SPI_FLASH_SectorErase(u32 SectorAddr);
- void SPI_FLASH_BulkErase(void);
- void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite);
- void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite);
- void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead);
- u32 SPI_FLASH_ReadID(void);
- u32 SPI_FLASH_ReadDeviceID(void);
- void SPI_FLASH_StartReadSequence(u32 ReadAddr);
- void SPI_Flash_PowerDown(void);
- void SPI_Flash_WAKEUP(void);
-
-
- u8 SPI_FLASH_ReadByte(void);
- u8 SPI_FLASH_SendByte(u8 byte);
- u16 SPI_FLASH_SendHalfWord(u16 HalfWord);
- void SPI_FLASH_WriteEnable(void);
- void SPI_FLASH_WaitForWriteEnd(void);
-
-
- #endif /* __SPI_FLASH_H */
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。