闲来无事,转眼就要开学了,学长说超声波测距用多个定时器太low了,而且还不让用定时器计时高电平时间的方法,对此学长的建议,我虚心接受,并在他的帮助教学下,完成了一个定时器四个channal复用映射 实现超声波四路测距,极大的优化了超声波测距的方法。鉴于超声波模块的测距原理网上很多,在此不再赘述,网上关于超声波测距的方法也很多,建议阅读此文章。下面进入本篇正片。
本超声波测距方式基于hal库,参考了正点原子的滴答定时器延时函数(非阻塞型延时),进行1ms一次的超声波测距发送触发trig函数(拉高拉低某一I/O电平 时间间隔为40us)
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
/* USER CODE BEGIN SysTick_IRQn 1 */
hcsr04_send();
/* USER CODE END SysTick_IRQn 1 */
}//1ms 进一次
void hcsr04_send()
{
//GPIOB->ODR|=1<<5; //PB.5 Êä³ö¸ß
//GPIOB->ODR=0x00000010||GPIOB->IDR;
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);
delay_us(40);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET);
}
至此,单片机已经能触发超声波模块的trig口,echo口已经能发送回波,我们需要测量超声波模块echo口的回波持续高电平时间。那么我们先完成一路超声波测回波时间,首先我们对于定时器3进行初始化,选择上升沿捕获,配置通道1,开启TIM3捕获通道1,使能中断更新,设置中断优先级,开启ITM3中断通道,使能TIM3时钟,复用推挽输入此channel对应的I/O,下拉,高速模式。打开定时器3中断服务函数。后来发现此通道的定时器捕获通道被LCD屏幕占用,果断选择I/O复用功能,查询数据手册得知STM32F103ZET6 TIM3四个捕获通道可全部复用到PC6至PC9。初始化至此完成。代码为配置四路复用I/O后的。
TIM_HandleTypeDef TIM3_Handler; //¶¨Ê±Æ÷¾ä±ú
//TIM_HandleTypeDef TIM4_Handler; //¶¨Ê±Æ÷¾ä±ú
//ͨÓö¨Ê±Æ÷3Öжϳõʼ»¯
//arr£º×Ô¶¯ÖØ×°Öµ¡£
//psc£ºÊ±ÖÓÔ¤·ÖƵÊý
//¶¨Ê±Æ÷Òç³öʱ¼ä¼ÆËã·½·¨:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=¶¨Ê±Æ÷¹¤×÷ƵÂÊ,µ¥Î»:Mhz
//ÕâÀïʹÓõÄÊǶ¨Ê±Æ÷3!
void TIM3_Init(u16 arr,u16 psc)
{
TIM_IC_InitTypeDef TIM3_CH1Config;
TIM3_Handler.Instance=TIM3; //ͨÓö¨Ê±Æ÷3
TIM3_Handler.Init.Prescaler=psc; //·ÖƵϵÊý
TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; //ÏòÉϼÆÊýÆ÷
TIM3_Handler.Init.Period=arr; //×Ô¶¯×°ÔØÖµ
TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;//ʱÖÓ·ÖƵÒò×Ó
HAL_TIM_IC_Init(&TIM3_Handler); //³õʼ»¯ÊäÈ벶»ñʱ»ù²ÎÊý
TIM3_CH1Config.ICPolarity=TIM_ICPOLARITY_RISING; //ÉÏÉýÑز¶»ñ
TIM3_CH1Config.ICSelection=TIM_ICSELECTION_DIRECTTI;//Ó³Éäµ½TI1ÉÏ
TIM3_CH1Config.ICPrescaler=TIM_ICPSC_DIV1; //ÅäÖÃÊäÈë·ÖƵ£¬²»·ÖƵ
TIM3_CH1Config.ICFilter=0; //ÅäÖÃÊäÈëÂ˲¨Æ÷£¬²»Â˲¨
HAL_TIM_IC_ConfigChannel(&TIM3_Handler,&TIM3_CH1Config,TIM_CHANNEL_1);//ÅäÖÃTIM3ͨµÀ1
HAL_TIM_IC_ConfigChannel(&TIM3_Handler,&TIM3_CH1Config,TIM_CHANNEL_2);//ÅäÖÃTIM3ͨµÀ2
HAL_TIM_IC_ConfigChannel(&TIM3_Handler,&TIM3_CH1Config,TIM_CHANNEL_3);//ÅäÖÃTIM3ͨµÀ3
HAL_TIM_IC_ConfigChannel(&TIM3_Handler,&TIM3_CH1Config,TIM_CHANNEL_4);//ÅäÖÃTIM3ͨµÀ4
HAL_TIM_IC_Start_IT(&TIM3_Handler,TIM_CHANNEL_1); //¿ªÆôTIM3µÄ²¶»ñͨµÀ1£¬²¢ÇÒ¿ªÆô²¶»ñÖжÏ
HAL_TIM_IC_Start_IT(&TIM3_Handler,TIM_CHANNEL_2); //¿ªÆôTIM3µÄ²¶»ñͨµÀ2£¬²¢ÇÒ¿ªÆô²¶»ñÖжÏ
HAL_TIM_IC_Start_IT(&TIM3_Handler,TIM_CHANNEL_3); //¿ªÆôTIM3µÄ²¶»ñͨµÀ3£¬²¢ÇÒ¿ªÆô²¶»ñÖжÏ
HAL_TIM_IC_Start_IT(&TIM3_Handler,TIM_CHANNEL_4); //¿ªÆôTIM3µÄ²¶»ñͨµÀ4£¬²¢ÇÒ¿ªÆô²¶»ñÖжÏ
__HAL_TIM_ENABLE_IT(&TIM3_Handler,TIM_IT_UPDATE); //ʹÄܸüÐÂÖжÏ
HAL_NVIC_SetPriority(TIM3_IRQn,2,0); //ÉèÖÃÖжÏÓÅÏȼ¶£¬ÇÀÕ¼ÓÅÏȼ¶2£¬×ÓÓÅÏȼ¶0
HAL_NVIC_EnableIRQ(TIM3_IRQn); //¿ªÆôITM3ÖжÏͨµÀ
__HAL_RCC_TIM3_CLK_ENABLE(); //ʹÄÜTIM3ʱÖÓ
TIM3_Init(65535,72-1); //¶¨Ê±Æ÷3³õʼ»¯
HAL_TIM_IC_Start_IT(&TIM3_Handler,TIM_CHANNEL_1);
__HAL_TIM_ENABLE_IT(&TIM3_Handler,TIM_IT_UPDATE);
}
//¶¨Ê±Æ3µ×²ãÇý¶¯£¬Ê±ÖÓʹÄÜ£¬Òý½ÅÅäÖÃ
//´Ëº¯Êý»á±»HAL_TIM_IC_Init()µ÷ÓÃ
//htim:¶¨Ê±Æ÷3¾ä±ú
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_TIM3_CLK_ENABLE(); //ʹÄÜTIM5ʱÖÓ
__HAL_AFIO_REMAP_TIM3_ENABLE(); //TIM3 ???????????
__HAL_RCC_GPIOC_CLK_ENABLE(); //¿ªÆôGPIOBʱÖÓ
//__HAL_RCC_AFIO_CLK_ENABLE(); //?????? IO ??
GPIO_Initure.Pin=GPIO_PIN_6 | GPIO_PIN_7| GPIO_PIN_8| GPIO_PIN_9; //PA0
GPIO_Initure.Mode=GPIO_MODE_AF_INPUT; //¸´ÓÃÍÆÍìÊäÈë
GPIO_Initure.Pull=GPIO_PULLDOWN; //ÏÂÀ
GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;//¸ßËÙ
HAL_GPIO_Init(GPIOC,&GPIO_Initure);
HAL_NVIC_SetPriority(TIM3_IRQn,2,0); //ÉèÖÃÖжÏÓÅÏȼ¶£¬ÇÀÕ¼ÓÅÏȼ¶2£¬×ÓÓÅÏȼ¶0
HAL_NVIC_EnableIRQ(TIM3_IRQn); //¿ªÆôITM5ÖжÏͨµÀ
}
//¶¨Ê±Æ÷3ÖжϷþÎñº¯Êý
void TIM3_IRQHandler(void)
{
HAL_TIM_IRQHandler(&TIM3_Handler); //¶¨Ê±Æ÷¹²Óô¦Àíº¯Êý
}
定义四个变量,分别为pre_tim3_count[1],sec_tim3_count[1],flag[1],scr04_count[1],注意,此方法的核心是通过捕获上升沿与下降沿所触发的时刻计数值,记录这两个值,得到高电平时间,也就完成了测距。在初始化中,将捕获定时器的定时触发时间设置为65.5ms溢出,注意,由超声波模块的使用手册可以得知这个捕获时间也就是在trig收到高低电平时间后的时间至下一次trig收到高低电平的时间间隔,理想的一次超声波测距应该是在第一个if判断标志位里的操作,此时测量超声波模块返回高电平的时间恰好在我们定时器计数的65.5ms之内,注意,若在测量超声波模块高电平中的某一时刻定时器发生了溢出,计数清零,那么会出现这个if后的else情况此时我们将定时器捕获方式改为下降沿捕获,此时才能得到回波信号的转换为低电平的时间计数点。
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//²¶»ñÖжϷ¢ÉúʱִÐÐ
{
if(htim == &TIM3_Handler)
{
/*****************³¬Éù²¨Í¨µÀ1 PC6********************************************/
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
if(!flag[1])
{
//HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_SET);
pre_tim3_count[1] = __HAL_TIM_GetCounter(&TIM3_Handler);
__HAL_TIM_SET_CAPTUREPOLARITY(&TIM3_Handler,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);
flag[1] = !flag[1];
}
else
{
sec_tim3_count[1] = __HAL_TIM_GetCounter(&TIM3_Handler);
__HAL_TIM_SET_CAPTUREPOLARITY(&TIM3_Handler,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);
if(pre_tim3_count[1] > pre_tim3_count[1])
{
scr04_count[1] = sec_tim3_count[1] - pre_tim3_count[1];
}
else
{
scr04_count[1] = 65535 - pre_tim3_count[1] + sec_tim3_count[1]+1;
}
flag[1] = !flag[1];
}
}
/*****************³¬Éù²¨Í¨µÀ1 PC6********************************************/
/*****************³¬Éù²¨Í¨µÀ2 PC7********************************************/
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
if(!flag[2])
{
pre_tim3_count[2] = __HAL_TIM_GetCounter(&TIM3_Handler);
__HAL_TIM_SET_CAPTUREPOLARITY(&TIM3_Handler,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_FALLING);
flag[2] = !flag[2];
}
else
{
sec_tim3_count[2] = __HAL_TIM_GetCounter(&TIM3_Handler);
__HAL_TIM_SET_CAPTUREPOLARITY(&TIM3_Handler,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_RISING);
if(pre_tim3_count[2] > pre_tim3_count[2])
{
scr04_count[2] = sec_tim3_count[2] - pre_tim3_count[2];
}
else
{
scr04_count[2] = 65535 - pre_tim3_count[2] + sec_tim3_count[2]+1;
}
flag[2] = !flag[2];
}
}
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
{
if(!flag[3])
{
pre_tim3_count[3] = __HAL_TIM_GetCounter(&TIM3_Handler);
__HAL_TIM_SET_CAPTUREPOLARITY(&TIM3_Handler,TIM_CHANNEL_3,TIM_INPUTCHANNELPOLARITY_FALLING);
flag[3] = !flag[3];
}
else
{
sec_tim3_count[3] = __HAL_TIM_GetCounter(&TIM3_Handler);
__HAL_TIM_SET_CAPTUREPOLARITY(&TIM3_Handler,TIM_CHANNEL_3,TIM_INPUTCHANNELPOLARITY_RISING);
if(pre_tim3_count[3] > pre_tim3_count[3])
{
scr04_count[3] = sec_tim3_count[3] - pre_tim3_count[3];
}
else
{
scr04_count[3] = 65535 - pre_tim3_count[3] + sec_tim3_count[3]+1;
}
flag[3] = !flag[3];
}
}
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
{
if(!flag[4])
{
pre_tim3_count[4] = __HAL_TIM_GetCounter(&TIM3_Handler);
__HAL_TIM_SET_CAPTUREPOLARITY(&TIM3_Handler,TIM_CHANNEL_4,TIM_INPUTCHANNELPOLARITY_FALLING);
flag[4] = !flag[4];
}
else
{
sec_tim3_count[4] = __HAL_TIM_GetCounter(&TIM3_Handler);
__HAL_TIM_SET_CAPTUREPOLARITY(&TIM3_Handler,TIM_CHANNEL_4,TIM_INPUTCHANNELPOLARITY_RISING);
if(pre_tim3_count[4] > pre_tim3_count[4])
{
scr04_count[4] = sec_tim3_count[4] - pre_tim3_count[4];
}
else
{
scr04_count[4] = 65535 - pre_tim3_count[4] + sec_tim3_count[4]+1;
}
flag[4] = !flag[4];
}
}
}
}
READ一下就完成啦。
void hcsr04_read()
{
// if(TIM3CH1_CAPTURE_STA & 0x80) //
// {
// time = TIM3CH1_CAPTURE_STA & 0x3F; //
// time *= 65536; //
// time += TIM3CH1_CAPTURE_VAL; //
// distance = time * 342.62*100/2000000;
// LCD_ShowxNum(20, 250, distance, 20, 16, 0);
// TIM3CH1_CAPTURE_STA = 0;
// }
distance[1] = (uint16_t)((scr04_count[1] * 342.62 * 100.0)/2000000.0);
// LCD_ShowString(0, 235, 20, 20, 16, "ONE");
// LCD_ShowxNum(40, 235, distance[1], 6, 16, 0);
distance[2] = (uint16_t)((scr04_count[2] * 342.62 * 100.0)/2000000.0);
// LCD_ShowString(0, 255, 20, 20, 16, "TWO");
// LCD_ShowxNum(40, 255, distance[2], 6, 16, 0);
distance[3] = (uint16_t)((scr04_count[3] * 342.62 * 100.0)/2000000.0);
// LCD_ShowString(0, 275, 20, 20, 16, "TRE");
// LCD_ShowxNum(40, 275, distance[3], 6, 16, 0);
distance[4] = (uint16_t)((scr04_count[4] * 342.62 * 100.0)/2000000.0);
// LCD_ShowString(0, 295, 20, 20, 16, "FOU");
// LCD_ShowxNum(40, 295, distance[4], 6, 16, 0);
}