基于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)
|