PWM出力実験の詳細例

目次

PWM出力実験

PWMの動作原理(例としてカウントを取り上げます)

PWMおよびAFIOピンの再マッピングの包括的な実験

ライブラリ機能の説明

PWM構成の基本的な知識ポイント

GPIOポート機能の再マッピング

クロック分割の意味

PWMの2つの比較モードは何ですか?

プリロードレジスタ(TIMx_CCMR1)の役割

PWM出力の極性は何ですか?

PWM構成に関する考慮事項

デューティサイクルの設定方法は?

ライブラリ関数の構成手順

ステップ1:GPIO / AFIO / TIMの周辺バスクロックを有効にする

ステップ2:ピン機能の再マッピングを構成する

ステップ3:タイマーの基本的なプロパティを構成する

手順4:PWM出力モードを構成する

手順5:プリロードレジスタを構成する

ステップ6:TIM機能を正式に有効にする

包括的なコード例

Main.c

Led.c

Led.h.

Timer.c

Timer.h

運用結果


PWM出力実験

PWMの動作原理(例としてカウントを取り上げます)

 

CCRXレジスタの値は、カウンタの値と比較するために使用されます。CNTカウンタの値がCCRXレジスタと等しい場合、一般的なタイマー出力信号レベルが反転します。最後に、カウンターがMAX(ARRの値)までカウントされると(「更新割り込み」もトリガーできます)、すぐに0に戻り、カウントアップを再開します。

PWMおよびAFIOピンの再マッピングの包括的な実験

ライブラリ機能の説明

ライブラリ関数名

特徴

RCC_APB1PeriphClockCmd()/ RCC_APB2PeriphClockCmd()

APBバス周辺クロックの有効化

GPIO_Init()

GPIO初期化機能

GPIO_PinRemapConfig()

GPIOポート再マッピング機能

TIM_ARRPreloadConfig()

ARRでのTIMxのプリロードレジスタを有効または無効にします

 

TIM_TimeBaseInit()

タイマーを初期化する

TIM_OCInit()

比較パラメータを初期化します

TIM_Cmd()

タイマーの有効化

TIM_SetCompare2()

比較値CCRxを絶えず変更して、さまざまなデューティサイクル効果を実現します

PWM構成の基本的な知識ポイント

GPIOポート機能の再マッピング

まず、TIM関数を次のように再マップするピンを明確にする必要があります。

 

 

AFIOのGPIO多重化機能の再マッピングから、「TIM3部分部分再マッピング」機能を使用すると、TIM3のTIM3_CH3ピンをPB5ピンにマッピングし、それを使用してLED0を駆動してPWM機能を表示できることがわかりました。 。

このとき、次の点に注意してください。

①GPIO出力モードは「多重プッシュプル出力」として設定する必要があります。下図のように、多重プッシュ設定の場合のみ、他の非IO機能の信号をこのGPIOピンから出力できます。プッシュプルとして設定した場合のみ。 、外部レベルに依存せずにハイレベルとローレベルを出力でき、プッシュプル出力はTIM3機能の出力要件を満たしています。

 

 

②GPIOピンのリマッピング機能を設定します

重要性と機能:TIM3の機能はPB5に属していませんが、TIM3機能をPB5ピンに再マップすると、「TIM3は機能をPB5ピンに再マップできる」ことがわかります。有効にする必要があります。 AFIOクロックと構成再マッピングレジスタ。

GPIO_InitTypeDef GPIO_InitStructure;  
  
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  

クロック分割の意味

TIMを構成するときは、次の関数を呼び出します。TIM_TimeBaseInit();

その中で、その構造パラメーターは「TIM_ClockDivision」属性を構成します。

まず、TIMER3がPSCで除算されたクロックとして取得される方法を理解しましょう。

 

 

私たちの実験では、APB1バスからのクロックを使用します(AHBクロック周波数は72MHzです)。AHB-> APB1分周器-> APB1では、APB1プリスケーラーの分周係数が1の場合、TIMXCLKのクロック周波数は次のようになります。 TIMCLK = APB1 = AHB "、APB1プリスケーラの分割係数がN(Nは1ではない)の場合、TIMXCLKのクロック周波数は" TIMCLK = 2xAPB1 = 2xAHB / N "です。

ただし、STが提供する初期化クロックソースライブラリ関数を呼び出すと、APB1分周器のデフォルトの分周係数は2であるため、最終的なTIMXCLK = 2xAPB1 = 2xAHB / 2 = AHBになります。

ここでのクロック分割は、APB1のプリスケーラ係数を表します。

PWMの2つの比較モードは何ですか?

 

 

プリロードレジスタ(TIMx_CCMR1)の役割

 

 

動作中にARRの値を更新する場合、プリロードレジスタのOC1PEが1に設定されていると、次のサイクルでARR値がカウンタに読み込まれます。0に設定されていると、ARR値はすぐにカウンタに読み込まれます。

PWM出力の極性は何ですか?

 

 

PWM構成に関する考慮事項

PWM信号をPB5ピンに出力するので、通常のようにGPIOピン属性を構成し、PB5に特定のレベルを割り当てる必要はありません。PB5は別のIOピンではないため、その状態は受信したPWM出力レベルによって決まります。

デューティサイクルの設定方法は?

timer.cでは次の部分のみを定義しました。

TIM_OC_InitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 选择PWM输出模式1——当计数器值小于比较值时输出有效电平;当计数器值大于比较值时输出无效电平  
TIM_OC_InitStructure.TIM_OutputState = TIM_OutputState_Enable; // PWM输出模式使能  
TIM_OC_InitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; // 配置有效电平——高电平有效  
TIM_OC2Init(TIM3, &TIM_OC_InitStructure); // 配置PWM输出比较的属性  

 

このコードは、「TIMER3の2つのポートのPWM出力プロパティ(PWMモード、有効レベル、有効または無効)を設定する方法」のみを説明し、「比較値」を設定しなかったため、デフォルトのデューティサイクルは100%です。

タイマーのPWMを設定した後、CCRx比較値を設定する必要があります。コードは次のとおりです。

TIM_SetCompare2(TIM3, CompareValue);  // 用于修改CCRx的值进而修改PWM占空比

 

ここでは、CCRx比較値を継続的に変更して、輝度が徐々に変化するLEDライト効果を生成するために使用されるmain関数で構成します。同様に、ARRの値を変更してPWM周期を調整することもできます。対応するライブラリ関数は次のとおりです。

TIM_SetAutoreload(TIM3, NEW_ARR); // 用于修改ARR的值进而修改PWM周期  

 

ライブラリ関数の構成手順

ステップ1:GPIO / AFIO / TIMの周辺バスクロックを有効にする

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟  
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟  

 

ステップ2:ピン機能の再マッピングを構成する

GPIO_InitTypeDef GPIO_InitStructure;  
PIO_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

  

ステップ3:タイマーの基本的なプロパティを構成する

  //初始化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的时间基数单位

  

手順4:PWM出力モードを構成する

TIM_OC_InitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 选择PWM输出模式1——当计数器值小于比较值时输出有效电平;当计数器值大于比较值时输出无效电平  
TIM_OC_InitStructure.TIM_OutputState = TIM_OutputState_Enable; // PWM输出模式使能  
TIM_OC_InitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 配置有效电平——高电平有效  
TIM_OC3Init(TIM3, &TIM_OC_InitStructure); // 配置PWM输出比较的属性  

 

手順5:プリロードレジスタを構成する

TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); // 使能比较值预加载寄存器  
TIM_ARRPreloadConfig(TIM3, ENABLE); // 使能预加载值寄存器  

 

TIM_OC3PreloadConfig()

「CCRx値のプリロードに使用される」レジスタを構成するために使用されます

TIM_ARRPreloadConfig()

「ARR値のプリロードに使用される」レジスタを構成するために使用されます

ステップ6:TIM機能を正式に有効にする

 

登録ワークフローのブロック図を見ると、タイマーのすべてのプロパティを構成した後、TIM機能を正式に有効にできることがわかります。

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

 

包括的なコード例

Main.c

#include "led.h"  
#include "sys.h"  
#include "timer.h"  
  
 int main(void)  
 {        
    u16 CompareValue=0;  
    u8 Dir=1;       
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);      //设置NVIC中断分组2:2位抢占优先级,2位响应优先级  
    LED_InitConfig();                //LED端口初始化  
    TIMER_InitConfig(899,0);     //不分频。PWM频率=72000000/900=80Khz  
       
    while(1)  
    {  
        if(Dir == 1)   
        {  
            CompareValue++;  
        }  
        else   
        {  
            CompareValue--;  
        }  
          
        if(CompareValue >= 300)  
        {  
            Dir = 0;  
        }  
        else  
        {  
            Dir = 1;  
        }  
          
        TIM_SetCompare2(TIM3, CompareValue);  
    }      
 }  

 

Led.c

#include "led.h"  
#include "stm32f10x.h"  
  
void LED_InitConfig()  
{  
    GPIO_InitTypeDef GPIO_InitStructure;  
      
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); // 使能LED1的外设时钟  
      
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
    GPIO_Init(GPIOE, &GPIO_InitStructure); // 配置LED1的输出属性  
      
    GPIO_SetBits(GPIOE, GPIO_Pin_5); // 配置初始引脚输出电平为低电平  
}  

 

Led.h.

#ifndef _LED_H  
#define _LED_H  
  
#include "sys.h"  
  
void LED_InitConfig();  
  
#define LED1 PEout(5)  
  
#endif  

 

Timer.c

#include "timer.h"  
#include "led.h"  
#include "stm32f10x.h"  
#include "delay.h"  
  
void TIMER_InitConfig(u16 ARR, u16 PR)  
{  
    GPIO_InitTypeDef GPIO_InitStructure;  
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;  
    TIM_OCInitTypeDef TIM_OC_InitStructure;  
    NVIC_InitTypeDef NVIC_InitStructure;  
      
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE); // 使能GPIOB的外设时钟  
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 使能TIM3的外设时钟  
      
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 一定要选择“复用推挽输出”  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
    GPIO_Init(GPIOB, &GPIO_InitStructure); // 配置GPIOB的引脚属性  
      
    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); // 引脚重映射配置  
      
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; // AHB到TIMxCLK之间没有分频  
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式  
    TIM_TimeBaseInitStructure.TIM_Period = ARR; // 0x1388 = 5000  
    TIM_TimeBaseInitStructure.TIM_Prescaler = PR; // 0x1C20 = 7200  
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); // 周期长度为1s  
      
    TIM_OC_InitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 选择PWM输出模式1——当计数器值小于比较值时输出有效电平;当计数器值大于比较值时输出无效电平  
    TIM_OC_InitStructure.TIM_OutputState = TIM_OutputState_Enable; // PWM输出模式使能  
    TIM_OC_InitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; // 配置有效电平——高电平有效  
    TIM_OC2Init(TIM3, &TIM_OC_InitStructure); // 配置PWM输出比较的属性  
      
    TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); // 使能比较值预加载寄存器  
    TIM_ARRPreloadConfig(TIM3, ENABLE); // 使能预加载值寄存器  
      
    TIM_Cmd(TIM3, ENABLE); // TIM3使能  
      
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;  
    NVIC_Init(&NVIC_InitStructure); // 配置NVIC嵌入式中断向量优先级  
      
    TIM_ITConfig(TIM3, TIM_IT_CC2, ENABLE); // 定时器具体中断模式配置  
}  
  
void TIM3_IRQHandler()  
{  
    delay_init();  
    if(TIM_GetITStatus(TIM3, TIM_IT_CC2) == SET)  
    {  
        delay_ms(500);  
        LED1 = !LED1;  
    }  
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);  
}  

 

Timer.h

#ifndef _TIMER_H  
#define _TIMER_H  
  
#include "sys.h"  
  
void TIMER_InitConfig(u16 ARR, u16 PR);  
  
#endif  

 

運用結果

LEDxステータス

ステータス変更位置

LED1が交互に点灯します

PWM比較割り込み

LED0の明るさはデューティサイクルによって異なります

PWM出力レベル

遅延としてdelay_ms(500)を使用したので、比較割り込み状態によりLED1が交互に変化することがはっきりとわかりますが、PWM比較値は+1ずつゆっくり変化するため、LED0の輝度変化を注意深く観察する時間が必要です。

 

おすすめ

転載: blog.csdn.net/weixin_45590473/article/details/108062177