04:TIMタイマ機能---出力比較機能(PWM)

目次

1: TIM出力比較機能

1: 再開

2:PWM波形

 3: 出力比較モード

4:パラメータ計算

5:PWM基本構造

 6: 出力比較機能の実用化

A:PWM駆動のLEDブリージングライト

1: 接続図

2: ステップ

 3: 機能紹介

4: コード

B:PWM駆動ステアリングギア

1: 接続図

2: ステアリングギアの紹介

3: ステップ

4: コード

C:PWM駆動DCモーター 

1: 接続図

 2: モーターと駆動回路

3: コード


1: TIM出力比較機能

1: 再開

        OC (Output Compare) 出力比較

        出力比較は、CNT と CCR レジスタの値の関係を比較することにより、出力レベルを 1 に設定、0 に設定、または反転することができ、特定の周波数とデューティ サイクルの PWM 波形を出力するために使用されます。

         各アドバンスト タイマーと一般タイマーには 4 つの出力比較チャネルがあります。

        アドバンストタイマーの最初の 3 チャネルには、デッドゾーン生成と相補出力の機能が追加されています。

2:PWM波形

        PWM(パルス幅変調)パルス幅変調

        慣性のあるシステムでは、一連のパルスの幅を変調することで必要なアナログパラメータを等価的に取得でき、モーター速度制御などの分野でよく使用されます。

        PWM パラメータ: 周波数 = 1 / TS デューティ サイクル = TON / TS 分解能 = デューティ サイクル変更ステップ

 

 3: 出力比較モード

 比較ユニットを構成する場合はTIM_OCXInit()を使用します

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //PWM1 のモードを選択

4:パラメータ計算

5:PWM基本構造

 6: 出力比較機能の実用化

A:PWM駆動のLEDブリージングライト

1: 接続図

2: ステップ

1: RCC がクロックをオンにします (TIM ペリフェラル --- RCC_APB1PeriphClockCmd および GPIO ペリフェラル -- RCC_APB2PeriphClockCmd クロックがオンになります)

2: GPIO の構成 ----GPIO_Init (2 番目のステップを最後に書き込みます)

3: クロック選択----TIM_InternalClockConfig (内部)

4: タイムベースユニットの設定-----TIM_TimeBaseInit()

5: 出力比較ユニットの構成---TIM_OC1Init()

6: タイマー開始-----TIM_Cmd

 3: 機能紹介

stm32f10x tim.h ファイル内の関数 ----- 出力比較ユニット関数を構成します

void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

TIM_OCXInit : 出力比較ユニットの設定 

stm32f10x tim.h ファイル内の関数

void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);

 TIM_OCStructInit:出力比較構造体にデフォルト値を割り当てます。

stm32f10x tim.h ファイル内の関数-----デューティ サイクル関数の変更

void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);

 TIM_SetCompareX: CCR レジスタの値を個別に変更する関数。デューティ サイクルを変更できます。

4: コード

ブリージングライトの機能を実現するために呼び出されるたびにデューティサイクルを変更します。


#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
void PWM_init(){
	//第一步,RCC开启时钟,把我们要用的TIM外设和GPIO外设的时钟打开
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//第二步,配置GPIO
	GPIO_InitTypeDef GPIO_INITStruct;
	GPIO_INITStruct.GPIO_Mode=GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_INITStruct.GPIO_Pin=GPIO_Pin_0 ;
	GPIO_INITStruct.GPIO_Speed= GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_INITStruct);
	//第三步,时钟源选择(内部时钟)
	TIM_InternalClockConfig(TIM2);
	//第四步,配置时基单元
	TIM_TimeBaseInitTypeDef TIM_INITStruct;
	TIM_INITStruct.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_INITStruct.TIM_CounterMode=TIM_CounterMode_Up;  向上计数
	TIM_INITStruct.TIM_Period=100-1;     ///自动重装载寄存器ARR
	TIM_INITStruct.TIM_Prescaler=720-1;    // //预分频器PSC
	TIM_INITStruct.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2,&TIM_INITStruct);
	//第五步,配置输出比较单元
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);//给输出比较结构体赋一个默认的值
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择PWM1的模式
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //有效电频为低电频
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  //使能
	TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	//第六步,启动定时器
	TIM_Cmd(TIM2,ENABLE);
}

void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2, Compare);
}



uint8_t i;

int main(void)
{
	OLED_Init();
	PWM_init();
	
	while (1)
	{
		for (i = 0; i <= 100; i++)
		{
			PWM_SetCompare1(i);
			Delay_ms(10);
		}
		for (i = 0; i <= 100; i++)
		{
			PWM_SetCompare1(100 - i);
			Delay_ms(10);
		}
	}
}


TIM_OC1Init を選ぶ理由

 ここでわかるように、PAO 行に TM2-CH1_ETR があります。これは、TIM2 の ETR ピンとチャネル 1 のピンが PAO ピンの位置を借用していることを意味します。 ; PAO ピンに多重化されるため、CH1 チャネルである TIM2 の OC1 を使用して PWM を出力したい場合、PA0 ピンには 1 つしか出力できず、ピン出力を任意に選択することはできません。; PA0 は PWM 波形を出力します

TIM_SetCompare1 を選択する理由

TIM_OC1Init CH1 チャネルが使用されるため

 TIM_SetCompareX: CCR レジスタの値を個別に変更する関数。デューティ サイクルを変更できます。

 ピンの再定義

 

まず、AFIO を使用するには、AFIO クロックをオンにする必要があります。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

ピンの再マッピング

void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);

   GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);//部分再マッピング 1

 PA0をPA15に変更します

PA15 は、電源投入後、デバッグ用に TDIT を返すためにデフォルトで多重化されているため、通常の GPIO または多重化されたタイマー チャネルとして使用したい場合は、最初にデバッグ ポートの多重化をオフにする必要があります (慎重に

    //PA15、PB3、PB4这三个引脚当做GPIO来使用的话
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//解除JTAG复用(解除重映射端口)
	//想重映射定时器或者其他外设的复用引脚
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);//GPIO_PartialRemap1_TIM2部分重映射1
	//如果重新映射的使调式端口使用
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);//GPIO_PartialRemap1_TIM2部分重映射1
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);解除JTAG复用(解除重映射端口)
	

 GPIO デバッグ選択多重化プッシュプル出力

GPIO_INITStruct.GPIO_Mode=GPIO_Mode_AF_PP; //多重プッシュプル出力、
出力制御はオンチップ周辺機器に転送され、ピンを介して PWM 波形を出力できます

計算する 

PWM 周波数: Freq = CK_PSC / (PSC + 1) / (ARR + 1)

PWM デューティ サイクル: デューティ = CCR / (ARR + 1)

PWM分解能: Reso = 1 / (ARR + 1)

CK_PSC=72MHZ PSC=TIM_INITStruct.TIM_Prescaler=; // //プリスケーラ PSC

ARR= TIM_INITStruct.TIM_Period=; ///自動リロードレジスタ ARR

CRR= TIM_OCInitStructure.TIM_Pulse = ; //CCR

分解能 = デューティサイクル変更ステップ

周波数 1KHz、デューティ サイクル 50%、分解能 1% の PWM 波形

 

B:PWM駆動ステアリングギア

1: 接続図

 赤-----USE5Vに接続(3vは使用できません)

橙色-----信号線 茶色-----アース線

2: ステアリングギアの紹介

        ステアリングギアは、入力された PWM 信号のデューティサイクルに応じて出力角度を制御するデバイスです。

        入力PWM信号要件:周期20ms、ハイレベル幅0.5ms~2.5ms

 ハイレベル幅 = 特定の電気周波数の持続時間

CCR=高周波

ステアリングギアの制御には一般に20msのタイムベースパルス(周期)が必要で、そのパルスのハイレベル部分は一般的に0.5ms~2.5msの範囲の角度制御パルス部分となります。180 度角度サーボを例にとると、対応する制御関係は次のようになります:
0.5ms-----0 度;
1.0ms---------- -45 度;
1.5 ミリ秒----------90 度;
2.0 ミリ秒-----------135 度;
2.5 ミリ秒----------- 180度;

3: ステップ

1: RCC がクロックをオンにします (TIM ペリフェラル --- RCC_APB1PeriphClockCmd および GPIO ペリフェラル -- RCC_APB2PeriphClockCmd クロックがオンになります)

2: GPIO の構成 ----GPIO_Init (2 番目のステップを最後に書き込みます)

3: クロック選択----TIM_InternalClockConfig (内部)

4: タイムベースユニットの設定-----TIM_TimeBaseInit()

5: 出力比較ユニットの構成 ----TIM_OC2Init()

6: タイマー開始-----TIM_Cmd

4: コード

これは CH2 チャンネルを使用し、上の LED は CH2 チャンネルを使用します。

使用法: TIM_SetCompareX および TIM_OCXInit 関数は、対応する X 値に変更されます。

X は 2 である必要があります。以下のピン定義表を参照してください。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
#include "Key.h"
void PWM_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
	TIM_OC2Init(TIM2, &TIM_OCInitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}

void PWM_SetCompare2(uint16_t Compare)
{
	TIM_SetCompare2(TIM2, Compare);
}


void Servo_Init(void)
{
	PWM_Init();
}

void Servo_SetAngle(float Angle)
{
	PWM_SetCompare2(Angle / 180 * 2000 + 500);
}


void Key_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

uint8_t Key_GetNum(void)
{
	uint8_t KeyNum = 0;
	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
	{
		Delay_ms(20);
		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);
		Delay_ms(20);
		KeyNum = 1;
	}
	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0)
	{
		Delay_ms(20);
		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);
		Delay_ms(20);
		KeyNum = 2;
	}
	
	return KeyNum;
}

uint8_t KeyNum;
float Angle;

int main(void)
{
	OLED_Init();
	Servo_Init();
	Key_Init();
	
	OLED_ShowString(1, 1, "Angle:");
	
	while (1)
	{
		KeyNum = Key_GetNum();
		if (KeyNum == 1)
		{
			Angle += 30;
			if (Angle > 180)
			{
				Angle = 0;
			}
		}
		Servo_SetAngle(Angle);
		OLED_ShowNum(1, 7, Angle, 3);
	}
}

計算する

 TIM_SetCompareX: CCR レジスタの値を個別に変更する関数。デューティ サイクルを変更できます。

 

ピン定義テーブル

 サーボの信号線は PA1 に接続されているため、CH2 チャンネル 2 が使用され、X は 2 となり、PA1 は PWM 波形を出力します。

C:PWM駆動DCモーター 

1: 接続図

 2: モーターと駆動回路

        DC モーターは電気エネルギーを機械エネルギーに変換する装置で、2 つの電極があり、電極がプラスに接続されるとモーターは正回転します。

        電極が逆になると、モーターが逆回転します。DC モーターは高出力デバイスなので、GPIO ポートで直接駆動することはできません。モーター駆動回路で動作させる必要があります。TB6612 は、デュアル H ブリッジ タイプの DC モーター ドライバーです
        。 2 つの DC モーターを駆動し、その速度と方向を制御できるチップ

 

 モータ駆動の詳細は「51:モータ(ULN2003D)」をご参照ください。

3: コード
#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "PWM.h"
#include "motor.h"
#include "Key.h"
void PWM_init(){
	//第一步,RCC开启时钟,把我们要用的TIM外设和GPIO外设的时钟打开
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	

	//第二步,配置GPIO
	GPIO_InitTypeDef GPIO_INITStruct;
	GPIO_INITStruct.GPIO_Mode=GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_INITStruct.GPIO_Pin=GPIO_Pin_2 ;
	GPIO_INITStruct.GPIO_Speed= GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_INITStruct);
	//第三步,时钟源选择(内部时钟)
	TIM_InternalClockConfig(TIM2);
	//第四步,配置时基单元
	TIM_TimeBaseInitTypeDef TIM_INITStruct;
	TIM_INITStruct.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_INITStruct.TIM_CounterMode=TIM_CounterMode_Up;  向上计数
	TIM_INITStruct.TIM_Period=100-1; 
	TIM_INITStruct.TIM_Prescaler=720-1;
	TIM_INITStruct.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2,&TIM_INITStruct);
	//第五步,配置输出比较单元
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);//给输出比较结构体赋一个默认的值
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择PWM1的模式
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //有效电频为低电频
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  //使能
	TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
	TIM_OC3Init(TIM2, &TIM_OCInitStructure);
	//第六步,启动定时器
	TIM_Cmd(TIM2,ENABLE);
}

void PWM_SetCompare3(uint16_t Compare)
{
	TIM_SetCompare3(TIM2, Compare);
}
void motor_init(){
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIO_InitTypeDef GPIO_INITstruct;
	GPIO_INITstruct.GPIO_Mode=GPIO_Mode_IPU;//GPIO_Mode_Out_PP  //GPIO_Mode_IPU
	GPIO_INITstruct.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5;
	GPIO_INITstruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_INITstruct);
	PWM_init();
}

void motor_serspeed(int8_t speed){
	if(speed >=0){
		GPIO_SetBits(GPIOA,GPIO_Pin_5);  //高电频
		GPIO_ResetBits(GPIOA,GPIO_Pin_4); //低电频
		PWM_SetCompare3(speed);
	}
	else
	{	
		GPIO_SetBits(GPIOA,GPIO_Pin_4);  //高电频
		GPIO_ResetBits(GPIOA,GPIO_Pin_5); //低电频
		//传穿过来的speed为负数,要变为正,所以要加一个负号;
		PWM_SetCompare3(-speed);
	}
}
void Key_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

uint8_t Key_GetNum(void)
{
	uint8_t KeyNum = 0;
	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
	{
		Delay_ms(20);
		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);
		Delay_ms(20);
		KeyNum = 1;
	}
	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0)
	{
		Delay_ms(20);
		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);
		Delay_ms(20);
		KeyNum = 2;
	}
	
	return KeyNum;
}


uint8_t key_num;
int8_t speed;  //速度必须是有符号的
int main(void)
{
	Key_Init();
	OLED_Init();
	motor_init();
	
	OLED_ShowString(1,1,"speed:");
	
	while (1)
		
	{	
		key_num=Key_GetNum();
		if (key_num==1){
			speed+=20;
			if(speed>100){
				speed=-100;
			}
		}
			motor_serspeed(speed);
			OLED_ShowSignedNum(1, 7, speed, 3);
	}
	
	
	}
	

おすすめ

転載: blog.csdn.net/m0_74739916/article/details/132414229