stm32f4外设学习篇(代码集合)(一)

简介: stm32f4外设学习篇(代码集合)


芯片:STM32F407(理论支持F4所有芯片)

开发环境:KEIL5-ARM

目的:单独的文件除了24c02和W25QXX会需要依赖iic和spi其余文件都是可以直接拷贝到工程使用的

日期:2021-8-12

有一些外设并没有经过测试所以在使用过程中自行调试

1、串口1

.c文件

#include "debug_usart.h"
/**
  * @brief  DEBUG_USART GPIO 配置,工作模式配置。115200 8-N-1
  * @param  无
  * @retval 无
  */
void Debug_USART_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
  RCC_AHB1PeriphClockCmd(DEBUG_USART_RX_GPIO_CLK | DEBUG_USART_TX_GPIO_CLK, ENABLE);
  /* 使能 UART 时钟 */
  RCC_APB2PeriphClockCmd(DEBUG_USART_CLK, ENABLE);
  /* 连接 PXx 到 USARTx_Tx*/
  GPIO_PinAFConfig(DEBUG_USART_RX_GPIO_PORT, DEBUG_USART_RX_SOURCE, DEBUG_USART_RX_AF);
  /*  连接 PXx 到 USARTx__Rx*/
  GPIO_PinAFConfig(DEBUG_USART_TX_GPIO_PORT, DEBUG_USART_TX_SOURCE, DEBUG_USART_TX_AF);
  /* 配置Tx引脚为复用功能  */
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
  /* 配置Rx引脚为复用功能 */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_PIN;
  GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
  /* 配置串DEBUG_USART 模式 */
  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_USART, &USART_InitStructure);
  USART_Cmd(DEBUG_USART, ENABLE);
}
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,  接收完成标志
//bit14,  接收到0x0d
//bit13~0,  接收到的有效字节数目
u16 USART_RX_STA = 0; //接收状态标记
void USART1_IRQHandler(void) //串口1中断服务程序
{
  u8 Res;
  if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
  {
    Res = USART_ReceiveData(USART1); //(USART1->DR);  //读取接收到的数据
    if ((USART_RX_STA & 0x8000) == 0) //接收未完成
    {
      if (USART_RX_STA & 0x4000) //接收到了0x0d
      {
        if (Res != 0x0a)
          USART_RX_STA = 0; //接收错误,重新开始
        else
          USART_RX_STA |= 0x8000; //接收完成了
      }
      else //还没收到0X0D
      {
        if (Res == 0x0d)
          USART_RX_STA |= 0x4000;
        else
        {
          USART_RX_BUF[USART_RX_STA & 0X3FFF] = Res;
          USART_RX_STA++;
          if (USART_RX_STA > (USART_REC_LEN - 1))
            USART_RX_STA = 0; //接收数据错误,重新开始接收
        }
      }
    }
  }
}
//buf:接收缓存首地址
//len:读到的数据长度
void get_uart_buff(uint8_t *buf, uint8_t *len)
{
  u8 rxlen = USART_RX_STA;
  u8 i = 0;
  *len = 0;                           //默认为0
  _uart_delay(0xff);                  //等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束
  if (rxlen == USART_RX_STA && rxlen) //接收到了数据,且接收完成了
  {
    for (i = 0; i < rxlen; i++)
    {
      buf[i] = USART_RX_BUF[i];
    }
    *len = USART_RX_STA; //记录本次数据长度
    USART_RX_STA = 0;    //清零
  }
}
//重定向c库函数printf到串口DEBUG_USART,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
  /* 发送一个字节数据到串口DEBUG_USART */
  USART_SendData(DEBUG_USART, (uint8_t)ch);
  /* 等待发送完毕 */
  while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_TXE) == RESET)
    ;
  return (ch);
}
//重定向c库函数scanf到串口DEBUG_USART,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
  /* 等待串口输入数据 */
  while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_RXNE) == RESET)
    ;
  return (int)USART_ReceiveData(DEBUG_USART);
}
/*********************************************END OF FILE**********************/

.h文件

#ifndef __DEBUG_USART_H
#define __DEBUG_USART_H
#include "stm32f4xx.h"
#include <stdio.h>
//引脚定义
/*******************************************************/
#define DEBUG_USART                             USART1
#define DEBUG_USART_CLK                         RCC_APB2Periph_USART1
#define DEBUG_USART_RX_GPIO_PORT                GPIOA
#define DEBUG_USART_RX_GPIO_CLK                 RCC_AHB1Periph_GPIOA
#define DEBUG_USART_RX_PIN                      GPIO_Pin_10
#define DEBUG_USART_RX_AF                       GPIO_AF_USART1
#define DEBUG_USART_RX_SOURCE                   GPIO_PinSource10
#define DEBUG_USART_TX_GPIO_PORT                GPIOA
#define DEBUG_USART_TX_GPIO_CLK                 RCC_AHB1Periph_GPIOA
#define DEBUG_USART_TX_PIN                      GPIO_Pin_9
#define DEBUG_USART_TX_AF                       GPIO_AF_USART1
#define DEBUG_USART_TX_SOURCE                   GPIO_PinSource9
#define USART_REC_LEN                           200   //定义最大接收字节数 200
      
extern uint8_t  USART_RX_BUF[USART_REC_LEN];            //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern uint16_t USART_RX_STA;                           //接收状态标记  
/************************************************************/
// 不精确的延时
static void _uart_delay(__IO u32 nCount)
{
  for (; nCount != 0; nCount--)
    ;
}
//串口波特率
#define DEBUG_USART_BAUDRATE                    115200
void Debug_USART_Config(void);
void get_uart_buff(uint8_t *buf, uint8_t *len);
int fputc(int ch, FILE *f);
#endif /* __USART1_H */

2、串口2(RS485)

.c文件

#include "rs485.h"
// 配置USART接收中断
static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  /* Configure the NVIC Preemption Priority Bits */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
  /* Enable the USARTy Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = _485_INT_IRQ;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}
/*
 * 函数名:_485_Config
 * 描述  :USART GPIO 配置,工作模式配置
 * 输入  :无
 * 输出  : 无
 * 调用  :外部调用
 */
void _485_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
  USART_ClockInitTypeDef USART_ClockInitStruct;
  RCC_AHB1PeriphClockCmd(_485_USART_RX_GPIO_CLK | _485_USART_TX_GPIO_CLK | _485_RE_GPIO_CLK, ENABLE);
  RCC_APB1PeriphClockCmd(_485_USART_CLK, ENABLE);
  USART_DeInit(_485_USART);
  USART_StructInit(&USART_InitStructure);
  USART_ClockStructInit(&USART_ClockInitStruct);
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_InitStructure.GPIO_Pin = _485_USART_TX_PIN;
  GPIO_Init(_485_USART_TX_GPIO_PORT, &GPIO_InitStructure);
  GPIO_PinAFConfig(_485_USART_TX_GPIO_PORT, GPIO_PinSource3, GPIO_AF_USART2);
  GPIO_InitStructure.GPIO_Pin = _485_USART_RX_PIN;
  GPIO_Init(_485_USART_RX_GPIO_PORT, &GPIO_InitStructure);
  GPIO_PinAFConfig(_485_USART_RX_GPIO_PORT, GPIO_PinSource2, GPIO_AF_USART2);
  USART_ClockInit(_485_USART, &USART_ClockInitStruct);
  USART_InitStructure.USART_BaudRate = _485_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(_485_USART, &USART_InitStructure);
  USART_ITConfig(_485_USART, USART_IT_RXNE, ENABLE); //接收中断使能
  USART_ClearITPendingBit(_485_USART, USART_IT_TC);  //清除中断TC位
  USART_Cmd(_485_USART, ENABLE);                     //使能串口
  USART_ClearFlag(_485_USART, USART_FLAG_TC);
  /***********************************GPIOA 1,RS485方向控制******************************/
  GPIO_InitStructure.GPIO_Pin = _485_RE_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(_485_RE_GPIO_PORT, &GPIO_InitStructure);
  NVIC_Configuration();
  /* 使能串口接收中断 */
  USART_ITConfig(_485_USART, USART_IT_RXNE, ENABLE);
  GPIO_ResetBits(_485_RE_GPIO_PORT, _485_RE_PIN); //默认进入接收模式
}
/***************** 发送一个字符  **********************/
//使用单字节数据发送前要使能发送引脚,发送后要使能接收引脚。
void _485_SendByte(uint8_t ch)
{
  /* 发送一个字节数据到USART1 */
  USART_SendData(_485_USART, ch);
  /* 等待发送完毕 */
  while (USART_GetFlagStatus(_485_USART, USART_FLAG_TXE) == RESET)
    ;
}
/*****************  发送指定长度的字符串 **********************/
void _485_SendStr_length(uint8_t *str, uint32_t strlen)
{
  unsigned int k = 0;
  _485_TX_EN(); //  使能发送数据
  do
  {
    _485_SendByte(*(str + k));
    k++;
  } while (k < strlen);
  _485_delay(0xfff);
  _485_RX_EN(); //  使能接收数据
}
/*****************  发送字符串 **********************/
void _485_SendString(uint8_t *str)
{
  unsigned int k = 0;
  _485_TX_EN(); //  使能发送数据
  do
  {
    _485_SendByte(*(str + k));
    k++;
  } while (*(str + k) != '\0');
  _485_delay(0xff);
  _485_RX_EN(); //  使能接收数据
}
//中断缓存串口数据
#define UART_BUFF_SIZE 64
//接收缓存区
u8 RS485_RX_BUF[64]; //接收缓冲,最大64个字节.
//接收到的数据长度
u8 RS485_RX_CNT = 0;
void bsp_485_IRQHandler(void)
{
  u8 res;
  if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收到数据
  {
    res = USART_ReceiveData(USART2); //;读取接收到的数据USART2->DR
    if (RS485_RX_CNT < UART_BUFF_SIZE)
    {
      RS485_RX_BUF[RS485_RX_CNT] = res; //记录接收到的值
      RS485_RX_CNT = RS485_RX_CNT + 1;  //接收数据增加1
      if (RS485_RX_CNT >= UART_BUFF_SIZE)
      {
        RS485_RX_CNT = 0;
      }
    }
    else
    {
      RS485_RX_CNT = 0;
      RS485_RX_BUF[RS485_RX_CNT] = res; //记录接收到的值
    }
  }
}
//RS485查询接收到的数据
//buf:接收缓存首地址
//len:读到的数据长度
void RS485_Receive_Data(u8 *buf, u8 *len)
{
  u8 rxlen = RS485_RX_CNT;
  u8 i = 0;
  *len = 0;                           //默认为0
  _485_delay(0xff);                   //等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束
  if (rxlen == RS485_RX_CNT && rxlen) //接收到了数据,且接收完成了
  {
    for (i = 0; i < rxlen; i++)
    {
      buf[i] = RS485_RX_BUF[i];
    }
    *len = RS485_RX_CNT; //记录本次数据长度
    RS485_RX_CNT = 0;    //清零
  }
}
// crc16 modbus
const uint16_t polynom = 0xA001;
//uint16_t ccr_data_con = crc16bitbybit(rs485buf,length-2);
//rs485buf[length-1] = ccr_data_con&0XFF;  //低八位
//rs485buf[length-2] = ccr_data_con>>8;    //高八位
uint16_t crc16bitbybit(uint8_t *ptr, uint16_t len)
{
  uint8_t i;
  uint16_t crc = 0xffff;
  uint8_t ch;
  if (len == 0)
  {
    len = 1;
  }
  while (len--)
  {
    ch = *ptr;
    crc ^= ch;
    for (i = 0; i < 8; i++)
    {
      if (crc & 1)
      {
        crc >>= 1;
        crc ^= polynom;
      }
      else
      {
        crc >>= 1;
      }
    }
    ptr++;
  }
  return crc;
}

.h文件

#ifndef __485_H
#define __485_H
#include "stm32f4xx.h"
#include "stdio.h"
#define _485_USART USART2
#define _485_USART_CLK RCC_APB1Periph_USART2
#define _485_USART_BAUDRATE 9600
#define _485_USART_RX_GPIO_PORT GPIOA
#define _485_USART_RX_GPIO_CLK RCC_AHB1Periph_GPIOA
#define _485_USART_RX_PIN GPIO_Pin_2
#define _485_USART_RX_AF GPIO_AF_USART2
#define _485_USART_RX_SOURCE GPIO_PinSource2
#define _485_USART_TX_GPIO_PORT GPIOA
#define _485_USART_TX_GPIO_CLK RCC_AHB1Periph_GPIOA
#define _485_USART_TX_PIN GPIO_Pin_3
#define _485_USART_TX_AF GPIO_AF_USART2
#define _485_USART_TX_SOURCE GPIO_PinSource3
#define _485_RE_GPIO_PORT GPIOA
#define _485_RE_GPIO_CLK RCC_AHB1Periph_GPIOA
#define _485_RE_PIN GPIO_Pin_1
#define _485_INT_IRQ USART2_IRQn
#define _485_IRQHandler USART2_IRQHandler
/// 不精确的延时
static void _485_delay(__IO u32 nCount)
{
  for (; nCount != 0; nCount--)
    ;
}
/*控制收发引脚*/
//进入接收模式,必须要有延时等待485处理完数据
#define _485_RX_EN()                              \
  _485_delay(1000);                               \
  GPIO_ResetBits(_485_RE_GPIO_PORT, _485_RE_PIN); \
  _485_delay(1000);
//进入发送模式,必须要有延时等待485处理完数据
#define _485_TX_EN()                            \
  _485_delay(1000);                             \
  GPIO_SetBits(_485_RE_GPIO_PORT, _485_RE_PIN); \
  _485_delay(1000);
void _485_Config(void);
void _485_SendByte(uint8_t ch);
void _485_SendStr_length(uint8_t *str, uint32_t strlen);
void _485_SendString(uint8_t *str);
void rs485_modbus_print(uint8_t *rs485_write_buff, uint8_t len);
uint16_t crc16bitbybit(uint8_t *ptr, uint16_t len);
void bsp_485_IRQHandler(void);
void RS485_Receive_Data(u8 *buf, u8 *len);
#endif /* __485_H */

3、定时器(多路)

.c文件

#include "timer.h"
//arr:自动重装值。
//psc:时钟预分频数
//定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定时器工作频率,单位:Mhz
//通用定时器3中断初始化
void TIM3_Int_Init(u16 arr, u16 psc)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); ///使能TIM3时钟
  TIM_TimeBaseInitStructure.TIM_Period = arr;                     //自动重装载值
  TIM_TimeBaseInitStructure.TIM_Prescaler = psc;                  //定时器分频
  TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
  TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); //初始化TIM3
  TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //允许定时器3更新中断
  TIM_Cmd(TIM3, ENABLE);                     //使能定时器3
  NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;              //定时器3中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; //抢占优先级1
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;        //子优先级3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}
//通用定时器2中断初始化
void TIM2_Int_Init(u16 arr, u16 psc)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); ///使能TIM3时钟
  TIM_TimeBaseInitStructure.TIM_Period = arr;                     //自动重装载值
  TIM_TimeBaseInitStructure.TIM_Prescaler = psc;                  //定时器分频
  TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
  TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //初始化TIM3
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //允许定时器3更新中断
  TIM_Cmd(TIM2, ENABLE);                     //使能定时器3
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;              //定时器3中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; //抢占优先级1
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;        //子优先级3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}
//通用定时器4中断初始化
void TIM4_Int_Init(u16 arr, u16 psc)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); ///使能TIM4时钟
  TIM_TimeBaseInitStructure.TIM_Period = arr;                     //自动重装载值
  TIM_TimeBaseInitStructure.TIM_Prescaler = psc;                  //定时器分频
  TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
  TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure); //初始化TIM4
  TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); //允许定时器4更新中断
  TIM_Cmd(TIM4, ENABLE);                     //使能定时器4
  NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;              //定时器4中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; //抢占优先级1
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x04;        //子优先级4
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}
//定时器2中断服务函数
void TIM2_IRQHandler(void)
{
  if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) //溢出中断
  {
    // app程序
  }
  TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除中断标志位
}
//定时器3中断服务函数
void TIM3_IRQHandler(void)
{
  if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) //溢出中断
  {
    // app程序
  }
  TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除中断标志位
}
//定时器4中断服务函数
void TIM4_IRQHandler(void)
{
  if (TIM_GetITStatus(TIM4, TIM_IT_Update) == SET) //溢出中断
  {
    // app程序
  }
  TIM_ClearITPendingBit(TIM4, TIM_IT_Update); //清除中断标志位
}

.h文件

#ifndef _TIMER_H
#define _TIMER_H
#include "stm32f4xx.h"
void TIM3_Int_Init(uint16_t arr, uint16_t psc);
void TIM2_Int_Init(uint16_t arr, uint16_t psc);
void TIM4_Int_Init(uint16_t arr, uint16_t psc);
#endif

4、PWM

.c文件

#include "pwm.h"
//TIM14 PWM部分初始化 
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM14_PWM_Init(u32 arr,u32 psc)
{              
  //此部分需手动修改IO口设置
  GPIO_InitTypeDef GPIO_InitStructure;
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;
  
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);    //TIM14时钟使能    
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);   //使能PORTF时钟 
  
  GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_TIM14); //GPIOF9复用为定时器14
  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;           //GPIOF9
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;  //速度100MHz
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽复用输出
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        //上拉
  GPIO_Init(GPIOC,&GPIO_InitStructure);              //初始化PF9
    
  TIM_TimeBaseStructure.TIM_Prescaler=psc;  //定时器分频
  TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
  TIM_TimeBaseStructure.TIM_Period=arr;   //自动重装载值
  TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
  
  TIM_TimeBaseInit(TIM14,&TIM_TimeBaseStructure);//初始化定时器14
  
  //初始化TIM14 Channel1 PWM模式  
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性低
  TIM_OC1Init(TIM14, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM1 4OC1
  TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);  //使能TIM14在CCR1上的预装载寄存器
 
  TIM_ARRPreloadConfig(TIM14,ENABLE);//ARPE使能 
  
  TIM_Cmd(TIM14, ENABLE);  //使能TIM14                
}

.h文件

#ifndef _PWM_H
#define _PWM_H
#include "stm32f4xx.h"
//TIM_SetCompare1(TIM14,pwmval);// 可以通过这个函数占空比调节
void TIM14_PWM_Init(u32 arr,u32 psc);
#endif

5、窗口看门狗

.c文件

#include "wwdg.h"
//保存WWDG计数器的设置值,默认为最大.
uint8_t WWDG_CNT = 0X7F;
//初始化窗口看门狗
//tr   :T[6:0],计数器值
//wr   :W[6:0],窗口值
//fprer:分频系数(WDGTB),仅最低2位有效
//Fwwdg=PCLK1/(4096*2^fprer). 一般PCLK1=42Mhz
void WWDG_Init(u8 tr, u8 wr, u32 fprer)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); //使能窗口看门狗时钟
  WWDG_CNT = tr & WWDG_CNT; //初始化WWDG_CNT.
  WWDG_SetPrescaler(fprer); //设置分频值
  WWDG_SetWindowValue(wr);  //设置窗口值
                            //  WWDG_SetCounter(WWDG_CNT);//设置计数值
  WWDG_Enable(WWDG_CNT);    //开启看门狗
  NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;              //窗口看门狗中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级为2
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;        //子优先级为3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;              //使能窗口看门狗
  NVIC_Init(&NVIC_InitStructure);
  WWDG_ClearFlag(); //清除提前唤醒中断标志位
  WWDG_EnableIT();  //开启提前唤醒中断
}
//窗口看门狗中断服务程序
void WWDG_IRQHandler(void)
{
  WWDG_SetCounter(WWDG_CNT); //重设窗口看门狗值
  WWDG_ClearFlag();          //清除提前唤醒中断标志位
}

.h文件

#ifndef _WWDG_H
#define _WWDG_H
#include "stm32f4xx.h"
// WWDG_Init(0x7F,0X5F,WWDG_Prescaler_8);   //计数器值为7f,窗口寄存器为5f,分频数为8
void WWDG_Init(u8 tr, u8 wr, u32 fprer);
void WWDG_IRQHandler(void);
#endif

6、独立看门狗

.c文件

#include "iwdg.h"
//初始化独立看门狗
//prer:分频数:0~7(只有低3位有效!)
//rlr:自动重装载值,0~0XFFF.
//分频因子=4*2^prer.但最大值只能是256!
//rlr:重装载寄存器值:低11位有效.
//时间计算(大概):Tout=((4*2^prer)*rlr)/32 (ms).
void IWDG_Init(u8 prer, u16 rlr)
{
  IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //使能对IWDG->PR IWDG->RLR的写
  IWDG_SetPrescaler(prer);                      //设置IWDG分频系数
  IWDG_SetReload(rlr);                          //设置IWDG装载
  IWDG_ReloadCounter();                         //reload
  IWDG_Enable();                                //使能看门狗
}
//喂独立看门狗
void IWDG_Feed(void)
{
  IWDG_ReloadCounter(); //reload
}

.h文件

#ifndef _IWDG_H
#define _IWDG_H
#include "stm32f4xx.h"
//IWDG_Init(4,500); //与分频数为64,重载值为500,溢出时间为1s
//IWDG_Feed();      //1s内必须调用一次的喂狗函数
void IWDG_Init(u8 prer, u16 rlr); //IWDG初始化
void IWDG_Feed(void);             //喂狗函数
#endif

7、GPIO(LED)

.c文件

#include "led.h"
/**  不精准延时函数   **/
static void Delay(uint32_t time)
{
  while (time--)
  {
    int i = 10000;
    for (; i > 0; i--)
      ;
  }
}
//LED IO初始化
void LED_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_AHB1PeriphClockCmd(RCC_GPIO_X, ENABLE); //使能GPIOF时钟
  GPIO_InitStructure.GPIO_Pin = LED0_PIN;          //LED0
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;    //普通输出模式
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;   //推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; //2MHz:led灯低速就行
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;     //上拉
  GPIO_Init(LED0_PORT, &GPIO_InitStructure);       //初始化GPIO
  GPIO_InitStructure.GPIO_Pin = LED1_PIN;    //LED0
  GPIO_Init(LED1_PORT, &GPIO_InitStructure); //初始化GPIO
  GPIO_SetBits(LED0_PORT, LED0_PIN); //设置高,灯灭
  GPIO_SetBits(LED1_PORT, LED1_PIN); //设置高,灯灭
}
/* 主函数中调用这个函数即可看到LED实验效果 */
void LED_Demo(void)
{
  LED_Init();
  while (1)
  {
    LED0_ON;
    LED1_OFF;
    Delay(0xfff);
    LED0_OFF;
    LED1_ON;
    Delay(0xfff);
  }
}

.h文件

#ifndef __LED_H
#define __LED_H
#include "stm32f4xx.h"
/**   API    **/
#define LED0_ON GPIO_ResetBits(LED0_PORT, LED0_PIN); //设置低,灯亮
#define LED0_OFF GPIO_SetBits(LED0_PORT, LED0_PIN);  //设置高,灯灭
#define LED1_ON GPIO_ResetBits(LED1_PORT, LED1_PIN);
#define LED1_OFF GPIO_SetBits(LED1_PORT, LED1_PIN);
/**   PORT AND PIN    **/
#define LED0_PIN GPIO_Pin_9
#define LED0_PORT GPIOF
#define LED1_PIN GPIO_Pin_10
#define LED1_PORT GPIOF
/**   RCC时钟    **/
#define RCC_GPIO_X RCC_AHB1Periph_GPIOF
void LED_Init(void); //初始化
#endif

8、外部中断(EXTI)

.c文件

#include "exti.h"
//外部中断0服务程序
void EXTI0_IRQHandler(void)
{
  // app程序
  EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位
}
//外部中断2服务程序
void EXTI2_IRQHandler(void)
{
  // app程序
  EXTI_ClearITPendingBit(EXTI_Line2); //清除LINE2上的中断标志位
}
//外部中断3服务程序
void EXTI3_IRQHandler(void)
{
  EXTI_ClearITPendingBit(EXTI_Line3); //清除LINE3上的中断标志位
}
//外部中断4服务程序
void EXTI4_IRQHandler(void)
{
  EXTI_ClearITPendingBit(EXTI_Line4); //清除LINE4上的中断标志位
}
//外部中断初始化程序
//初始化PE2~4,PA0为中断输入.
void EXTIX_Init(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  EXTI_InitTypeDef EXTI_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //使能SYSCFG时钟
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource2); //PE2 连接到中断线2
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource3); //PE3 连接到中断线3
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource4); //PE4 连接到中断线4
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0); //PA0 连接到中断线0
  /* 配置EXTI_Line0 */
  EXTI_InitStructure.EXTI_Line = EXTI_Line0;             //LINE0
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;    //中断事件
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;              //使能LINE0
  EXTI_Init(&EXTI_InitStructure);                        //配置
  /* 配置EXTI_Line2,3,4 */
  EXTI_InitStructure.EXTI_Line = EXTI_Line2 | EXTI_Line3 | EXTI_Line4;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;     //中断事件
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;               //中断线使能
  EXTI_Init(&EXTI_InitStructure);                         //配置
  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;             //外部中断0
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; //抢占优先级0
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;        //子优先级2
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;              //使能外部中断通道
  NVIC_Init(&NVIC_InitStructure);                              //配置
  NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;             //外部中断2
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x03; //抢占优先级3
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;        //子优先级2
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;              //使能外部中断通道
  NVIC_Init(&NVIC_InitStructure);                              //配置
  NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;             //外部中断3
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;        //子优先级2
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;              //使能外部中断通道
  NVIC_Init(&NVIC_InitStructure);                              //配置
  NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;             //外部中断4
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; //抢占优先级1
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;        //子优先级2
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;              //使能外部中断通道
  NVIC_Init(&NVIC_InitStructure);                              //配置
}

.h文件

#ifndef __EXTI_H
#define __EXIT_H
#include "stm32f4xx.h"
/** 外部中断初始化后可以直接在服务函数中写逻辑函数 **/
void EXTIX_Init(void); //外部中断初始化
#endif


stm32f4外设学习篇(代码集合)(二)https://developer.aliyun.com/article/1472516

相关文章
|
6月前
【STM32】基于HAL库的360度编码器、摇杆代码编写
【STM32】基于HAL库的360度编码器、摇杆代码编写
|
27天前
stm32学习 3-2 LED流水灯
stm32学习 3-2 LED流水灯
58 4
|
27天前
stm32学习3-1 LED闪烁
stm32学习3-1 LED闪烁
32 4
|
5月前
|
开发者
【经典案例】使用HAL库配置STM32F407的SPI外设
在嵌入式系统开发中,STM32F407是一款广泛应用的微控制器,而SPI(Serial Peripheral Interface)是一种常用的通信接口。本文将详细介绍如何使用STM32的硬件抽象层(HAL)库配置STM32F407的SPI外设,并提供完整的代码示例。
488 1
|
5月前
|
存储 数据安全/隐私保护 芯片
【STM32】详解嵌入式中FLASH闪存的特性和代码示例
【STM32】详解嵌入式中FLASH闪存的特性和代码示例
【STM32】详解独立看门狗的本质和使用步骤&代码
【STM32】详解独立看门狗的本质和使用步骤&代码
|
5月前
|
传感器 数据格式
【STM32】DHT11温湿度模块传感器详解&代码
【STM32】DHT11温湿度模块传感器详解&代码
|
6月前
|
传感器
STM32循迹小车原理介绍和代码示例
STM32循迹小车原理介绍和代码示例
|
6月前
stm32f4外设学习篇(代码集合)(三)
stm32f4外设学习篇(代码集合)
113 0
|
6月前
stm32f4外设学习篇(代码集合)(二)
stm32f4外设学习篇(代码集合)