目录
- 1.传感器准备工作
- 2.redme
- 3.实验项目核心部分
- 3.1 模式菜单(自动模式-常亮模式-常灭模式)
- 3.2 模式循环切换
- 3.3 RD03雷达处理函数
- 3.4 按键切换状态
- 3.5 反射传感器切换模式
1.传感器准备工作
2.redme
/********************************************************************************************/
【】程序简介
-工程名称 :综合实验二 感应灯具(RD03雷达)
-实验平台 :野火 STM32F103C8T6-STM32开发板
【 !】功能简介:
1-RD03雷达模块定期自动发送数据给开发板,开发板接收数据后进行处理,再把处理结果返回给上位机
2-感应灯部分:
工作模式(按键/反射传感器切换)
1>自动模式:
1.设备上电后为“自动模式“ 核心板绿灯长亮,其他板载指示灯灭
2.当雷达触发,LED4亮,否则灭
2>常亮模式:
1.设备切换为“常亮模式“ 核心板蓝灯长亮,其他板载指示灯灭
2.LED4进入亮
3>常灭模式:
1.设备切换为“常灭模式“ 核心板红灯长亮,其他板载指示灯灭
2.LED4进入灭
3>模式切换:按KEY1或者使用手遮挡反射传感器一段固定时间(约一秒多,程序可自定义),可来回循环切换“自动模式”、“常亮模式”、“常灭模式”。
【 !】实验操作:
1.保证开发板相关硬件连接正确,用USB线连接开发板的USB转串口跟电脑, 2.在电脑端打开串口,调试助手并配置好相关参数:115200 8-N-1, 3.编译并下载程序到开发板即可观察现象。 4.复位开发板,RD03雷达模块定期自动发送数据给开发板,开发板接收数据后进行处理,再把处理结果返回给上位机 5-感应灯部分: 工作模式(按键/反射传感器切换) 1>自动模式: 1.设备上电后为“自动模式“ 核心板绿灯长亮,其他板载指示灯灭 2.当雷达触发,LED4亮,否则灭 2>常亮模式: 1.设备切换为“常亮模式“ 核心板蓝灯长亮,其他板载指示灯灭 2.LED4进入亮 3>常灭模式: 1.设备切换为“常灭模式“ 核心板红灯长亮,其他板载指示灯灭 2.LED4进入灭 3>模式切换:按KEY1或者使用手遮挡反射传感器一段固定时间(约一秒多,程序可自定义),可来回循环切换“自动模式”、“常亮模式”、“常灭模式”。/*********************************************************************************************/
【*】 引脚分配
KEY1->PA0 按键按下为高电平 核心板板载默认下拉且硬件有消抖
NRST->NRST 按键按下为低电平 核心板板载默认上拉且硬件有消抖
LED_R->LED1->PA1 核心板板载LED灯低电平亮
LED_G->LED2->PA2 核心板板载LED灯低电平亮
LED_B->LED3->PA3 核心板板载LED灯低电平亮
LED4->PB5 用户自定义LED灯低电平亮
DEBUG_TX->USART1_TXD->PA9 PA9作为USART1的TXD 核心板默认使用 PA9 做 DEBUG_TX
DEBUG_RX->USART1_RXD->PA10 PA10作为USART1的RXD 核心板默认使用 PA10 做 DEBUG_RX
RD03_TX->USART3_TXD->PB10 PB10作为USART3的TXD RD03雷达模块串口_TX
RD03_RX->USART3_RXD->PB11 PB11作为USART3的RXD RD03雷达模块串口_RX
热敏模块:
AO <—>不接
TRACK_DO <—>PA11
循迹传感器达不到阈值的时候,D0是高电平,达到阈值的时候,D0是低电平
VDD <—>3V3
GND <—>GND
/*********************************************************************************************/
3.实验项目核心部分
3.1 模式菜单(自动模式-常亮模式-常灭模式)
由于需要三种模式,所以定义一个枚举模式枚举
/* 模式切换 */typedefenum{Sensor_Light_Mode_Auto=0,//自动模式Sensor_Light_Mode_AlwaysOn=1,//常亮模式Sensor_Light_Mode_AlwaysOff=2,//常灭模式Sensor_Light_Mode_NUM=3,//用来统计枚举数量,作为临界点判断}Sensor_Light_Mode_Type;再定义一个结构体,用来封装感应灯信息
/*感应灯/反射传感器 模式状态信息*/typedefstruct{Sensor_Light_Mode_Type mode;ReflectSensor_StateType last_state;uint32_ttime;}Sensor_Light_Mode_State_Info;各个模式处理的功能函数模块
/** * @brief 感应灯具 模式配置(指定模式配置) * @param mode:感应灯模式 * @retval 无 */voidSensor_Light_Set_Mode(Sensor_Light_Mode_Type mode){switch(mode){//自动模式caseSensor_Light_Mode_Auto:{/* 绿灯常亮(G) 其他灯灭(R、B、LED4) */LED_GPIO_OFF(R_LED1_GPIO_PORT,R_LED1_GPIO_PIN,LED_LOW_TRIGGER);LED_GPIO_ON(G_LED2_GPIO_PORT,G_LED2_GPIO_PIN,LED_LOW_TRIGGER);LED_GPIO_OFF(B_LED3_GPIO_PORT,B_LED3_GPIO_PIN,LED_LOW_TRIGGER);LED_GPIO_OFF(LED4_GPIO_PORT,LED4_GPIO_PIN,LED_LOW_TRIGGER);printf("Sensor_Light_Mode_Auto\n");/* 保存当前模式状态(自动模式) */Sensor_Light_ModeState.mode=Sensor_Light_Mode_Auto;break;}//常亮模式caseSensor_Light_Mode_AlwaysOn:{/* 蓝灯、LED4常亮(B、LED4) 其他灯灭(R、G) */LED_GPIO_OFF(R_LED1_GPIO_PORT,R_LED1_GPIO_PIN,LED_LOW_TRIGGER);LED_GPIO_OFF(G_LED2_GPIO_PORT,G_LED2_GPIO_PIN,LED_LOW_TRIGGER);LED_GPIO_ON(B_LED3_GPIO_PORT,B_LED3_GPIO_PIN,LED_LOW_TRIGGER);LED_GPIO_ON(LED4_GPIO_PORT,LED4_GPIO_PIN,LED_LOW_TRIGGER);printf("Sensor_Light_Mode_AlwaysOn\n");/* 保存当前模式状态(常亮模式) */Sensor_Light_ModeState.mode=Sensor_Light_Mode_AlwaysOn;break;}//常灭模式caseSensor_Light_Mode_AlwaysOff:{/* 红灯常亮(R) 其他灯灭(G、B、LED4) */LED_GPIO_ON(R_LED1_GPIO_PORT,R_LED1_GPIO_PIN,LED_LOW_TRIGGER);LED_GPIO_OFF(G_LED2_GPIO_PORT,G_LED2_GPIO_PIN,LED_LOW_TRIGGER);LED_GPIO_OFF(B_LED3_GPIO_PORT,B_LED3_GPIO_PIN,LED_LOW_TRIGGER);LED_GPIO_OFF(LED4_GPIO_PORT,LED4_GPIO_PIN,LED_LOW_TRIGGER);printf("Sensor_Light_Mode_AlwaysOff\n");/* 保存当前模式状态(常灭模式) */Sensor_Light_ModeState.mode=Sensor_Light_Mode_AlwaysOff;break;}default:break;}}自动模式:绿灯亮,红灯、蓝灯灭,LED4受到雷达影响
常亮模式:蓝灯亮,绿灯,红灯灭,LED4亮
常灭模式:红灯亮,绿灯,蓝灯灭,LED4灭
初始化是自动模式,所以可以在初始化部分调用该函数,传递模式是自动模式
3.2 模式循环切换
枚举定义,结构体封装
/* 模式切换 */typedefenum{Sensor_Light_Mode_Auto=0,//自动模式Sensor_Light_Mode_AlwaysOn=1,//常亮模式Sensor_Light_Mode_AlwaysOff=2,//常灭模式Sensor_Light_Mode_NUM=3,//用来统计枚举数量,作为临界点判断}Sensor_Light_Mode_Type;/*感应灯/反射传感器 模式状态信息*/typedefstruct{Sensor_Light_Mode_Type mode;ReflectSensor_StateType last_state;uint32_ttime;}Sensor_Light_Mode_State_Info;模式循环切换函数模块
/** * @brief 感应灯具 模式配置(循环切换[自动-常亮-常灭]) * @param 无 * @retval 无 */voidSensor_Light_SwitchMode(void){Sensor_Light_Mode_Type mode_temp=(Sensor_Light_Mode_Type)(Sensor_Light_ModeState.mode+1);if(mode_temp==Sensor_Light_Mode_NUM){mode_temp=Sensor_Light_Mode_Auto;}Sensor_Light_Set_Mode(mode_temp);}每一次调用这个函数,当前模式枚举的值+1,当如果达到3就切换到自动模式,同时还需要调用设置模式函数
3.3 RD03雷达处理函数
当检测到有人LED4亮,无人LED4灭,同时是只能在自动模式才能处理。
思路:在RD03应用层定义RD03枚举,枚举有人和无人,然后用结构体封装,在RD03应用层中,将检测的有人和无人状态保存在结构体封装的枚举里面,由于该结构体变量设置的作用域是static,只能被自己的源文件夹访问,不可以被其他源文件访问,所以我还需要写一个对外扩展的函数接口,返回被封装的雷达检测状态结构体变量。
在雷达处理函数中
1.判断当前是不是自动模式,如果是才有以下操作
2.通过雷达状态对外扩展的函数接口获取雷达检测状态有人/无人
3.判断当前有人,LED4亮
4.判断当前无人,LED4灭
RD03状态枚举以及结构体封装
// 雷达目标检测状态枚举typedefenum{RD03_STATUS_NONE=0,// 无人RD03_STATUS_DETECTED=1,// 有人}Rd03_StatusTypeDef;typedefstruct{Rd03_StatusTypeDef human_status;// 枚举:有人/无人状态uint16_tdistance;// 检测距离}Rd03_ResultInfo;对外扩展雷达结构体检测信息
staticRd03_ResultInfo Rd03_Result={RD03_STATUS_NONE,0};/** * @brief RD03串口 目标信息获取 * @param 无 * @retval 无 */Rd03_ResultInfoRD03_GetResult(void){//获取人状态: 有人/无人 距离returnRd03_Result;}感应灯具雷达处理函数
/** * @brief 感应灯具 RD03雷达数据处理函数 * @param 无 * @retval 无 */voidSensor_Light_Rd03_DataHandle(void){//自动模式if(Sensor_Light_ModeState.mode==Sensor_Light_Mode_Auto){//获取雷达检测结果: 有人/无人/距离Rd03_ResultInfo result=RD03_GetResult();//有人 LED4点亮if(result.human_status==RD03_STATUS_DETECTED){LED_GPIO_ON(LED4_GPIO_PORT,LED4_GPIO_PIN,LED_LOW_TRIGGER);}//无人 LED4灭elseif(result.human_status==RD03_STATUS_NONE){LED_GPIO_OFF(LED4_GPIO_PORT,LED4_GPIO_PIN,LED_LOW_TRIGGER);}}}3.4 按键切换状态
只需要在按键任务处理函数里面去调用循环切换函数即可
/** * @brief 按键 任务 * @param 无 * @retval 无 */voidKey_Task(void){if(key_task.flag==1){KEY_Evnet current_event;current_event=KEY_SystickScan(&key1_info);/* 短按*/if(current_event==EVENT_SHORT_RELEASE){//模式切换(自动-常亮-常灭)Sensor_Light_SwitchMode();}Key_TaskReset();}}3.5 反射传感器切换模式
反射传感器有两种状态,遮挡/无遮挡,所以需要定义一个枚举,接着将反射传感器枚举状态变量封装在结构体里面。还需要在结构体里面定义一个保存时间的。
思路:
定义一个临时枚举变量,用来获取当前反射传感器检测到有遮挡还是无遮挡。
定义一个静态结构体变量,这个变量封装了反射传感器两种状态的变量,以及还有一个时间变量
初始化反射传感器状态是无遮挡,时间是0
通过分支判断
分支1.初始化是无遮挡,当前检测状态是有遮挡
结构体反射传感器有无遮挡状态设置遮挡状态
并且时间变量记录当前起始时间
这个时间通过配置定时器,每1ms中断一次,定义了一个变量,每次值+1,通过返回该变量的值获取时间。
分支2 变量结构体保存的状态是遮挡状态,当前状态是无遮挡
每隔20ms轮询一次检测,意思是上一次检测的状态是遮挡状态保存起来了,当前反射传感器检测状态是无遮挡,就是在遮挡小于1s范围内取消遮挡了。
结构体反射传感器有无遮挡状态设置无遮挡状态
分支3 变量结构体保存的状态是遮挡状态,当前状态是遮遮挡
定义一个时间临时变量
判断当前的时间 与第一次分支1记录的时间做差值,结果大于1200,而这个1200可以用一个宏定义封装起来,当结果大于1200,说明时间到了,调用循环切换函数,结构体保存的时间不是初始化0.
时间到了切换状态,保存时间初始话0的后果
假设时间初始化0,当我手一直遮挡就算1200到了我还是在遮挡,也就是分支3还在进去的,临时时间变量值- 0 肯定大于1200的,就会瞬间又切换模式了,也就是说我第一次遮挡了模式切换了,然后瞬间20ms轮询,给人感觉瞬间秒切换下一个模式了。
正确做法是,保存的时间保存通过获取当前的时间函数的时间值。
就算下一次20ms轮询继续进去,结构体时间变量记录上一次模式切换的时间。
时间临时变量保存下一次20ms轮询的时间,做差值,只是20ms,并不会大于1200,不会出现瞬间切换下一根模式这种问题。
遮挡枚举结构体定义
// 反射式红外传感器状态枚举typedefenum{Sensor_Light_TRACK_NO_BLOCK=0,// 无遮挡(收到反射光)Sensor_Light_TRACK_BLOCKED=1// 有遮挡(挡住,没有反射)}ReflectSensor_StateType;/*感应灯/反射传感器 模式状态信息*/typedefstruct{Sensor_Light_Mode_Type mode;ReflectSensor_StateType last_state;uint32_ttime;}Sensor_Light_Mode_State_Info;遮挡模式切换处理函数
/** * @brief 感应灯具 反射传感器 数据处理函数 * @param 无 * @retval 无 */voidSensor_Light_Track_DataHandle(void){ReflectSensor_StateType curr_state;//Bit_SET(没有检测到物体)、Bit_RESET(检测到物体)if(TRACK_Scan(TRACK_GPIO_PORT,TRACK_GPIO_PIN)==Bit_RESET){curr_state=Sensor_Light_TRACK_BLOCKED;}else{curr_state=Sensor_Light_TRACK_NO_BLOCK;}//上一次检测状态是初始化,当前检测状态是有遮挡if(Sensor_Light_ModeState.last_state==Sensor_Light_TRACK_NO_BLOCK&&curr_state==Sensor_Light_TRACK_BLOCKED){Sensor_Light_ModeState.last_state=Sensor_Light_TRACK_BLOCKED;Sensor_Light_ModeState.time=SysTick_GetCount();}//上一次检测状态是遮挡,当前检测状态是无遮挡elseif(Sensor_Light_ModeState.last_state==Sensor_Light_TRACK_BLOCKED&&curr_state==Sensor_Light_TRACK_NO_BLOCK){Sensor_Light_ModeState.last_state=Sensor_Light_TRACK_NO_BLOCK;Sensor_Light_ModeState.time=0;}//上一次检测状态和当前状态都是遮挡状态elseif(Sensor_Light_ModeState.last_state==Sensor_Light_TRACK_BLOCKED&&curr_state==Sensor_Light_TRACK_BLOCKED){int32_tcurr_time=SysTick_GetCount();//获取当前的时间if(curr_time-Sensor_Light_ModeState.time>=SWITCH_HOLD_MS){Sensor_Light_SwitchMode();Sensor_Light_ModeState.time=SysTick_GetCount();}}}