Lunホバークラフトパート2

良い一日!



約束どおり、電子充填とソフトウェアのより詳細な説明で前回の投稿を続けます。











Lun 1.0





最初の設計オプションは非常にシンプルでした。stm32vl-discovery、古代のラジコンマシンからのリモートコントロール、およびモーター用の2つのインバーター。 概略的には、次のようになりました。







ファームウェアだけでなく、レイアウトにも、複雑なものはありませんでした。 すべてがstm32vl-discoveryによって制御され、コードはCoIDEで数時間で記述されました。 また、このプログラミング環境の開発者に深いお辞儀を申し上げたいと思います。もしそれが便利でなかったら、誰でも知っているかもしれませんが、AVRで登ったことはないでしょう。



管理の実装は単純でしたが、完全に不便でした。 SVPでは、3つのエンジンを制御する必要があり、コンソールでは2つのエンジンのみを制御できました。 どうにかして、「前進」ボタンで牽引ねじを制御し、「戻る」ボタンで船舶を停止し、デバッグボード自体のボタンを押すことで船舶を発射しなければなりませんでした。



初期ファームウェア
#include <stm32f10x.h>

#include <stm32f10x_gpio.h>

#include <stm32f10x_rcc.h>

#include <stm32f10x_tim.h>

#include <misc.h>



void init_leds();

void init_motors();

void init_timer();

void init_button();

void Delay_sig();



int sec = 0;

int sm1 = 1000;

int m1 = 750;

int m2 = 750;

int i、l;



uint8_t r1 = 0、r2 = 0、r3 = 0、r4 = 0;



#define first_motor GPIO_Pin_10

#define second_motor GPIO_Pin_12

#defineservo_motor GPIO_Pin_11

#define blue_led GPIO_Pin_8

#define green_led GPIO_Pin_9



#define radio4 GPIO_Pin_8

#define radio3 GPIO_Pin_9

#define radio2 GPIO_Pin_10

#define radio1 GPIO_Pin_11



#define BUTTON GPIO_Pin_0



int main()



{

init_leds();

init_button();

init_motors();

init_timer();



SysTick_Config(SystemCoreClock / 300);



する

{



r1 = GPIO_ReadInputDataBit(GPIOA、radio1);

r2 = GPIO_ReadInputDataBit(GPIOA、radio2);

r3 = GPIO_ReadInputDataBit(GPIOA、radio3);

r4 = GPIO_ReadInputDataBit(GPIOA、radio4);



} while(1);

}



void SysTick_Handler()

{

static uint8_t btn_old_state = 0;

uint8_t btn_state = GPIO_ReadInputDataBit(GPIOA、BUTTON);



if(btn_old_state == 0 && btn_state == 1)

{

if(m1 <1000)m1 = m1 + 50;

}



if(r1 == 1)

{

if(sm1 <1600)sm1 = sm1 + 10;

}



他に

{

if(sm1> 1000)sm1 = sm1-10;

}



if(r3 == 1)

{

m2 = 900;

}



他に

{

m2 = 750;

}



if(r2 == 1)

{

if(sm1> 400)sm1 = sm1-10;

}



他に

{

if(sm1 <1000)sm1 = sm1 + 10;

}



if(r4 == 1)

{

m1 = 750;

}



btn_old_state = btn_state;

}



void init_leds()

{

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC、ENABLE);

GPIO_InitTypeDef gpio;

GPIO_StructInit(&gpio);

gpio.GPIO_Mode = GPIO_Mode_Out_PP;

gpio.GPIO_Pin = blue_led | green_led;

GPIO_Init(GPIOC、およびgpio);

GPIO_ResetBits(GPIOC、blue_led);

GPIO_ResetBits(GPIOC、green_led);

}



void init_motors()

{

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC、ENABLE);

GPIO_InitTypeDef gpio;

GPIO_StructInit(&gpio);

gpio.GPIO_Mode = GPIO_Mode_Out_PP;

gpio.GPIO_Pin = first_motor | second_motor | servo_motor;

GPIO_Init(GPIOC、およびgpio);

GPIO_ResetBits(GPIOC、first_motor);

GPIO_ResetBits(GPIOC、second_motor);

GPIO_ResetBits(GPIOC、servo_motor);

}



void init_button()

{

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA、ENABLE);

GPIO_InitTypeDef gpio;

GPIO_StructInit(&gpio);

gpio.GPIO_Mode = GPIO_Mode_IPD;

gpio.GPIO_Pin = BUTTON | radio1 | radio2 | radio3 | radio4 | BT_en;

gpio.GPIO_Speed = GPIO_Speed_2MHz;

GPIO_Init(GPIOA、およびgpio);

}



void init_timer()

{

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6、ENABLE);

TIM_TimeBaseInitTypeDef base_timer;

TIM_TimeBaseStructInit(&base_timer);

base_timer.TIM_Prescaler = 12000-1;

base_timer.TIM_Period = 20;

TIM_TimeBaseInit(TIM6、およびbase_timer);

TIM_ITConfig(TIM6、TIM_IT_Update、ENABLE);



TIM_Cmd(TIM6、有効);

NVIC_EnableIRQ(TIM6_DAC_IRQn);

}



void Delay_sig()

{

int us = 0;

for(us = 0; us <5000; us ++)

{

if(us == sm1){GPIO_ResetBits(GPIOC、servo_motor);}

if(us == m1){GPIO_ResetBits(GPIOC、first_motor);}

if(us == m2){GPIO_ResetBits(GPIOC、second_motor);}

}

}



void TIM6_DAC_IRQHandler()

{

if(TIM_GetITStatus(TIM6、TIM_IT_Update)!= RESET)

{

TIM_ClearITPendingBit(TIM6、TIM_IT_Update);

GPIO_SetBits(GPIOC、first_motor);

GPIO_SetBits(GPIOC、second_motor);

GPIO_SetBits(GPIOC、servo_motor);

Delay_sig();

}

}





un 2.0





プログラムとロボットの機械部分の両方に松葉杖の山を設置したので、すべてを完全にやり直す必要があると判断しました。

最初に、安定性と管理の容易さを追加することにしました。 このため、MPU-6050センサーとBluetoothモジュールHC-04が購入されました。

ブルートゥースに問題はありませんでしたが、何らかの理由で加速度計が正しく機能しませんでした。 まず、10秒間の操作後、彼は電源を切り、その後完全に応答を停止しました。

考えられるオプションを検討した結果、デバッグボードを交換し、レイアウトボード全体を交換することになりました。



これが判明しました:







主な失望は、CoIDEがSTM32F303マイクロコントローラーのプログラミングをサポートしていないことを見つけることでした。 ためらうことなく、同じ日食の商用アセンブリ-Atollic TrueSTUDIOがインストールされました。 Liteバージョンはコンパイルされたファームウェアのサイズ(32KB以下)によって制限されていたため、私たちに適していて、プロジェクトは別の環境に移行しました。

STのWebサイトで、このIDEの例のソースコードをダウンロードできます。 彼らがコードを徹底的に研究し始めたときに問題が現れました。 実際、以前のファームウェアからコードをコピーすることはできません; STM32f3では、STM32f100と比較して、多くのレジスタの目的が変更されました。 そして、その時点でメーカーからの例だけを見つけましたが、このデバッグボードはもう1年も販売されていませんでしたが、誰もこのデバッグボードをやっていないように感じました。 湿度センサーの設置を決定したときに問題が追加されました。 記事「STM32 + DHT11」からセンサーを操作するためのコードを正直に借りましたが、ここまでに書かれたファームウェアは新しいコードでの動作を完全に拒否し、実行されませんでした。 コンパイル中にエラーや警告はありませんでしたが、コードは頑固に正しく実行することを望まず、2日間を殺し、多くの神経細胞が、設定で最適化を無効にするとすべてが機能することを明らかにしました。 しかし、ここではまったく期待していなかった問題がありました。最適化を無効にすると、ファームウェアサイズが32Kを超え始めたため、新しい開発環境を探す必要がありました。 しばらく検索した後、EclipseベースのIDEのセットアップに関する記事に出会いました。 プロジェクトを作成して再度移動することは残っています。

Bluetoothモジュールの購入に伴い、Android用アプリケーションの開発が始まりました。 それ以前は、モバイルデバイス用のアプリケーションを作成したことがないため、開始するのは非常に困難でした。 グラフィカルエディタでボタンがどのように移動したかを誤解するとエラーが発生し、アプリケーションを閉じることが特にイライラしました。

プログラムによる変更に加えて、レイアウト処理に多くの時間が費やされました。







胴体、スカート、マストは最初のバージョンからの誘導エンジンが残っています。 エンジンは垂直に設置され、電子機器は1か所に移動されました。 また、周辺を接続する便宜のために、配電盤が飼育されました:







記事にすべてのプログラムコードを掲載する意味はありません。問題の原因にもっと注意を払う方が良いと思います。



プログラムに設定されたタスク:



0.サーボおよびインバーターを制御するため。

1.デバッグボードに組み込まれたセンサーからデータを読み取ります。

2.指示に従って、コースを調整します。

3.データを電話に送受信します。

4.途中で障害物を停止または回避します。

5.適切なルートを検索します。

6.周辺センサーからデータを読み取ります。

7.バッテリーを使い切ってはいけません。



ポイントゼロは、3つのチャネルを持つPWMで編成されました。 その結果、コードを実行すると、次の図が表示されるはずです。





、縦に1つのセルは0.4ボルト、横に1つのセルは2.5 msです。



PWMの初期化




void TIM_Init()



{



uint16_t Channel1Pulse = 139、Channel2Pulse = 104、Channel3Pulse = 104;



TIM_Config();



/ * TIM1クロックイネーブル* /



RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1、ENABLE);



/ *タイムベース設定* /



TIM_TimeBaseStructure.TIM_Prescaler =(uint16_t)((SystemCoreClock / 100000));



TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;



TIM_TimeBaseStructure.TIM_Period =(1000);



TIM_TimeBaseStructure.TIM_ClockDivision = 0;



TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;



TIM_TimeBaseInit(TIM1、およびTIM_TimeBaseStructure);



/ * PWMモードでのチャンネル1、2、3構成* /



TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;



TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;



TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;



TIM_OCInitStructure.TIM_Pulse = Channel1Pulse;



TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;



TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;



TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;



TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;



TIM_OC1Init(TIM1、およびTIM_OCInitStructure);



TIM_OCInitStructure.TIM_Pulse = Channel2Pulse;



TIM_OC2Init(TIM1、およびTIM_OCInitStructure);



TIM_OCInitStructure.TIM_Pulse = Channel3Pulse;



TIM_OC3Init(TIM1、およびTIM_OCInitStructure);



/ * TIM1カウンターの有効化* /



TIM_Cmd(TIM1、有効);



/ * TIM1メイン出力イネーブル* /



TIM_CtrlPWMOutputs(TIM1、有効);



}







速度を変更するには、次の記述のみが必要でした。



TIM_OCInitStructure.TIM_Pulse = n;

TIM_OC1Init(TIM1、およびTIM_OCInitStructure);





最初のポイントは、メーカーの例によって完全に決定されました。 はい、データを取得できましたが、処理せずに何かをすることは困難でした。











グラフには、フィルターなしの加速度計の測定値が表示されます。 最初にロールがあり、次にピッチがあり、次に同時にロールとピッチの両方があります。



したがって、ネットワーク内の1つのセンサーの位置補正のソースコードがまだ存在する場合、2番目のセンサーではすでにより困難でした。3つのセンサーすべてを考慮して補正を検索する必要がありました。 Wikipedia( AHRSIMUQuaternionEuler CornersKalman Filter )を読んで、ソースコードをグーグルで調べて、記事やフォーラムを読んだ後、Rudolph Emil Kalman自身が私の夢に現れ、一般的に従事している英国企業へのリンクを決定しました私と同じ。 彼らと一緒になって、センサーからのデータを処理するためのオープンライブラリを探しました。 そこには、小さな説明と適用方法もあります。 それから、ロール、ピッチ、ヨーの四元数から計算するための公式を取りました。



float getPitch()

{

return atan2(2 *(q2 * q3 + q0 * q1)、q0 * q0-q1 * q1-q2 * q2 + q3 * q3);

}



フロートgetYaw()

{

return asin(-2 *(q1 * q3-q0 * q2));

}



float getRoll()

{

return atan2(2 *(q1 * q2 + q0 * q3)、q0 * q0 + q1 * q1-q2 * q2-q3 * q3);

}





SVPがコース修正モードに入ると、現在位置が基準点として使用されます。



nullkorr = getRoll()* DegToRadIMU;




次に、現在位置が同じ方法で決定され、基準点と現在位置の間の角度が計算されます。



float retangle(float a、float b)

{

a + = 180;

b + = 180;

int r1 = 0;

r1 = ab;

r1 = r1%360;

if(r1 <0)r1 + = 360;

if(r1> 180)return-(360-r1);

それ以外の場合は、r1を返します。

}





角度を計算した後、データはサーボドライブに送信され、現在の回転角度から補正角度が減算されます。



3番目の段落に問題はありませんでした。UARTまたはHC-04で作業する例を見つけることは難しくありません。

4番目の点では、いくつかの問題があり、超音波センサーは湿度センサーと同時に到着し、新しい開発環境を探していました。 はい。センサーをテストすると、まっすぐな細いビームに当たって、素材や表面の回転角度に関係なく反射されるというピンクの夢が破壊されました。 不要なタスクでMKをロードしないために、センサーとの通信は割り込みで編成されます。 この場所のこの善良なから例を取ります。 STM32f3でタイマーが少し変更されたため、コードを少しやり直さなければなりませんでした。



変更されたオプション




/ **



** ================================================ =============================



**



**要約:超音波センサー割り込みハンドラー



**



** ================================================ =============================



* /



void EXTI3_IRQHandler(void)



{



//前線を突いた場合



if(!catcher_status)



{



//パルス幅のカウントを開始します



TIM6-> CR1 | = TIM_CR1_CEN;



//立ち下がりエッジをキャッチするように切り替えます



catcher_status = 1;



EXTI-> RTSR&=〜EXTI_RTSR_TR3;



EXTI-> FTSR | = EXTI_FTSR_TR3;



}



//立ち下がりエッジをキャッチした場合



他に



{



TIM6-> CR1&=〜TIM_CR1_CEN; //タイマーを停止します



if(TIM6-> CNT> 58)



{



期間= TIM6-> CNT; //マイクロ秒単位で期間を読み取ります



if(期間<5800 && korr <25 && korr> -25 && stepmode == 5)



{



m1 = 0;



upper_ctrl(m1); //モーターオフ



bbf = 0;



stepmode = 1;



}



smas [scnum] = TIM6-> CNT;



}



TIM6-> CNT = 0; //ゼロレジスタカウンター



//立ち上がりエッジをキャッチするように切り替えます



catcher_status = 0;



EXTI-> FTSR&=〜EXTI_FTSR_TR3;



EXTI-> RTSR | = EXTI_RTSR_TR3;



//タイマー6を50ミリ秒のカウントダウンで開始します



TIM6-> DIER | = TIM_DIER_UIE; //タイマー割り込みを有効にします



TIM6-> CR1 | = TIM_CR1_CEN; //タイマーを開始します



}



EXTI-> PR | = 0x01; //フラグをクリア



}



/ **



** ================================================ =============================



**



**要約:超音波センサー割り込みハンドラー



** TIM7割り込みハンドラー



**タイマー7が信号パルスに対して10μsをカウントした後に呼び出されます



** ================================================ =============================



* /



void TIM7_IRQHandler(void)



{



TIM7-> SR&=〜TIM_SR_UIF; // UIFフラグをリセットします



GPIOD-> ODR&=〜〜GPIO_Pin_2; //信号インパルスを停止します



TIM7-> DIER&=〜TIM_DIER_UIE; //タイマー割り込み7を無効にします



}



/ **



** ================================================ =============================



**



**要約:超音波センサー割り込みハンドラー



**割り込みハンドラーTIM6_DAC



**タイマー6がサイクル期間に50μsをカウントした後に呼び出されます



** ================================================ =============================



* /



void TIM6_DAC_IRQHandler(void)



{



TIM6-> SR&=〜TIM_SR_UIF; // UIFフラグをリセットします



if(スキャン== 2)



{



if(smas [scnum]> 800)



{



scnum ++;



US_servo_ctrl(scnum);



if(scnum> = 160)



{



scnum = 0;



スキャン= 3;



US_servo_ctrl(80);



}



}



他に



{



scd ++;



if(scd> 3)



{



scd = 0;



smas [scnum] = 23200;



scnum ++;



US_servo_ctrl(scnum);



}



}



}



GPIOD-> ODR | = GPIO_Pin_2; //信号パルスをオンにします



//タイマー7を10ミリ秒のカウントダウンで開始



TIM7-> DIER | = TIM_DIER_UIE; //タイマー割り込み7を有効にします



TIM7-> CR1 | = TIM_CR1_CEN; //タイマーを開始します



}



void USsensor_init()



{



// ================================================= ==========================



//タイマー6を設定します



// 2つの目的で使用されます:



// 1)エコーパルスの持続時間をカウントする(150μs-25 ms)



// 2)サイクル期間を報告するための中断を伴うカウント-時間、



//エコーラインの残留振動の減衰に必要



// ================================================= ==========================



//タイマーのタイミングをオンにします



RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6、ENABLE);



//マイクロ秒に1回トリガーするようにリミッターを設定します



TIM6-> PSC = 72-1;



//トリガー制限-50 ms = 50,000μs



TIM6-> ARR = 50000;



// TIM6_IRQn割り込みを有効にします-サイクル期間をカウントするために必要です



NVIC_SetPriority(TIM6_DAC_IRQn、3);



NVIC_EnableIRQ(TIM6_DAC_IRQn);



// ================================================= ==========================



//タイマー7を設定します



// ================================================= ==========================



//タイマーのタイミングをオンにします



RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7、ENABLE);



//マイクロ秒に1回トリガーするようにリミッターを設定します



TIM7-> PSC = 72-1;



//応答制限-10μs



TIM7-> ARR = 10;



// TIM7_IRQn割り込みを有効にします-信号パルスをカウントするために必要です



NVIC_SetPriority(TIM7_IRQn、2);



NVIC_EnableIRQ(TIM7_IRQn);



// ================================================= ==========================



EXTI_InitTypeDef EXTI_InitStructure;



GPIO_InitTypeDef GPIO_InitStructure;



NVIC_InitTypeDef NVIC_InitStructure;



RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG、ENABLE);



RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD、有効);



GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;



GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;



GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;



GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;



GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;



GPIO_Init(GPIOD、およびGPIO_InitStructure);



GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;



GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;



GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;



GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;



GPIO_Init(GPIOD、およびGPIO_InitStructure);



SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOD、EXTI_PinSource3);



/ * EXTI3回線を設定します* /



EXTI_InitStructure.EXTI_Line = EXTI_Line3;



EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;



EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;



EXTI_InitStructure.EXTI_LineCmd = ENABLE;



EXTI_Init(&EXTI_InitStructure);



NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;



NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;



NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;



NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;



NVIC_Init(&NVIC_InitStructure);



}







このコードはPORTD.3で割り込みを使用するか、PORTDで使用する必要がありますが、3番目のピンのすべてのポートで割り込みがトリガーされる理由はまだわかりません。 割り込みの使用は、メーカーの例から取られ、割り込み設定レジスタに直接書き込もうとしましたが、結果は「0」であるか、割り込みがないか、すべてのポートにあります。

エラーが非常に感謝する場所を誰かが説明した場合。



5番目のポイントはすぐに通過しましたが、6番目のADCのチューニングは頭痛の種でした。

繰り返しますが、例、苦情はありません、例は正常に動作します。 例でのみ、1つのADCチャネルからの読み取りを検討しましたが、そのうち4つがあります。 データシートは、チャネル、通常のグループ、入力されたグループについて署名します。 時間が限られているため、古い「祖父」方式が選択されました。

-チャンネルの選択;

-1回限りの読み取りを開始します。

-結果の処理。

-繰り返し。



ADCの読み取り


void ADC1_2_IRQHandler(void)



{



ADC_ClearITPendingBit(ADC1、ADC_IT_EOC);



ADC1ConvertedValue = ADC_GetConversionValue(ADC1);



/ *電圧を計算* /



ADC1ConvertedVoltage =(ADC1ConvertedValue * 3300)/ 0xFFF;



adcp [iadc] = ADC1ConvertedVoltage;



iadc ++;



ADCready = 1;



}



void SetADCchannel()



{



/ * ADCチャネルの構成* /



numadc [0] = 7; // BT



numadc [1] = 16; //テルモメーター



numadc [2] = 6; //バッテリー電圧



numadc [3] = 3; //ガスセンサー



kadc = 4; //数量チャネル



}



void getADC(uint8_tチャネル)



{



if(ADCready == 1)



{



ADCready = 0;



ADC_RegularChannelConfig(ADC1、チャンネル、1、ADC_SampleTime);



ADC_StartConversion(ADC1);



}



}



uint8_t ADC_init()



{



uint16_t calibration_value = 0;



ADC_InitTypeDef ADC_InitStructure;



ADC_CommonInitTypeDef ADC_CommonInitStructure;



GPIO_InitTypeDef GPIO_InitStructure;



/ * ADCクロックを設定* /



RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div2);



/ * ADC1クロックを有効にします* /



RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12、有効);



/ * ADCチャネル構成* /



/ * GPIOC Periphクロックイネーブル* /



RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC、ENABLE);



RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA、有効);



/ * ADC Channel7をアナログ入力として設定* /



GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;



GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;



GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;



GPIO_Init(GPIOC、およびGPIO_InitStructure);



GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;



GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;



GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;



GPIO_Init(GPIOA、およびGPIO_InitStructure);



ADC_StructInit(&ADC_InitStructure);



/ *キャリブレーション手順* /



ADC_VoltageRegulatorCmd(ADC1、有効);



/ *に等しい遅延を挿入* /



遅延(15);



ADC_SelectCalibrationMode(ADC1、ADC_CalibrationMode_Single);



ADC_StartCalibration(ADC1);



while(ADC_GetCalibrationStatus(ADC1)!= RESET);



キャリブレーション値= ADC_GetCalibrationValue(ADC1);



ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;



ADC_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode;



ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;



ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_OneShot;



ADC_CommonInitStructure.ADC_TwoSamplingDelay = 1000;



ADC_CommonInit(ADC1、およびADC_CommonInitStructure);



ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Disable;



ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;



ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0;



ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None;



ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;



ADC_InitStructure.ADC_OverrunMode = ADC_OverrunMode_Disable;



ADC_InitStructure.ADC_AutoInjMode = ADC_AutoInjec_Disable;



ADC_InitStructure.ADC_NbrOfRegChannel = 1;



ADC_Init(ADC1、およびADC_InitStructure);



ADC_RegularChannelSequencerLengthConfig(ADC1,1);



/ * ADC1通常のchannel7構成* /



ADC_RegularChannelConfig(ADC1、ADC_Channel_7、1、ADC_SampleTime);



ADC_TempSensorCmd(ADC1、有効);



/ * ADC1を有効にする* /



ADC_Cmd(ADC1、有効);



/ * ADRDYを待つ* /



while(!ADC_GetFlagStatus(ADC1、ADC_FLAG_RDY));



NVIC_InitTypeDef NVIC_InitStructure;



NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn;



NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;



NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;



NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;



NVIC_Init(&NVIC_InitStructure);



ADC_ITConfig(ADC1、ADC_IT_EOC、ENABLE);



1を返します。



}



/ *および主要な場所のどこかに



if(iadc <kadc)



{



getADC(numadc [iadc]);



}



他に



{



iadc = 0;



}



* /







ADCを理解した後、7番目の段落は問題を引き起こしませんでした。



アンドロイドのアプリケーションは、神経細胞の部分に特別な困難と損失を引き起こしませんでした(ボタンの位置を変更することからの逸脱を除く)ネットワーク上のbluetoothを操作するための多くの例があり、この記事のわずかに修正されたクラスは、指を上に動かすことで血管の速度と方向を制御する機能を追加しました/下および左/右画面。



クラスsomeview




パブリッククラスSomeView extends View {



ペイントペイント;



int [] X;



int [] Y;



最終的な静的整数半径= 50;



int PointerCount;



パブリックSomeView(コンテキストコンテキスト、AttributeSet attrs)



{



super(コンテキスト、attrs);



paint = new Paint();



paint.setColor(Color.RED);



paint.setStyle(Style.STROKE);



paint.setStrokeWidth(3);



PointerCount = 0;



X = new int [10]; //これらは座標の配列になります(最大10本の指を認識します)



Y = new int [10];



}



public boolean onTouchEvent(MotionEventイベント)



{



StringBuilder result = new StringBuilder(300);



PointerCount = event.getPointerCount();



for(int i = 0; i <PointerCount; i ++)



{



int ptrId = event.getPointerId(i);



X [i] =(int)event.getX(i); //座標を記憶する



Y [i] =(int)event.getY(i);



MainActivity.flag = 1;



MainActivity.setX(X [i]、Y [i]、ptrId);



}



trueを返します。



}



保護されたvoid onDraw(キャンバスキャンバス)



{



for(int i = 0; i <PointerCount; i ++)



{



if(Y [i] <(MainActivity.height / 4))Y [i] = MainActivity.height / 4;



if(Y [i]>(MainActivity.height * 0.75)-75)Y [i] =(int)(MainActivity.height * 0.75)-75;



canvas.drawCircle(X [i]、Y [i]、半径、ペイント);



canvas.drawLine(MainActivity.width / 2、(int)(MainActivity.height * 0.75)-25、X [i]、Y [i]、paint);



canvas.drawLine(0、(int)(MainActivity.height / 4)-50、MainActivity.width、(int)(MainActivity.height / 4)-50、paint);



canvas.drawLine(0、(int)(MainActivity.height * 0.75)-25、MainActivity.width、(int)(MainActivity.height * 0.75)-25、paint);



}



無効化();



}



}







また、センサーに関する情報を表示するために、DialogFragmentが使用されました。



ダイアログクラス




パブリッククラスダイアログは、DialogFragmentがOnClickListener {



final String LOG_TAG = "myLogs";



android.widget.TextView datch;



public View onCreateView(LayoutInflater inflater、ViewGroupコンテナー、



バンドルsavedInstanceState){



getDialog()。setTitle( "センサー測定値");



ビューv = inflater.inflate(R.layout.dialog、null);



v.findViewById(R.id.btnYes).setOnClickListener(this);



datch =(android.widget.TextView)v.findViewById(R.id.textView1);



datch.setText(MainActivity.mesdat);



return v;



}



public void onClick(View v){



Log.d(LOG_TAG、「ダイアログ:」+((ボタン)v).getText());



却下();



}



public void onDismiss(DialogInterfaceダイアログ){



super.onDismiss(ダイアログ);



Log.d(LOG_TAG、「ダイアログ:onDismiss」);



}



public void onCancel(DialogInterfaceダイアログ){



super.onCancel(ダイアログ);



Log.d(LOG_TAG、「ダイアログ:onCancel」);



}



}







あとがき





作成プロセスは一般的な用語でしかカバーされていないことを知っていますが、質問がある場合は間違いなく答えようとします。 管理プログラムは理想とはほど遠いですが、まだ考慮すべきことがたくさんあります。 たとえば、急旋回の場合、船舶の慣性により、さらに7メートルの間「尾を振る」ことができます。 しかし、作業を継続して改善します。



All Articles