STM32单片机使用Modbus-Rtu与PLC进行通讯控制16路PWM,频率、占空比可调(二)

一.程序编写思路

1.1串口接收数据方法选择

经查阅资料本次想采用以下两种方法之一来配置串口接收部分:1.定时器判断超时、2.串口空闲中断

1.11定时器判断超时接收

入选原因是modbus rtu协议中,主机在接收从机数据后,在3.5个字节时间后认为数据包接收完毕。那在这种情况下,一般的做法是设置一个定时器,在每接收到一个字节时清零定时器重新计数,直到定时器超过3.5个字节时间后触发中断即默认数据包接收完毕。此方法对于硬件配置比较低,也属于通常做法,方便后面移植到其他单片机。

1.12串口空闲中断判断超时接收

入选原因是STM32单片机拥有这个功能,可以自动判断串口是否接受完一帧数据。与定时器判断超时相比较能节省一个定时器,并在程序上简单一些

1.13最终结论

本次还是决定使用定时器判断超时,主要是为了后面方便移植到其他单片机。

1.2串口接收数据方法实现

选择好串口接收数据的方法后,开始配置STM32的串口和定时器,因为开发板采用的是串口1连接的RS485,所以程序需要配置串口1。选用通用定时器1做串口接收超时判断。

二.程序实现串口超时接收判断一帧数据

2.1配置串口1为9600、8、n、1

void uart1_init(u32 bound)
{
  //GPIO端口设置
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;	
	
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
  	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;				 //端口配置,A8为485换向引脚
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
  GPIO_Init(GPIOA, &GPIO_InitStructure);					 //根据设定参数初始化GPIOB.5
  GPIO_SetBits(GPIOA,GPIO_Pin_8);						 //PA.8 输出高
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9,USART1_TX
  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;//PA10,USART1_RX
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  

  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级3
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;		//子优先级3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
  NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
  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);//开启串口接受中断
  USART_Cmd(USART1, ENABLE);                    //使能串口1 
  RS485_RE=0;  //485默认接收
}

2.2配置串口1中断

/**************************************************************************
*函数名称:void USART1_IRQHandler(void)
*函数功能:串口1中断函数
*输入参数:无
*返回值: 无
*编写人:张楠
*编写日期:2022.04.02
**************************************************************************/
void USART1_IRQHandler(void)                	
{
   if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
   {
     uart1_rx_buf[uart1_rx_count] = USART_ReceiveData(USART1); //接收到的数据填入uart1_rx_buf
	 uart1_rx_count++;                                         //串口1接受计数加1		
	 uart1_rx_timer_count=0;                                   //每次接收到数据,串口1接收计数都重新开始计时
	 uart1_rx_timer_count_flag=1;                              //串口1是否开始进入超时计算标志位置1		
   }
} 

2.3配置定时器1为1ms进入一次中断

/*********************************************
定时器     CH1      CH2       CH3      CH4 
timer1     PA8      PA9       PA10    PA11       做串口超时及喂狗计时
timer2     PA0      PA1       PA2     PA3        √
timer3     PA6      PA7       PB0     PB1        √
timer4     PB6      PB7       PB8     PB9        √
**********************************************/

/**************************************************************************
*函数名称:void TIM1_Int_Init(u16 arr,u16 psc)
*函数功能:定时器1初始化
*输入参数:arr:定时器累积到此数值进入中断,psc:设置定时器每次加一个数的间隔时间
*返回值: 无
*编写人:张楠
*编写日期:2022.04.02
**************************************************************************/
void TIM1_Int_Init(u16 arr,u16 psc)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  NVIC_InitTypeDef NVIC_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); //时钟使能
	
  //定时器TIM1初始化
  TIM_TimeBaseStructure.TIM_Period = arr-1; //设置 
  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(TIM1, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
 
  TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE ); //使能指定的TIM1中断,允许更新中断

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

  TIM_Cmd(TIM1, ENABLE);  //使能TIM1					 
}

2.4配置定时器1中断

/**************************************************************************
*函数名称:void TIM1_UP_IRQHandler(void)
*函数功能:定时器1中断程序,每1ms进入一次中断,负责串口1超时接收判断、看门狗喂狗计数、LED指示灯计数
*输入参数:无
*返回值: 无
*编写人:张楠
*编写日期:2022.04.02
**************************************************************************/
void TIM1_UP_IRQHandler(void)   
{
	if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)  //检查TIM1更新中断发生与否	 
	{
		TIM_ClearITPendingBit(TIM1, TIM_IT_Update);     //清除TIM1更新中断标志
		feed_watchdog_count++;                          //喂狗计时加1
		if(uart1_rx_timer_count_flag==1)                //如果串口接收到数据,会将计数清零,标志位置1,定时器开始超时计时
		{
		  uart1_rx_timer_count++;		
		  if(uart1_rx_timer_count>5)                    //设置5ms超时接收完成判断
		  {		
			uart1_rx_timer_count=0;
			uart1_timeout_flag=1;	                      //串口1超时接收完成标志位置1,主循环检测到则开始分析串口1数据
		  }					
		}			
		  if(feed_watchdog_count>800)                     //看门狗计时判断
		  {
			feed_watchdog_count_flag=1;                   //喂狗标志位置1,主循环检测到则开始喂狗              
		  }		
	  }
}


2.41验证

2.5设置16路PWM初始化

#include "pwm.h"
#include "modbusrtu.h"
/*********************************************
定时器     CH1      CH2       CH3      CH4 
timer1     PA8      PA9       PA10    PA11       做串口超时及喂狗计时
timer2     PA0      PA1       PA2     PA3        √
timer3     PA6      PA7       PB0     PB1        √
timer4     PB6      PB7       PB8     PB9        √
**********************************************/  
	

/**************************************************************************
*函数名称:void TIM2_PWM_CH1_Init(u16 fre,u16 duty_ratio)
*函数功能:定时器2通道1初始化
*输入参数:fre:频率,duty_ratio:占空比(0-100)
*返回值: 无
*编写人:张楠
*编写日期:2022.04.02
**************************************************************************/
void TIM2_PWM_CH1_Init(u16 fre,u16 duty_ratio)
{  
	
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	fre=10000/fre;
	duty_ratio=(fre*duty_ratio)/100;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);	//使能定时器2时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //使能GPIO外设
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //TIM2_CH1
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
	
	TIM_TimeBaseStructure.TIM_Period = fre-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值,计数到多少us进入中断
	TIM_TimeBaseStructure.TIM_Prescaler =71; //设置用来作为TIMx时钟频率除数的预分频值 ,1us加一次
	
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//始终不分割
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM2 OC1
	TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);  //使能TIM2在CCR1上的预装载寄存器	

	TIM_SetCompare1(TIM2,duty_ratio);	//设置占空比
	TIM_Cmd(TIM2, ENABLE);  //使能TIM2
	TIM2->CCER&=0xFFFE;  //关闭第1路PWM使能
}

/**************************************************************************
*函数名称:void TIM2_PWM_CH2_Init(u16 fre,u16 duty_ratio)
*函数功能:定时器2通道2初始化
*输入参数:fre:频率,duty_ratio:占空比(0-100)
*返回值: 无
*编写人:张楠
*编写日期:2022.04.02
**************************************************************************/
void TIM2_PWM_CH2_Init(u16 fre,u16 duty_ratio)
{  
	
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	fre=10000/fre;
	duty_ratio=(fre*duty_ratio)/100;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);	//使能定时器2时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //使能GPIOA外设
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //TIM2_CH2
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
 
	TIM_TimeBaseStructure.TIM_Period = fre-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值,计数到多少us进入中断
	TIM_TimeBaseStructure.TIM_Prescaler =71; //设置用来作为TIMx时钟频率除数的预分频值 ,1us加一次
	
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	
	TIM_OC2Init(TIM2, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM2 OC2

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

	TIM_SetCompare2(TIM2,duty_ratio);	
	TIM_Cmd(TIM2, ENABLE);  //使能TIM2
	TIM2->CCER&=0xFFEF;  //关闭第2路PWM使能
}

/**************************************************************************
*函数名称:void TIM2_PWM_CH3_Init(u16 fre,u16 duty_ratio)
*函数功能:定时器2通道3初始化
*输入参数:fre:频率,duty_ratio:占空比(0-100)
*返回值: 无
*编写人:张楠
*编写日期:2022.04.02
**************************************************************************/
void TIM2_PWM_CH3_Init(u16 fre,u16 duty_ratio)
{  
	
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	fre=10000/fre;
	duty_ratio=(fre*duty_ratio)/100;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);	//使能定时器2时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //使能GPIOA外设
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //TIM2_CH3
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
 
	TIM_TimeBaseStructure.TIM_Period = fre-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值,计数到多少us进入中断
	TIM_TimeBaseStructure.TIM_Prescaler =71; //设置用来作为TIMx时钟频率除数的预分频值 ,1us加一次
	
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	

    TIM_OC3Init(TIM2, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM2 OC3
    TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);  //使能TIM3在CCR3上的预装载寄存器
	
	TIM_SetCompare3(TIM2,duty_ratio);	
	TIM_Cmd(TIM2, ENABLE);  //使能TIM2
	TIM2->CCER&=0xFEFF;  //关闭第3路PWM使能
}

/**************************************************************************
*函数名称:void TIM3_PWM_CH4_Init(u16 fre,u16 duty_ratio)
*函数功能:定时器2通道4初始化
*输入参数:fre:频率,duty_ratio:占空比(0-100)
*返回值: 无
*编写人:张楠
*编写日期:2022.04.02
**************************************************************************/
void TIM2_PWM_CH4_Init(u16 fre,u16 duty_ratio)
{  
	
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	fre=10000/fre;
	duty_ratio=(fre*duty_ratio)/100;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);	//使能定时器2时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //使能GPIOA外设
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //TIM2_CH4
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
 
	TIM_TimeBaseStructure.TIM_Period = fre-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值,计数到多少us进入中断
	TIM_TimeBaseStructure.TIM_Prescaler =71; //设置用来作为TIMx时钟频率除数的预分频值 ,1us加一次
	
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	
	TIM_OC4Init(TIM2, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM2 OC4
	TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);  //使能TIM2在CCR4上的预装载寄存器
	
	TIM_SetCompare4(TIM2,duty_ratio);	
	TIM_Cmd(TIM2, ENABLE);  //使能TIM2
	TIM2->CCER&=0xEFFF;  //关闭第4路PWM使能
}

/**************************************************************************
*函数名称:void TIM3_PWM_CH1_Init(u16 fre,u16 duty_ratio)
*函数功能:定时器3通道1初始化
*输入参数:fre:频率,duty_ratio:占空比(0-100)
*返回值: 无
*编写人:张楠
*编写日期:2022.03.28
**************************************************************************/
void TIM3_PWM_CH1_Init(u16 fre,u16 duty_ratio)
{  
	
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	fre=10000/fre;
	duty_ratio=(fre*duty_ratio)/100;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//使能定时器2时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //TIM3_CH1
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
 
	TIM_TimeBaseStructure.TIM_Period = fre-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值,计数到多少us进入中断
	TIM_TimeBaseStructure.TIM_Prescaler =71; //设置用来作为TIMx时钟频率除数的预分频值 ,1us加一次
	
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	
	TIM_OC1Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC1
	TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR1上的预装载寄存器	

	TIM_SetCompare1(TIM3,duty_ratio);	
	TIM_Cmd(TIM3, ENABLE);  //使能TIM3
	TIM3->CCER&=0xFFFE;  //关闭第5路PWM使能	
}

/**************************************************************************
*函数名称:void TIM3_PWM_CH2_Init(u16 fre,u16 duty_ratio)
*函数功能:定时器3通道2初始化
*输入参数:fre:频率,duty_ratio:占空比(0-100)
*返回值: 无
*编写人:张楠
*编写日期:2022.04.02
**************************************************************************/
void TIM3_PWM_CH2_Init(u16 fre,u16 duty_ratio)
{  
	
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	fre=10000/fre;
	duty_ratio=(fre*duty_ratio)/100;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//使能定时器3时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //使能GPIOA外设
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //TIM3_CH2
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
 
	TIM_TimeBaseStructure.TIM_Period = fre-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值,计数到多少us进入中断
	TIM_TimeBaseStructure.TIM_Prescaler =71; //设置用来作为TIMx时钟频率除数的预分频值 ,1us加一次
	
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
 	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_SetCompare2(TIM3,duty_ratio);	
	TIM_Cmd(TIM3, ENABLE);  //使能TIM3
	TIM3->CCER&=0xFFEF;  //关闭第6路PWM使能	
}

/**************************************************************************
*函数名称:void TIM3_PWM_CH3_Init(u16 fre,u16 duty_ratio)
*函数功能:定时器3通道3初始化
*输入参数:fre:频率,duty_ratio:占空比(0-100)
*返回值: 无
*编写人:张楠
*编写日期:2022.04.02
**************************************************************************/
void TIM3_PWM_CH3_Init(u16 fre,u16 duty_ratio)
{  
	
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	fre=10000/fre;
	duty_ratio=(fre*duty_ratio)/100;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//使能定时器3时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);  //使能GPIOB外设
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //TIM3_CH3
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
 
	TIM_TimeBaseStructure.TIM_Period = fre-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值,计数到多少us进入中断
	TIM_TimeBaseStructure.TIM_Prescaler =71; //设置用来作为TIMx时钟频率除数的预分频值 ,1us加一次
	
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	
	TIM_OC3Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC3	
	TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器	

	TIM_SetCompare3(TIM3,duty_ratio);	
	TIM_Cmd(TIM3, ENABLE);  //使能TIM3
	TIM3->CCER&=0xFEFF;  //关闭第7路PWM使能	
}

/**************************************************************************
*函数名称:void TIM3_PWM_CH4_Init(u16 fre,u16 duty_ratio)
*函数功能:定时器3通道4初始化
*输入参数:fre:频率,duty_ratio:占空比(0-100)
*返回值: 无
*编写人:张楠
*编写日期:2022.04.02
**************************************************************************/
void TIM3_PWM_CH4_Init(u16 fre,u16 duty_ratio)
{  
	
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	fre=10000/fre;
	duty_ratio=(fre*duty_ratio)/100;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//使能定时器3时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //使能GPIOA外设
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //TIM3_CH4
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO

	TIM_TimeBaseStructure.TIM_Period = fre-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值,计数到多少us进入中断
	TIM_TimeBaseStructure.TIM_Prescaler =71; //设置用来作为TIMx时钟频率除数的预分频值 ,1us加一次
	
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	
	TIM_OC4Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC4
	TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR4上的预装载寄存器	

	TIM_SetCompare4(TIM3,duty_ratio);	
	TIM_Cmd(TIM3, ENABLE);  //使能TIM2
	TIM3->CCER&=0xEFFF;  //关闭第8路PWM使能	
}

/**************************************************************************
*函数名称:void TIM4_PWM_CH1_Init(u16 fre,u16 duty_ratio)
*函数功能:定时器4通道1初始化
*输入参数:fre:频率,duty_ratio:占空比(0-100)
*返回值: 无
*编写人:张楠
*编写日期:2022.04.02
**************************************************************************/
void TIM4_PWM_CH1_Init(u16 fre,u16 duty_ratio)
{  
	
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	fre=10000/fre;
	duty_ratio=(fre*duty_ratio)/100;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);	//使能定时器2时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //使能GPIOB外设
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //TIM4_CH1
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB
 
	TIM_TimeBaseStructure.TIM_Period = fre-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值,计数到多少us进入中断
	TIM_TimeBaseStructure.TIM_Prescaler =71; //设置用来作为TIMx时钟频率除数的预分频值 ,1us加一次
	
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	
	TIM_OC1Init(TIM4, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC1
	TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);  //使能TIM4在CCR1上的预装载寄存器	

	TIM_SetCompare1(TIM4,duty_ratio);	
	TIM_Cmd(TIM4, ENABLE);  //使能TIM4
	TIM4->CCER&=0xFFFE;  //关闭第9路PWM使能	
}

/**************************************************************************
*函数名称:void TIM4_PWM_CH2_Init(u16 fre,u16 duty_ratio)
*函数功能:定时器4通道2初始化
*输入参数:fre:频率,duty_ratio:占空比(0-100)
*返回值: 无
*编写人:张楠
*编写日期:2022.04.02
**************************************************************************/
void TIM4_PWM_CH2_Init(u16 fre,u16 duty_ratio)
{  
	
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	fre=10000/fre;
	duty_ratio=(fre*duty_ratio)/100;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);	//使能定时器4时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //使能GPIOB外设
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //TIM4_CH2
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB
 
	TIM_TimeBaseStructure.TIM_Period = fre-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值,计数到多少us进入中断
	TIM_TimeBaseStructure.TIM_Prescaler =71; //设置用来作为TIMx时钟频率除数的预分频值 ,1us加一次
	
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	
	TIM_OC2Init(TIM4, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC2	
	TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);  //使能TIM4在CCR2上的预装载寄存器	

	TIM_SetCompare2(TIM4,duty_ratio);	
	TIM_Cmd(TIM4, ENABLE);  //使能TIM4
	TIM4->CCER&=0xFFEF;  //关闭第10路PWM使能	
}

/**************************************************************************
*函数名称:void TIM4_PWM_CH3_Init(u16 fre,u16 duty_ratio)
*函数功能:定时器2通道1初始化
*输入参数:fre:频率,duty_ratio:占空比(0-100)
*返回值: 无
*编写人:张楠
*编写日期:2022.04.02
**************************************************************************/
void TIM4_PWM_CH3_Init(u16 fre,u16 duty_ratio)
{  
	
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	fre=10000/fre;
	duty_ratio=(fre*duty_ratio)/100;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);	//使能定时器4时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //使能GPIOB外设
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //TIM4_CH3
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB
 
	TIM_TimeBaseStructure.TIM_Period = fre-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值,计数到多少us进入中断
	TIM_TimeBaseStructure.TIM_Prescaler =71; //设置用来作为TIMx时钟频率除数的预分频值 ,1us加一次

	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	
	TIM_OC3Init(TIM4, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC3
	TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);  //使能TIM4在CCR3上的预装载寄存器	

	TIM_SetCompare3(TIM4,duty_ratio);	
	TIM_Cmd(TIM4, ENABLE);  //使能TIM4
	TIM4->CCER&=0xFEFF;  //关闭第11路PWM使能		
}


/**************************************************************************
*函数名称:void TIM4_PWM_CH4_Init(u16 fre,u16 duty_ratio)
*函数功能:定时器4通道4初始化
*输入参数:fre:频率,duty_ratio:占空比(0-100)
*返回值: 无
*编写人:张楠
*编写日期:2022.04.02
**************************************************************************/
void TIM4_PWM_CH4_Init(u16 fre,u16 duty_ratio)
{  
	
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	fre=10000/fre;
	duty_ratio=(fre*duty_ratio)/100;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);	//使能定时器4时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //使能GPIOB外设
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //TIM4_CH4
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
 
	TIM_TimeBaseStructure.TIM_Period = fre-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值,计数到多少us进入中断
	TIM_TimeBaseStructure.TIM_Prescaler =71; //设置用来作为TIMx时钟频率除数的预分频值 ,1us加一次

	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	
	TIM_OC4Init(TIM4, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC4
	TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);  //使能TIM4在CCR4上的预装载寄存器	
	TIM_SetCompare4(TIM4,duty_ratio);	
	TIM_Cmd(TIM4, ENABLE);  //使能TIM4
	TIM4->CCER&=0xEFFF;  //关闭第12路PWM使能		
}


/**************************************************************************
*函数名称:void All_Timer_Pwm_Init(void)
*函数功能:12路PWM初始化函数
*输入参数:无
*返回值: 无
*编写人:张楠
*编写日期:2022.04.02
**************************************************************************/
void All_Timer_Pwm_Init(void)
{	
  TIM2_PWM_CH1_Init((Pwm_Status[25]<<8)+Pwm_Status[26],(Pwm_Status[31]<<8)+Pwm_Status[32]);
  TIM2_PWM_CH2_Init((Pwm_Status[25]<<8)+Pwm_Status[26],(Pwm_Status[33]<<8)+Pwm_Status[34]);
	TIM2_PWM_CH3_Init((Pwm_Status[25]<<8)+Pwm_Status[26],(Pwm_Status[35]<<8)+Pwm_Status[36]);
	TIM2_PWM_CH4_Init((Pwm_Status[25]<<8)+Pwm_Status[26],(Pwm_Status[37]<<8)+Pwm_Status[38]);

  TIM3_PWM_CH1_Init((Pwm_Status[27]<<8)+Pwm_Status[28],(Pwm_Status[39]<<8)+Pwm_Status[40]);
  TIM3_PWM_CH2_Init((Pwm_Status[27]<<8)+Pwm_Status[28],(Pwm_Status[41]<<8)+Pwm_Status[42]);
	TIM3_PWM_CH3_Init((Pwm_Status[27]<<8)+Pwm_Status[28],(Pwm_Status[43]<<8)+Pwm_Status[44]);
	TIM3_PWM_CH4_Init((Pwm_Status[27]<<8)+Pwm_Status[28],(Pwm_Status[45]<<8)+Pwm_Status[46]);
	
  TIM4_PWM_CH1_Init((Pwm_Status[29]<<8)+Pwm_Status[30],(Pwm_Status[47]<<8)+Pwm_Status[48]);
  TIM4_PWM_CH2_Init((Pwm_Status[29]<<8)+Pwm_Status[30],(Pwm_Status[49]<<8)+Pwm_Status[50]);
  TIM4_PWM_CH3_Init((Pwm_Status[29]<<8)+Pwm_Status[30],(Pwm_Status[51]<<8)+Pwm_Status[52]);
  TIM4_PWM_CH4_Init((Pwm_Status[29]<<8)+Pwm_Status[30],(Pwm_Status[53]<<8)+Pwm_Status[54]);	
}
  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张楠0805

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值