/**
************************************* Copyright ******************************
* (C) Copyright 2020,Wenkic,China, GCU.
* All Rights Reserved
*
* By(Wenkic)
* https://blog.csdn.net/Wekic
*
* FileName : PWM.h
* Version : v1.0
* Author : Wenkic
* Date : 2020-06-16
* Description :
* Function List:
******************************************************************************
*/
/********************************End of Head************************************/
#ifndef _PWM_H
#define _PWM_H
#include "stm32f10x.h"
typedef enum _CH
{
CH1=0x01,
CH2=0x02,
CH3=0x04,
CH4=0x08
}CH_enum;
typedef struct _PWM
{
u16 Period; //裝載值
u16 Prescaler; //分頻係數
}PWM_TypeDef;
extern PWM_TypeDef PWM1;
void Time1_PWM_Init(void); //定時器1PWM初始化
void TIM_PWM_GetInitDat(u32 Target_Hz,PWM_TypeDef *PWM_Struct); //計算分頻初始值 (目標頻率,獲取參數)
void adjuctTIM_Fre(TIM_TypeDef* TIMx,PWM_TypeDef PWM_Struct); //調整定時器時鐘基準
void Timer1_PWM_Out(u16 CHx,PWM_TypeDef PWM_Struct,FunctionalState NewState); //通道輸出 //(通道,參數,新狀態)
#endif
/********************************End of File************************************/
/*
************************************* Copyright ******************************
*
* (C) Copyright 2020,Wenkic,China, GCU.
* All Rights Reserved
*
* By(Wenkic)
* https://blog.csdn.net/Wekic
*
* FileName : PWM.c
* Version : v1.0
* Author : Wenkic
* Date : 2020-06-16
* Description :
* Function List:
******************************************************************************
*/
/********************************End of Head************************************/
#include "PWM.h"
#include "debug.h"
/* |
*TIM5複用功能重映射|
*------------------|---------------------------|-----------------------------------------------------------------------------|
*複用功能 | TIM5CH4_IREMAP = 0 | TIM5CH4_IREMAP = 1 |
*------------------|---------------------------|-----------------------------------------------------------------------------|
*TIM5_CH4 | TIM5的通道4連至PA3 | LSI內部時鐘連至TIM5_CH4的輸入作爲校準使用 |
*------------------|---------------------------|-----------------------------------------------------------------------------|
*TIM4複用功能重映射|
*------------------|---------------------------|-----------------------------------------------------------------------------|
*複用功能 | TIM4_REMAP = 0 | TIM4_REMAP = 1 |
*------------------|---------------------------|-----------------------------------------------------------------------------|
*TIM4_CH1 | PB6 | PD12 |
*------------------|---------------------------|-----------------------------------------------------------------------------|
*TIM4_CH2 | PB7 | PD13 |
*------------------|---------------------------|-----------------------------------------------------------------------------|
*TIM4_CH3 | PB8 | PD14 |
*------------------|---------------------------|-----------------------------------------------------------------------------|
*TIM4_CH4 | PB9 | PD15 |
*------------------|---------------------------|-----------------------------------------------------------------------------|
*TIM3複用功能重映射|
*------------------|---------------------------|-------------------------|---------------------------------------------------|
*複用功能 | TIM3_REMAP[1:0] = 00 | TIM3_REMAP[1:0] = 10 | TIM3_REMAP[1:0] = 01 |
*------------------|---------------------------|-------------------------|---------------------------------------------------|
*TIM3_CH1 | PA6 | PB4 | PC6 |
*------------------|---------------------------|-------------------------|---------------------------------------------------|
*TIM3_CH2 | PA7 | PB5 | PC7 |
*------------------|---------------------------|-------------------------|---------------------------------------------------|
*TIM3_CH3 | PB0 | PC8 |
*------------------|-----------------------------------------------------|---------------------------------------------------|
*TIM3_CH4 | PB1 | PC9 |
*------------------|-----------------------------------------------------|---------------------------------------------------|
*TIM2複用功能重映射|
*------------------|---------------------------|-------------------------|---------------------------|-----------------------|
*複用功能 | TIM2_REMAP[1:0] = 00 | TIM2_REMAP[1:0] =01 | TIM2_REMAP[1:0] = 10 | TIM2_REMAP[1:0] = 11 |
*------------------|---------------------------|-------------------------|---------------------------|-----------------------|
*TIM2_CH1_ETR(2) | PA0 | PA15 | PA0 | PA15 |
*------------------|---------------------------|-------------------------|---------------------------|-----------------------|
*TIM2_CH2 | PA1 | PB3 | PA1 | PA3 |
*------------------|---------------------------|-------------------------|---------------------------|-----------------------|
*TIM2_CH3 | PA2 | PB10 |
*------------------|-----------------------------------------------------|---------------------------------------------------|
*TIM2_CH4 | PA3 | PB11 |
*------------------|-----------------------------------------------------|---------------------------------------------------|
*TIM1複用功能重映射
*-------------------|--------------------------|-------------------------|---------------------------------------------------|
*複用功能 | TIM1_REMAP[1:0] = 00 | TIM1_REMAP[1:0] = 01 | TIM1_REMAP[1:0] = 11 |
*-------------------|--------------------------|-------------------------|---------------------------------------------------|
*TIM1_ETR | PA12 | PE7 |
*-------------------|----------------------------------------------------|---------------------------------------------------|
*TIM1_CH1 | PA8 | PE9 |
*-------------------|----------------------------------------------------|---------------------------------------------------|
*TIM1_CH2 | PA9 | PE11 |
*-------------------|----------------------------------------------------|---------------------------------------------------|
*TIM1_CH3 | PA10 | PE12 |
*-------------------|----------------------------------------------------|---------------------------------------------------|
*TIM1_CH4 | PA11 | PE14 |
*-------------------|--------------------------|-------------------------|---------------------------------------------------|
*TIM1_BKIN | PB12 | PA6 | PE15 |
*-------------------|--------------------------|-------------------------|---------------------------------------------------|
*TIM1_CH1N | PB13 | PA7 | PE8 |
*-------------------|--------------------------|-------------------------|---------------------------------------------------|
*TIM1_CH2N | PB14 | PB0 | PE10 |
*-------------------|--------------------------|-------------------------|---------------------------------------------------|
*TIM1_CH3N | PB15 | PB1 | PE12 |
*-------------------|--------------------------|-------------------------|---------------------------------------------------|
*
*--------------------------------------------------------------------------------------------------------------------------
*PC6 TIM3_CH1
*/
//typedef enum _CH
//{
// CH1=0x01,
// CH2=0x02,
// CH3=0x04,
// CH4=0x08
//}CH_enum;
//typedef struct _PWM
//{
// u16 Period; //裝載值
// u16 Prescaler; //分頻係數
//}PWM_TypeDef;
void Time1_PWM_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); //打開時鐘
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//初始化TIM1
TIM_DeInit ( TIM1 );
//GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);//改變指定管腳的映射
//TIMx的時間基準校準
//(1+TIM_Prescaler )/72M)*(1+TIM_Period )=((1+7199)/72M)*(1+9999)=1秒 = 10000
// (1+預分頻數)(1+自動重裝值) /系統時鐘 = 時間
// Prescaler = SystemCoreClock / 1000 - 1; //得到1KHz (分頻係數)
// Period = n100us - 1; //(裝載值)
TIM_TimeBaseInitTypeDef Tim_TimeBaseInitStruct; //初始化TIMx的時間基準校準
/* 配置輸出頻率 */
Tim_TimeBaseInitStruct.TIM_Period = 0x18-1; //自動裝載值(PWM分辨率)
Tim_TimeBaseInitStruct.TIM_Prescaler = 3-1; //分頻係數(Prescaler = 4,定時器頻率爲14.4KHz )(Prescaler = 9,定時器頻率爲7.2KHz )
Tim_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1 ;//時鐘分割
Tim_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//計數方向
TIM_TimeBaseInit(TIM1,&Tim_TimeBaseInitStruct);
//初始化定時TIMx外設
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; //脈衝寬度調製模式1
//輸出極性
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_Low; //輸出極性 低
TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High; //互補輸出極性 高
TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set; //在空閒時輸出 高
TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Reset; //在空閒時互補輸出 低
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; //PWM輸出使能
TIM_OCInitStruct.TIM_Pulse = 9; //捕獲比較的脈衝值
TIM_OC1Init(TIM1,&TIM_OCInitStruct);
TIM_OC1PolarityConfig(TIM1, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM1, ENABLE); //使能預裝載寄存器
TIM_Cmd(TIM1, ENABLE); //使能定時器1
TIM_CtrlPWMOutputs(TIM1, ENABLE); //pwm輸出
}
//素數判斷
int isPrime(u32 n) {
for (u32 i = 2; i < n; i++) {
//可以被別的數整除,不是素數
if (n % i == 0)
return 0;
}
return 1;
}
//質因數分解,分解素數爲止
int getPrimeFactor(u32 n,u32 *out) { //可以不返回值,此處返回-1表示出錯,返回1表示正常。
//1以下都不是素數
if (n < 2)
return -1;
//判斷是否是素數,如果是直接輸出
if (isPrime(n)) {
*out = n;
return 1;
}
else {
//遞歸因式分解
for (u32 i = 2; i < n; i++) {
if (n % i == 0) {
getPrimeFactor(n/i,out); //下一輪求素數
break;
}
}
}
return 1;
}
//計算分頻初始值 (目標頻率,獲取參數)
void TIM_PWM_GetInitDat(u32 Target_Hz,PWM_TypeDef *PWM_Struct)
{
RCC_ClocksTypeDef sys;
RCC_GetClocksFreq(&sys);
//PWM_hz = sysFre/[(1+Pre)*(1+Per)]
u32 sysHZ = sys.SYSCLK_Frequency;
u32 Period=0;
u32 Prescaler = 0;
u32 temp = 0;
u32 TargetTemp = sysHZ/Target_Hz; //
//TargetTemp = (1+Pre)*(1+Per)
//涉及質因數分解,素數
if(getPrimeFactor(TargetTemp,&temp)==1)
{
Period = TargetTemp/temp;
Prescaler = temp;
}else{
pr_err("因式分解輸入錯誤");
return ;
}
while(Period>=0xFFFF) //防止溢出,特別是小頻率時
{
if(getPrimeFactor(Period,&temp)==1)
{
Prescaler *= temp;
Period = TargetTemp/Prescaler;
}else{
pr_err("因式分解輸入錯誤");
return ;
}
}
//因式分解出的最小素數作爲定時器的分頻係數
PWM_Struct->Period = Period; //預裝載值
PWM_Struct->Prescaler = Prescaler; //分頻係數
}
//調整定時器時鐘基準
void adjuctTIM_Fre(TIM_TypeDef* TIMx,PWM_TypeDef PWM_Struct)
{
TIM_TimeBaseInitTypeDef Tim_TimeBaseInitStruct; //初始化TIMx的時間基準校準
/* 配置輸出頻率 */
Tim_TimeBaseInitStruct.TIM_Period = PWM_Struct.Period-1; //自動裝載值(PWM分辨率)
Tim_TimeBaseInitStruct.TIM_Prescaler = PWM_Struct.Prescaler-1; //分頻係數(Prescaler = 4,定時器頻率爲14.4KHz )(Prescaler = 9,定時器頻率爲7.2KHz )
Tim_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1 ;//時鐘分割
Tim_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//計數方向
TIM_TimeBaseInit(TIMx,&Tim_TimeBaseInitStruct);
}
PWM_TypeDef PWM1;
//(通道,參數,新狀態)
void Timer1_PWM_Out(u16 CHx,PWM_TypeDef PWM_Struct,FunctionalState NewState)
{
if(NewState == DISABLE)
{
if(CHx&0x01) TIM_SetCompare1(TIM1,0);
if(CHx&0x02) TIM_SetCompare2(TIM1,0);
if(CHx&0x04) TIM_SetCompare3(TIM1,0);
if(CHx&0x08) TIM_SetCompare4(TIM1,0);
}else{
if(CHx&0x01) TIM_SetCompare1(TIM1,PWM_Struct.Period/2);
if(CHx&0x02) TIM_SetCompare2(TIM1,PWM_Struct.Period/2);
if(CHx&0x04) TIM_SetCompare3(TIM1,PWM_Struct.Period/2);
if(CHx&0x08) TIM_SetCompare4(TIM1,PWM_Struct.Period/2);
}
}
#if 0 //測試使用
void Use_PWM_Test(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
Time1_PWM_Init(); //定時器1PWM初始化
TIM_PWM_GetInitDat(1000000,&PWM1); //計算時基1MHz PWM
adjuctTIM_Fre(TIM1,PWM1); //更新時基
Timer1_PWM_Out(CH1,PWM1,ENABLE); //輸出PWM
}
#endif
/********************************End of File************************************/