基于STM32的紅外舵機自動壁障小車
單片機源程序如下:
- #include "stm32f10x_it.h"
- #include "stm32f10x_lib.h"
- #include "stm32f10x_type.h"
- #include "stm32f10x_usart.h"
- #include "defines.h"
- #include "stm32f10x_flash.h"
- #include "cpu.h"
- #include <stdio.h>
- #define FLASH_ADDRESS (0x08000000 + 1024 * 32 - 4096) /* 存儲數據Flash頁首地址 */
- #define DUTY_WIDTH 25 //占空比最大級數
- #define CAR_QIAN_JIN 0 //小車前進
- #define CAR_HOU_TUI 1 //小車后退
- u8 debug_switch = 0;//調試開關
- u32 IR_ref_value_L = 0;//紅外感應參考值,開機前將小車置于空曠位置,系統便于識別環境光強度
- u32 IR_ref_value_R = 0;//紅外感應參考值,開機前將小車置于空曠位置,系統便于識別環境光強度
- u8 moto_run = 0;//電機運行標志
- u8 moto_R_speed = 0;//電機速度
- u8 moto_R_dir = CAR_QIAN_JIN;//電機方向
- u8 moto_L_speed = 0;//電機速度
- u8 moto_L_dir = CAR_QIAN_JIN;//電機方向
- u8 moto_speed = 0;//電機前進的速度
- s8 moto_speed_adj = 1;//左右電機速度校正,-3~+3,已左邊輪子速度為基準,在右邊輪子速度加校正值
- //u32 TIME_L_R = (TIMER_FREQ / 3);//轉彎時間,完成后自動歸正
- u8 moto_L_switch = 0;//左轉有效
- u8 moto_R_switch = 0;//右轉有效
- u32 left_turn_cnt = 0; //轉彎時間定時器
- u32 right_turn_cnt = 0; //轉彎時間定時器
- u32 b_led_cnt = 0;//剎車燈時間定時器
- u32 beep_cnt = 0;//喇叭時間定時器,ms
- u8 lamp_front_bright = 0; //大燈亮度
- u8 lamp_f = 0; //大燈開關切換
- void Lamp_front(u8 de);
- /***********************************************************************
- 函數功能: 寫flash,數據長度不超過1扇區
- 入口參數:
- 出口參數:
- ***********************************************************************/
- void WriteFlash(u32 byte_addr , u16 len , u8 *dat)
- {
- u16 i = 0;
- len = len / 2 * 2 + (len % 2) * 2;
- FLASH_Unlock();
- FLASH_ErasePage(byte_addr); /* 擦除頁 */
- //FLASH_ProgramWord(FLASH_ADR,0 << 1 | 0); /* 寫16位半字 */
- for(i = 0 ; i < len ; i += 2)
- {
- FLASH_ProgramHalfWord(byte_addr + i , *(u16*)&dat[i]); /* 寫16位半字 */
- }
- FLASH_Lock();
- }
- /***********************************************************************
- 函數功能:延時_dlytime毫秒
- 入口參數:
- 出口參數:
- ***********************************************************************/
- void Delay_ms(u32 _dlytime)
- {
- u32 i;
- u32 j;
- for (i = 0; i < _dlytime * 10; i++)
- for (j = 0; j < 0xff; j++);
- }
- /***********************************************************************
- 函數功能:延時
- 入口參數:
- 出口參數:
- ***********************************************************************/
- void Delay(u32 _dlytime)
- {
- u32 i;
- u32 j;
- for (i = 0; i < _dlytime * 1; i++)
- for (j = 0; j < 0x13; j++);
- }
- /***********************************************************************
- 函數功能:獲取AD值
- 入口參數:
- 出口參數:
- ***********************************************************************/
- u16 GetADCVal(u8 ADC_Channel)
- {
- ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_239Cycles5);
-
- /* Start ADC1 Software Conversion */
- ADC_SoftwareStartConvCmd(ADC1, ENABLE);
- while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
- return ADC_GetConversionValue(ADC1);
- }
- /***********************************************************************
- 函數功能:判斷左側是否有障礙物
- 入口參數:
- 出口參數: 1:有障礙,
- ***********************************************************************/
- u8 CheckHinder_Left()
- {
- u16 adc = 0 , avg = 0;
- static u32 adc_temp = 0 , times = 0;
- adc = GetADCVal(ADC_Channel_5);
-
- adc_temp += adc;
- times ++;
- if(adc > IR_ref_value_L + 350)
- return 1;
- avg = (adc_temp / times); //獲取平均值
- if(adc > avg + 60)//如果當前值大于平均值較多,也認為是有障礙
- return 2;
- return 0;
- }
- /***********************************************************************
- 函數功能:判斷右側是否有障礙物
- 入口參數:
- 出口參數: 1:有障礙,
- ***********************************************************************/
- u8 CheckHinder_Right()
- {
- u16 adc = 0 , avg = 0;
- static u32 adc_temp = 0 , times = 0;
- adc = GetADCVal(ADC_Channel_4);
-
- adc_temp += adc;
- times ++;
- if(adc > IR_ref_value_R + 150)
- return 1;
- avg = (adc_temp / times); //獲取平均值
- if(adc > avg + 50)//如果當前值大于平均值較多,也認為是有障礙
- return 2;
- return 0;
- }
- /***********************************************************************
- 函數功能:向串口發數據
- 入口參數:
- 出口參數:
- ***********************************************************************/
- void SendDataToUart(u8 dat)
- {
- UART1_SendByte(dat);
- }
- /***********************************************************************
- 函數功能:發送數據
- 入口參數:
- 出口參數:
- ***********************************************************************/
- void SendStrToUart(char*str)
- {
- while(*str)
- {
- SendDataToUart(*str ++);
- }
- }
- /***********************************************************************
- 函數功能:
- 入口參數:
- 出口參數:
- ***********************************************************************/
- void Timer2ISR(void)
- {
- static u32 cnt = 0 , st = 0 , cnt_t = 0 , beep_freq_cnt = 0 , beep_freq = 1000 ;
- static u8 b = 0 , l_r_led = 0;
- static u32 l_r_led_cnt = 0;//轉彎燈時間定時器
- u32 audio_adc_val = 0;
- //
- if(cnt < DUTY_WIDTH)//占空比計數
- {
- cnt ++;
- }
- else
- {
- cnt = 0;
- }
- GPIO_WriteBit(GPIOC , GPIO_Pin_13 , l_r_led); //cpu狀態指示燈
- GPIO_WriteBit(GPIOB, GPIO_Pin_2 , l_r_led);
- //剎車燈控制
- if(b_led_cnt < TIMER_FREQ / 2)
- {
- b_led_cnt ++;
- GPIO_WriteBit(GPIOB, GPIO_Pin_2 , 1);
- }
- else
- {
- //GPIO_WriteBit(GPIOB, GPIO_Pin_2 , 0);
- }
- if(l_r_led_cnt < TIMER_FREQ / 5)
- {
- l_r_led_cnt ++ ;
- }
- else
- {
- l_r_led_cnt = 0;
- l_r_led = !l_r_led;
- }
- //轉彎控制
- if(moto_L_switch) //左轉
- {
- if(left_turn_cnt > 0)
- {
- left_turn_cnt --;
- GPIO_WriteBit(GPIOA, GPIO_Pin_1 , l_r_led);
- GPIO_WriteBit(GPIOA, GPIO_Pin_12 , 0);
- }
- else
- {
- moto_L_speed = moto_speed;//轉彎結束,自動歸正
- moto_R_speed = moto_speed;//轉彎結束,自動歸正
- moto_L_switch = 0;
- moto_L_dir = CAR_QIAN_JIN;
- moto_R_dir = CAR_QIAN_JIN;
- GPIO_WriteBit(GPIOA, GPIO_Pin_1 , 0);
- }
- }
- else
- if(moto_R_switch) //右轉
- {
- if(right_turn_cnt > 0)
- {
- right_turn_cnt --;
- GPIO_WriteBit(GPIOA, GPIO_Pin_12 , l_r_led);
- GPIO_WriteBit(GPIOA, GPIO_Pin_1 , 0);
- }
- else
- {
- moto_L_speed = moto_speed;//轉彎結束,自動歸正
- moto_R_speed = moto_speed;//轉彎結束,自動歸正
- moto_R_switch = 0;
- moto_R_dir = CAR_QIAN_JIN;
- moto_L_dir = CAR_QIAN_JIN;
- GPIO_WriteBit(GPIOA, GPIO_Pin_12 , 0);
- }
- }
- //右電機控制,定時器模擬PWM控制
- GPIO_WriteBit(GPIOB, GPIO_Pin_3 , moto_R_speed > 0 ? (cnt <= moto_R_speed + moto_speed_adj ? (moto_R_dir == CAR_QIAN_JIN ? moto_run & 1 : 0) : 0) : 0);
- GPIO_WriteBit(GPIOA, GPIO_Pin_15 , moto_R_speed > 0 ? (cnt <= moto_R_speed + moto_speed_adj ? (moto_R_dir == moto_run & 1 ? moto_run & 1 : 0) : 0) : 0);
-
- //左電機控制,定時器模擬PWM控制
- GPIO_WriteBit(GPIOA, GPIO_Pin_2 , moto_L_speed > 0 ? (cnt <= moto_L_speed ? (moto_L_dir == moto_run & 1 ? moto_run & 1 : 0) : 0) : 0);
- GPIO_WriteBit(GPIOA, GPIO_Pin_3 , moto_L_speed > 0 ? (cnt <= moto_L_speed ? (moto_L_dir == CAR_QIAN_JIN ? moto_run & 1 : 0) : 0) : 0);
-
- GPIO_WriteBit(GPIOA, GPIO_Pin_11 , cnt < lamp_front_bright);// 大燈
- if(beep_freq_cnt < TIMER_FREQ / beep_freq / 2)//喇叭頻率計數器
- {
- beep_freq_cnt ++;
- }
- else
- {
- beep_freq_cnt = 0;
- b = !b;
- }
- if(beep_cnt > 0)//喇叭響持續時間
- {
- beep_cnt --;
- GPIO_WriteBit(GPIOB, GPIO_Pin_0 , b);
- }
- else
- {
- GPIO_WriteBit(GPIOB, GPIO_Pin_0 , 0);
- }
- }
-
-
- /***********************************************************************
- 函數功能:串口接收數據中斷程序,處理命令
- 入口參數:
- 出口參數:
- ***********************************************************************/
- void Uart1RevISR(u8 dat)
- {
- char txt[33];
- switch(dat)
- {
- case '0': //開關大燈
- lamp_f = !lamp_f;
- break;
- case 'a': //查詢連接
- SendStrToUart("b");
- break;
- case 'd': //調試開關
- debug_switch = !debug_switch;
- sprintf(txt , "調試開關:%d\r\n" , debug_switch);
- SendStrToUart(txt);
- break;
- case '5': //開關喇叭
- beep_cnt = (TIMER_FREQ / 1000) * 300;
-
- sprintf(txt , "beep:%d\r\n" , beep_cnt);
- SendStrToUart(txt);
- break;
- case ' ': //開關喇叭
- beep_cnt = (TIMER_FREQ / 1000) * 300;
- sprintf(txt , "beep:%d\r\n" , beep_cnt);
- SendStrToUart(txt);
- break;
- case '8': //加速
- moto_run = 1;
- if(CAR_QIAN_JIN == moto_L_dir && CAR_QIAN_JIN == moto_R_dir) //
- {
- if(moto_speed < DUTY_WIDTH - 4)
- moto_speed += 1;
- }
- else
- if(CAR_HOU_TUI == moto_L_dir && CAR_HOU_TUI == moto_R_dir) //
- {
- if(moto_speed > 0)
- moto_speed -= 1;
- else
- {
- moto_speed = 0;
- moto_L_dir = CAR_QIAN_JIN; //減速到0時開始后退
- moto_R_dir = CAR_QIAN_JIN; //減速到0時開始后退
- }
- }
- moto_L_speed = moto_speed;
- moto_R_speed = moto_speed;
- sprintf(txt , "L:%d , R:%d\r\n" , moto_L_speed , moto_R_speed);
- SendStrToUart(txt);
- break;
- case '2': //減速
- if(CAR_QIAN_JIN == moto_L_dir && CAR_QIAN_JIN == moto_R_dir) //
- {
- if(moto_speed > 0)
- moto_speed -= 1;
- else
- {
- moto_speed = 0;
- moto_L_dir = CAR_HOU_TUI; //減速到0時開始后退
- moto_R_dir = CAR_HOU_TUI; //減速到0時開始后退
- }
- }
- else
- if(CAR_HOU_TUI == moto_L_dir && CAR_HOU_TUI == moto_R_dir) //
- {
- if(moto_speed < DUTY_WIDTH / 2)
- moto_speed += 1;
- }
- b_led_cnt = 0;
- moto_L_speed = moto_speed;
- moto_R_speed = moto_speed;
- sprintf(txt , "L:%d , R:%d\r\n" , moto_L_speed , moto_R_speed);
- SendStrToUart(txt);
- break;
- case '7': //左轉校正
- if(moto_speed_adj < 3)
- moto_speed_adj ++;
- break;
- case '9': //右轉校正
- if(moto_speed_adj > -3)
- moto_speed_adj --;
- break;
- case '4': //左轉
- moto_L_switch = 1;
- moto_R_switch = 0;
- moto_L_dir = CAR_QIAN_JIN;
- moto_R_dir = CAR_QIAN_JIN;
- left_turn_cnt = (TIMER_FREQ / 5);//轉彎時間定時器
- moto_L_speed = moto_speed / 3;
- moto_R_speed = moto_speed;
- sprintf(txt , "L:%d , R:%d\r\n" , moto_L_switch , moto_R_switch);
- SendStrToUart(txt);
- break;
- case '6': //右轉
- moto_R_switch = 1;
- moto_L_switch = 0;
- moto_R_dir = CAR_QIAN_JIN;
- moto_L_dir = CAR_QIAN_JIN;
- right_turn_cnt = (TIMER_FREQ / 5);//轉彎時間定時器
- moto_R_speed = moto_speed / 3;
- moto_L_speed = moto_speed;
- sprintf(txt , "L:%d , R:%d\r\n" , moto_L_switch , moto_R_switch);
- SendStrToUart(txt);
- break;
- case 'l': //左轉大彎,并稍微后退,避障用
- moto_L_switch = 1;
- moto_R_switch = 0;
- moto_L_dir = CAR_HOU_TUI;
- moto_R_dir = CAR_HOU_TUI;
- left_turn_cnt = (TIMER_FREQ / (moto_speed / 20 + 1) );//轉彎時間定時器, 轉彎時間與速度相關
- moto_L_speed = moto_speed;
- moto_R_speed = moto_speed / 4;
- //sprintf(txt , "L:%d , R:%d\r\n" , moto_L_switch , moto_R_switch);
- //SendStrToUart(txt);
- break;
- case 'r': //右轉大彎,并稍微后退,避障用
- moto_R_switch = 1;
- moto_L_switch = 0;
- moto_R_dir = CAR_HOU_TUI;
- moto_L_dir = CAR_HOU_TUI;
- right_turn_cnt = (TIMER_FREQ / (moto_speed / 20 + 1) );//轉彎時間定時器, 轉彎時間與速度相關
- moto_R_speed = moto_speed;
- moto_L_speed = moto_speed / 4;
- //sprintf(txt , "L:%d , R:%d\r\n" , moto_L_switch , moto_R_switch);
- //SendStrToUart(txt);
- break;
- }
- }
- /***********************************************************************
- 函數功能:串口接收數據中斷程序,處理命令
- 入口參數:
- 出口參數:
- ***********************************************************************/
- void Uart2RevISR(u8 dat)
- {
- u8 n = 0 , i = 0 , len = 0 , ch = 0;
- float val = 0.0;
- static float current_adj = 1.0;
-
- }
- /***********************************************************************
- 函數功能:大燈控制
- 入口參數:
- 出口參數:
- ***********************************************************************/
- void Lamp_front(u8 de)
- {
- u8 i = 0;
- if(de == 1)//燈漸亮
- {
- if(lamp_front_bright == 0)
- {
- for(i = 0 ; i < DUTY_WIDTH ; i ++)
- {
- lamp_front_bright = i;
- Delay_ms(20);
- }
- }
- }
- else //燈漸暗
- {
- if(lamp_front_bright == DUTY_WIDTH - 1)
- {
- for(i = 0 ; i < DUTY_WIDTH ; i ++)
- {
- lamp_front_bright = DUTY_WIDTH - i - 1;
- Delay_ms(20);
- }
- }
- }
- }
- /***********************************************************************
- 函數功能:
- 入口參數:
- 出口參數:
- ***********************************************************************/
- int main(void)
- {
- char txt[44];
- int i = 0 , ls = 0 , rs = 0 , t = 0;
- s32 ad = 0;
- STM32_Board_Init();
- //SendStrToUart("AT+BAUD8");//設置波特率為115200
- moto_speed = 18; //
- moto_run = 1;
- moto_R_speed = moto_speed;
- moto_R_dir = CAR_QIAN_JIN;//電機方向
- moto_L_speed = moto_speed;
- moto_L_dir = CAR_QIAN_JIN ;//電機方向
- Delay_ms(200);
- //自動識別環境光強度
- for(i = 0 ; i < 20 ; i ++)
- {
- t += GetADCVal(ADC_Channel_5);
- }
- t /= 20;
- IR_ref_value_L = t;
- t = 0;
- for(i = 0 ; i < 20 ; i ++)
- {
- t += GetADCVal(ADC_Channel_4);
- }
- t /= 20;
- IR_ref_value_R = t;
- //FlashData=*(vu32*)(FLASH_ADR); /* 讀取地址中的16位數據 */
- //SendDataToUart('A');
- lamp_front_bright = 0; //大燈亮度
- beep_cnt = (TIMER_FREQ / 1000) * 100;//喇叭叫
- while(1)
- {
- if(debug_switch == 0)
- {
- if(lamp_front_bright == 0)
- {
- if(lamp_f == 1)
- {
- Lamp_front(lamp_f);
- }
- }
- else
- {
- if(lamp_f == 0)
- {
- Lamp_front(lamp_f);
- }
- }
-
- rs = CheckHinder_Right();
-
- if( rs ) //判斷右側是否有障礙物 , 如有則左轉
- {
- if(moto_L_switch == 0)
- {
- Uart1RevISR('l'); //發送左轉指令
-
- if(lamp_f == 0) //如果大燈沒開,這里打開大燈
- lamp_front_bright = (rs - 0 ) * 10 + 0;
-
- if(beep_cnt == 0)
- beep_cnt = (TIMER_FREQ / 1000) * 50; //喇叭叫一聲
- //SendStrToUart("<<<\r\n");
- }
- }
- else
- {
- ls = CheckHinder_Left();
- //判斷左側是否有障礙物 , 如有則右轉
- if(ls)
- {
- if(moto_R_switch == 0)
- {
- Uart1RevISR('r'); //發送右轉指令
-
- if(lamp_f == 0) //如果大燈沒開,這里打開大燈
- lamp_front_bright = (ls - 0 ) * 10 + 0;
-
- if(beep_cnt == 0)
- beep_cnt = (TIMER_FREQ / 1000) * 10; //喇叭叫一聲
- //SendStrToUart(">>>\r\n");
- }
- }
- else
- {
- if(lamp_f == 0 && lamp_front_bright > 0)
- lamp_front_bright = 0;
- }
- }
-
- Delay_ms(10);
-
- if(GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_9) == 0) //key1按下 ,開車和停車切換
- {
- moto_run = !moto_run;
-
- while(GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_9) == 0);
- Delay_ms(20);
- }
- #if 0
- if(lamp_f == 0) //如果大燈沒開,這里打開大燈
- {
- ad = GetADCVal(ADC_Channel_6);
- ad -= 2000;
- if(ad > 0)
- ad = 0;
- ad = 0 - ad;
- ad /= 200;
- lamp_front_bright = ad;
- }
- #endif
- }
- //GPIO_WriteBit(GPIOC , GPIO_Pin_13 , 0);//led
- //Delay_ms(200);
- //GPIO_WriteBit(GPIOC , GPIO_Pin_13 , 1);//led
- if(debug_switch)
- {
- Delay_ms(50);
- sprintf(txt , "右側紅外感應AD4:%4d,左側紅外感應AD5:%4d,音頻:%4d\r\n" , GetADCVal(ADC_Channel_4) , GetADCVal(ADC_Channel_5) , GetADCVal(ADC_Channel_6) );
- SendStrToUart(txt);
- }
- }
- return 0;
- }
復制代碼
所有資料51hei提供下載:
stm32 Car V1.0.zip
(603.16 KB, 下載次數: 23)
2018-4-8 17:36 上傳
點擊文件名下載附件
|