どう?
写真、スキーム、またはシールさえありません。 そうではないが。 なります。
それは、コードだけがさらに先に進むからです。 ここでは、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"
#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;
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 ++){}
}
{
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);
}
{
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);
}
}
{
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);
}
{
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_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);
}
{
MotorResetGPIO();
SetLaserPower(0);
SetLightPower(0);
}
そしてもちろんメイン:
メイン
int main(void)
{
InitMotorGPIO();
InitLaserAndLight();
InitUsart();
(1)
{
}
}
{
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);
}
{
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」です。
最後に、受信バッファをクリアし、割り込みフラグをクリアします。
これでコードが終了します。
ファイナル
それだけです。 この資料が、私の経験を繰り返すことを決定した人(または教師が強制する人)に役立つことを願っています。 私は完璧なソリューションのふりをしたり、すべてが正しく行われたりするつもりはありません。 もちろん、すべての段階でより良い方法があります。 したがって、繰り返すだけでなく、追加/終了することをお勧めします。
開発とプロジェクトのすべての人に幸運を! これが誰かの助けになることを願っています。