当前位置:网站首页>2021-06-18 STM32F103 DMA 与 DMA串口代码 使用固件库
2021-06-18 STM32F103 DMA 与 DMA串口代码 使用固件库
2022-06-21 07:38:00 【DRMIVET Stone】
本文展示了STM32 DMA程序串口的
内容涉及 :
DMA 内存传输 DMA外设内存传输
USART串口的识别
IO口输入输出
按键的外部中断处理
32位数据通讯,字符串通讯,单字符通讯
完整代码
文章目录
- 前言
- 一、 编程要点
- 二、使用步骤
- 1.理解原理图
- 2.建立DMA传输的 头文件 DMA_book.h
- 3.建立DMA传输的 头文件 DMA_book.c
- 4.建立USART串口的 头文件 USART_book.h
- 5.建立USART串口的 头文件 USART_book.c
- 6.利用之前的Systick 定时输出的 头文件 Systick_book.h
- 7.利用之前的Systick 输出的 头文件 Systick_book.c
- 8.利用之前的RCC_book输出的 头文件 RCC_book.h
- 9.利用之前的RCC_book输出的 头文件 RCC_book.c
- 10.利用之前的LED输出的 头文件 Led_book.h
- 11.利用之前的LED输出的 头文件 Led_book.c
- 12.利用Key输出的程序 Key_book.h
- 13.利用Key输出的程序 Key_book.c
- 14.利用复习Exit中断的程序 Exit_book.h
- 15.利用复习Exit中断的程序 Exit_book.c
- 16.建立USART 输出的 主程序 main.c
- 总结
前言
STM32 的 DMA简介 DMA(Direct Memory Access)—直接存储器存取,是单片机的一个外设,它的主要功能是用来搬数据,但是不需要占用 CPU,即在传输数据的时候,CPU 可以干其他的事情,好像是多线程一样。数据传输支持从外设到存储器或者存储器到存储器,这里的存储器可以是 SRAM 或者是 FLASH。DMA 控制器包含了 DMA1 和 DMA2,其中 DMA1 有 7 个通道,DMA2 有 5 个通道,这里的通道可以理解为传输数据的一种管道。要注意的是 DMA2 只存 在于大容量的单片机中。DMA 传输数据的方向有三个:从外设到存储器,从存储器到外设,从存储 器到存储器。
一、 编程要点
USART:1) 使能 DMA 时钟;
2) 配置 DMA 数据参数;
3) 使能 DMA,进行传输;
4) 等待传输完成,并对源数据和目标地址数据进行比较。
5) 配置 USART 通信功能;
6) 设置串口 DMA 工作参数;
7) 使能 DMA;
8) DMA 传输同时 CPU 可以运行其他任务。
二、使用步骤
1.理解原理图


代码如下:
: STM32F103ZET6 串口引脚位PA9 ,10
: STM32F103ZET6 输出口为PB5低电平点有效
: STM32F103ZET6 Key检测脚为PA8
2.建立DMA传输的 头文件 DMA_book.h
代码如下(示例):
#ifndef __DMA_BOOK_H_
#define __DMA_BOOK_H_
#include "stm32f10x.h"
#define DMA_CLOCK RCC_AHBPeriph_DMA1 //DMA 时钟
/****** A ****************** ROM 到 RAM 的DMA输出 *******************************/
#define Map_DMA_CHANNEL DMA1_Channel6 // 当使用存储器到存储器模式时候,通道可以随便选,没有硬性的规定
#define Map_BUFFER_SIZE 32 // 要发送的数据大小
#define DMA_FLAG_TC DMA1_FLAG_TC6 // 传输完成标志
/* 定义 aSRC_Const_Buffer 数组作为 DMA 传输数据源 * const 关键字将 aSRC_Const_Buffer 数组变量定义为常量类型 * 表示数据存储在内部的 FLASH 中*/
extern const uint32_t aSRC_Cont_Buffer[Map_BUFFER_SIZE] ;
/* 定义 DMA 传输目标存储器存储在内部的 SRAM 中*/
extern uint32_t aDST_Buffer[Map_BUFFER_SIZE];
/*************************************************************************************/
/******** B **************** USART 到 RAM 的DMA输出 *******************************/
#define USART_DMA_CHANNEL DMA1_Channel4 //串口对应的 DMA 请求通道
#define USART_Source_ADDR (USART1_BASE+0x04) //串口数据的地址
#define USART_BUFFER_SIZE 9000 // 要发送的数据大小
extern uint32_t USART_DMA_Buffer[USART_BUFFER_SIZE];
/************************************************************************************/
void _DMA_Config(DMA_Channel_TypeDef* _DMAy_Channelx , uint32_t _BUFFER_SIZE , uint32_t _DMA_OutSource_ADDR, uint32_t _DMA_InSource_ADDR , uint32_t _DMA_DIR);
uint8_t Buffercmp(const uint32_t *pBuffer, uint32_t * pBuffer1 , uint16_t BufferLength);
void _USART_DMA_Config(DMA_Channel_TypeDef* _DMAy_Channelx , uint32_t _BUFFER_SIZE , uint32_t _DMA_OutSource_ADDR, uint32_t _DMA_InSource_ADDR , uint32_t _DMA_DIR);
#define _Map_DMA_Config_ _DMA_Config(Map_DMA_CHANNEL ,Map_BUFFER_SIZE ,aSRC_Cont_Buffer , aDST_Buffer , DMA_DIR_PeripheralSRC)
// ROM 到 RAM 的DMA输出 的程序初始化 DMA_DIR_PeripheralSRC:为方向外设到内存
#define _DMA_InnerChange_ Buffercmp(aSRC_Cont_Buffer , aDST_Buffer, Map_BUFFER_SIZE)
// ROM 到 RAM 的DMA输出 的数据验证
#define _USART_DMA_Config_ _USART_DMA_Config(USART_DMA_CHANNEL ,USART_BUFFER_SIZE ,USART_Source_ADDR , USART_DMA_Buffer , DMA_DIR_PeripheralDST)
// ROM 到 RAM 的DMA输出 的程序初始化 DMA_DIR_PeripheralDST:为方向外设到内存
#endif
3.建立DMA传输的 头文件 DMA_book.c
代码如下(示例):
#include "DMA_book.h"
#include "USART_book.h"
const uint32_t aSRC_Cont_Buffer [Map_BUFFER_SIZE]={
'A','B','C','D',
'E','F','B','C',
'A','X','B','C',
'A','D','B','C',
'A','C','B','C',
'A','V','B','C',
'A','B','W','C',
' A','R','B','C'
};
uint32_t aDST_Buffer[Map_BUFFER_SIZE] ;
uint32_t USART_DMA_Buffer[USART_BUFFER_SIZE];
void _DMA_Config(DMA_Channel_TypeDef* _DMAy_Channelx , uint32_t _BUFFER_SIZE , uint32_t _DMA_Source_ADDR, uint32_t _DMA_AIM_ADDR , uint32_t _DMA_DIR){
DMA_InitTypeDef DMA_InitStructure ;
//开启DMA时钟
RCC_AHBPeriphClockCmd(DMA_CLOCK,ENABLE);
//源数据缓存地址(外设地址)
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)_DMA_Source_ADDR ;
//转换缓存地址地址(内存地址)
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)_DMA_AIM_ADDR;
//方向:外设到存储器(这里的外设是内部的FLASH)DMA_DIR_PeripheralSRC:为方向外设到内存 DMA_DIR_PeripheralDST:为方向外设到内存
DMA_InitStructure.DMA_DIR = _DMA_DIR ;
//传输大小
DMA_InitStructure.DMA_BufferSize = _BUFFER_SIZE;
//外设(内部的FLASH)地址递增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
//内存地址递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//外设数据单位
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
//内存数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
//DMA模式,一次或者循环模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
//DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
//优先级:高
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
//使能内存到内存的传输
DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
//配置DMA通道
DMA_Init(_DMAy_Channelx , &DMA_InitStructure);
//使能DMA
DMA_Cmd(_DMAy_Channelx , ENABLE);
}
uint8_t Buffercmp(const uint32_t *pBuffer, uint32_t * pBuffer1 , uint16_t BufferLength){
/*数据长度递减*/
while(BufferLength--){
Usart_SendHalf_32_Word(_DEBUG_USARTx,*pBuffer);
Usart_SendHalf_32_Word(_DEBUG_USARTx,*pBuffer1);
/*判断两个数据源是否相等*/
if(*pBuffer != *pBuffer1){
/* 对应数据源不相等马上退出函数,并返回 0 */
return 0;
}
/* 递增两个数据源的地址指针 */
pBuffer++;
pBuffer1++;
}
/* 完成判断并且对应数据相对 */
return 1;
}
void _USART_DMA_Config(DMA_Channel_TypeDef* _DMAy_Channelx , uint32_t _BUFFER_SIZE , uint32_t _DMA_Source_ADDR, uint32_t _DMA_AIM_ADDR , uint32_t _DMA_DIR){
DMA_InitTypeDef DMA_InitStructure ;
//开启DMA时钟
RCC_AHBPeriphClockCmd(DMA_CLOCK,ENABLE);
//源数据缓存地址(外设地址)
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)_DMA_Source_ADDR ;
//转换缓存地址地址(内存地址)
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)_DMA_AIM_ADDR;
//方向:外设到存储器(这里的外设是内部的FLASH)DMA_DIR_PeripheralSRC:为方向外设到内存 DMA_DIR_PeripheralDST:为方向外设到内存
DMA_InitStructure.DMA_DIR = _DMA_DIR ;
//传输大小
DMA_InitStructure.DMA_BufferSize = _BUFFER_SIZE;
//外设(内部的FLASH)地址递增
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模式,一次或者循环模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
//DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
//优先级:高
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
//使能内存到内存的传输
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
//配置DMA通道
DMA_Init(_DMAy_Channelx , &DMA_InitStructure);
//使能DMA
DMA_Cmd(_DMAy_Channelx , ENABLE);
}
4.建立USART串口的 头文件 USART_book.h
代码如下(示例):
#ifndef __USART_BOOK_H_
#define __USART_BOOK_H_
#include "stm32f10x.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_rcc.h"
//串口的宏定义 不同的串口挂在的总线和IO不一样
//串口1
#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_TX_GPIO_MODE GPIO_Mode_AF_PP
#define _DEBUG_USART_RX_GPIO_PORT GPIOA
#define _DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
#define _DEBUG_USART_RX_GPIO_MODE GPIO_Mode_IN_FLOATING
#define _DEBUG_NVIC_USART_IRQ USART1_IRQn
#define _DRBUG_USART_IRQHandler USART1_IRQHandler
void fn_USART_IO_Config(void);
void fn_USART_Config(void);
void fn_USART_Init(void);
void fn_Usart_Send_Byte(USART_TypeDef * pUSARTx , uint8_t ch );
void fn_Usart_SendString(USART_TypeDef *pUSARTx , char * str);
void Usart_SendHalf_32_Word( USART_TypeDef * pUSARTx, uint32_t ch);
void _DRBUG_USART_IRQHandler(void);
#endif
5.建立USART串口的 头文件 USART_book.c
代码如下(示例):
#include "USART_book.h"
/************************************************************** * @brief * void fn_LED_Corporate(GPIO_TypeDef* _GPIO_x , uint16_t _GPIO_Pin_x , * LED_Corporate_state_t _LED_Corporate_state_t ); * @param * //串口1 * #define _DEBUG_NVIC_USART_IRQ USART1_IRQn * #define _DRBUG_NVIC_USART_IRQHandler USART1_IRQHandler * @retval *************************************************************/
static void NVIC_Configuration(void){
NVIC_InitTypeDef NVIC_InitStructure;
/* 嵌套向量中断控制寄存器组选择*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 配置 USART 为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = _DEBUG_NVIC_USART_IRQ;
/* 抢断优先级为 1 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 子优先级为 1 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中断 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置 NVIC */
NVIC_Init(&NVIC_InitStructure);
}
/************************************************************** * @brief * void fn_LED_Corporate(GPIO_TypeDef* _GPIO_x , uint16_t _GPIO_Pin_x , * LED_Corporate_state_t _LED_Corporate_state_t ); * @param * //串口1 * // 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_TX_GPIO_MODE GPIO_Mode_AF_PP * #define _DEBUG_USART_RX_GPIO_PORT GPIOA * #define _DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10 * #define _DEBUG_USART_RX_GPIO_MODE GPIO_Mode_AF_FLOATING * @retval *************************************************************/
void fn_USART_IO_Config(void){
GPIO_InitTypeDef GPIO_InitStructure;
// 打开串口 GPIO 的时钟
_DEBUG_USART_GPIO_APBxCLKCmd(_DEBUG_USART_GPIO_CLK , ENABLE);
//将USART TX 的GPIO配置为推挽模式
GPIO_InitStructure.GPIO_Pin = _DEBUG_USART_TX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = _DEBUG_USART_TX_GPIO_MODE;
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 = _DEBUG_USART_RX_GPIO_MODE;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(_DEBUG_USART_RX_GPIO_PORT,&GPIO_InitStructure);
}
/************************************************************** * @brief * void fn_LED_Corporate(GPIO_TypeDef* _GPIO_x , uint16_t _GPIO_Pin_x , * LED_Corporate_state_t _LED_Corporate_state_t ); * @param * //串口1 * #define _DEBUG_USARTx USART1 * #define _DEBUG_USART_CLK RCC_APB2Periph_USART1 * #define _DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd * #define _DEBUG_USART_BAUDRATE 115200 * @retval *************************************************************/
void fn_USART_Config(void){
USART_InitTypeDef USART_InitStructure;
// 打开串口外设的时钟
_DEBUG_USART_APBxClkCmd(_DEBUG_USART_CLK , ENABLE);
//配置串口的工作参数
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);// 完成串口的初始化配置
NVIC_Configuration();// 串口中断优先级配置
USART_ITConfig(_DEBUG_USARTx , USART_IT_RXNE , ENABLE);// 使能串口接收中断
USART_Cmd(_DEBUG_USARTx , ENABLE);// 使能串口
}
/************************************************************** * @brief * void fn_Usart_Send_Byte(USART_TypeDef * pUSARTx , uint8_t ch ); * @param * //串口1 * #define _DEBUG_USARTx USART1 * #define _DEBUG_USART_CLK RCC_APB2Periph_USART1 * #define _DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd * #define _DEBUG_USART_BAUDRATE 115200 * @retval *************************************************************/
void fn_Usart_Send_Byte(USART_TypeDef * pUSARTx , uint8_t ch ){
/*发送一个字节数据到USART*/
USART_SendData(pUSARTx , ch);
/*等待发送数据寄存器为空*/
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE)==RESET);
}
/************************************************************** * @brief * void fn_Usart_SendString(USART_TypeDef *pUSARTx , char * str); * @param * //串口1 * #define _DEBUG_USARTx USART1 * #define _DEBUG_USART_CLK RCC_APB2Periph_USART1 * #define _DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd * #define _DEBUG_USART_BAUDRATE 115200 * @retval *************************************************************/
void fn_Usart_SendString(USART_TypeDef *pUSARTx , char * str){
unsigned int k = 0;
do{
fn_Usart_Send_Byte(pUSARTx,*(str + k++));
}while(*(str + k)!='\0');
/*等待发送完成*/
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC));
}
/************************************************************** * @brief * void Usart_SendHalf_32_Word( USART_TypeDef * pUSARTx, uint32_t ch); * @param * @retval *************************************************************/
void Usart_SendHalf_32_Word( USART_TypeDef * pUSARTx, uint32_t ch){
uint32_t temp_Half32;
uint8_t temp_Half=0,i_Half=4;
temp_Half32 =ch;
while(i_Half-->0){
temp_Half=(temp_Half32 & 0xFF000000)>>24;
temp_Half32<<=8;
fn_Usart_Send_Byte(pUSARTx,temp_Half);
}
/*等待发送完成*/
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC));
}
/************************************************************** * @brief * void USART1_IRQHandler(void); * @param * @retval *************************************************************/
void _DRBUG_USART_IRQHandler(void){
uint8_t ucTemp = 0;
if(USART_GetITStatus(_DEBUG_USARTx,USART_IT_RXNE)!=RESET){
ucTemp = USART_ReceiveData(_DEBUG_USARTx);
USART_SendData(_DEBUG_USARTx ,ucTemp );
}
}
/************************************************************** * @brief * void fn_USART_Init(void); * @param * @retval *************************************************************/
void fn_USART_Init(void){
fn_USART_IO_Config();
fn_USART_Config();
}
6.利用之前的Systick 定时输出的 头文件 Systick_book.h
代码如下(示例):
#ifndef __SYSTIC_BOOK_H_
#define __SYSTIC_BOOK_H_
#include "stm32f10x.h"
#include "Key_book.h"
typedef enum {
_Systick_us = 1,
_Systick_ms = 2,
_Systick_s = 3,
} Systick_time_state_t;
void fn_Systick_Delay(uint32_t _Delay_time , Systick_time_state_t _Systick_time_state_t);
void fn_Systick_Delay_Handler_set(uint32_t _Delay_ms , Systick_time_state_t _Systick_time_state_t);
void fn_SysTick_delay_decrement(void);
void SysTick_Handler(void);
#define __Systick_Delay_Handler_set__ fn_Systick_Delay_Handler_set(10,_Systick_ms)
#endif
7.利用之前的Systick 输出的 头文件 Systick_book.c
代码如下(示例):
#include "Systick_book.h"
/************************************************************ * @brief * void fn_Systick_Delay(uint32_t _Delay_time , \ Systick_time_state_t _Systick_time_state_t){ * @param * @retval *************************************************************/
void fn_Systick_Delay(uint32_t _Delay_time , Systick_time_state_t _Systick_time_state_t){
uint32_t i;
if(_Systick_time_state_t == _Systick_us){
SysTick_Config(SystemCoreClock/1000000);}
if(_Systick_time_state_t == _Systick_ms){
SysTick_Config(SystemCoreClock/1000);
}
else{
SysTick_Config(SystemCoreClock);}
for( i=0;i<_Delay_time ; i++){
while(!((SysTick->CTRL)&(1<<16)));
}
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}
/************************************************************ * @brief * void fn_Systick_Delay_Handler_set(uint32_t _Delay_ms , \ * Systick_time_state_t _Systick_time_state_t){ * @param * @retval *************************************************************/
static uint32_t _SysTick_delay = 0 ;
void fn_Systick_Delay_Handler_set(uint32_t _Delay_ms , Systick_time_state_t _Systick_time_state_t){
if(_Systick_time_state_t == _Systick_us){
SysTick_Config(SystemCoreClock/1000000);}
if(_Systick_time_state_t == _Systick_ms){
SysTick_Config(SystemCoreClock/1000);
}
else{
SysTick_Config(SystemCoreClock);}
_SysTick_delay = _Delay_ms ;
}
/************************************************************ * @brief * void fn_SysTick_delay_decrement(void) * @param * @retval *************************************************************/
static uint32_t SysTick_delay = 0 ;
void fn_SysTick_delay_decrement(void){
if(SysTick_delay++ > _SysTick_delay){
SysTick_delay = 0;
bkey_10ms = 1;
}
}
/************************************************************ * @brief * void SysTick_Handler(void) * @param * @retval *************************************************************/
void SysTick_Handler(void){
fn_SysTick_delay_decrement();
}
8.利用之前的RCC_book输出的 头文件 RCC_book.h
代码如下(示例):
#ifndef __RCC_BOOK_H_
#define __RCC_BOOK_H_
#include "stm32f10x.h"
#define RCC_OUT_GPIO_Port GPIOA //GPIO Point
#define RCC_OUT_GPIO_Clock RCC_APB2Periph_GPIOA //GPIO clock
#define RCC_OUT_GPIO_Pin GPIO_Pin_8
#define RCC_OUT_GPIO_Pin_Bit 8
#define RCC_OUT_GPIO_Modle GPIO_Mode_AF_PP
#define RCC_OUT_GPIO_Speed GPIO_Speed_10MHz
void fn_HRCC_SetSystic( uint32_t _RCC_PLLMul_x );
void fn_IRCC_SetSystic( uint32_t _RCC_PLLMul_x );
void fn_MCO_GPIO_Config(void);
void fn_RCC_Init(void);
#endif
9.利用之前的RCC_book输出的 头文件 RCC_book.c
代码如下(示例):
#include "RCC_book.h"
/************************************************************ * @brief * void fn_HRCC_SetSystic( uint32_t _RCC_PLLMul_x ); * @param * @retval *************************************************************/
void fn_HRCC_SetSystic( uint32_t _RCC_PLLMul_x ){
__IO uint32_t HSEStatus = 0;
/* SYSCLK , HCLK , PCLK2 and PCLK1 cnfiguration */
RCC_DeInit();
/* Enable HSE */
RCC_HSEConfig(RCC_HSE_ON);
/* wait till HSE is ready and if Time Out is reached exit*/
HSEStatus = RCC_WaitForHSEStartUp();
if(HSEStatus == SUCCESS){
// Enable Prefetch Buffer 缓冲区可开启
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
// Flash 2 wait state
FLASH_SetLatency(FLASH_Latency_2);
// 这些位表示SYSCLK(系统时钟)周期与闪存访问的比例
// SYSCLK 周期与闪存访问时间的比例设置,这里统一设置成 2
// 设置成 2 的时候,SYSCLK 低于 48M 也可以工作,如果设置成 0 或者 1 的时候,
// 如果配置的 SYSCLK 超出了范围的话,则会进入硬件错误,程序就死了
// 0:0 < SYSCLK <= 24M
// 1:24< SYSCLK <= 48M
// 2:48< SYSCLK <= 72M */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* HCLK = SYSCLK */ //AHB预分频 (AHB Prescaler)
RCC_PCLK1Config(RCC_HCLK_Div2);
/* PCLK1 = HCLK */ //低速APB预分频(APB1) (APB low-speed prescaler (APB1))
RCC_PCLK2Config(RCC_HCLK_Div1);
/* PCLK1 = HCLK */ //低速APB预分频(APB1) (APB low-speed prescaler (APB1))
RCC_PLLConfig(RCC_PLLSource_HSE_Div1 ,_RCC_PLLMul_x);
RCC_PLLCmd(ENABLE);
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz // PLLSRC: PLL输入时钟源 (PLL entry clock source) // RCC_PLLSource_HSE_Div1 RCC_PLLSource_HSE_Div2 RCC_PLLSource_HSI_Div1 // _RCC_PLLMul_x 为倍频因子*/
while((RCC_GetFlagStatus(RCC_FLAG_PLLRDY))==RESET);
/* Wait till PLL is ready */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* Select PLL as system clock source */
// SW[1:0]:系统时钟切换 (System clock switch) 位1:0
// 由软件置’1’或清’0’来选择系统时钟源。
// 在从停止或待机模式中返回时或直接或间接作为系统时钟的HSE出现故障时,由硬件强制选择
// HSI作为系统时钟(如果时钟安全系统已经启动)
// 00:HSI作为系统时钟;
// 01:HSE作为系统时钟;
// 10:PLL输出作为系统时钟;
// 11:不可用 */
while (RCC_GetSYSCLKSource()!=0x08);
}else{
}
}
/************************************************************ * @brief * void fn_IRCC_SetSystic( uint32_t _RCC_PLLMul_x ); * @param * @retval *************************************************************/
void fn_IRCC_SetSystic( uint32_t _RCC_PLLMul_x ){
__IO uint32_t HSIStatus = 0;
__IO uint32_t StartUpCounter = 0;
/*SYSCLK HCLK PCLK2 PCLK1 con figuration---*/
RCC_DeInit();
/*Enable HSE*/
RCC_HSICmd(ENABLE);
/* Wait till HSE is ready and if Time out is reached exit */
do{
HSIStatus = RCC->CR & RCC_CR_HSIRDY;
StartUpCounter++;
}while((HSIStatus == 0)&&(StartUpCounter != HSE_STARTUP_TIMEOUT));
if(HSIStatus == SUCCESS){
/*Enable Prefetch Buffer 预计缓冲区开启 */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/*FLASH 2 Wait state */ //这些位表示SYSCLK(系统时钟)周期与闪存访问时间的比例
FLASH_SetLatency(FLASH_Latency_2);
// 这些位表示SYSCLK(系统时钟)周期与闪存访问的比例
// SYSCLK 周期与闪存访问时间的比例设置,这里统一设置成 2
// 设置成 2 的时候,SYSCLK 低于 48M 也可以工作,如果设置成 0 或者 1 的时候,
// 如果配置的 SYSCLK 超出了范围的话,则会进入硬件错误,程序就死了
// 0:0 < SYSCLK <= 24M
// 1:24< SYSCLK <= 48M
// 2:48< SYSCLK <= 72M */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* HCLK = SYSCLK */ //AHB预分频 (AHB Prescaler)
RCC_PCLK1Config(RCC_HCLK_Div2);
/* PCLK1 = HCLK */ //低速APB预分频(APB1) (APB low-speed prescaler (APB1))
RCC_PCLK2Config(RCC_HCLK_Div1);
/* PCLK1 = HCLK */ //低速APB预分频(APB1) (APB low-speed prescaler (APB1))
RCC_PLLConfig(RCC_PLLSource_HSI_Div2,_RCC_PLLMul_x);
RCC_PLLCmd(ENABLE);
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz // PLLSRC: PLL输入时钟源 (PLL entry clock source) // RCC_PLLSource_HSE_Div1 RCC_PLLSource_HSE_Div2 RCC_PLLSource_HSI_Div1 // _RCC_PLLMul_x 为倍频因子*/
while((RCC_GetFlagStatus(RCC_FLAG_PLLRDY))== RESET);
/* Wait till PLL is ready */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* Select PLL as system clock source */
// SW[1:0]:系统时钟切换 (System clock switch) 位1:0
// 由软件置’1’或清’0’来选择系统时钟源。
// 在从停止或待机模式中返回时或直接或间接作为系统时钟的HSE出现故障时,由硬件强制选择
// HSI作为系统时钟(如果时钟安全系统已经启动)
// 00:HSI作为系统时钟;
// 01:HSE作为系统时钟;
// 10:PLL输出作为系统时钟;
// 11:不可用
/** Wait till PLL is used as system clock source - 0x00: HSI used as system clock - 0x04: HSE used as system clock - 0x08: PLL used as system clock */
while(RCC_GetSYSCLKSource()!=0x08);
}else{
}
}
/************************************************************ * @brief * void fn_MCO_GPIO_Config(void); * @param * #define RCC_OUT_GPIO_Port GPIOA //GPIO Point * #define RCC_OUT_GPIO_Clock RCC_APB2Periph_GPIOA //GPIO clock * #define RCC_OUT_GPIO_Pin GPIO_Pin_8 * #define RCC_OUT_GPIO_Pin_Bit 8 * #define RCC_OUT_GPIO_Modle GPIO_Mode_AF_PP * #define RCC_OUT_GPIO_Speed GPIO_Speed_10MHz * @retval *************************************************************/
void fn_MCO_GPIO_Config(void){
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = RCC_OUT_GPIO_Modle;
GPIO_InitStruct.GPIO_Pin = RCC_OUT_GPIO_Pin;
GPIO_InitStruct.GPIO_Speed = RCC_OUT_GPIO_Speed;
RCC_APB2PeriphClockCmd(RCC_OUT_GPIO_Clock,ENABLE);
GPIO_Init(RCC_OUT_GPIO_Port,&GPIO_InitStruct);
RCC_MCOConfig(RCC_MCO_SYSCLK);
//RCC_MCOConfig(RCC_MCO_HSI);
//RCC_MCOConfig(RCC_MCO_HSE);
}
/************************************************************ * @brief * void fn_RCC_Init(void); * @param * @retval *************************************************************/
void fn_RCC_Init(void){
fn_HRCC_SetSystic(RCC_PLLMul_9 );
//fn_IRCC_SetSystic(RCC_PLLMul_9 );
//fn_MCO_GPIO_Config();
}
10.利用之前的LED输出的 头文件 Led_book.h
代码如下(示例):
#ifndef __LED_BOOK_H_
#define __LED_BOOK_H_
#include "stm32f10x.h"
#define LED_OUT_GPIO_Port GPIOB //GPIO Point
#define LED_OUT_GPIO_Clock RCC_APB2Periph_GPIOB //GPIO clock
#define LED_OUT_GPIO_Pin GPIO_Pin_5
#define LED_OUT_GPIO_Pin_Bit 5
#define LED_OUT_GPIO_Modle GPIO_Mode_Out_PP
#define LED_R_OUT_GPIO_Pin GPIO_Pin_5
#define LED_G_OUT_GPIO_Pin GPIO_Pin_0
#define LED_B_OUT_GPIO_Pin GPIO_Pin_1
typedef enum {
LED_Corporate_On = 1,
LED_Corporate_OFF = 2,
LED_Corporate_Toggle = 3,
} LED_Corporate_state_t;
void fn_LED_GPIO_Config(GPIO_TypeDef* _GPIO_x , uint32_t _GPIO_Clock ,\
uint16_t _GPIO_Pin_x , GPIOMode_TypeDef _GPIOMode_TypeDef);
void fn_Led_Init(void);
void fn_LED_Corporate(GPIO_TypeDef* _GPIO_x , uint16_t _GPIO_Pin_x , \
LED_Corporate_state_t _LED_Corporate_state_t );
void fn_LED_ALL_OFF(void);
#define __LED_Change__ fn_LED_Corporate(LED_OUT_GPIO_Port,LED_OUT_GPIO_Pin,LED_Corporate_Toggle)
#define __R_OUT__ GPIO_ResetBits(LED_OUT_GPIO_Port,LED_R_OUT_GPIO_Pin)
#define __G_OUT__ GPIO_ResetBits(LED_OUT_GPIO_Port,LED_G_OUT_GPIO_Pin)
#define __B_OUT__ GPIO_ResetBits(LED_OUT_GPIO_Port,LED_B_OUT_GPIO_Pin)
#endif
11.利用之前的LED输出的 头文件 Led_book.c
代码如下(示例):
#include "Led_book.h"
/************************************************************** * @brief * void fn_LED_GPIO_Config(GPIO_TypeDef* _GPIO_x , uint32_t _GPIO_Clock , * uint16_t _GPIO_Pin_x , GPIOMode_TypeDef _GPIOMode_TypeDef); * @param * @retval *************************************************************/
#define LED_GPIO_Speed GPIO_Speed_10MHz
void fn_LED_GPIO_Config(GPIO_TypeDef* _GPIO_x , uint32_t _GPIO_Clock ,uint16_t _GPIO_Pin_x , GPIOMode_TypeDef _GPIOMode_TypeDef){
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = _GPIOMode_TypeDef;
GPIO_InitStruct.GPIO_Pin = _GPIO_Pin_x;
GPIO_InitStruct.GPIO_Speed = LED_GPIO_Speed;
RCC_APB2PeriphClockCmd(_GPIO_Clock ,ENABLE);
GPIO_Init(_GPIO_x , &GPIO_InitStruct) ;
GPIO_SetBits(_GPIO_x,_GPIO_Pin_x);
}
/************************************************************** * @brief * void fn_Led_Init(void); * @param * @retval *************************************************************/
void fn_Led_Init(void){
fn_LED_GPIO_Config (LED_OUT_GPIO_Port,LED_OUT_GPIO_Clock,LED_OUT_GPIO_Pin,LED_OUT_GPIO_Modle);
fn_LED_GPIO_Config (LED_OUT_GPIO_Port,LED_OUT_GPIO_Clock,LED_R_OUT_GPIO_Pin,LED_OUT_GPIO_Modle);
fn_LED_GPIO_Config (LED_OUT_GPIO_Port,LED_OUT_GPIO_Clock,LED_G_OUT_GPIO_Pin,LED_OUT_GPIO_Modle);
fn_LED_GPIO_Config (LED_OUT_GPIO_Port,LED_OUT_GPIO_Clock,LED_B_OUT_GPIO_Pin,LED_OUT_GPIO_Modle);
fn_LED_ALL_OFF();
}
/************************************************************** * @brief * void fn_LED_Corporate(GPIO_TypeDef* _GPIO_x , uint16_t _GPIO_Pin_x , * LED_Corporate_state_t _LED_Corporate_state_t ); * @param * @retval *************************************************************/
void fn_LED_Corporate(GPIO_TypeDef* _GPIO_x , uint16_t _GPIO_Pin_x , LED_Corporate_state_t _LED_Corporate_state_t ){
switch(_LED_Corporate_state_t){
case LED_Corporate_On :
GPIO_SetBits(_GPIO_x,_GPIO_Pin_x);
break;
case LED_Corporate_OFF:
GPIO_ResetBits(_GPIO_x,_GPIO_Pin_x);
break;
case LED_Corporate_Toggle:
GPIO_ReadOutputDataBit(_GPIO_x,_GPIO_Pin_x)?GPIO_ResetBits(_GPIO_x,_GPIO_Pin_x):GPIO_SetBits(_GPIO_x,_GPIO_Pin_x);
break;
}
}
void fn_LED_ALL_OFF(void){
GPIO_SetBits(LED_OUT_GPIO_Port,LED_R_OUT_GPIO_Pin);
GPIO_SetBits(LED_OUT_GPIO_Port,LED_G_OUT_GPIO_Pin);
GPIO_SetBits(LED_OUT_GPIO_Port,LED_B_OUT_GPIO_Pin);
}
//practice
//fn_LED_GPIO_Config (LED_OUT_GPIO_Port,LED_OUT_GPIO_Clock,LED_OUT_GPIO_Pin,LED_OUT_GPIO_Modle);
// while(1){
// delay(10000);
// fn_LED_Corporate(LED_OUT_GPIO_Port,LED_OUT_GPIO_Pin,LED_Corporate_Toggle);
// }
12.利用Key输出的程序 Key_book.h
代码如下(示例):
#ifndef __KEY_BOOK_H_
#define __KEY_BOOK_H_
#include "stm32f10x.h"
#include "Led_book.h"
#define KEY_IN_GPIO_Port GPIOA
#define KEY_IN_GPIO_Clock RCC_APB2Periph_GPIOA
#define KEY_IN_GPIO_Pin GPIO_Pin_0
#define KEY_IN_GPIO_Pin_Bit 0
#define Key_IN_GPIO_Modle GPIO_Mode_IN_FLOATING //浮空输入
#define KEY2_IN_GPIO_Port GPIOC
#define KEY2_IN_GPIO_Clock RCC_APB2Periph_GPIOC
#define KEY2_IN_GPIO_Pin GPIO_Pin_13
#define KEY2_IN_GPIO_Pin_Bit 13
#define Key2_IN_GPIO_Modle GPIO_Mode_IN_FLOATING //浮空输入
typedef union {
struct{
unsigned char BIT0:1;unsigned char BIT1:1;unsigned char BIT2:1;unsigned char BIT3:1;
unsigned char BIT4:1;unsigned char BIT5:1;unsigned char BIT6:1;unsigned char BIT7:1;
//unsigned char BIT8:1;unsigned char BIT9:1;unsigned char BIT10:1;unsigned char BIT11:1;
//unsigned char BIT12:1;unsigned char BIT13:1;unsigned char BIT14:1;unsigned char BIT15:1;
}DATA_BIT;
uint8_t DATA_BYTE;
}Per_key_type;
extern volatile Per_key_type key_flag;
#define bkey_10ms key_flag.DATA_BIT.BIT0
#define bkey_judge key_flag.DATA_BIT.BIT1
#define bkey_judge_long key_flag.DATA_BIT.BIT2
#define bkey_Effect key_flag.DATA_BIT.BIT3
#define bkey_LongEffect key_flag.DATA_BIT.BIT4
#define bkey_Effect_Lose key_flag.DATA_BIT.BIT5
#define bkey_Effect_LLose key_flag.DATA_BIT.BIT6
void fn_Key_GPIO_Config( GPIO_TypeDef* _GPIO_x , uint32_t _GPIO_Clock , uint16_t _GPIO_Pin_x , GPIOMode_TypeDef _GPIOMode_TypeDef );
void fn_Key_Init(void);
void fn_key_judge(void);
void fn_key_Effect(void);
void fn_key_Check(void);
#endif
13.利用Key输出的程序 Key_book.c
代码如下(示例):
#include "Key_book.h"
volatile Per_key_type key_flag;
/************************************************************** * @brief * void fn_Key_GPIO_Config( GPIO_TypeDef* _GPIO_x , uint32_t _GPIO_Clock , * uint16_t _GPIO_Pin_x , GPIOMode_TypeDef _GPIOMode_TypeDef ); * @param * #define KEY_IN_GPIO_Port GPIOA * #define KEY_IN_GPIO_Clock RCC_APB2Periph_GPIOA * #define KEY_IN_GPIO_Pin GPIO_Pin_0 * #define KEY_IN_GPIO_Pin_Bit 0 * #define Key_IN_GPIO_Modle GPIO_Mode_IN_FLOATING //浮空输入 * * #define KEY2_IN_GPIO_Port GPIOC * #define KEY2_IN_GPIO_Clock RCC_APB2Periph_GPIOC * #define KEY2_IN_GPIO_Pin GPIO_Pin_13 * #define KEY2_IN_GPIO_Pin_Bit 13 * #define Key2_IN_GPIO_Modle GPIO_Mode_IN_FLOATING //浮空输入 * @retval *************************************************************/
void fn_Key_GPIO_Config( GPIO_TypeDef* _GPIO_x , uint32_t _GPIO_Clock , uint16_t _GPIO_Pin_x , GPIOMode_TypeDef _GPIOMode_TypeDef ){
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = _GPIOMode_TypeDef;
GPIO_InitStruct.GPIO_Pin = _GPIO_Pin_x;
RCC_APB2PeriphClockCmd(_GPIO_Clock,ENABLE);
GPIO_Init(_GPIO_x , &GPIO_InitStruct);
}
/************************************************************** * @brief * void fn_Key_Init(void); * @param * @retval *************************************************************/
void fn_Key_Init(void){
fn_Key_GPIO_Config(KEY_IN_GPIO_Port,KEY_IN_GPIO_Clock,KEY_IN_GPIO_Pin,Key_IN_GPIO_Modle);
fn_Key_GPIO_Config(KEY2_IN_GPIO_Port,KEY2_IN_GPIO_Clock,KEY2_IN_GPIO_Pin,Key2_IN_GPIO_Modle);
}
/************************************************************ * @brief * void fn_key_judge(void); * @param * @retval **************************************************************/
#define _LONG_key 30
static uint16_t count_key ;
void fn_key_judge(void){
if(!bkey_10ms){
return;}
bkey_10ms = 0;
if(GPIO_ReadInputDataBit(KEY_IN_GPIO_Port,KEY_IN_GPIO_Pin)){
if(count_key++<3){
return;}
if(!bkey_judge){
bkey_judge = 1;
bkey_Effect = 1;
}else{
if(count_key>_LONG_key){
bkey_judge_long = 1;
bkey_LongEffect = 1;
}
}
}
else{
count_key = 0;
if(bkey_judge){
bkey_judge = 0;
if(bkey_judge_long){
bkey_judge_long = 0;
bkey_Effect_LLose = 1;
}else{
bkey_judge_long = 0;
bkey_Effect_Lose = 1;
}
}else{
bkey_judge = 0;
}
}
}
/************************************************************ * @brief * void fn_key_Effect(void); * @param * @retval *************************************************************/
void fn_key_Effect(void){
if(bkey_Effect){
bkey_Effect = 0;
fn_LED_Corporate(LED_OUT_GPIO_Port,LED_OUT_GPIO_Pin,LED_Corporate_Toggle);
}
}
/************************************************************** * @brief * void fn_key_Check(void); * @param * @retval *************************************************************/
void fn_key_Check(void){
fn_key_judge();
fn_key_Effect();
}
14.利用复习Exit中断的程序 Exit_book.h
代码如下(示例):
#ifndef __EXIT_BOOK_H_
#define __EXIT_BOOK_H_
#include "stm32f10x.h"
#define _KEY_EXTI_IN_GPIO_Port GPIOA
#define _KEY_EXTI_IN_GPIO_Pin GPIO_Pin_0
#define _EXTI_IN_GPIO_PortSource GPIO_PortSourceGPIOA
#define _EXTI_IN_GPIO_PinSource GPIO_PinSource0
#define _EXTI_IN_EXTI_Line EXTI_Line0
#define _EXTI_IN_EXTI_Trigger EXTI_Trigger_Rising
#define _EXTI_IN_GPIO_Clock RCC_APB2Periph_AFIO
#define _EXTI_IN_EXTI_Mode EXTI_Mode_Interrupt
#define _EXTI_IN_EXTI_LineCmd ENABLE
#define _NVIC_IN_EXTI_IRQChannel EXTI0_IRQn
#define _NVIC_IN_EXTI_IRQChannelCmd ENABLE
#define _KEY2_EXTI_IN_GPIO_Port GPIOC
#define _KEY2_EXTI_IN_GPIO_Pin GPIO_Pin_13
#define _EXTI_IN2_GPIO_PortSource GPIO_PortSourceGPIOC
#define _EXTI_IN2_GPIO_PinSource GPIO_PinSource13
#define _EXTI_IN2_EXTI_Line EXTI_Line13
#define _EXTI_IN2_EXTI_Trigger EXTI_Trigger_Falling
#define _EXTI_IN2_GPIO_Clock RCC_APB2Periph_AFIO
#define _EXTI_IN2_EXTI_Mode EXTI_Mode_Interrupt
#define _EXTI_IN2_EXTI_LineCmd ENABLE
#define _NVIC_IN2_EXTI_IRQChannel EXTI15_10_IRQn
#define _NVIC_IN2_EXTI_IRQChannelCmd ENABLE
void fn_EXTI_GPIO_Config(void);
void fn_NVIC_Config(void);
void EXTI0_IRQHandler(void);
#endif
15.利用复习Exit中断的程序 Exit_book.c
代码如下(示例):
#include "Exit_book.h"
#include "Led_book.h"
/************************************************************** * @brief * void fn_EXTI_GPIO_Config(void) * @param * * #define _KEY_EXTI_IN_GPIO_Port GPIOA * #define _KEY_EXTI_IN_GPIO_Pin GPIO_Pin_0 * #define _EXTI_IN_GPIO_PortSource GPIO_PortSourceGPIOA * #define _EXTI_IN_GPIO_PinSource GPIO_PinSource0 * #define _EXTI_IN_EXTI_Line EXTI_Line0 * #define _EXTI_IN_EXTI_Trigger EXTI_Trigger_Rising * #define _EXTI_IN_GPIO_Clock RCC_APB2Periph_AFIO * #define _EXTI_IN_EXTI_Mode EXTI_Mode_Interrupt * #define _EXTI_IN_EXTI_LineCmd ENABLE * * #define _KEY2_EXTI_IN_GPIO_Port GPIOC * #define _KEY2_EXTI_IN_GPIO_Pin GPIO_Pin_13 * #define _EXTI_IN2_GPIO_PortSource GPIO_PortSourceGPIOC * #define _EXTI_IN2_GPIO_PinSource GPIO_PinSource13 * #define _EXTI_IN2_EXTI_Line EXTI_Line13 * #define _EXTI_IN2_EXTI_Trigger EXTI_Trigger_Falling * #define _EXTI_IN2_GPIO_Clock RCC_APB2Periph_AFIO * #define _EXTI_IN2_EXTI_Mode EXTI_Mode_Interrupt * #define _EXTI_IN2_EXTI_LineCmd ENABLE * @retval *************************************************************/
void fn_EXTI_GPIO_Config(void){
EXTI_InitTypeDef EXIT_InitStruck;
RCC_APB2PeriphClockCmd(_EXTI_IN_GPIO_Clock , ENABLE);
//注意:我们除了开 GPIO 的端口时钟外,我们还打开了 AFIO 的时钟
GPIO_EXTILineConfig(_EXTI_IN_GPIO_PortSource | _EXTI_IN2_GPIO_PortSource , _EXTI_IN_GPIO_PinSource | _EXTI_IN2_GPIO_PinSource);
/* 选择 EXTI 的信号源 */
// GPIO_EXTILineConfig 函数用来指定中断/事件线的输入源,它实际是设定外部中断配
// 置寄存器的 AFIO_EXTICRx 值,该函数接收两个参数,第一个参数指定 GPIO 端口源,第
// 二个参数为选择对应 GPIO 引脚源编号。
EXIT_InitStruck.EXTI_Line = _EXTI_IN_EXTI_Line ; /* 选择 EXTI 的信号源 */
EXIT_InitStruck.EXTI_Mode = _EXTI_IN_EXTI_Mode; /* EXTI 为中断模式 */
EXIT_InitStruck.EXTI_Trigger = _EXTI_IN_EXTI_Trigger ; /* 上升沿中断 */
EXIT_InitStruck.EXTI_LineCmd = _EXTI_IN_EXTI_LineCmd; /* 使能中断 */
EXTI_Init(&EXIT_InitStruck);
// EXTI初始化配置的变量
// fn_NVIC_Config();
// 调用 NVIC_Configuration函数完成对按键 1、按键 2 优先级配置并使能中断通道
EXIT_InitStruck.EXTI_Line = _EXTI_IN2_EXTI_Line; /* 选择 EXTI 的信号源 */
EXIT_InitStruck.EXTI_Mode = _EXTI_IN2_EXTI_Mode; /* EXTI 为中断模式 */
EXIT_InitStruck.EXTI_Trigger = _EXTI_IN2_EXTI_Trigger; /* 下降沿中断 */
EXIT_InitStruck.EXTI_LineCmd = _EXTI_IN_EXTI_LineCmd;/* 使能中断 */
EXTI_Init(&EXIT_InitStruck);
fn_NVIC_Config();
}
/************************************************************** * @brief * void fn_NVIC_Config(void) * @param * #define _NVIC_IN_EXTI_IRQChannel EXTI0_IRQn * #define _NVIC_IN_EXTI_IRQChannelCmd ENABLE * #define _NVIC_IN2_EXTI_IRQChannel EXTI15_10_IRQn * #define _NVIC_IN2_EXTI_IRQChannelCmd ENABLE * @retval *************************************************************/
void fn_NVIC_Config(void){
NVIC_InitTypeDef NVIC_InitStruct;
/* 配置 NVIC 为优先级组 1 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/* 配置中断源: */
NVIC_InitStruct.NVIC_IRQChannel = _NVIC_IN_EXTI_IRQChannel; //EXTI0_IRQn;
/* 配置抢占优先级:1 */
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
/* 配置子优先级:1 */
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
/* 使能中断通道 */
NVIC_InitStruct.NVIC_IRQChannelCmd = _NVIC_IN_EXTI_IRQChannelCmd; //ENABLE
NVIC_Init(&NVIC_InitStruct);
/* 配置中断源: */
NVIC_InitStruct.NVIC_IRQChannel = _NVIC_IN2_EXTI_IRQChannel; //EXTI0_IRQn;
NVIC_Init(&NVIC_InitStruct);
}
/************************************************************** * @brief * void fn_NVIC_Config(void) * @param * #define _KEY_EXTI_IN_GPIO_Port GPIOA * #define _KEY_EXTI_IN_GPIO_Pin GPIO_Pin_0 * @retval *************************************************************/
void EXTI0_IRQHandler(void){
// EXTI_GetITStatus 函数用来获取 EXTI 的中断标志位状态,如果 EXTI 线有中断发生函
//数返回“SET”否则返回“RESET”。实际上,EXTI_GetITStatus 函数是通过读取
//EXTI_PR寄存器值来判断 EXTI线状态的。
if(EXTI_GetITStatus(_EXTI_IN_EXTI_Line)!= RESET){
if(GPIO_ReadInputDataBit(_KEY_EXTI_IN_GPIO_Port, _KEY_EXTI_IN_GPIO_Pin)==1){
__LED_Change__;
}
}
EXTI_ClearITPendingBit(_EXTI_IN_EXTI_Line); // 重要的清除中断标志位
}
void EXTI15_10_IRQHandler(void){
if(EXTI_GetITStatus(_EXTI_IN2_EXTI_Line)!= RESET){
if(GPIO_ReadInputDataBit(_KEY2_EXTI_IN_GPIO_Port, _KEY2_EXTI_IN_GPIO_Pin)==0){
__LED_Change__;
}
}
EXTI_ClearITPendingBit(_EXTI_IN2_EXTI_Line); // 重要的清除中断标志位
}
16.建立USART 输出的 主程序 main.c
代码如下(示例):
/** ****************************************************************************** * @file GPIO/JTAG_Remap/main.c * @author MCD Application Team * @version V3.5.0 * @date 08-April-2011 * @brief Main program body ****************************************************************************** * @attention * * ****************************************************************************** */
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "PROJ_book.h"
/* Private functions ---------------------------------------------------------*/
/** * @brief Main program. * @param None * @retval None */
void delay(int x);
void fn_LED_Flash_Init(void);
void fn_usart_show_Init(void);
int main(void)
{
uint32_t i;
fn_RCC_Init(); //CPU 倍频
fn_Led_Init(); //LED 输出初始化
fn_Key_Init(); //按键 输入初始化
fn_USART_Init(); //串口输出初始化
fn_LED_Flash_Init(); //RGB 输出测试
fn_usart_show_Init(); //串口输出测试
fn_EXTI_GPIO_Config();
fn_Usart_SendString(_DEBUG_USARTx,": 开始 ROM内存到RAM内存的DMA操作 \n");
_Map_DMA_Config_; //内存到内存DMA初始化
while(DMA_GetFlagStatus(DMA_FLAG_TC) == RESET); //判断DMA传输结果是否正确
if(_DMA_InnerChange_== 0 ){
fn_LED_ALL_OFF();
__B_OUT__;
}else{
fn_LED_ALL_OFF();
__G_OUT__;
}
fn_Usart_SendString(_DEBUG_USARTx,": ROM内存到RAM内存的DMA操作完成 \n");
//----------------------------------------------------------------
//----------------------------------------------------------------
fn_Usart_SendString(_DEBUG_USARTx,": ROM内存到USART外设的DMA操作开始 \n");
for (i=0; i<USART_BUFFER_SIZE; i++){
//对内存初始化
USART_DMA_Buffer[i] = 'F';
}
// 开始 USART内存到RAM内存的DMA操作
fn_Usart_SendString(_DEBUG_USARTx,": ROM内存初始化开始 \n");
_USART_DMA_Config_;
USART_DMACmd(_DEBUG_USARTx , USART_DMAReq_Tx , ENABLE); //串口DMA使能
/*USART_DMACmd 函数用于控制 USART 的 DMA 请求的启动和关闭。它接收三个参 数,第一个参数用于设置串口外设,可以是 USART1/2/3 和 UART4/5 这 5 个参数可选,第 二个参数设置串口的具体 DMA 请求,有串口发送请求 USART_DMAReq_Tx 和接收请求 USART_DMAReq_Rx 可选,第三个参数用于设置启动请求 ENABLE 或者关闭请求*/
while(1){
fn_Systick_Delay(50,_Systick_ms); //DMA 传输进程中进行LED输出闪烁
__LED_Change__;
if(USART_GetFlagStatus(_DEBUG_USARTx,USART_FLAG_TXE)!=RESET){
fn_Usart_SendString(_DEBUG_USARTx,": ROM内存到USART外设的DMA操作完毕 \n"); //这个函数需要Delay 一段时间才可以用
break;
}
}
while(1);
}
void fn_LED_Flash_Init(void){
uint16_t count_Init = 2;
while(count_Init-->0){
fn_LED_ALL_OFF();
__R_OUT__;
fn_Systick_Delay(500,_Systick_ms);
fn_LED_ALL_OFF();
__G_OUT__;
fn_Systick_Delay(100,_Systick_ms);
fn_LED_ALL_OFF();
__B_OUT__;
fn_Systick_Delay(100,_Systick_ms);
fn_LED_ALL_OFF();
__R_OUT__;
}
}
void fn_usart_show_Init(void){
fn_Usart_Send_Byte(_DEBUG_USARTx,'T');
fn_Usart_Send_Byte(_DEBUG_USARTx,'O');
Usart_SendHalf_32_Word(_DEBUG_USARTx,0xA1B2C3D4);
fn_Usart_SendString(_DEBUG_USARTx," : wangqi \n");
}
void delay(int x){
int y = 0xFFFFF;
while((x--)>0){
while((y--)>0){
__NOP();
__NOP();
__NOP();
__NOP();
__NOP();
}
}
}
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
www.firebbs.cn。
参考笔记。
_STM32f103 中断 以及 EXT
STM32 EXIT – LED 程序
STM32 EXIT – EXIT 程序
STM32 EXIT – Key 程序
STM32 RCC – 主程序
总结

- 要传多少,单位是什么
当我们配置好数据要从哪里来到哪里去之后,我们还需要知道我们要传输的数据是多
少,数据的单位是什么。
以串口向电脑发送数据为例,我们可以一次性给电脑发送很多数据,具体多少由
DMA_CNDTR 配置,这是一个 32 位的寄存器,一次最多只能传输 65535 个数据。
要想数据传输正确,源和目标地址存储的数据宽度还必须一致,串口数据寄存器是 8
位的,所以我们定义的要发送的数据也必须是 8 位。外设的数据宽度由 DMA_CCR 的
PSIZE[1:0]配置,可以是 8/16/32 位,存储器的数据宽度由 DMA_CCR 的 MSIZE[1:0]配置,
可以是 8/16/32 位。
在 DMA 控制器的控制下,数据要想有条不紊的从一个地方搬到另外一个地方,还必
须正确设置两边数据指针的增量模式。外设的地址指针由 DMA_CCRx 的 PINC 配置,存储
器的地址指针由 MINC 配置。以串口向电脑发送数据为例,要发送的数据很多,每发送完
一个,那么存储器的地址指针就应该加 1,而串口数据寄存器只有一个,那么外设的地址
指针就固定不变。具体的数据指针的增量模式由实际情况决定。
- 什么时候传输完成
数据什么时候传输完成,我们可以通过查询标志位或者通过中断的方式来鉴别。每个
DMA 通道在 DMA 传输过半、传输完成和传输错误时都会有相应的标志位,如果使能了该
类型的中断后,则会产生中断。有关各个标志位的详细描述请参考 DMA 中断状态寄存器
DMA_ISR 的详细描述。
传输完成还分两种模式,是一次传输还是循环传输,一次传输很好理解,即是传输一
次之后就停止,要想再传输的话,必须关断 DMA 使能后再重新配置后才能继续传输。循
环传输则是一次传输完成之后又恢复第一次传输时的配置循环传输,不断的重复。具体的
由 DMA_CCR 寄存器的 CIRC 循环模式位控制。
DMA_ InitTypeDef 初始化结构体
typedef struct{
uint32_t DMA_PeripheralBaseAddr; // 外设地址
uint32_t DMA_MemoryBaseAddr; // 存储器地址
uint32_t DMA_DIR; // 传输方向
uint32_t DMA_BufferSize; // 传输数目
uint32_t DMA_PeripheralInc; // 外设地址增量模式
uint32_t DMA_MemoryInc; // 存储器地址增量模式
uint32_t DMA_PeripheralDataSize; // 外设数据宽度
uint32_t DMA_MemoryDataSize; // 存储器数据宽度
uint32_t DMA_Mode; // 模式选择
uint32_t DMA_Priority; // 通道优先级
uint32_t DMA_M2M; // 存储器到存储器模式
} DMA_InitTypeDef;
1) DMA_PeripheralBaseAddr:外设地址,设定 DMA_CPAR 寄存器的值;一般设置
为外设的数据寄存器地址,如果是存储器到存储器模式则设置为其中一个存储器
地址。
2) DMA_Memory0BaseAddr:存储器地址,设定 DMA_CMAR 寄存器值;一般设置
为我们自定义存储区的首地址。
3) DMA_DIR:传输方向选择,可选外设到存储器、存储器到外设。它设定
DMA_CCR 寄存器的 DIR[1:0]位的值。这里并没有存储器到存储器的方向选择,
当使用存储器到存储器时,只需要把其中一个存储器当作外设使用即可。
4) DMA_BufferSize:设定待传输数据数目,初始化设定 DMA_CNDTR 寄存器的值。
5) DMA_PeripheralInc:如果配置为 DMA_PeripheralInc_Enable,使能外设地址自动
递增功能,它设定 DMA_CCR 寄存器的 PINC 位的值;一般外设都是只有一个数
据寄存器,所以一般不会使能该位。
6) DMA_MemoryInc:如果配置为 DMA_MemoryInc_Enable,使能存储器地址自动
递增功能,它设定 DMA_CCR 寄存器的 MINC 位的值;我们自定义的存储区一般
都是存放多个数据的,所以要使能存储器地址自动递增功能。
7) DMA_PeripheralDataSize:外设数据宽度,可选字节(8 位)、半字(16 位)和字(32
位),它设定 DMA_CCR 寄存器的 PSIZE[1:0]位的值。
8) DMA_MemoryDataSize:存储器数据宽度,可选字节(8 位)、半字(16 位)和字(32
位),它设定 DMA_CCR 寄存器的 MSIZE[1:0]位的值。当外设和存储器之间传数
据时,两边的数据宽度应该设置为一致大小。
9) DMA_Mode:DMA 传输模式选择,可选一次传输或者循环传输,它设定
DMA_CCR 寄存器的 CIRC 位的值。例程我们的 ADC 采集是持续循环进行的,所
以使用循环传输模式。
10) DMA_Priority:软件设置通道的优先级,有 4 个可选优先级分别为非常高、高、
中和低,它设定 DMA_CCR 寄存器的 PL[1:0]位的值。DMA 通道优先级只有在多
个 DMA 通道同时使用时才有意义,如果是单个通道,优先级可以随便设置。
11) DMA_M2M :存 储器 到存 储器 模式 ,使 用存储 器到 存储 器时 用到, 设定
DMA_CCR 的位 14 MEN2MEN 即可启动存储器到存储器模式。


边栏推荐
- Research Report on market supply and demand and strategy of oil-free scroll compressor industry in China
- Dynamic programming to solve the problem of looting
- 海思系列量产硬件调试记录
- What are the differences between SQL and MySQL
- . Net 4.5 asynchronous programming pilot (async and await)
- Integrating eslint in old projects [02]
- Vite + whistle: a development environment proxy solution once and for all
- Japanese programming learning website
- How to write the statement of executing stored procedure in MySQL
- QML control type: drawer
猜你喜欢

Root cause analysis | inventory of nine scenarios with abnormal status of kubernetes pod

Four necessary steps for building a digital factory

【osg】osg开发(02)—基于MinGW编译构建osgQt库

mysql如何关闭事务

应用程序卡死,如何快速退出?

WordPress website security in 2022

How to make MySQL case insensitive

Traversal of binary tree

MATLAB 三维图(非常规)

Course design of supply chain modeling and simulation based on Flexsim
随机推荐
sql与mysql有哪些区别
[graduation season - advanced technology Er]: the technology sharing of senior college students and the future encouragement
MATLAB快速入门
海思系列量产硬件调试记录
[untitled]
操作成功的提示信息动态添加
Realize the industry vision of decentralization, safety, accuracy and real-time price feeding
Postman发布API文档
如何让mysql不区分大小写
Research Report on inorganic copper fungicide industry - market status analysis and development prospect forecast
What is Eureka? What can Eureka do? How does Eureka work?
A table to easily understand the prefix and suffix of increment and decrement operators
RDKIT | 基于分子指纹的分子相似性
How to write circular statements in MySQL stored procedures
mysql如何关闭事务
Traversal of binary tree
[OSG] OSG development (02) - build osgqt Library Based on MinGW compilation
Random random number class
Root cause analysis | inventory of nine scenarios with abnormal status of kubernetes pod
如何安装Visual Studio Code编辑器?