固件库模板
GPIO 输入输出
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_SetBits(GPIOB, GPIO_Pin_0);
GPIO_ResetBits(GPIOB, GPIO_Pin_0);
按键
以野火STM32F103ZET6为例,按键有硬件消抖功能,故不用延时
void KEY_GPIO_Config()
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 ;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void Key(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
if(GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == 1)
{
·······
while(GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == 1);
}
else
{
······
}
}
位带操作
// sys.h
#ifndef __SYS_H
#define __SYS_H
#include "stm32f10x.h"
typedef struct
{
volatile unsigned short bit0 : 1;
volatile unsigned short bit1 : 1;
volatile unsigned short bit2 : 1;
volatile unsigned short bit3 : 1;
volatile unsigned short bit4 : 1;
volatile unsigned short bit5 : 1;
volatile unsigned short bit6 : 1;
volatile unsigned short bit7 : 1;
volatile unsigned short bit8 : 1;
volatile unsigned short bit9 : 1;
volatile unsigned short bit10 : 1;
volatile unsigned short bit11 : 1;
volatile unsigned short bit12 : 1;
volatile unsigned short bit13 : 1;
volatile unsigned short bit14 : 1;
volatile unsigned short bit15 : 1;
} GPIO_Bit_TypeDef;
#define PORTA_OUT ((GPIO_Bit_TypeDef *)(&(GPIOA->ODR)))
#define PORTA_IN ((GPIO_Bit_TypeDef *)(&(GPIOA->IDR)))
#define PORTB_OUT ((GPIO_Bit_TypeDef *)(&(GPIOB->ODR)))
#define PORTB_IN ((GPIO_Bit_TypeDef *)(&(GPIOB->IDR)))
#define PORTC_OUT ((GPIO_Bit_TypeDef *)(&(GPIOC->ODR)))
#define PORTC_IN ((GPIO_Bit_TypeDef *)(&(GPIOC->IDR)))
#define PORTD_OUT ((GPIO_Bit_TypeDef *)(&(GPIOD->ODR)))
#define PORTD_IN ((GPIO_Bit_TypeDef *)(&(GPIOD->IDR)))
#define PORTE_OUT ((GPIO_Bit_TypeDef *)(&(GPIOE->ODR)))
#define PORTE_IN ((GPIO_Bit_TypeDef *)(&(GPIOE->IDR)))
#define PORTF_OUT ((GPIO_Bit_TypeDef *)(&(GPIOF->ODR)))
#define PORTF_IN ((GPIO_Bit_TypeDef *)(&(GPIOF->IDR)))
#define PORTG_OUT ((GPIO_Bit_TypeDef *)(&(GPIOG->ODR)))
#define PORTG_IN ((GPIO_Bit_TypeDef *)(&(GPIOG->IDR)))
#define PAout(n) (PORTA_OUT->bit##n)
#define PAin(n) (PORTA_IN->bit##n)
#define PBout(n) (PORTB_OUT->bit##n)
#define PBin(n) (PORTB_IN->bit##n)
#define PCout(n) (PORTC_OUT->bit##n)
#define PCin(n) (PORTC_IN->bit##n)
#define PDout(n) (PORTD_OUT->bit##n)
#define PDin(n) (PORTD_IN->bit##n)
#define PEout(n) (PORTE_OUT->bit##n)
#define PEin(n) (PORTE_IN->bit##n)
#define PFout(n) (PORTF_OUT->bit##n)
#define PFin(n) (PORTF_IN->bit##n)
#define PGout(n) (PORTG_OUT->bit##n)
#define PGin(n) (PORTG_IN->bit##n)
#define CLK_PA RCC_APB2Periph_GPIOA
#define CLK_PB RCC_APB2Periph_GPIOB
#define CLK_PC RCC_APB2Periph_GPIOC
#define CLK_PD RCC_APB2Periph_GPIOD
#define CLK_PE RCC_APB2Periph_GPIOE
#define CLK_PF RCC_APB2Periph_GPIOF
#define CLK_PG RCC_APB2Periph_GPIOG
#define HIGH 1
#define LOW 0
void Pin_out(uint32_t Periph_CLK, uint16_t GPIO_Pin, uint16_t elec_level);
#endif
// sys.c
#include "sys.h"
void Pin_out(uint32_t Periph_CLK, uint16_t GPIO_Pin, uint16_t elec_level)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(Periph_CLK, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
if(Periph_CLK == CLK_PA)
{
GPIO_Init(GPIOA, &GPIO_InitStruct);
if(elec_level)
{
GPIO_SetBits(GPIOA, GPIO_Pin);
}
else
{
GPIO_ResetBits(GPIOA, GPIO_Pin);
}
}
else if(Periph_CLK == CLK_PB)
{
GPIO_Init(GPIOB, &GPIO_InitStruct);
if(elec_level)
{
GPIO_SetBits(GPIOB, GPIO_Pin);
}
else
{
GPIO_ResetBits(GPIOB, GPIO_Pin);
}
}
else if(Periph_CLK == CLK_PC)
{
GPIO_Init(GPIOC, &GPIO_InitStruct);
if(elec_level)
{
GPIO_SetBits(GPIOC, GPIO_Pin);
}
else
{
GPIO_ResetBits(GPIOC, GPIO_Pin);
}
}
else if(Periph_CLK == CLK_PD)
{
GPIO_Init(GPIOD, &GPIO_InitStruct);
if(elec_level)
{
GPIO_SetBits(GPIOD, GPIO_Pin);
}
else
{
GPIO_ResetBits(GPIOD, GPIO_Pin);
}
}
else if(Periph_CLK == CLK_PE)
{
GPIO_Init(GPIOE, &GPIO_InitStruct);
if(elec_level)
{
GPIO_SetBits(GPIOE, GPIO_Pin);
}
else
{
GPIO_ResetBits(GPIOE, GPIO_Pin);
}
}
else if(Periph_CLK == CLK_PF)
{
GPIO_Init(GPIOF, &GPIO_InitStruct);
if(elec_level)
{
GPIO_SetBits(GPIOF, GPIO_Pin);
}
else
{
GPIO_ResetBits(GPIOF, GPIO_Pin);
}
}
else if(Periph_CLK == CLK_PG)
{
GPIO_Init(GPIOG, &GPIO_InitStruct);
if(elec_level)
{
GPIO_SetBits(GPIOG, GPIO_Pin);
}
else
{
GPIO_ResetBits(GPIOG, GPIO_Pin);
}
}
}
位带操作例题:
main.c
#include "stm32f10x.h"
#include "sys.h"
int main()
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
PBout(0) = 1;
return 0;
}
系统时钟
// BSP_RCC_clkconfig.h
#ifndef __BSP_RCC_CLKCONFIG_H
#define __BSP_RCC_CLKCONFIG_H
#include "stm32f10x.h"
void HSE_SetSysClk(uint32_t RCC_PLLMul_x);
void MCO_GPIO_Config();
#endif
// BSP_RCC_clkconfig.c
#include "BSP_RCC_clkconfig.h"
void HSE_SetSysClk(uint32_t RCC_PLLMul_x)
{
ErrorStatus HSEStatus;
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);
HSEStatus = RCC_WaitForHSEStartUp();
if(HSEStatus == SUCCESS)
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_x);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(RCC_GetSYSCLKSource() != 0x08);
}
else
{
}
}
void MCO_GPIO_Config()
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
}
main.c
#include "stm32f10x.h"
#include "BSP_RCC_clkconfig.h"
#include "sys.h"
void Delay(uint32_t t)
{
while(t--);
}
int main()
{
HSE_SetSysClk(RCC_PLLMul_2);
MCO_GPIO_Config();
RCC_MCOConfig(RCC_MCO_SYSCLK);
while(1)
{
Pin_out(CLK_PB, GPIO_Pin_0, HIGH);
Delay(0xFFFFF);
Pin_out(CLK_PB, GPIO_Pin_0, LOW);
Delay(0xFFFFF);
}
return 0;
}
中断
中断/事件线
EXTI有20个中断/事件线,每个GPIO都可以被设置为输入线,占用EXTI0和EXTI15,还有4个用于特点的外设事件。它们如下:
EXTI0中断/事件线:输入由PA0~PI0等组成。 EXTI1中断/事件线:输入由PA1~PI1等组成。 EXTI2中断/事件线:输入由PA2~PI2等组成。 EXTI3中断/事件线:输入由PA3~PI3等组成。 EXTI4中断/事件线:输入由PA4~PI4等组成。 EXTI5中断/事件线:输入由PA5~PI5等组成。 EXTI6中断/事件线:输入由PA6~PI6等组成。 EXTI7中断/事件线:输入由PA7~PI7等组成。 EXTI8中断/事件线:输入由PA8~PI8等组成。 EXTI9中断/事件线:输入由PA9~PI9等组成。 EXTI10中断/事件线:输入由PA10~PI10等组成。 EXTI11中断/事件线:输入由PA11~PI11等组成。 EXTI12中断/事件线:输入由PA12~PI12等组成。 EXTI13中断/事件线:输入由PA13~PI13等组成。 EXTI14中断/事件线:输入由PA14~PI15等组成。 EXTI15中断/事件线:输入由PA15~PI15等组成。 EXTI16中断/事件线:PVD输出。 EXTI17中断/事件线:RTC闹钟事件。 EXTI18中断/事件线:USB唤醒事件。 EXTI19中断/事件线:以太网唤醒事件(只适用互联型)。
// BSP_Exti.h
#ifndef __BSP_EXTI_H
#define __BSP_EXTI_H
#include "stm32f10x.h"
void EXTI_key_Config();
void Delay_ms(uint32_t t);
#endif
// BSP_Exti.c
#include "BSP_Exti.h"
void Delay_ms(uint32_t t)
{
uint32_t i = 0;
SysTick_Config(72000);
for(i = 0; i < t; i++)
{
while( !((SysTick->CTRL) & (1 << 16)));
}
SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk);
}
void EXTI_NVIC_Config()
{
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
void EXTI_key_Config()
{
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_NVIC_Config();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOA, &GPIO_InitStruct);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
}
1)在 stm32f10x_it.c 中编写中断服务函数
中断服务函数命名类型: 引脚0 ~ 4 void EXTI0_IRQHandler() void EXTI1_IRQHandler() void EXTI2_IRQHandler() void EXTI3_IRQHandler() void EXTI4_IRQHandler() //引脚5 ~ 9 void EXTI9_5_IRQHandler() //引脚10 ~ 15 void EXTI15_10_IRQHandler()
void EXTI0_IRQHandler()
{
if(EXTI_GetITStatus(EXTI_Line0) != RESET)
{
GPIOB->ODR ^= GPIO_Pin_0;
Delay_ms(300);
}
GPIO_SetBits(GPIOB, GPIO_Pin_0);
EXTI_ClearITPendingBit(EXTI_Line0);
}
系统滴答定时器
// BSP_Systick.h
#ifndef __BSP_SYSTICK_H
#define __BSP_SYSTICK_H
#include "stm32f10x.h"
#include "core_cm3.h"
void Systick_Delay_us(uint32_t us);
void Systick_Delay_ms(uint32_t ms);
#endif
// BSP_Systick.c
#include "BSP_Systick.h"
void Systick_Delay_us(uint32_t us)
{
uint32_t i = 0;
SysTick_Config(72);
for(i = 0; i < us; i++)
{
while( !((SysTick->CTRL) & (1 << 16)) );
}
SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk);
}
void Systick_Delay_ms(uint32_t ms)
{
uint32_t i = 0;
SysTick_Config(72000);
for(i = 0; i < ms; i++)
{
while( !((SysTick->CTRL) & (1 << 16)) );
}
SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk);
}
#if 0
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1);
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
return (0);
}
#endif
串口通讯 USART1
勾选上 Use McroLIB 才可以用 printf() 函数
// bsp_usart.h
#ifndef __USART_H
#define __USART_H
#include "stm32f10x.h"
#include <stdio.h>
#define DEBUG_USARTx USART1
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
#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
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
// bsp_usart.c
#include "bsp_usart.h"
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
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);
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_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(DEBUG_USARTx, &USART_InitStructure);
USART_Cmd(DEBUG_USARTx, ENABLE);
}
void Usart_SendByte( USART_TypeDef *pUSARTx, uint8_t ch)
{
USART_SendData(pUSARTx, ch);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == 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)
{}
}
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);
}
int fputc(int ch, FILE *f)
{
USART_SendData(DEBUG_USARTx, (uint8_t) ch);
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
return (ch);
}
int fgetc(FILE *f)
{
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(DEBUG_USARTx);
}
// main 函数
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_usart.h"
static void Show_Message(void);
int main(void)
{
char ch;
LED_GPIO_Config();
USART_Config();
Show_Message();
while(1)
{
ch=getchar();
printf("接收到字符:%c\n",ch);
switch(ch)
{
case '1':
LED_RED;
break;
case '2':
LED_GREEN;
break;
case '3':
LED_BLUE;
break;
case '4':
LED_YELLOW;
break;
case '5':
LED_PURPLE;
break;
case '6':
LED_CYAN;
break;
case '7':
LED_WHITE;
break;
case '8':
LED_RGBOFF;
break;
default:
Show_Message();
break;
}
}
}
static void Show_Message(void)
{
printf("\r\n 这是一个通过串口通信指令控制RGB彩灯实验 \n");
printf("使用 USART 参数为:%d 8-N-1 \n",DEBUG_USART_BAUDRATE);
printf("开发板接到指令后控制RGB彩灯颜色,指令对应如下:\n");
printf(" 指令 ------ 彩灯颜色 \n");
printf(" 1 ------ 红 \n");
printf(" 2 ------ 绿 \n");
printf(" 3 ------ 蓝 \n");
printf(" 4 ------ 黄 \n");
printf(" 5 ------ 紫 \n");
printf(" 6 ------ 青 \n");
printf(" 7 ------ 白 \n");
printf(" 8 ------ 灭 \n");
}
DMA (直接存储器访问)
DMA(Direct Memory Access,直接存储器访问) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于 CPU 的大量中断负载。否则,CPU 需要从来源把每一片段的资料复制到暂存器,然后把它们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。 DMA 传输将数据从一个地址空间复制到另外一个地址空间。当CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。DMA 传输对于高效能 嵌入式系统算法和网络是很重要的。
在实现DMA传输时,是由DMA控制器直接掌管总线,因此,存在着一个总线控制权转移问题。即DMA传输前,CPU要把总线控制权交给DMA控制器,而在结束DMA传输后,DMA控制器应立即把总线控制权再交回给CPU。一个完整的DMA传输过程必须经过DMA请求、DMA响应、DMA传输、DMA结束4个步骤。
请求 CPU对DMA控制器初始化,并向I/O接口发出操作命令,I/O接口提出DMA请求。 响应 DMA控制器对DMA请求判别优先级及屏蔽,向总线裁决逻辑提出总线请求。当CPU执行完当前总线周期即可释放总线控制权。此时,总线裁决逻辑输出总线应答,表示DMA已经响应,通过DMA控制器通知I/O接口开始DMA传输。 传输 DMA控制器获得总线控制权后,CPU即刻挂起或只执行内部操作,由DMA控制器输出读写命令,直接控制RAM与I/O接口进行DMA传输。 在DMA控制器的控制下,在存储器和外部设备之间直接进行数据传送,在传送过程中不需要中央处理器的参与。开始时需提供要传送的数据的起始位置和数据长度。 结束 当完成规定的成批数据传送后,DMA控制器即释放总线控制权,并向I/O接口发出结束信号。当I/O接口收到结束信号后,一方面停 止I/O设备的工作,另一方面向CPU提出中断请求,使CPU从不介入的状态解脱,并执行一段检查本次DMA传输操作正确性的代码。最后,带着本次操作结果及状态继续执行原来的程序。 由此可见,DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM与I/O设备开辟一条直接传送数据的通路,使CPU的效率大为提高。
// bsp_usart_dma.h
#ifndef __USARTDMA_H
#define __USARTDMA_H
#include "stm32f10x.h"
#include <stdio.h>
#define DEBUG_USARTx USART1
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
#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 USART_TX_DMA_CHANNEL DMA1_Channel4
#define USART_DR_ADDRESS (USART1_BASE+0x04)
#define SENDBUFF_SIZE 5000
void USART_Config(void);
void USARTx_DMA_Config(void);
#endif
// bsp_usart_dma.c
#include "bsp_usart_dma.h"
uint8_t SendBuff[SENDBUFF_SIZE];
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
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);
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_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(DEBUG_USARTx, &USART_InitStructure);
USART_Cmd(DEBUG_USARTx, ENABLE);
}
void Usart_SendByte( USART_TypeDef *pUSARTx, uint8_t ch)
{
USART_SendData(pUSARTx, ch);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
void Usart_SendArray( USART_TypeDef *pUSARTx, uint8_t *array, uint16_t num)
{
uint8_t i;
for(i = 0; i < num; i++)
{
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)
{}
}
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);
}
int fputc(int ch, FILE *f)
{
USART_SendData(DEBUG_USARTx, (uint8_t) ch);
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
return (ch);
}
int fgetc(FILE *f)
{
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(DEBUG_USARTx);
}
void USARTx_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStructure);
DMA_Cmd (USART_TX_DMA_CHANNEL, ENABLE);
}
// main.c
#include "stm32f10x.h"
#include "bsp_usart_dma.h"
#include "bsp_led.h"
extern uint8_t SendBuff[SENDBUFF_SIZE];
static void Delay(__IO u32 nCount);
int main(void)
{
uint16_t i;
USART_Config();
USARTx_DMA_Config();
LED_GPIO_Config();
for(i=0;i<SENDBUFF_SIZE;i++)
{
SendBuff[i] = 'L';
}
USART_DMACmd(DEBUG_USARTx, USART_DMAReq_Tx, ENABLE);
while(1)
{
LED1_TOGGLE
Delay(0xFFFFF);
}
}
static void Delay(__IO uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
例题:I2C—读写EEPROM
// bsp_i2c_ee.h
#ifndef __I2C_EE_H
#define __I2C_EE_H
#include "stm32f10x.h"
#define EEPROM_I2Cx I2C1
#define EEPROM_I2C_APBxClock_FUN RCC_APB1PeriphClockCmd
#define EEPROM_I2C_CLK RCC_APB1Periph_I2C1
#define EEPROM_I2C_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd
#define EEPROM_I2C_GPIO_CLK RCC_APB2Periph_GPIOB
#define EEPROM_I2C_SCL_PORT GPIOB
#define EEPROM_I2C_SCL_PIN GPIO_Pin_6
#define EEPROM_I2C_SDA_PORT GPIOB
#define EEPROM_I2C_SDA_PIN GPIO_Pin_7
#define I2C_Speed 400000
#define I2Cx_OWN_ADDRESS7 0X0A
#define I2C_PageSize 8
#define I2CT_FLAG_TIMEOUT ((uint32_t)0x1000)
#define I2CT_LONG_TIMEOUT ((uint32_t)(10 * I2CT_FLAG_TIMEOUT))
#define EEPROM_DEBUG_ON 0
#define EEPROM_INFO(fmt,arg...) printf("<<-EEPROM-INFO->> "fmt"\n",##arg)
#define EEPROM_ERROR(fmt,arg...) printf("<<-EEPROM-ERROR->> "fmt"\n",##arg)
#define EEPROM_DEBUG(fmt,arg...) do{\
if(EEPROM_DEBUG_ON)\
printf("<<-EEPROM-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
}while(0)
#define EEPROM_Block0_ADDRESS 0xA0
void I2C_EE_Init(void);
void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr, u16 NumByteToWrite);
uint32_t I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr);
uint32_t I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite);
uint32_t I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead);
void I2C_EE_WaitEepromStandbyState(void);
#endif
// bsp_i2c_ee.c
#include "./i2c/bsp_i2c_ee.h"
#include "./usart/bsp_usart.h"
uint16_t EEPROM_ADDRESS;
static __IO uint32_t I2CTimeout = I2CT_LONG_TIMEOUT;
static uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode);
static void I2C_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EEPROM_I2C_APBxClock_FUN ( EEPROM_I2C_CLK, ENABLE );
EEPROM_I2C_GPIO_APBxClock_FUN ( EEPROM_I2C_GPIO_CLK, ENABLE );
GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SCL_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(EEPROM_I2C_SCL_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SDA_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(EEPROM_I2C_SDA_PORT, &GPIO_InitStructure);
}
static void I2C_Mode_Configu(void)
{
I2C_InitTypeDef I2C_InitStructure;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = I2Cx_OWN_ADDRESS7;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;
I2C_Init(EEPROM_I2Cx, &I2C_InitStructure);
I2C_Cmd(EEPROM_I2Cx, ENABLE);
}
void I2C_EE_Init(void)
{
I2C_GPIO_Config();
I2C_Mode_Configu();
#ifdef EEPROM_Block0_ADDRESS
EEPROM_ADDRESS = EEPROM_Block0_ADDRESS;
#endif
#ifdef EEPROM_Block1_ADDRESS
EEPROM_ADDRESS = EEPROM_Block1_ADDRESS;
#endif
#ifdef EEPROM_Block2_ADDRESS
EEPROM_ADDRESS = EEPROM_Block2_ADDRESS;
#endif
#ifdef EEPROM_Block3_ADDRESS
EEPROM_ADDRESS = EEPROM_Block3_ADDRESS;
#endif
}
void I2C_EE_BufferWrite(u8 *pBuffer, u8 WriteAddr, u16 NumByteToWrite)
{
u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;
Addr = WriteAddr % I2C_PageSize;
count = I2C_PageSize - Addr;
NumOfPage = NumByteToWrite / I2C_PageSize;
NumOfSingle = NumByteToWrite % I2C_PageSize;
if(Addr == 0)
{
if(NumOfPage == 0)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_EE_WaitEepromStandbyState();
}
else
{
while(NumOfPage--)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
I2C_EE_WaitEepromStandbyState();
WriteAddr += I2C_PageSize;
pBuffer += I2C_PageSize;
}
if(NumOfSingle != 0)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_EE_WaitEepromStandbyState();
}
}
}
else
{
if(NumOfPage == 0)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_EE_WaitEepromStandbyState();
}
else
{
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / I2C_PageSize;
NumOfSingle = NumByteToWrite % I2C_PageSize;
if(count != 0)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, count);
I2C_EE_WaitEepromStandbyState();
WriteAddr += count;
pBuffer += count;
}
while(NumOfPage--)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
I2C_EE_WaitEepromStandbyState();
WriteAddr += I2C_PageSize;
pBuffer += I2C_PageSize;
}
if(NumOfSingle != 0)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_EE_WaitEepromStandbyState();
}
}
}
}
uint32_t I2C_EE_ByteWrite(u8 *pBuffer, u8 WriteAddr)
{
I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);
I2CTimeout = I2CT_FLAG_TIMEOUT;
while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(0);
}
I2CTimeout = I2CT_FLAG_TIMEOUT;
I2C_Send7bitAddress(EEPROM_I2Cx, EEPROM_ADDRESS, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);
}
I2C_SendData(EEPROM_I2Cx, WriteAddr);
I2CTimeout = I2CT_FLAG_TIMEOUT;
while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(2);
}
I2C_SendData(EEPROM_I2Cx, *pBuffer);
I2CTimeout = I2CT_FLAG_TIMEOUT;
while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
}
I2C_GenerateSTOP(EEPROM_I2Cx, ENABLE);
return 1;
}
uint32_t I2C_EE_PageWrite(u8 *pBuffer, u8 WriteAddr, u8 NumByteToWrite)
{
I2CTimeout = I2CT_LONG_TIMEOUT;
while(I2C_GetFlagStatus(EEPROM_I2Cx, I2C_FLAG_BUSY))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(4);
}
I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);
I2CTimeout = I2CT_FLAG_TIMEOUT;
while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(5);
}
I2C_Send7bitAddress(EEPROM_I2Cx, EEPROM_ADDRESS, I2C_Direction_Transmitter);
I2CTimeout = I2CT_FLAG_TIMEOUT;
while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(6);
}
I2C_SendData(EEPROM_I2Cx, WriteAddr);
I2CTimeout = I2CT_FLAG_TIMEOUT;
while(! I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(7);
}
while(NumByteToWrite--)
{
I2C_SendData(EEPROM_I2Cx, *pBuffer);
pBuffer++;
I2CTimeout = I2CT_FLAG_TIMEOUT;
while (!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(8);
}
}
I2C_GenerateSTOP(EEPROM_I2Cx, ENABLE);
return 1;
}
uint32_t I2C_EE_BufferRead(u8 *pBuffer, u8 ReadAddr, u16 NumByteToRead)
{
I2CTimeout = I2CT_LONG_TIMEOUT;
while(I2C_GetFlagStatus(EEPROM_I2Cx, I2C_FLAG_BUSY))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(9);
}
I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);
I2CTimeout = I2CT_FLAG_TIMEOUT;
while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(10);
}
I2C_Send7bitAddress(EEPROM_I2Cx, EEPROM_ADDRESS, I2C_Direction_Transmitter);
I2CTimeout = I2CT_FLAG_TIMEOUT;
while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(11);
}
I2C_Cmd(EEPROM_I2Cx, ENABLE);
I2C_SendData(EEPROM_I2Cx, ReadAddr);
I2CTimeout = I2CT_FLAG_TIMEOUT;
while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(12);
}
I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);
I2CTimeout = I2CT_FLAG_TIMEOUT;
while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(13);
}
I2C_Send7bitAddress(EEPROM_I2Cx, EEPROM_ADDRESS, I2C_Direction_Receiver);
I2CTimeout = I2CT_FLAG_TIMEOUT;
while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(14);
}
while(NumByteToRead)
{
if(NumByteToRead == 1)
{
I2C_AcknowledgeConfig(EEPROM_I2Cx, DISABLE);
I2C_GenerateSTOP(EEPROM_I2Cx, ENABLE);
}
I2CTimeout = I2CT_LONG_TIMEOUT;
while(I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) == 0)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
}
{
*pBuffer = I2C_ReceiveData(EEPROM_I2Cx);
pBuffer++;
NumByteToRead--;
}
}
I2C_AcknowledgeConfig(EEPROM_I2Cx, ENABLE);
return 1;
}
void I2C_EE_WaitEepromStandbyState(void)
{
vu16 SR1_Tmp = 0;
do
{
I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);
SR1_Tmp = I2C_ReadRegister(EEPROM_I2Cx, I2C_Register_SR1);
I2C_Send7bitAddress(EEPROM_I2Cx, EEPROM_ADDRESS, I2C_Direction_Transmitter);
}
while(!(I2C_ReadRegister(EEPROM_I2Cx, I2C_Register_SR1) & 0x0002));
I2C_ClearFlag(EEPROM_I2Cx, I2C_FLAG_AF);
I2C_GenerateSTOP(EEPROM_I2Cx, ENABLE);
}
static uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode)
{
EEPROM_ERROR("I2C 等待超时!errorCode = %d", errorCode);
return 0;
}
// mian.c
#include "stm32f10x.h"
#include "./led/bsp_led.h"
#include "./usart/bsp_usart.h"
#include "./i2c/bsp_i2c_ee.h"
#include <string.h>
#define EEP_Firstpage 0x00
uint8_t I2c_Buf_Write[256];
uint8_t I2c_Buf_Read[256];
uint8_t I2C_Test(void);
int main(void)
{
LED_GPIO_Config();
LED_BLUE;
USART_Config();
printf("\r\n 这是一个I2C外设(AT24C02)读写测试例程 \r\n");
I2C_EE_Init();
if(I2C_Test() == 1)
{
LED_GREEN;
}
else
{
LED_RED;
}
while (1)
{
}
}
uint8_t I2C_Test(void)
{
uint16_t i;
printf("写入的数据\n\r");
for ( i = 0; i <= 255; i++ )
{
I2c_Buf_Write[i] = i;
printf("0x%02X ", I2c_Buf_Write[i]);
if(i % 16 == 15)
printf("\n\r");
}
I2C_EE_BufferWrite( I2c_Buf_Write, EEP_Firstpage, 256);
EEPROM_INFO("\n\r写成功\n\r");
EEPROM_INFO("\n\r读出的数据\n\r");
I2C_EE_BufferRead(I2c_Buf_Read, EEP_Firstpage, 256);
for (i = 0; i < 256; i++)
{
if(I2c_Buf_Read[i] != I2c_Buf_Write[i])
{
EEPROM_ERROR("0x%02X ", I2c_Buf_Read[i]);
EEPROM_ERROR("错误:I2C EEPROM写入与读出的数据不一致\n\r");
return 0;
}
printf("0x%02X ", I2c_Buf_Read[i]);
if(i % 16 == 15)
printf("\n\r");
}
EEPROM_INFO("I2C(AT24C02)读写测试成功\n\r");
return 1;
}
什么是SPI SPI 是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola(摩托罗拉)首先在其MC68HCXX系列处理器上定义的。
SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。
SPI主从模式 SPI分为主、从两种模式,一个SPI通讯系统需要包含一个(且只能是一个)主设备,一个或多个从设备。提供时钟的为主设备(Master),接收时钟的设备为从设备(Slave),SPI接口的读写操作,都是由主设备发起。当存在多个从设备时,通过各自的片选信号进行管理。
SPI是全双工且SPI没有定义速度限制,一般的实现通常能达到甚至超过10 Mbps
SPI信号线 SPI接口一般使用四条信号线通信: SDI(数据输入),SDO(数据输出),SCK(时钟),CS(片选)
MISO: 主设备输入/从设备输出引脚。该引脚在从模式下发送数据,在主模式下接收数据。 MOSI: 主设备输出/从设备输入引脚。该引脚在主模式下发送数据,在从模式下接收数据。 SCLK:串行时钟信号,由主设备产生。 CS/SS:从设备片选信号,由主设备控制。它的功能是用来作为“片选引脚”,也就是选择指定的从设备,让主设备可以单独地与特定从设备通讯,避免数据线上的冲突。
// bsp_spi_flash.h
#ifndef __SPI_FLASH_H
#define __SPI_FLASH_H
#include "stm32f10x.h"
#include <stdio.h>
#define sFLASH_ID 0XEF4017
#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
#define WIP_Flag 0x01
#define Dummy_Byte 0xFF
#define FLASH_SPIx SPI1
#define FLASH_SPI_APBxClock_FUN RCC_APB2PeriphClockCmd
#define FLASH_SPI_CLK RCC_APB2Periph_SPI1
#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
#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
#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
#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 )
#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
// bsp_spi_flash.c
#include "./flash/bsp_spi_flash.h"
static __IO uint32_t SPITimeout = SPIT_LONG_TIMEOUT;
static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);
void SPI_FLASH_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
FLASH_SPI_APBxClock_FUN ( FLASH_SPI_CLK, ENABLE );
FLASH_SPI_CS_APBxClock_FUN ( FLASH_SPI_CS_CLK | FLASH_SPI_SCK_CLK |
FLASH_SPI_MISO_PIN | FLASH_SPI_MOSI_PIN, ENABLE );
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);
GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(FLASH_SPI_SCK_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;
GPIO_Init(FLASH_SPI_MISO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;
GPIO_Init(FLASH_SPI_MOSI_PORT, &GPIO_InitStructure);
SPI_FLASH_CS_HIGH();
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_Cmd(FLASH_SPIx , ENABLE);
}
void SPI_FLASH_SectorErase(u32 SectorAddr)
{
SPI_FLASH_WriteEnable();
SPI_FLASH_WaitForWriteEnd();
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);
SPI_FLASH_CS_HIGH();
SPI_FLASH_WaitForWriteEnd();
}
void SPI_FLASH_BulkErase(void)
{
SPI_FLASH_WriteEnable();
SPI_FLASH_CS_LOW();
SPI_FLASH_SendByte(W25X_ChipErase);
SPI_FLASH_CS_HIGH();
SPI_FLASH_WaitForWriteEnd();
}
void SPI_FLASH_PageWrite(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
SPI_FLASH_WriteEnable();
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++;
}
SPI_FLASH_CS_HIGH();
SPI_FLASH_WaitForWriteEnd();
}
void SPI_FLASH_BufferWrite(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
Addr = WriteAddr % SPI_FLASH_PageSize;
count = SPI_FLASH_PageSize - Addr;
NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
if (Addr == 0)
{
if (NumOfPage == 0)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
}
else
{
while (NumOfPage--)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
}
}
else
{
if (NumOfPage == 0)
{
if (NumOfSingle > count)
{
temp = NumOfSingle - count;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
WriteAddr += count;
pBuffer += count;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
}
else
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
}
}
else
{
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
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);
}
}
}
}
void SPI_FLASH_BufferRead(u8 *pBuffer, u32 ReadAddr, u16 NumByteToRead)
{
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--)
{
*pBuffer = SPI_FLASH_SendByte(Dummy_Byte);
pBuffer++;
}
SPI_FLASH_CS_HIGH();
}
u32 SPI_FLASH_ReadID(void)
{
u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
SPI_FLASH_CS_LOW();
SPI_FLASH_SendByte(W25X_JedecDeviceID);
Temp0 = SPI_FLASH_SendByte(Dummy_Byte);
Temp1 = SPI_FLASH_SendByte(Dummy_Byte);
Temp2 = SPI_FLASH_SendByte(Dummy_Byte);
SPI_FLASH_CS_HIGH();
Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
return Temp;
}
u32 SPI_FLASH_ReadDeviceID(void)
{
u32 Temp = 0;
SPI_FLASH_CS_LOW();
SPI_FLASH_SendByte(W25X_DeviceID);
SPI_FLASH_SendByte(Dummy_Byte);
SPI_FLASH_SendByte(Dummy_Byte);
SPI_FLASH_SendByte(Dummy_Byte);
Temp = SPI_FLASH_SendByte(Dummy_Byte);
SPI_FLASH_CS_HIGH();
return Temp;
}
void SPI_FLASH_StartReadSequence(u32 ReadAddr)
{
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);
}
u8 SPI_FLASH_ReadByte(void)
{
return (SPI_FLASH_SendByte(Dummy_Byte));
}
u8 SPI_FLASH_SendByte(u8 byte)
{
SPITimeout = SPIT_FLAG_TIMEOUT;
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;
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 );
}
u16 SPI_FLASH_SendHalfWord(u16 HalfWord)
{
SPITimeout = SPIT_FLAG_TIMEOUT;
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;
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 );
}
void SPI_FLASH_WriteEnable(void)
{
SPI_FLASH_CS_LOW();
SPI_FLASH_SendByte(W25X_WriteEnable);
SPI_FLASH_CS_HIGH();
}
#define WIP_Flag 0x01
void SPI_FLASH_WaitForWriteEnd(void)
{
u8 FLASH_Status = 0;
SPI_FLASH_CS_LOW();
SPI_FLASH_SendByte(W25X_ReadStatusReg);
do
{
FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);
}
while ((FLASH_Status & WIP_Flag) == SET);
SPI_FLASH_CS_HIGH();
}
void SPI_Flash_PowerDown(void)
{
SPI_FLASH_CS_LOW();
SPI_FLASH_SendByte(W25X_PowerDown);
SPI_FLASH_CS_HIGH();
}
void SPI_Flash_WAKEUP(void)
{
SPI_FLASH_CS_LOW();
SPI_FLASH_SendByte(W25X_ReleasePowerDown);
SPI_FLASH_CS_HIGH();
}
static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)
{
FLASH_ERROR("SPI 等待超时!errorCode = %d", errorCode);
return 0;
}
// main.c
#include "stm32f10x.h"
#include "./usart/bsp_usart.h"
#include "./led/bsp_led.h"
#include "./flash/bsp_spi_flash.h"
typedef enum { FAILED = 0, PASSED = !FAILED} TestStatus;
#define TxBufferSize1 (countof(TxBuffer1) - 1)
#define RxBufferSize1 (countof(TxBuffer1) - 1)
#define countof(a) (sizeof(a) / sizeof(*(a)))
#define BufferSize (countof(Tx_Buffer)-1)
#define FLASH_WriteAddress 0x00000
#define FLASH_ReadAddress FLASH_WriteAddress
#define FLASH_SectorToErase FLASH_WriteAddress
uint8_t Tx_Buffer[] = "感谢您选用野火stm32开发板\r\n";
uint8_t Rx_Buffer[BufferSize];
__IO uint32_t DeviceID = 0;
__IO uint32_t FlashID = 0;
__IO TestStatus TransferStatus1 = FAILED;
void Delay(__IO uint32_t nCount);
TestStatus Buffercmp(uint8_t *pBuffer1, uint8_t *pBuffer2, uint16_t BufferLength);
int main(void)
{
LED_GPIO_Config();
LED_BLUE;
USART_Config();
printf("\r\n 这是一个8Mbyte串行flash(W25Q64)实验 \r\n");
SPI_FLASH_Init();
DeviceID = SPI_FLASH_ReadDeviceID();
Delay( 200 );
FlashID = SPI_FLASH_ReadID();
printf("\r\n FlashID is 0x%X,\
Manufacturer Device ID is 0x%X\r\n", FlashID, DeviceID);
if (FlashID == sFLASH_ID)
{
printf("\r\n 检测到串行flash W25Q64 !\r\n");
SPI_FLASH_SectorErase(FLASH_SectorToErase);
SPI_FLASH_BufferWrite(Tx_Buffer, FLASH_WriteAddress, BufferSize);
printf("\r\n 写入的数据为:%s \r\t", Tx_Buffer);
SPI_FLASH_BufferRead(Rx_Buffer, FLASH_ReadAddress, BufferSize);
printf("\r\n 读出的数据为:%s \r\n", Rx_Buffer);
TransferStatus1 = Buffercmp(Tx_Buffer, Rx_Buffer, BufferSize);
if( PASSED == TransferStatus1 )
{
LED_GREEN;
printf("\r\n 8M串行flash(W25Q64)测试成功!\n\r");
}
else
{
LED_RED;
printf("\r\n 8M串行flash(W25Q64)测试失败!\n\r");
}
}
else
{
LED_RED;
printf("\r\n 获取不到 W25Q64 ID!\n\r");
}
while(1);
}
TestStatus Buffercmp(uint8_t *pBuffer1, uint8_t *pBuffer2, uint16_t BufferLength)
{
while(BufferLength--)
{
if(*pBuffer1 != *pBuffer2)
{
return FAILED;
}
pBuffer1++;
pBuffer2++;
}
return PASSED;
}
void Delay(__IO uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
|