芯片: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