文章目錄
- 1 背景
- 2 系統設計方案
- 2.1 實作功能
- 2.1.1 硬體部分:
- 2.1.2 軟體部分:
- 2.1.3 WIFI通信功能:
- 2.2 系統架構
- 2.2.1 WiFi 通信
- 2.2.2 電機驅動
- 2.2.3 攝像頭
- 2.2.4 舵機
- 2.2.5 PWM舵機控制
- 2.2.6 紅外循跡模塊
- 3 軟體設計
- 4 測驗效果
- 5 部分關鍵代碼
- 6 最后
1 背景
近幾年,人們的生活正在逐漸向智能化轉變, 嵌入式技術及一些新技術的快速發展, 使人們生活和作業變得越來越智能化 ,智能小車可以在所處的環境中通過傳感器自 行進行判斷和分析,在無人操作的情況下自 主完成任務,
設計的智能小車通過WIFI實作遠程無線控制,同時具有避障及溫度采集功能, 實作了小車的智能化, 可以作為研究智能汽車或者其他移動機器人的基礎模型,具有較大的研究空間,
2 系統設計方案
2.1 實作功能
學長設計的小車能夠實作無線控制, 避障, 循跡等功能, 由硬體, 軟體,無線傳輸三大部分組成,現對以上三部分功能進行具體的敘述 ,
2.1.1 硬體部分:
輸出 PWM 控制電機; 檢測障礙物, 檢測距離為 10cm;串口通信, 需要通過串口對智能小車進行除錯, 串口波特率設定為 115200;對接收到的命令進行處理和判斷;通過溫度傳感器檢測環境溫度; 連接WIFI 模塊及控制 WIFI模塊;通過uCOS-II實作多個任務同時執行,
2.1.2 軟體部分:
操作界面功能;通過SOCKET編程實作聯網,可以連接到 WIFI模塊;接收STM32開發板傳輸的資料和發送指令資料;利用攝像頭進行拍照, 在小車行駛程序中接收小車傳輸的圖片資訊并顯示;實作小車的模式切換, 模式 1 為無線控制行駛模式,模式2為自動行駛模式,
2.1.3 WIFI通信功能:
與 PC 端進行聯網連接;實作PC 與單片機之間的資料交換功能,
2.2 系統架構
小車采用 STM32F103 開發板,與 51 單片機相比, STM32可以搭載小型系統且速度更快,設計方案如下圖所示,
STM32開發板作為本設計的控制中心, 使用 PWM 輸出波形驅動電機轉動, 通過內部定時器達到控制方向的效果, 同時將接收到的資料及命令經過處理器判斷和計算從IO口輸出,
- 利用溫度傳感器采集溫度資訊通過串口傳輸到 WIFI模塊,在PC 端顯示;
- 利用紅外傳感器實作探測障礙和循跡功能,
- WIFI模塊是 PC 端和開發板進行資料互動的媒介, PC 端的操作指令由WIFI模塊進行發送,開發板和 PC 端之間設定了相應的資料協議,由此判斷接收到的是哪種型別的命令,小車根據命令執行相應的操作,

2.2.1 WiFi 通信
WIFI通信模塊作為 STM32和 PC 端通信的中介, 兩端都通過 WIFI模塊進行資料互動, 該模塊選用 ESP8266芯片 [5] , 其特點就是如果斷開連接, 再次連接, 模塊會連接到最近一次連接過的熱點,
ESP8266支持三種模式, 分別為 STA 模式, AP模式, STA+AP 模式,
這里學長使用 AP 模式, 使其他網 絡能 夠連接到ESP8266, 本設計使用 ESP8266的 AP模式,使其他網路能夠連接到 ESP8266,與STM32的引腳連接如表所示,


2.2.2 電機驅動

為了實作PC 端能夠控制小車的速度以及滿足直流電機的驅動 電 壓, 本設計選用 L298N 電 機驅動 模塊給直流 電 機供電 ,
電機狀態與STM32輸入如表2, 電機驅動共有兩個電源輸入介面,一個是5V,另一個是12V,在使用時12V的介面輸入電壓要大于7V,5V的介面就可以向單片機供電,

2.2.3 攝像頭
ov7670是OmniVision公司生產的一款感光整列,30W像素,

為什么要用帶FIFO的模塊呢?因為stm32速度比較慢,帶FIFO可已將攝像頭拍攝的資料暫時存在FIFO里,然后我們的stm32再慢慢的將拍攝的資料讀出來,通過串口發送到串口上位機顯示,
FIFO,即first in first out的縮寫,在這里,FIFO的速度很快,可以將攝像頭的資料暫時存起了,以便我們慢速的CPU將獲得的資料慢慢取出來并處理,達到一個類似水庫的作用,
2.2.4 舵機

舵機的輸入線共有三條, 紅色中間, 是電源線, 一邊黑色的是地線, 這輛根線給舵機提供最基本的能源保證, 主要是電機的轉動消耗, 電源有兩種規格, 一是 4.8V, 一是 6.0V, 分別對應不同的轉矩標準, 即輸出力矩不同, 6.0V 對應的要大一些, 具體看應用條件; 另外一根線是控制信號線, Futaba 的一般為白色, JR 的一般為桔黃色,
另外要注意一點, SANWA 的某些型號的舵機引線電源線在邊上而不是中間, 需要辨認,但記住紅色為電源, 黑色為地線, 一般不會有錯,
2.2.5 PWM舵機控制
舵機的控制信號為周期是 20ms 的脈寬調制( PWM) 信號, 其中脈沖寬度從0.5ms-2.5ms, 相對應舵盤的位置為 0-180 度, 呈線性變化, 也就是說, 給它提供一定的脈寬, 它的輸出軸就會保持在一個相對應的角度上, 無論外界轉矩怎樣改變, 直到給它提供一個另外寬度的脈沖信號, 它才會改變輸出角度到新的對應的位置上,
2.2.6 紅外循跡模塊
采用TCRT5000紅外反射傳感器,一種集發射與接收于一體的光電傳感器,它由一個紅外發光二極管和一個NPN紅外光電三極管組成,檢測反射距離1mm-25mm適用,傳感器特設M3固定安裝孔,調節方向與固定方便易用,使用寬電壓LM393比較器,信號干凈,波形好,驅動能力強,超過15mA,可以應用于機器人避障、機器人進行白線或者黑線的跟蹤,可以檢測白底中的黑線,也可以檢測黑底中的白線,是尋線機器人的必備傳感器,流水線計件、電度表脈沖資料采樣、傳真機碎紙機紙張檢測等眾多場合,

3 軟體設計
小車控制是通過 stm32單片機控制驅動電路和給舵機送控制信號, 然而這些控制信號的命令又是電腦等終端設備通過無線路由器串口傳送給單片機的, 所以在程式中我們需要設計到串口的使用、 定時器使用、 I/O 口的使用,
系統主程式模塊主要完成對系統中各模塊電路的初始化等作業, 主要包括對定時器、 串口中斷、 外部中斷的初始化, 同時執行電腦等終端設備所發送的命令, 等待外部中斷以及根據所需要的功能進行相應操作, 軟體總體設計及程式流程如下圖

4 測驗效果



5 部分關鍵代碼
主程式
#include "stm32f10x.h"
#include "bsp_SysTick.h"
#include "bsp_led.h"
#include <string.h>
#include <stdlib.h>
#include "bsp_pwm_output.h"
#include "infrared.h"
#include "delay.h"
//全域變數
unsigned int Task_Delay[NumOfTask];
/**
* @brief 主函式
* @param 無
* @retval 無
*/
int main(void)
{
//初始化systick
SysTick_Init(); //用于延時等操作
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;
TIMx_PWM_Init(); //PWM波初始化
infrared_Initial(); //紅外初始化
while(1)
{
if((infrared_Scan(infrared_5_GPIO_PORT,infrared_5_GPIO_PIN)==INFRARED_ON)&&\
(infrared_Scan(infrared_6_GPIO_PORT,infrared_6_GPIO_PIN)==INFRARED_ON))//前方有障礙,必須兩邊同時檢測到才能觸發,否則均認為是誤觸
{
DelayS(3); //延遲3秒
if((infrared_Scan(infrared_5_GPIO_PORT,infrared_5_GPIO_PIN)==INFRARED_ON)&&\
(infrared_Scan(infrared_6_GPIO_PORT,infrared_6_GPIO_PIN)==INFRARED_ON))//仍舊有障礙
{
TIMx_Mode_Config(500,0,0,500);//右轉500ms
DelayMs(500);
}
else
{
TIMx_Mode_Config(500,0,0,500);//直行500ms
DelayMs(500);
}
}
else
{
if((infrared_Scan(infrared_3_GPIO_PORT,infrared_3_GPIO_PIN)==INFRARED_ON))//循跡,右側內部傳感器見到黑線,說明車身方向偏右
TIMx_Mode_Config(0,0,600,0);//輕微左轉
else if((infrared_Scan(infrared_2_GPIO_PORT,infrared_2_GPIO_PIN)==INFRARED_ON))//循跡,左側內部傳感器見到黑線,說明車身方向偏左
TIMx_Mode_Config(600,0,0,0);//輕微右轉
else if((infrared_Scan(infrared_4_GPIO_PORT,infrared_4_GPIO_PIN)==INFRARED_ON))//循跡,右側外部傳感器見到黑線,說明車身方向偏左
TIMx_Mode_Config(0,0,900,0);//劇烈左轉
else if((infrared_Scan(infrared_1_GPIO_PORT,infrared_1_GPIO_PIN)==INFRARED_ON))//循跡,左側外部傳感器見到黑線,說明車身方向偏左
TIMx_Mode_Config(900,0,0,0);//劇烈右轉
else
TIMx_Mode_Config(500,0,500,0);//直行
}
}
}
PWM程式
#include "bsp_pwm_output.h"
/**
* @brief 配置TIM3復用輸出PWM時用到的I/O
* @param 無
* @retval 無
*/
static void TIMx_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 設定TIM3CLK 為 72MHZ */
// RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
macTIM_APBxClock_FUN (macTIM_CLK, ENABLE);
/* GPIOA and GPIOB clock enable */
macTIM_GPIO_APBxClock_FUN (macTIM_GPIO_CLK, ENABLE);
/*GPIOA Configuration: TIM3 channel 1 as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = macTIM_CH1_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 復用推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(macTIM_CH1_PORT, &GPIO_InitStructure);
/*GPIOB Configuration: TIM3 channel 2 as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = macTIM_CH2_PIN;
GPIO_Init(macTIM_CH2_PORT, &GPIO_InitStructure);
/*GPIOB Configuration: TIM3 channel 3 as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = macTIM_CH3_PIN;
GPIO_Init(macTIM_CH3_PORT, &GPIO_InitStructure);
/*GPIOB Configuration: TIM3 channel 4 as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = macTIM_CH4_PIN;
GPIO_Init(macTIM_CH4_PORT, &GPIO_InitStructure);
}
/**
* @brief 配置TIM3輸出的PWM信號的模式,如周期、極性、占空比
* @param 無
* @retval 無
*/
/*
* TIMxCLK/CK_PSC --> TIMxCNT --> TIMx_ARR --> TIMxCNT 重新計數
* TIMx_CCR(電平發生變化)
* 信號周期=(TIMx_ARR +1 ) * 時鐘周期
* 占空比=TIMx_CCR/(TIMx_ARR +1)
*/
void TIMx_Mode_Config(u16 CCR1_Val,u16 CCR2_Val,u16 CCR3_Val, u16 CCR4_Val)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* -----------------------------------------------------------------------
macTIMx Channel1 duty cycle = (macTIMx_CCR1/ macTIMx_ARR+1)* 100% = 50%
macTIMx Channel2 duty cycle = (macTIMx_CCR2/ macTIMx_ARR+1)* 100% = 37.5%
macTIMx Channel3 duty cycle = (macTIMx_CCR3/ macTIMx_ARR+1)* 100% = 25%
macTIMx Channel4 duty cycle = (macTIMx_CCR4/ macTIMx_ARR+1)* 100% = 12.5%
----------------------------------------------------------------------- */
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 999; //當定時器從0計數到999,即為1000次,為一個定時周期
TIM_TimeBaseStructure.TIM_Prescaler = 0; //設定預分頻:不預分頻,即為72MHz
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1 ; //設定時鐘分頻系數:不分頻(這里用不到)
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上計數模式
TIM_TimeBaseInit(macTIMx, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //配置為PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR1_Val; //設定跳變值,當計數器計數到這個值時,電平發生跳變
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //當定時器計數值小于CCR1_Val時為高電平
TIM_OC1Init(macTIMx, &TIM_OCInitStructure); //使能通道1
TIM_OC1PreloadConfig(macTIMx, TIM_OCPreload_Enable);
/* PWM1 Mode configuration: Channel2 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR2_Val; //設定通道2的電平跳變值,輸出另外一個占空比的PWM
TIM_OC2Init(macTIMx, &TIM_OCInitStructure); //使能通道2
TIM_OC2PreloadConfig(macTIMx, TIM_OCPreload_Enable);
/* PWM1 Mode configuration: Channel3 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR3_Val; //設定通道3的電平跳變值,輸出另外一個占空比的PWM
TIM_OC3Init(macTIMx, &TIM_OCInitStructure); //使能通道3
TIM_OC3PreloadConfig(macTIMx, TIM_OCPreload_Enable);
/* PWM1 Mode configuration: Channel4 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR4_Val; //設定通道4的電平跳變值,輸出另外一個占空比的PWM
TIM_OC4Init(macTIMx, &TIM_OCInitStructure); //使能通道4
TIM_OC4PreloadConfig(macTIMx, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(macTIMx, ENABLE); // 使能TIM3多載暫存器ARR
/* TIM3 enable counter */
TIM_Cmd(macTIMx, ENABLE); //使能定時器3
}
/**
* @brief TIM3 輸出PWM信號初始化,只要呼叫這個函式
* TIM3的四個通道就會有PWM信號輸出
* @param 無
* @retval 無
*/
void TIMx_PWM_Init(void)
{
TIMx_GPIO_Config();
TIMx_Mode_Config(0,0,0,0);
}
延時程式
#include "stm32f10x.h"
#include "delay.h"
static u8 fac_us=0;//us延時倍乘數
static u16 fac_ms=0;//ms延時倍乘數
//初始化延遲函式
//當使用ucos的時候,此函式會初始化ucos的時鐘節拍
//SYSTICK的時鐘固定為HCLK時鐘的1/8
//SYSCLK:系統時鐘
void DelayInit()
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //選擇外部時鐘 HCLK/8
fac_us=SystemCoreClock/8000000; //為系統時鐘的1/8
fac_ms=(u16)fac_us*1000;//非ucos下,代表每個ms需要的systick時鐘數
}
//延時nus
//nus為要延時的us數.
void DelayUs(unsigned long nus)
{
u32 temp;
SysTick->LOAD=nus*fac_us; //時間加載
SysTick->VAL=0x00; //清空計數器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //開始倒數
do
{
temp=SysTick->CTRL;
}
while(temp&0x01&&!(temp&(1<<16)));//等待時間到達
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //關閉計數器
SysTick->VAL =0X00; //清空計數器
}
//延時nms
//注意nms的范圍
//SysTick->LOAD為24位暫存器,所以,最大延時為:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK單位為Hz,nms單位為ms
//對72M條件下,nms<=1864
void DelayMs(unsigned int nms)
{
u32 temp;
SysTick->LOAD=(u32)nms*fac_ms;//時間加載(SysTick->LOAD為24bit)
SysTick->VAL =0x00; //清空計數器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //開始倒數
do
{
temp=SysTick->CTRL;
}
while(temp&0x01&&!(temp&(1<<16)));//等待時間到達
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //關閉計數器
SysTick->VAL =0X00; //清空計數器
}
void DelayS(unsigned int ns)//延時秒
{
unsigned char i;
for(i=0;i<ns;i++)
{
DelayMs(1000);
}
}
6 最后
技術解答、畢設幫助、開題指導
print("Q 746876041")

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/376031.html
標籤:其他
上一篇:作業系統(上)
