STM32紅外尋跡小車

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();//右轉
			}		
		}		
	}
}

以上就是我在調試尋跡小車時的程序,和得到的一些注意事項。分享給大家希望對大家有所幫驟。如果有問題希望大家評論區留言我及時改正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章