如何快速移植(从STM32F103到STM32F407)

2023-12-13 12:33:25

最近用到F4的地方比较多,网上代码还是F1多一些,便需要移植代码,如何快速移植代码呢?
看下面这篇文章

外设

首先就是STM32的外设了。

STM32F407ZGT6的基本外设

STM32F407ZGT6 作为 MCU,该芯片是
STM32F407 里面配置非常强大的了,它拥有的资源包括:集成 FPU 和 DSP 指令,并具有 192KB
SRAM、1024KB FLASH、1216 位定时器、232 位定时器、2 个 DMA 控制器(共 16 个通道)、3 个 SPI、2 个全双工 I2S、3 个 IIC、6 个串口、2 个 USB(支持 HOST /SLAVE)、2 个CAN、312 位 ADC、212 位 DAC、1 个 RTC(带日历功能)、1 个 SDIO 接口、1 个 FSMC接口、110/100M 以太网 MAC 控制器、1 个摄像头接口、1 个硬件随机数生成器、以及 112个通用 IO 口等。该芯片的配置十分强悍,很多功能相对 STM32F1 来说进行了重大改进,比如
FSMC 的速度,F4 刷屏速度可达 3300W 像素/秒,而 F1 的速度则只有 500W 左右。

STM32F103ZET6的基本外设

STM32F103ZETT6 作为 MCU,该芯片是
STM32F103 里面配置非常强大的了,它拥有的资源包括:64KB SRAM、512KB FLASH、2 个基本定时器、4 个通用定时器、2 个高级定时器、2 个 DMA 控制器(共 12 个通道)、3 个 SPI、2 个 IIC、5 个串口、1 个 USB、1 个 CAN、312 位 ADC、112 位 DAC、1 个 SDIO 接口、1 个 FSMC 接口以及 112 个通用 IO 口。该芯片的配置十分强悍,并且还带外部总线(FSMC)
可以用来外扩 SRAM 和连接 LCD 等,通过 FSMC 驱动 LCD,可以显著提高 LCD 的刷屏速度,是 STM32F1 家族常用型号里面,最高配置的芯片了

然后是比较重要的一个功能。

时钟

为什么说时钟重要呢,在做SPI或者一些对时的时候,这个时候时钟的重要性就突显出来了。

F407的时钟

SYSCLK(系统时钟) =168MHz
AHB 总线时钟(HCLK=SYSCLK) =168MHz
APB1 总线时钟(PCLK1=SYSCLK/4) =42MHz
APB2 总线时钟(PCLK2=SYSCLK/2) =84MHz
PLL 主时钟 =168MHz

F103的时钟

SYSCLK(系统时钟) =72MHz
AHB 总线时钟(使用 SYSCLK) =72MHz
APB1 总线时钟(PCLK1=SYSCLK/2) =36MHz
APB2 总线时钟(PCLK2) =72MHz
PLL 时钟 =72MHz

IO的配置

1、输入浮空
2、输入上拉
3、输入下拉
4、模拟输入
5、开漏输出
6、推挽输出
7、推挽式复用功能
8、开漏式复用功能

模式就不用说了,这个大家应该都知道,重要的是如何配置。

F407

一定要注意使能IO口时钟,而且要写对 博主就踩了几次坑

使能 IO 口时钟。调用函数为 RCC_AHB1PeriphClockCmd ()
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//使能GPIOF时钟
初始化 IO 参数。调用函数 GPIO_Init();
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化GPIO

上面的是输出配置,下面看一下输入配置,大家可以比较一下。

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4; 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE2,3,4

F103

GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_4|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE4,3

然后我们看一下不同点

首先F4的io的时钟挂载在AHB1下,调用
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//使能GPIOF时钟

其次
typedef struct
{
 uint32_t GPIO_Pin;
 GPIOMode_TypeDef GPIO_Mode;
 GPIOSpeed_TypeDef GPIO_Speed;
 GPIOOType_TypeDef GPIO_OType;//配置输出模式 
 GPIOPuPd_TypeDef GPIO_PuPd; //上下拉的配置
}GPIO_InitTypeDef;

typedef enum
{ 
  GPIO_PuPd_NOPULL = 0x00,
  GPIO_PuPd_UP     = 0x01,
  GPIO_PuPd_DOWN   = 0x02
}GPIOPuPd_TypeDef;

f4能在GPIO_Init配置时就配置引脚的上下拉高低电平

typedef enum
{ 
  GPIO_OType_PP = 0x00,
  GPIO_OType_OD = 0x01
}GPIOOType_TypeDef;

f4配置了输出后专门可以选择配置开漏输出和推挽输出,也就是比103分的更细一些了

f4的速度最高可以配置为100mhz 103只有50mhz

NVIC

首先两者都要在main函数里面设置中断优先级的分组,且只设置一次设置了就别改了避免发生错误

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

F407

STM32F40xx/STM32F41xx 的 92 个中断里面,包括 10 个内核中断和 82 个可屏蔽中断,具
有 16 级可编程的中断优先级,而我们常用的就是这 82 个可屏蔽中断

F103

说了 CM3 内核支持 256 个中断,这里用 8 个 32 位寄存器来控制,每个位控制一个中断。但是
STM32F103 的可屏蔽中断只有 60 个

他们NVIC的配置是一样的

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口 1 中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;// 抢占优先级为 1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;// 子优先级位 2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
NVIC_Init(&NVIC_InitStructure); //根据上面指定的参数初始化 NVIC 寄存器

外部中断

他们之间的中断服务函数都是一样的

EXTI0_IRQHandler           
EXTI1_IRQHandler
EXTI2_IRQHandler           
EXTI3_IRQHandler           
EXTI4_IRQHandler           
EXTI9_5_IRQHandler         
EXTI15_10_IRQHandler    

F407

STM32F407 的中断控制器支持 22
个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。
STM32F407 的 22 个外部中断为:
EXTI 线 0~15:对应外部 IO 口的输入中断。
EXTI 线 16:连接到 PVD 输出。
EXTI 线 17:连接到 RTC 闹钟事件。
EXTI 线 18:连接到 USB OTG FS 唤醒事件。
EXTI 线 19:连接到以太网唤醒事件。
EXTI 线 20:连接到 USB OTG HS(在 FS 中配置)唤醒事件。
EXTI 线 21:连接到 RTC 入侵和时间戳事件。
EXTI 线 22:连接到 RTC 唤醒事件。

STM32F4 供 IO 口使用的中断线只有 16

配置步骤

使能SYSCFG时钟: 
         RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
初始化IO口为输入。
       GPIO_Init();
设置IO口与中断线的映射关系。
        void SYSCFG_EXTILineConfig();
初始化线上中断,设置触发条件等。
       EXTI_Init();
配置中断分组(NVIC),并使能中断。
       NVIC_Init();
编写中断服务函数。
      EXTIx_IRQHandler();
清除中断标志位
      EXTI_ClearITPendingBit();

实例
一定要注意这里
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource3);//PE3 连接到中断线3
这两个是不一样的,F4是使能SYSCFG时钟来配置中断

NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource3);//PE3 连接到中断线3

  EXTI_InitStructure.EXTI_Line =EXTI_Line3
  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 = EXTI3_IRQn;//外部中断3
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级2
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
  NVIC_Init(&NVIC_InitStructure);//配置

中断服务格式

void EXTI3_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line3)!=RESET)//判断某个线上的中断是否发生
{ …中断逻辑…
EXTI_ClearITPendingBit(EXTI_Line3); //清除 LINE 上的中断标志位
}
}

F103

初始化IO口为输入。
       GPIO_Init();
 开启IO口复用时钟。
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
设置IO口与中断线的映射关系。
        void GPIO_EXTILineConfig();
初始化线上中断,设置触发条件等。
       EXTI_Init();
配置中断分组(NVIC),并使能中断。
       NVIC_Init();
编写中断服务函数。
      EXTIx_IRQHandler();
清除中断标志位
      EXTI_ClearITPendingBit();

实例

io初始化省略
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//使能复用功能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	

//配置 GPIO 与中断线的映射关系
//void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)

GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
将中断线 3 与 GPIOE 映射起来,那么很显然是 GPIOE.3 与 EXTI3 中断线连接了

//初始化线上中断,设置触发条件等
EXTI_InitStructure.EXTI_Line=EXTI_Line3; //设置中断线的标号
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断模式
//有两个模式中断和事件可选这里是中断	
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//设置触发方式
//设置触发方式,有上升沿和下降沿,还有双边沿,这里配置的是下降沿
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);	  	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

//配置中断分组(NVIC),并使能中断
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;			//使能外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;					//子优先级1 
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure);  	  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

后面就是根据具体的要求写中断函数了

中断服务格式

void EXTI3_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line3)!=RESET)//判断某个线上的中断是否发生
{
中断逻辑…
EXTI_ClearITPendingBit(EXTI_Line3); //清除 LINE 上的中断标志位
}
}

串口

串口也是很重要的一个环节。

F407

配置步骤

串口时钟使能:RCC_APBxPeriphClockCmd();
     GPIO时钟使能:RCC_AHB1PeriphClockCmd();
引脚复用映射:
     GPIO_PinAFConfig();
GPIO端口模式设置:GPIO_Init(); 模式设置为GPIO_Mode_AF
串口参数初始化:USART_Init();
开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
      NVIC_Init();
      USART_ITConfig();
使能串口:USART_Cmd();
编写中断处理函数:USARTx_IRQHandler();
串口数据收发:
void USART_SendData();//发送数据到串口,DR
uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据
串口传输状态获取:
FlagStatus USART_GetFlagStatus();
void USART_ClearITPendingBit();

实例

 //GPIO端口设置
  GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟
 
	//串口1对应引脚复用映射
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9复用为USART1
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1
	
	//USART1端口配置
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//速度50MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
	GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10

   //USART1 初始化设置
	USART_InitStructure.USART_BaudRate = bound;//波特率设置
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	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(USART1, &USART_InitStructure); //初始化串口1
	

   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断

	//Usart1 NVIC 配置
   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
 	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器、

    USART_Cmd(USART1, ENABLE);  //使能串口1 

中断服务函数

F103

串口时钟使能,GPIO时钟使能:RCC_APB2PeriphClockCmd();
串口复位:USART_DeInit(); 这一步不是必须的
GPIO端口模式设置:GPIO_Init(); 
串口参数初始化:USART_Init();
开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
      NVIC_Init();
      USART_ITConfig();
使能串口:USART_Cmd();
编写中断处理函数:USARTx_IRQHandler();
串口数据收发:
void USART_SendData();//发送数据到串口,DR
uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据
串口传输状态获取:
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);

实例

GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//①串口时钟使能,GPIO 时钟使能,复用时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|
RCC_APB2Periph_GPIOA, ENABLE); //使能 USART1,GPIOA 时钟

//②串口复位
USART_DeInit(USART1); //复位串口 1

//③GPIO 端口模式设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //ISART1_TX PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.9

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //USART1_RX PA.10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.10

//④串口参数初始化
USART_InitStructure.USART_BaudRate = 115200; //波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为 8 位
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(USART1, &USART_InitStructure); 

//⑤初始化 NVIC
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ; //抢占优先级 3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级 3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
NVIC_Init(&NVIC_InitStructure); //中断优先级初始化

//⑤开启中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启中断

//⑥使能串口
USART_Cmd(USART1, ENABLE); //使能串口

中断服务函数

不同点

1.首先都要开启usart的时钟和对应串口引脚的时钟,不同的是103串口的tx引脚配置的复用推挽输出,而rx配置的是浮空输入,而407rx,tx两个都配置的复用推完输出
2.407需要对串口对应的引脚设置引脚复用器映射:调用 GPIO_PinAFConfig 函数。
这两点大家一定要注意!

定时器

103的定时器资源
103的高级定时器是TIM1和TIM8
2,3,4,5是通用定时器
6,7是基本定时器
都是16位的

407的定时器资源
407的高级定时器是TIM1和TIM8
2,3,4,5,9,10,11,12,13,14是通用定时器
6,7是基本定时器
有16位和32位的

103和407的定时器中断

这个基本定时器的配置是一样的


能定时器时钟。
       RCC_APB1PeriphClockCmd();
初始化定时器,配置ARR,PSC。
      TIM_TimeBaseInit();
开启定时器中断,配置NVIC。
      void TIM_ITConfig();
      NVIC_Init();
 使能定时器。
      TIM_Cmd();
编写中断服务函数。
      TIMx_IRQHandler();

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
	
	//定时器TIM3初始化
	TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载的值	
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断

	//中断优先级NVIC设置
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器


	TIM_Cmd(TIM3, ENABLE);  //使能TIMx	



//定时器3中断服务函数
void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断
	{
		LED1=!LED1;//DS1翻转
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  //清除中断标志位
}

PWM

F407

使能定时器14和相关IO口时钟。
         使能定时器14时钟:RCC_APB1PeriphClockCmd();
         使能GPIOF时钟:RCC_AHB1PeriphClockCmd ();
初始化IO口为复用功能输出。函数:GPIO_Init();
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能GPIOF9复用映射到定时器14
        GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14); 	
 初始化定时器:ARR,PSC等:
        TIM_TimeBaseInit();
 初始化输出比较参数:
         TIM_OC1Init();
 使能预装载寄存器: 
        TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable); 
使能自动重装载的预装载寄存器允许位
          TIM_ARRPreloadConfig(TIM14,ENABLE);
使能定时器。 
          TIM_Cmd();
不断改变比较值CCRx,达到不同的占空比效果: 
        TIM_SetCompare1();

GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);  	//TIM14时钟使能    
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); 	//使能PORTF时钟	
	
	GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14); //GPIOF9复用为定时器14
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;           //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(GPIOF,&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

F103

使能定时器3和相关IO口时钟。
         使能定时器3时钟:
         RCC_APB1PeriphClockCmd();
         使能GPIOB时钟:
         RCC_APB2PeriphClockCmd();

 初始化IO口为复用功能输出。函数:
         GPIO_Init();
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;      
这里我们是要把PB5用作定时器的PWM输出引脚,所以要重映射配置,
所以需要开启AFIO时钟。同时设置重映射。
         RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
		 GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); 

初始化定时器:ARR,PSC等:
		TIM_TimeBaseInit();
 初始化输出比较参数:
 		TIM_OC2Init();
使能预装载寄存器: 
		TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); 
使能定时器。
		TIM_Cmd();
不断改变比较值CCRx,达到不同的占空比效果:
		TIM_SetCompare2();

GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//使能定时器3时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟
	
	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射  TIM3_CH2->PB5    
 
   //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形	GPIOB.5
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
 
   //初始化TIM3
	TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载值
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	//初始化TIM3 Channel2 PWM模式	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2

	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器
 
	TIM_Cmd(TIM3, ENABLE);  //使能TIM3

总结

如果移植之后发现不能用,首先检查IO的使能,如果使能没有问题进一步检查引脚配置的模式。该复用成对应功能的有没有复用。有用中断要注意F4中断时钟初始化的写法,如果用到SPI这种需要时序的,确认上面的没问题了,在检查一下时钟。
如果你的SPI发现自己动一动线就有数据了,这个时候就去看引脚的模式,是不是推挽输出。该浮空输入的有没有浮空输入,那个默认无上下拉的配置直接不要,不要写那个东西。

跳转链接
我这篇文章也是引用这位博主的文章,在此感谢。

文章来源:https://blog.csdn.net/qq_51963216/article/details/134843019
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。