電子機器3Dスキャナーのファームウェア

続けますが、この記事で説明した自家製3Dスキャナーの設計の説明はおそらくこの記事で終わります 。 一般に、ほぼ2年前、私たちがこのプロジェクトを始めたばかりのとき、今日ほど多くのスキャナーはありませんでした。 そのため、メカニズムを記述することは意味がなく(このようなすべてのスキャナーで同じです)、ソフトウェア部分は書きませんでした。 そしてこの記事は、それでもスキャナーを自分で組み立てることを決めた人たちを助けることができます。 この記事は彼らのために書かれています。





どう?



写真、スキーム、またはシールさえありません。 そうではないが。 なります。

画像



それは、コードだけがさらに先に進むからです。 ここでは、3番目のスキャナーのファームウェアが失われたため、4番目のスキャナーのみにプログラムを提供します(その事件の後、バックアップを作成し始めました)。 おそらく覚えているように、STM32F401REマイクロコントローラーは4番目のスキャナーのマザーボード上にあるため、コードはF4ファミリー用に記述されます。



図書館



まず、必要なすべてのライブラリを接続する必要があります。

図書館
#include "stm32f4xx.h"

#include "stm32f4xx_exti.h"

#include "stm32f4xx_gpio.h"

#include "stm32f4xx_rcc.h"

#include "stm32f4xx_tim.h"

#include "stm32f4xx_usart.h"

#include "misc.h"



ライブラリの名前から、STM32F4ファミリ全体で同じであることがわかります(つまり、コードはこのファミリの他のマイクロコントローラに簡単に転送できます。たとえば、STM32F407VBに)。 名前からわかる2番目のことは、これらのライブラリが必要な周辺機器の名前です。 ライブラリはmisc.hになります。 このライブラリは、割り込みを処理するために必要です。



周辺機器と変数の初期化



グローバル変数を宣言することから始めましょう。

変数
intステップ;

int DelayTime = 100000;

char ConfigState;

uint8_t StepsPerComand = 1;

uint8_t LaserPower = 0;

uint8_t LightPower = 0;



ステップ変数は、現在のモーターのステップを示します。 DelayTimeは、ステップ間の時間を設定します。 これは、モーターがシャフトを回転させる時間があるために必要です。 プロセッササイクル数で設定されます。 ConfigStateとStepsPerComandについては後で説明します。 LaserPowerとLightPowerは、それぞれレーザー出力とバックライトを設定します(バックライトは実装されていませんが、PWMは引き続き出力されます)。

グローバル変数は終わりました。 機能に移りましょう。 最初に、このようなシンプルで便利な関数をここに記述します。

遅延
無効遅延(uint32_t n)

{

uint32_t i;

for(i = 0; i <n; i ++){}

}



コメントは不要だと思います。 さらに、モーターが接続されているピンを初期化する機能。 私はそれをA5、A6、A7、B6に持っています:

モーターピン
void InitMotorGPIO(void)

{

GPIO_InitTypeDef MotorGPIO;



RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA、ENABLE);

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB、ENABLE);



MotorGPIO.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;

MotorGPIO.GPIO_Mode = GPIO_Mode_OUT;

MotorGPIO.GPIO_OType = GPIO_OType_PP;

MotorGPIO.GPIO_PuPd = GPIO_PuPd_DOWN;

MotorGPIO.GPIO_Speed = GPIO_Speed_2MHz;

GPIO_Init(GPIOA、およびMotorGPIO);



MotorGPIO.GPIO_Pin = GPIO_Pin_6;

GPIO_Init(GPIOB、およびMotorGPIO);

}



次に、モーターを制御する必要があります。 このためにそのような機能があります:

モーター制御
void MotorResetGPIO(void)

{

GPIO_ResetBits(GPIOA、GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7);

GPIO_ResetBits(GPIOB、GPIO_Pin_6);

}



void MotorCoil(intコイル)

{

MotorResetGPIO();

スイッチ(コイル)

{

ケース1:GPIO_SetBits(GPIOA、GPIO_Pin_5); 休憩;

ケース2:GPIO_SetBits(GPIOA、GPIO_Pin_6); 休憩;

ケース3:GPIO_SetBits(GPIOA、GPIO_Pin_7); 休憩;

ケース4:GPIO_SetBits(GPIOB、GPIO_Pin_6); 休憩;

}

}



void MotorStepUP(int n)

{

int i;

for(i = 0; i <n; i ++)

{

ステップ++;

if(ステップ> 4){ステップ= 1;}

MotorCoil(Step);

遅延(DelayTime);

}

}



void MotorStepDOWN(int n)

{

int i;

for(i = 0; i <n; i ++)

{

ステップ-;

if(ステップ<1){ステップ= 4;}

MotorCoil(Step);

遅延(DelayTime);

}

}



MotorResetGPIO関数は、すべてのモーターピンを0にリセットします。 この関数は、次のMotorCoil関数で使用されます。 この関数はログを設定します。 モーターピンの1つ。 各ピンはステッピングモーターコイルに対応しているため、コイルの1つをそれぞれオンにします。 これを正しい順序で実行すると(つまり、この関数では設定されます)、エンジンはステップを実行します。

最後の2つの関数(MotorStepUPおよびMotorStepDOWN)は、入力として数値(完了しなければならないステップの数)を取ります。

モーターの機能の後、USARTを初期化します。

ネタバレ見出し
void InitUsartGPIO(void)

{

GPIO_InitTypeDef UsartGPIO;



RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA、ENABLE);



GPIO_PinAFConfig(GPIOA、GPIO_PinSource2、GPIO_AF_USART2);

GPIO_PinAFConfig(GPIOA、GPIO_PinSource3、GPIO_AF_USART2);



UsartGPIO.GPIO_OType = GPIO_OType_PP;

UsartGPIO.GPIO_PuPd = GPIO_PuPd_UP;

UsartGPIO.GPIO_Mode = GPIO_Mode_AF;

UsartGPIO.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;

UsartGPIO.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA、およびUsartGPIO);

}



void InitUsart(void)

{

InitUsartGPIO();



USART_InitTypeDef USART_InitStructure;



RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2、ENABLE);



USART_InitStructure.USART_BaudRate = 9600;

USART_InitStructure.USART_WordLength = USART_WordLength_8b;

USART_InitStructure.USART_StopBits = USART_StopBits_1;

USART_InitStructure.USART_Parity = USART_Parity_No;

USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

USART_Init(USART2、およびUSART_InitStructure);

USART_Cmd(USART2、有効);



NVIC_InitTypeDef UsartNVIC;



UsartNVIC.NVIC_IRQChannel = USART2_IRQn;

UsartNVIC.NVIC_IRQChannelPreemptionPriority = 2;

UsartNVIC.NVIC_IRQChannelSubPriority = 2;

UsartNVIC.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&UsartNVIC);



USART_ITConfig(USART2、USART_IT_RXNE、ENABLE);

}



コメントする特別なものもありません。 A2-Rx、A3-Tx。 速度は9600ボーです。 最後の9行に注意を払えない限り。 そこで、割り込みを初期化します。 USARTデータを受信すると発生します。

機能の最後のブロックは、レーザーとバックライトを制御する機能です。 これを行うには、タイマーを設定し、関心のあるレッグ(マイクロコントローラー)にPWMを表示する必要があります。

タイマーの初期化
void InitLaserGPIO(void)

{

GPIO_InitTypeDef LaserGPIO;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC、ENABLE);

GPIO_PinAFConfig(GPIOC、GPIO_PinSource7、GPIO_AF_TIM3);



LaserGPIO.GPIO_Mode = GPIO_Mode_AF;

LaserGPIO.GPIO_OType = GPIO_OType_PP;

LaserGPIO.GPIO_Pin = GPIO_Pin_7;

LaserGPIO.GPIO_PuPd = GPIO_PuPd_UP;

LaserGPIO.GPIO_Speed = GPIO_Speed_100MHz;

GPIO_Init(GPIOC、およびLaserGPIO);

}



void InitLightGPIO(void)

{

GPIO_InitTypeDef LightGPIO;

GPIO_PinAFConfig(GPIOB、GPIO_PinSource4、GPIO_AF_TIM3);



RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB、ENABLE);

LightGPIO.GPIO_Mode = GPIO_Mode_AF;

LightGPIO.GPIO_OType = GPIO_OType_PP;

LightGPIO.GPIO_Pin = GPIO_Pin_4;

LightGPIO.GPIO_PuPd = GPIO_PuPd_NOPULL;

LightGPIO.GPIO_Speed = GPIO_Speed_100MHz;

GPIO_Init(GPIOB、およびLightGPIO);

}



void InitLaserAndLight(void)

{

InitLaserGPIO();

InitLightGPIO();



TIM_TimeBaseInitTypeDef BaseTIM;



RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3、ENABLE);



BaseTIM.TIM_Period = 0xFF;

BaseTIM.TIM_Prescaler = 3;

BaseTIM.TIM_CounterMode = TIM_CounterMode_Up;

BaseTIM.TIM_ClockDivision = 0;

TIM_TimeBaseInit(TIM3、およびBaseTIM);



TIM_OCInitTypeDef TimOC;



TimOC.TIM_OCMode = TIM_OCMode_PWM1;

TimOC.TIM_OutputState = TIM_OutputState_Enable;

TimOC.TIM_Pulse = 0;

TimOC.TIM_OCPolarity = TIM_OCPolarity_High;



TIM_OC1Init(TIM3、およびTimOC);

TIM_OC1PreloadConfig(TIM3、TIM_OCPreload_Enable);



TimOC.TIM_OutputState = TIM_OutputState_Enable;

TimOC.TIM_Pulse = 0;



TIM_OC2Init(TIM3、およびTimOC);

TIM_OC2PreloadConfig(TIM3、TIM_OCPreload_Enable);



TIM_ARRPreloadConfig(TIM3、ENABLE);

TIM_Cmd(TIM3、有効);

}



void SetLaserPower(uint8_t p)

{

TIM3-> CCR2 = p;

}



void SetLightPower(uint8_t p)

{

TIM3-> CCR1 = p;

}



まず、GPIOを初期化します(レーザーの場合はC7、バックライトの場合はB4)。 次に、タイマーを設定します。 最後の2つの関数は非常に明確に呼び出されます。

これは、周辺が終了する場所です。 すべてを完全にオフにする機能を残します(不要なときにウォームアップしないように)。

完全なシャットダウン
void FullReset(ボイド)

{

MotorResetGPIO();

SetLaserPower(0);

SetLightPower(0);

}



そしてもちろんメイン:

メイン
int main(void)

{

InitMotorGPIO();

InitLaserAndLight();

InitUsart();



(1)

{

}

}



メインの小さなコードのようなものですよね? これはすべて、すべての処理が割り込みに送られるためです。 おそらく、USSARTのセットアップ時に初期化したものです。 この割り込みのハンドラーを検討してください。

もっとケースが必要です!!!
void USART2_IRQHandler(void)

{

charデータ。

データ= USART_ReceiveData(USART2);

if(data <10){MotorStepUP(data);}

if(ConfigState){

スイッチ(ConfigState){

ケース 'd':DelayTime = data; 休憩;

ケース 'p':LaserPower = data; SetLaserPower(LaserPower); 休憩;

ケース 'i':StepsPerComand = data; 休憩;

ケース 'l':LightPower = data; 休憩;

}

ConfigState = 0;

USART_SendData(USART2、 'R');

}

その他{

スイッチ(データ){

ケース 's':MotorStepUP(StepsPerComand); 休憩;

ケース 'n':SetLaserPower(LaserPower); 休憩;

ケース 'f':SetLaserPower(0); 休憩;

ケース 'r':FullReset(); 休憩;

ケース 'b':MotorStepDOWN(StepsPerComand); 休憩;

ケース 'h':SetLightPower(LightPower); 休憩;

ケース 'u':SetLightPower(0); 休憩;

デフォルト:ConfigState = data;

}

if(ConfigState){USART_SendData(USART2、 '#');}

else {USART_SendData(USART2、 'R');}

}

USART_ReceiveData(USART2);

データ= 0;

USART_ClearITPendingBit(USART2、USART_IT_RXNE);

}



行ごとにわかります。 最初にデータ変数を表示しました。 次に、USARTからのデータを記録しました。 うん そして、このマジックナンバー10とは何ですか? そして、ここにちょっとしたトリックがあります。 番号(シンボルコード)が10未満の場合、モーターはシンボルコードに等しいステップ数を使用します。 次はConfigStateチェックです。 そして、この変数を2回スキップして、他に何が書かれているかを考えます。 コマンドのセットは次のとおりです。

s-StepsPerComを実行し、先に進みます(これは、記事の冒頭でスキップした変数です)。

n-レーザーをオンにします(出力はLaserPowerで示されます)。

f-レーザーをオフにする

r-完全なシャットダウン(ええ、いいですね)。

b-StepsPerComandに戻ります。

h-バックライトをオンにします(電源はLightPowerで示されます)。

u-バックライトをオフにします。

コマンドが上記の条件のいずれにも適合しない場合、文字はConfigState変数に書き込まれます。 関数の4行目の条件に再び戻りましょう。 ConfigStateが0でない場合、パラメーターを構成します。 新しい値を設定します。 dが来たら、新しいDelayTimeを設定し、pの場合、新しいレーザーパワーを設定し(そしてこのパワーはレーザーに即座にインストールされます、つまりオンになります)、iが到着したらStepsPerComand変数を変更しますが、lの場合は変更しますバックライト電源。 また、ConfigStateに何かが書き込まれると、マイクロコントローラーは「#」を端末に送信して、2番目の文字を待っていることを示します。 彼がコマンドを実行したばかりの場合、答えは「R」です。

最後に、受信バッファをクリアし、割り込みフラグをクリアします。

これでコードが終了します。



ファイナル



それだけです。 この資料が、私の経験を繰り返すことを決定した人(または教師が強制する人)に役立つことを願っています。 私は完璧なソリューションのふりをしたり、すべてが正しく行われたりするつもりはありません。 もちろん、すべての段階でより良い方法があります。 したがって、繰り返すだけでなく、追加/終了することをお勧めします。

開発とプロジェクトのすべての人に幸運を! これが誰かの助けになることを願っています。



All Articles