注:0から1までのQuadrotor UAVの実装(11)UAVMCUドライバー→PWM

著者:妖精の妻謝が店主です
日付:2021/2/18

この記事を使用して、自分の成長を記録してください。
余談:
この小さな4軸ドローンは大学時代に作られたもので、今では仕事や勉強に組み込まれていることをより深く理解しているので、小さな4軸を再編成して、これで大きな4軸を実現したいと思います飛行制御設計、これらは空き時間に完成します!
コードは記事の最後に添付されています。コードの前の分析が重要です。記事全体を読むことをお勧めします。この記事では、PWMが電圧制御を実現する方法を簡単かつ簡単に分析します。

この実験
MCU:STM32F373CCT6
IDE:KEIL MDK5
実験の目的は、PWM構成を完了するためのこの実験を通じて、PWMの生成と制御のコアを深く理解し、PWMサービスオブジェクトの中空カップモーターについて次の記事で詳しく説明します。 、リンクはここにあります、私はそれが好きです友達
コアレスモーターポータルを見に行くことができます。
この実験に必要な情報:STM32F373xxデータマニュアルポータ​​ル

1.PWMの概要

PWM(Pulse Width Modulation)中国語の翻訳は、パルス幅変調です。これは、サイクル内の高レベルのパルスが占める時間を調整することです(これは、パルスのデューティ比を調整します)。
PWMは何に使用できますか?パルスのデューティサイクルを調整することで電圧の大きさを制御できます(たとえば、デューティサイクルが100%の場合、電圧は12Vです。デューティサイクルを調整することで、電圧は8V、3V、さらには0Vになります。制御出力電圧の)。
次に、デューティサイクルを調整した後に出力電圧が変化するのはなぜですか?この問題を理解するには、中学校の物理学で学んだ等価面積法を使用して説明する必要があります。上の図は次のように説明しています。

たとえば、この図では、1msのサイクルタイムで、フルデューティサイクルが100%のときに出力電圧が12Vになり、次に50%のデューティサイクルで出力電圧が12Vになります(つまり、サイクルタイムのハイレベルが占める時間は0.5です。 ms)この場合、サイクル全体の高レベルの面積はわずか1/2です。このとき、出力電圧は12V * 1/2 = 6Vです。これは、デューティサイクルを調整することで電圧を調整できることを意味します。 。
電圧レベルの制御を実現しました。このスキルは強力すぎるため、多くのことができます。たとえば、LEDライトを制御して呼吸光効果にすることも、DCを制御することもできます。モーターの速度、モーターの速度調整などを実現します。これは偶然です、友人、私たちがDCモーターの電圧を調整できるようにする必要がある小さな4軸ドローン。

上記は多くの話ですが、以下では、UAVによってMCUがコアレスモーターの回転を制御するために4チャネルPWMを生成する方法と、STM32F373CCT6がPWM波を生成するプロセスについて説明します。
ドローンエンジニアリングでは、モーターの制御にPWMを使用する必要があることがわかりました。PWMはサイクルタイムに依存するため、サイクルタイムはクロックによって生成されるため、右側に焦点を当てます。タイマーの使用。

2. PWMは何を構成する必要がありますか?

ここでは、最初に設定が必要な設定を引き出し、次にタイマーセクションでこれらの構成を分析します
。1。タイマーの有効化
2.カウント方向(アップカウント、ダウンカウント、中央揃えモードカウント)
3。プリスケーラ係数設定
4.設定リロードレジスタ値が
5の設定キャプチャ/コンペアレジスタ値の前記設定
PWM波モード(モード1およびモード2)
7の設定の有効レベル
PWM 8. PWM波出力波、有効

三、タイマー

STM32F373XXデータマニュアルから、利用できるタイマーがもっとあることがわかります。4軸ドローンのニーズと組み合わせると、モーターを駆動するために4つのPWM、つまり4チャンネルのPWM波が必要です。この実験では3つのタイマーを使用します。これらの4つのPWM波を生成するために使用されます:TIM2のCH1、TIM5のCH1、TIM12のCH1、TIM12のCH2、各タイマーはいくつかの機能にいくつかの違いがあるかもしれませんが、ほとんどのタイマー機能はすべて同じです。
したがって、ここでは、Timer2を使用してPWM波を構成する方法を紹介するだけで済みます。
ここでは汎用タイマーを選択しています。タイマーは互いに独立しており、リソースを共有していません。各タイマーは同期して実行できます。
この本は前の部分に続きます。PWM用に何を構成する必要がありますか?
最初に画像を見てください。これは簡単な分析です。画像で構成する必要の
あるPWMパラメーターの横軸は時間tを表し、縦軸はカウンターTIMx_CNTの値を表します。この波形は、実際には次の値です。時間tが増加するにつれてTIMx_CNTが変化します。

その中で、
TIMx_ARR:レジスタ値のリロードTIMx_CCR1:レジスタ値の
キャプチャ/比較
TIMx_CNT:カウンタ値

この写真で何を気にする必要がありますか?
STM32F373CCT6のメインクロックは72MHzで、周波数を分割せずに直接72MHzを使用できます。この72MHzは、カウンタがタイマーで回数をカウントするのに必要な時間が1 / 72MHzであることを意味するため、1000をカウントする必要があります。時間は(1 / 72MHz)* 1000はサイクル時間です。1000回カウントした後、PWM波のサイクルであるため、これらを全体で1000回考慮すると、このPWM波形の周波数は72KHzであることがわかります。サイクルタイムT = 1 / f、ここでfは周波数、キャリア周波数とも呼ばれます。このサイクルタイムはT = 1 / 72kHz = 0.0139msとして計算できます。メインクロックを除算するとどうなりますか。周波数を4で割って72MHz / 4 = 18MHzを取得し、1000回をサイクルとしてカウントします(T = 1 / 18kHz = 0.0556ms)。したがって、18KHzの搬送周波数が得られます。
したがって、ここで構成する内容を知ることができます
。①タイマークロックを有効にします。タイマーを
使用する場合は、72MHzになるようにタイマークロックをオンにする必要があります。
②プリスケーラ係数、
除算の有無、除算数を設定します。
③リロード値TIMx_ARR;
上記の1000はリロード値、つまり設定したサイクルタイムでカウンタがカウントする回数です。
④カウントモード、
エッジアラインモード(カウントアップ、カウントダウン)、センターアラインモード(カウントアップ、カウントダウン)のいずれか
⑤キャプチャ/比較レジスタTIMx_CCR1の
値を設定します。この値が固定されている場合、デューティサイクルは固定されます。この値が変化すると、PWM制御で出力電圧が変化し、次に
スロットルスティック処理のその値に対応する値が変化します。もちろん、出力比較モードに設定する必要があります。
⑥PWM波モード(モード1、モードII)および設定されたPWM波がアクティブレベルに設定されます;
PWMモード1:
TIMx_CNT <TIMx_CCR1の場合、カウントアップすると、出力レベルは
TIMx_CNT> TIMx_CCR1の場合、アクティブレベルが高くなります。カウントダウン時、出力レベルがハイまたはロー、無効レベル
PWMモード2:
TIMx_CNT <TIMx_CCR1の場合、カウントアップ時、出力レベルがハイまたはロー、無効レベル
TIMx_CNT> TIMx_CCR1の場合、およびカウントダウン時、出力レベルは、実効レベル
∥PWM波出力が有効になると、高または低になります
これまでに、上記の問題(2つ、PWM用に何を構成する必要があるか)について説明してきました。

レジスタを直接操作します。データシートによると、使用する必要のあるレジスタは次のとおり
です。1。TIMx_CR1(DataSheet P363)
ここに画像の説明を挿入
TIMx_CR1レジスタは16ビットレジスタであり、ここでは10ビットのみが使用されます。

1.タイマーの有効
化このタイマーを使用するには、タイマーを有効にする必要があります。実際に動作するのはレジスター、つまりTIMx_CR1の0番目のCENビットです。

コードをアップロード

//小四轴无人机设计四个空心杯电机,需要四路PWM,这里的4个引脚分别来自于3个Timer
#include "pwm.h"

/*******************************************************************************
 * fuction	pwm_gpio_init
 * brief	GPIO初始化配置
 * param	无
 * return	无
 *******************************************************************************/  
void pwm_gpio_init(void)
{
    
    
	/*结构体变量定义*/
	GPIO_InitTypeDef  GPIO_InitStructure;
	/*开启引脚时钟*/
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA|RCC_AHBPeriph_GPIOB, ENABLE);
	/*开启引脚复用功能PB14/PB15*/
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_9);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_9);
	/*开启引脚复用功能PA8/PA15*/
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_2);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource15,GPIO_AF_1);
	/*引脚的配置PB14/PB15*/
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_14|GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOB,&GPIO_InitStructure);	
	/*引脚的配置PA8/PA15*/
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8|GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
}
/*******************************************************************************
 * fuction	time2_config      
 * brief	定时器2初始化配置
 * param	无
 * return	无
 *******************************************************************************/  
void time2_config(void)
{
    
    
	/*结构体变量定义*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	/*开启time2时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	/*time2时基单元的配置*/
	TIM_TimeBaseStructure.TIM_Prescaler 		= 3;
	TIM_TimeBaseStructure.TIM_CounterMode 		= TIM_CounterMode_Up;
	TIM_TimeBaseStructure.TIM_Period 			= 1000;
	TIM_TimeBaseStructure.TIM_ClockDivision 	= TIM_CKD_DIV1;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
	/*CH1 pwm1 模式配置*/
	TIM_OCInitStructure.TIM_OCMode 				= TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState 		= TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse 				= 0;
	TIM_OCInitStructure.TIM_OCPolarity 			= TIM_OCPolarity_High;
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
	TIM_ARRPreloadConfig(TIM2, ENABLE);
	TIM_Cmd(TIM2, ENABLE);
}
/*******************************************************************************
 * fuction	time5_config     
 * brief	定时器5初始化配置
 * param	无
 * return	无
 *******************************************************************************/
void time5_config(void)
{
    
    
	/*结构体变量定义*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	/*开启time2时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
	/*time2时基单元的配置*/
	TIM_TimeBaseStructure.TIM_Prescaler 		= 3;
	TIM_TimeBaseStructure.TIM_CounterMode 		= TIM_CounterMode_Up;
	TIM_TimeBaseStructure.TIM_Period 			= 1000;
	TIM_TimeBaseStructure.TIM_ClockDivision 	= TIM_CKD_DIV1;
	TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);
	/*CH1 pwm1 模式配置*/
	TIM_OCInitStructure.TIM_OCMode 				= TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState 		= TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse 				= 0;
	TIM_OCInitStructure.TIM_OCPolarity 			= TIM_OCPolarity_High;
	TIM_OC1Init(TIM5, &TIM_OCInitStructure);
	TIM_OC1PreloadConfig(TIM5, TIM_OCPreload_Enable);
	TIM_ARRPreloadConfig(TIM5, ENABLE);
	TIM_Cmd(TIM5, ENABLE);
}
/*******************************************************************************
 * fuction	time12_config     
 * brief	定时器12初始化配置
 * param	无
 * return	无
 *******************************************************************************/
void time12_config(void)
{
    
    
	/*结构体变量定义*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	/*开启time2时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM12, ENABLE);
	/*time2时基单元的配置*/
	TIM_TimeBaseStructure.TIM_Prescaler 		= 3;
	TIM_TimeBaseStructure.TIM_CounterMode 		= TIM_CounterMode_Up;
	TIM_TimeBaseStructure.TIM_Period 			= 1000;
	TIM_TimeBaseStructure.TIM_ClockDivision 	= TIM_CKD_DIV1;
	TIM_TimeBaseInit(TIM12,&TIM_TimeBaseStructure);
	/*CH1 pwm1 模式配置*/
	TIM_OCInitStructure.TIM_OCMode 				= TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState 		= TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse 				= 0;
	TIM_OCInitStructure.TIM_OCPolarity 			= TIM_OCPolarity_High;
	TIM_OC1Init(TIM12, &TIM_OCInitStructure);
	TIM_OC1PreloadConfig(TIM12, TIM_OCPreload_Enable);
	TIM_OC2Init(TIM12, &TIM_OCInitStructure);
	TIM_OC2PreloadConfig(TIM12, TIM_OCPreload_Enable);
	TIM_ARRPreloadConfig(TIM12, ENABLE);
	TIM_Cmd(TIM12, ENABLE);
}
/*******************************************************************************
 * fuction	pwm_init    
 * brief	PWM初始化函数封装
 * param	无
 * return	无
 *******************************************************************************/
void pwm_init(void)
{
    
    
	 pwm_gpio_init();
	 time2_config();
	 time5_config();
	 time12_config();
}
#ifndef _PWM_H__
#define _PWM_H__

#include "board_define.h"

void pwm_init(void);

#endif

おすすめ

転載: blog.csdn.net/FutureStudio1994/article/details/113853254