stm32f3discoveryデバッグボード上のPWMを使用したコンパス

PWM(ワイドパルス変調)を使用したstm32でのコンパス実装のアイデアは、コンパスの回転角度に応じて隣接するLED間の強度が変化する場合の機能です。 しかし、初心者にとっては、通常のコンパスをコーディングするだけです(北を指すようにするため)。



すべての作業は、Eclipseのプログラミング環境であるCooCox(かなりバグの多い)で行われました。 STM32Cub MXを使用できます-はるかに便利なプログラムですが、複雑です(著者のチームはそれを理解しませんでした)。



加速度計、磁力計(そう、すべてこれはstm-keの小さなチップにあります)などの機能を使用するには、多くのサードパーティライブラリを接続する必要があります(実際、著者はペンで大量のコードを記述したくありませんでした)。



セクションを含める:

#include "stm32f30x.h"-マイクロコントローラーでの作業用。

#include "stm32f30x_gpio.h"-周辺機器(LED)の操作用。

#include "stm32f30x_i2c.h"-加速度計と磁力計と超小型回路の間のデータ交換用。

#include "stm32f30x_rcc.h"-周辺機器に電力を供給します。

#include "stm32f3_discovery_lsm303dlhc.h"-加速度計と磁力計を使用するためのバン。

#include "stm32f30x_exti.h"-必要;

#include "stm32f30x_syscfg.h"-また必要です。

#include <stdio.h>-Cの関数。

#include "math.h"-マット用。 関数(ala sin、cos);

#include "stm32f3_discovery.h"-ボードを使用したチームの作業を促進するため。

#include "stm32f30x_tim.h"-タイマー。



この良いものをインターネット上で数日間検索した後、すべてをCooCoxに接続する必要があり、最初の問題が始まりました。



stm32f30x_gpio.hのような標準ライブラリでは、stm32f30x_tim.hはすべて平凡でしたが、サードパーティ(stm32f3_discovery_lsm303dlhおよびstm32f3_discovery)では少し困難が生じました。 パスを手動で登録し、目的のフォルダーにスローする必要がありましたが、それらの多くが存在し、どのパスを使用するかは明確ではありません。



Projectの階層構造では、cmis_lib / include(ヘッダー)でそれらをスローする必要がありました。 2番目の方法:cmis_lib / source(c-ファイル)。 しかし、その後、コンパイラは引き続き誓います。 コンパイラが自身を構成するには、ヘッダーファイルの2つのライブラリに複製する必要があります。



#include "stm32f30x.h"

#include "stm32f30x_exti.h"

#include "stm32f30x_syscfg.h"

#include "stm32f30x_gpio.h"

#include "stm32f30x_i2c.h"

#include "stm32f30x_rcc.h"

#include "stm32f30x_usart.h"

#include "stm32f30x_spi.h"

#include "stm32f30x_misc.h"



これで作業を開始できます...



数日、夜、週、コーヒーカップ(スニーカー付き)の後、コンパスが生まれました(キャンプに行くことができます、バッテリーを使用することを忘れないでください!)、その大きさを考慮して以下に与えられない大量のたわごとで、しかし論理構造が記述されています(このエンコードを確認したい人のために、最後にダウンロードリンクがあります)。 まあ、多分小さなコードがそれをさせます。



コンパスを実装するには、ボードに統合されたLSM303DLHCチップを使用する必要があります。 将来のコンパスを操作するためのすべてがあります:磁力計(磁場のデータを読み取るため)と加速度計(ボードの傾きによる読み取り値を調整するため)。



まず、地球の磁場ベクトルの方向と磁力計のX軸の間の方位角を計算する必要があります。 方位角を計算するには、磁力計のX軸とY軸に沿った磁場の大きさに関するデータが必要です。 これらは、地球の磁場ベクトルのX軸とY軸上の投影です。次に、角度を計算するために、ジオメトリレッスンを呼び出して、最も単純な式arctan(Y / X)を適用できます。



これらの操作は、完全に平らな表面に適しています。 さまざまな角度で偏差がない場合。 しかし、人間の手は揺れる能力があり、平らな表面についてまったく何も知りません。 この問題を解決するために、この勾配を考慮した加速度計が使用されました。



また、プロジェクトは、各軸の加速度データなしでは実行できません。 ロール角とピッチ角を計算できます。これは、北への方向を計算するときに考慮されます(Wikipediaを参照)。 磁力計と加速度計からのデータの読み取りは、以下に説明する機能を使用して行われます。



リスト1.加速度計データを読み取るための関数

void Demo_CompassReadAss(float *pfData) { int16_t pnRawData[3]; uint8_t ctrlx[2]; uint8_t buffer[6], cDivider; uint8_t i = 0; float LSM_Acc_Sensitivity = LSM_Acc_Sensitivity_2g; LSM303DLHC_Read(ACC_I2C_ADDRESS, LSM303DLHC_CTRL_REG4_A, ctrlx,2);//     LSM303DLHC_Read(ACC_I2C_ADDRESS, LSM303DLHC_OUT_X_L_A, buffer, 6); if(ctrlx[1]&0x40) cDivider=64; else cDivider=16; if(!(ctrlx[0] & 0x40) || (ctrlx[1] & 0x40)) { for(i=0; i<3; i++) { pnRawData[i]=((int16_t)((uint16_t)buffer[2*i+1] << 8) + buffer[2*i])/cDivider;//    (  - ) } } else { for(i=0; i<3; i++) pnRawData[i]=((int16_t)((uint16_t)buffer[2*i] << 8) + buffer[2*i+1])/cDivider; } LSM303DLHC_Read(ACC_I2C_ADDRESS, LSM303DLHC_CTRL_REG4_A, ctrlx,2); if(ctrlx[1]&0x40) { LSM_Acc_Sensitivity = 0.25; } else { switch(ctrlx[0] & 0x30)//    { case LSM303DLHC_FULLSCALE_2G: LSM_Acc_Sensitivity = LSM_Acc_Sensitivity_2g; break; case LSM303DLHC_FULLSCALE_4G: LSM_Acc_Sensitivity = LSM_Acc_Sensitivity_4g; break; case LSM303DLHC_FULLSCALE_8G: LSM_Acc_Sensitivity = LSM_Acc_Sensitivity_8g; break; case LSM303DLHC_FULLSCALE_16G: LSM_Acc_Sensitivity = LSM_Acc_Sensitivity_16g; break; } } for(i=0; i<3; i++) { pfData[i]=(float)pnRawData[i]/LSM_Acc_Sensitivity;//          } }<source> <b> 2.     </b> <source>void Demo_CompassRegMag(float *pfData) { static int16_t buffer[3]={0}; uint8_t *ptr=buffer; uint8_t CTRLB=0; uint16_t Magn_Sensitivity_XY=0, Magn_Sensitivity_Z=0; uint8_t i=0; float fpfData[3]={0.0f}; LSM303DLHC_Read(MAG_I2C_ADDRESS, LSM303DLHC_CRB_REG_M, &CTRLB, 1);//   LSM303DLHC_Read(MAG_I2C_ADDRESS, LSM303DLHC_OUT_X_H_M, ptr, 1); LSM303DLHC_Read(MAG_I2C_ADDRESS, LSM303DLHC_OUT_X_L_M, ptr+1, 1); LSM303DLHC_Read(MAG_I2C_ADDRESS, LSM303DLHC_OUT_Y_H_M, ptr+2, 1); LSM303DLHC_Read(MAG_I2C_ADDRESS, LSM303DLHC_OUT_Y_L_M, ptr+3, 1); LSM303DLHC_Read(MAG_I2C_ADDRESS, LSM303DLHC_OUT_Z_H_M, ptr+4, 1); LSM303DLHC_Read(MAG_I2C_ADDRESS, LSM303DLHC_OUT_Z_L_M, ptr+5, 1); switch(CTRLB & 0xE0)//  { case LSM303DLHC_FS_1_3_GA: Magn_Sensitivity_XY = LSM303DLHC_M_SENSITIVITY_XY_1_3Ga; Magn_Sensitivity_Z = LSM303DLHC_M_SENSITIVITY_Z_1_3Ga; break; case LSM303DLHC_FS_1_9_GA: Magn_Sensitivity_XY = LSM303DLHC_M_SENSITIVITY_XY_1_9Ga; Magn_Sensitivity_Z = LSM303DLHC_M_SENSITIVITY_Z_1_9Ga; break; case LSM303DLHC_FS_2_5_GA: Magn_Sensitivity_XY = LSM303DLHC_M_SENSITIVITY_XY_2_5Ga; Magn_Sensitivity_Z = LSM303DLHC_M_SENSITIVITY_Z_2_5Ga; break; case LSM303DLHC_FS_4_0_GA: Magn_Sensitivity_XY = LSM303DLHC_M_SENSITIVITY_XY_4Ga; Magn_Sensitivity_Z = LSM303DLHC_M_SENSITIVITY_Z_4Ga; break; case LSM303DLHC_FS_4_7_GA: Magn_Sensitivity_XY = LSM303DLHC_M_SENSITIVITY_XY_4_7Ga; Magn_Sensitivity_Z = LSM303DLHC_M_SENSITIVITY_Z_4_7Ga; break; case LSM303DLHC_FS_5_6_GA: Magn_Sensitivity_XY = LSM303DLHC_M_SENSITIVITY_XY_5_6Ga; Magn_Sensitivity_Z = LSM303DLHC_M_SENSITIVITY_Z_5_6Ga; break; case LSM303DLHC_FS_8_1_GA: Magn_Sensitivity_XY = LSM303DLHC_M_SENSITIVITY_XY_8_1Ga; Magn_Sensitivity_Z = LSM303DLHC_M_SENSITIVITY_Z_8_1Ga; break; } fpfData[0]=(((float)buffer[0])/1000)/Magn_Sensitivity_XY;//     fpfData[1]=(((float)buffer[1])/1000)/Magn_Sensitivity_XY; fpfData[2]=(((float)buffer[2])/1000)/Magn_Sensitivity_Z; for(i=0;i<3;i++) { pfData[i]=fpfData[i]*(-1); //   .    " "   -1 } }<source>         : fNormAcc=sqrt((AccBuffer[0]*AccBuffer[0])+(AccBuffer[1]*AccBuffer[1])+(AccBuffer[2]*AccBuffer[2])); ,           (     ),      (Roll)   (Pitch): fSinRoll = -AccBuffer[1]/ fNormAcc; fCosRoll = sqrt(1.0 - (fSinRoll *fSinRoll)); fSinPitch = AccBuffer[0]/fNormAcc; fCosPitch = sqrt(1.0 -(fSinPitch * fSinPitch));        : RollAng = acos(fCosRoll) * 180/PI; PitchAng = acos(fCosPitch) *180/PI;            180  360 ,      .      ,                .          : fTitledX=MagBuffer[0]*fCosPitch+MagBuffer[2]*fSinPitch; fTitledY=MagBuffer[0]*fSinRoll*fSinPitch+MagBuffer[1]*fCosRoll-MagBuffer[1]*fSinRoll*fCosPitch;   : HeadingValue= 180.0f - (float)((atan2f((float)fTitledY,(float)fTitledX))*180)/PI;//   ,      -.   :       3D .      .       .  .  -.       .      (  Pin-  Pin- ). .        1 (TIM1) -  datasheet,              Pin-  ,     4,   - 8.   datasheet     (TIM3).  : PC6, PC7, PC8, PC9.    ,      .      user manual.  : led4, led5, led6, led9. ,  Pin-: PE8, PE10, PE12, PE15.     :    Pin-   Pin-       ( TIM1  TIM3): PE8-PC6 PE10-PC7 PE12-PC8 PE15-PC9.        1.  3  . <source>{ GPIO_StructInit(&gpio2); gpio2.GPIO_Mode = GPIO_Mode_AF; gpio2.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9; gpio2.GPIO_Speed=GPIO_Speed_Level_1; gpio2.GPIO_OType=GPIO_OType_PP; gpio2.GPIO_PuPd=GPIO_PuPd_NOPULL; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC,ENABLE); GPIO_Init(GPIOC,&gpio2); GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_2);//PC6-PE8(LD4) GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_2);//PC7-PE10(LED5) GPIO_PinAFConfig(GPIOC,GPIO_PinSource8,GPIO_AF_2);//PC8-PE12(LED9) GPIO_PinAFConfig(GPIOC,GPIO_PinSource9,GPIO_AF_2);//PC9-PE15(LED6) // RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //  TIM_TimeBaseStructInit(&timer3); timer3.TIM_Prescaler = 720; timer3.TIM_Period = 100; TIM_TimeBaseInit(TIM3, &timer3); TIM_OCStructInit(&timer3_oc); timer3_oc.TIM_OCMode=TIM_OCMode_PWM1; timer3_oc.TIM_OutputState=TIM_OutputState_Enable; TIM_OC1Init(TIM3, &timer3_oc);//LED4 TIM_OC2Init(TIM3, &timer3_oc);//LED5 TIM_OC3Init(TIM3, &timer3_oc);//LED9 TIM_OC4Init(TIM3, &timer3_oc);//LED6 TIM3->CCR1=10; // . TIM_SetCompare1(TIM3,0); TIM_SetCompare2(TIM3,0); TIM_SetCompare3(TIM3,0); TIM_SetCompare4(TIM3,0); TIM_CCxCmd(TIM3,TIM_Channel_1,TIM_CCx_Enable);//     LED4  TIM_CCxCmd(TIM3,TIM_Channel_2,TIM_CCx_Enable);//     LED5  TIM_CCxCmd(TIM3,TIM_Channel_3,TIM_CCx_Enable);//     LED9  TIM_CCxCmd(TIM3,TIM_Channel_4,TIM_CCx_Enable);//     LED8  TIM_Cmd(TIM3,ENABLE); }<source>        -   8          .    :     .          HadingValue.  ,    (HadingValue)    .  ,     0  45 .   - . void onLED(void) { if(HeadingValue < 0) { HeadingValue=HeadingValue+360; } if ((fRollAng <= 40.0f) && (fPitchAng <= 40.0f))// LED10 { if (((HeadingValue < 25.0f)&&(HeadingValue >= 0.0f))||((HeadingValue >=340.0f)&&(HeadingValue <= 360.0f))) { TIM_SetCompare1(TIM1,0); TIM_SetCompare2(TIM1,0); TIM_SetCompare3(TIM1,((int)(45.0f-HeadingValue))*2);//LED10 TIM_SetCompare4(TIM1,((int)(HeadingValue-0))*2);//led8 //---------------------- TIM_SetCompare1(TIM3,0); TIM_SetCompare2(TIM3,0); TIM_SetCompare3(TIM3,0); TIM_SetCompare4(TIM3,0); } /*..... */ }        (  1 )    ,         .          TIM2. <source>//  void timer_init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseStructInit(&timer); timer.TIM_Prescaler=720; timer.TIM_Period=100;//   2  TIM_TimeBaseInit(TIM2,&timer); TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); TIM_Cmd(TIM2,ENABLE); NVIC_EnableIRQ(TIM2_IRQn); } //  void TIM2_IRQHandler(void) { calcangle(); onLED(); TIM_ClearFlag(TIM2, TIM_FLAG_Update); }<source>          main: <source>uint16_t intensity=0; TIM_OCInitTypeDef timer_oc; RCC_ClocksTypeDef RCC_Clocks; TIM_TimeBaseInitTypeDef timer; TIM_TimeBaseInitTypeDef timer3; TIM_OCInitTypeDef timer3_oc; GPIO_InitTypeDef gpio; GPIO_InitTypeDef gpio2; float fNormAcc=0.0f; float HeadingValue=0.0f; float fSinRoll=0.0f,fCosRoll=0.0f; float fSinPitch=0.0f, fCosPitch=0.0f; float fRollAng=0.0f,fPitchAng=0.0f; float fTitledX=0.0f, fTitledY=0.0f; uint32_t TimingDelay = 0; const float PI=3.14; float MagBuffer[3]={0.0f}; float AccBuffer[3]={0.0f}; int main(void) { //  RCC_GetClocksFreq(&RCC_Clocks); SysTick_Config(RCC_Clocks.HCLK_Frequency / 100); //  timer3_init();// 1  3  timer1_init(); //    Demo_CompassConfig(); //calcangle(); //onLED(); //  timer_init(); while(1) { } }<source>   !   : https://yadi.sk/d/s7vAizVKh3jFx Datasheet: https://yadi.sk/i/kmUrRQzeh3jJ9 User Manual: https://yadi.sk/i/IxbW4Gn-h3jKa
      
      






All Articles