STM32紅外尋跡小車(寄存器版)
最近學習了STM32,想通過製作一輛小車來加深對STM32的理解,在平時學習時經常用正點原子提供的源代碼稍加該裝就行,但是正點原子沒有提供關於紅外尋跡模板的相關程序。儘管網上很多關於STM32的紅外尋跡的資料和源代碼,但是幾乎沒有寄存器版本的源代碼。有些博主有寄存器版的程序源碼但是得花錢才能下載。那麼今天我就分享一下製作尋跡小車的經驗和程序源碼。
一、紅外尋跡小車原理
循跡模塊我用的是紅外傳感器。黑線的檢測原理是紅外發射管發射光線到路面,紅外光遇到白底則被反射,接收管接收到反射光,經施密特觸發器整形後輸出低電平;當紅外光遇到黑線時則被吸收,接收管沒有接收到反射光,經施密特觸發器整形後輸出高電平。簡單的說就是當紅外尋跡模板遇見黑線時會產生一個高電平,遇見白線時會返回一個低電平。所以根據原理設計思路爲當左側紅外傳感器遇見黑線時左拐,右邊紅外傳感器遇見黑線時右拐。這樣就可以完成
尋跡 | 黑線尋跡 | 白線尋跡 |
---|---|---|
原理 | 左側紅外傳感器遇見黑線時左拐,右邊紅外傳感器遇見黑線時右拐。 | 當左側紅外傳感器遇見黑線時右拐,右側紅外傳感器遇見黑線時左拐。 |
二、尋跡小車設計注意事項
(1)因爲硬件條件有限,反應速度不是很快會有一定的誤差,所以小車的速度要儘量慢下來,從而彌補硬件的不足讓小車有足夠的反應時間。
(2)在設置兩個紅外傳感器的IO口模式時要設置爲浮空輸入,這樣才能通過程序讀取IO口的狀態來判斷。
(3)在測試小車時儘量在光線較暗的條件下來測試小車,避免光線過亮影響測試。
(4)紅外尋跡模塊的OUT不能接在有上拉電阻的IO口。
三、尋跡小車程序
1.新建工程在工程文件下新建MOTER、TIMER、XUNJI這3個文件夾,然後在各自文件夾下建立相關文件小寫的.c和.h文件。
2.timer.c的程序如下:
#include "timer.h"
void TIM3_Int_Init(u16 arr,u16 psc)//初識化定時器3
{
RCC->APB1ENR|=1<<1; //TIM3時鐘使能
TIM3->ARR=arr; //設定計數器自動重裝值//剛好1ms
TIM3->PSC=psc; //預分頻器7200,得到10Khz的計數時鐘
TIM3->DIER|=1<<0; //允許更新中斷
TIM3->CR1|=0x01; //使能定時器3
MY_NVIC_Init(1,3,TIM3_IRQn,2);//搶佔1,子優先級3,組2
}
void TIM3_PWM_Init(u16 arr,u16 psc)
{
//此部分需手動修改IO口設置
RCC->APB1ENR|=1<<1; //TIM3時鐘使能
RCC->APB2ENR|=1<<3; //使能PORTB時鐘
RCC->APB2ENR|=1<<2; //使能PORTA時鐘
GPIOB->CRL&=0XFFFFFFF0; //PB0輸出
GPIOB->CRL|=0X0000000B; //複用功能輸出
GPIOA->CRL&=0XF0FFFFFF; //PA6輸出
GPIOA->CRL|=0X0B000000; //複用輸出
TIM3->ARR=arr; //設定計數器自動重裝值
TIM3->PSC=psc; //預分頻器不分頻
TIM3->CCMR1|=6<<4; //CH1 PWM2模式
TIM3->CCMR1|=1<<3; //CH1預裝載使能
TIM3->CCMR2|=6<<4; //CH3預裝載使能
TIM3->CCMR2|=1<<3; //CH3輸出使能
TIM3->CCER|=1<<0; //OC1 輸出使能
TIM3->CCER|=1<<8;
TIM3->CR1=0x0080; //ARPE使能
TIM3->CR1|=0x01; //使能定時器3
STBY=1;
}
timer.h代碼如下:
#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"
#define left TIM3->CCR1
#define right TIM3->CCR3
void TIM3_Int_Init(u16 arr,u16 psc);
void TIM3_PWM_Init(u16 arr,u16 psc);
#endif
moter.c代碼如下:
RCC->APB2ENR|=1<<2; //使能PORTA時鐘
RCC->APB2ENR|=1<<3; //使能PORTB時鐘
RCC->APB2ENR|=1<<4; //使能PORTC時鐘
GPIOA->CRL&=0XFF0FFFFF;
GPIOA->CRL|=0X00300000;
GPIOA->ODR|=1<<5;
GPIOA->CRL&=0X0FFFFFFF;
GPIOA->CRL|=0X30000000;
GPIOA->ODR|=1<<7;
GPIOB->CRL&=0XFFFFFF0F;
GPIOB->CRL|=0X00000030;
GPIOB->ODR|=1<<1;
GPIOB->CRL&=0XFFFFF0FF;
GPIOB->CRL|=0X00000300;
GPIOB->ODR|=1<<2;
GPIOB->CRL&=0XFFFF0FFF;
GPIOB->CRL|=0X00003000;
GPIOB->ODR|=1<<3;
GPIOB->CRL&=0XFFF0FFFF;
GPIOB->CRL|=0X00030000;
GPIOB->ODR|=1<<4;
GPIOC->CRL&=0XFFF0FFFF;
GPIOC->CRL|=0X00030000;
GPIOC->ODR|=1<<4;
GPIOC->CRL&=0XFF0FFFFF;
GPIOC->CRL|=0X00300000;
GPIOC->ODR|=1<<5;
moter.h代碼如下:
#ifndef __MOTER_H
#define __MOTER_H
#include "sys.h"
//電機端口定義(PWMA PB0 PWMB PA6)
#define AIN2 PBout(1)
#define AIN1 PBout(2)
#define STBY PBout(3)
#define BIN2 PCout(5)
#define BIN1 PCout(4)
void MOTER_Init(void); //初始化
#endif
xunji.c代碼如下:
#include "xunji.h"
void XUNji_init(void)
{
RCC->APB2ENR|=1<<4; //使能PORTC時鐘
GPIOC->CRL&=0XF0FFFFFF;
GPIOC->CRL|=0X08000000;//PC6浮空輸入
GPIOC->CRL&=0X0FFFFFFF;
GPIOC->CRL|=0X80000000;//PC7浮空輸入
}
xunji.h代碼如下
#ifndef __XUNJI_H
#define __XUNJI_H
#include "sys.h"
#define left_led PCin(6)
#define right_led PCin(7)
void XUN_Init(void); //初始化
#endif
這段代碼中很容易犯錯誤爲#define left_led PCout(6) #define right_led PCout(7)
因爲我們要讀取IO口的狀態,所以不能用out必須用in,寫成#define left_led PCin(6)和#define right_led PCin(7)
test.c代碼如下:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "moter.h"
#include "timer.h"
#include "xunji.h"
void HOU(void)//定義後退函數
{
AIN1=0;
AIN2=1;
BIN1=0;
BIN2=1;
}
void STOP(void)//停
{
AIN1=0;
AIN2=0;
BIN1=1;
BIN2=1;
}
void YOU(void)//右拐
{
AIN1=1;
AIN2=0;
BIN1=1;
BIN2=1;
}
void ZUO(void)//左拐
{
AIN1=0;
AIN2=0;
BIN1=1;
BIN2=0;
}
void GO(void)//前進
{
AIN1=1;
AIN2=0;
BIN1=1;
BIN2=0;
}
int main(void)
{
Stm32_Clock_Init(9); //系統時鐘設置
uart_init(72,115200); //串口初始化爲115200
delay_init(72); //延時初始化
TIM3_PWM_Init(899,0); //不分頻。PWM頻率=72000/(899+1)=80Khz
MOTER_Init();
void XUN_Init();
left=400;
right=400;
while(1)
{
if(left_led == 1 && right_led == 1)//左右尋跡探頭識別到黑線
{
GO();//前進
}
else
{
if(left_led == 1 && right_led == 0)//小車右邊出線,左轉修正
{
ZUO();//左轉
}
if(left_led == 0 && right_led == 1)//小車左邊出線,右轉修正
{
YOU();//右轉
}
}
}
}
以上就是我在調試尋跡小車時的程序,和得到的一些注意事項。分享給大家希望對大家有所幫驟。如果有問題希望大家評論區留言我及時改正。