电子类研究生的STM32小白入门 一个定时器 四个channel复用映射 实现超声波四路测距

闲来无事,转眼就要开学了,学长说超声波测距用多个定时器太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);    
}

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现不同频率闪烁LED灯,可以使用定时器控制LED的闪烁周期。 首先,选择一个合适的定时器,比如GD32系列芯片中常用的定时器TIM3。然后,按照以下步骤进行设置: 1. 启动定时器:配置定时器的时钟源、预分频系数和计数器周期,并使能定时器。 2. 配置定时器的输出比较模式:选择定时器通道,并设置比较值。 3. 配置GPIO引脚:将LED连接到相应的GPIO引脚上,并设置为输出模式。 4. 编写中断处理函数:在定时器溢出或比较匹配时触发中断,通过中断处理函数来控制LED的状态变化。 下面是一个简单的示例代码,实现两个LED以不同频率闪烁: ```c #include "gd32f30x.h" void delay(uint32_t count) { while(count--); } int main(void) { /* 启动定时器3 */ rcu_periph_clock_enable(RCU_TIMER3); timer_deinit(TIMER3); timer_parameter_struct timer_initpara; timer_struct_para_init(&timer_initpara); timer_initpara.prescaler = 7199; // 设置预分频系数 timer_initpara.period = 9999; // 设置计数器周期 timer_init(TIMER3, &timer_initpara); timer_enable(TIMER3); /* 配置定时器3的通道1输出比较模式 */ timer_channel_output_config(TIMER3, TIMER_CH_1, TIMER_OC_MODE_TOGGLE); timer_channel_output_pulse_value_config(TIMER3, TIMER_CH_1, 5000); // 设置比较值 timer_channel_output_state_config(TIMER3, TIMER_CH_1, TIMER_CCX_ENABLE); /* 配置GPIO引脚 */ rcu_periph_clock_enable(RCU_GPIOC); gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_0 | GPIO_PIN_1); while(1) { delay(500000); // 延时一段时间 gpio_bit_write(GPIOC, GPIO_PIN_0, (bit_status)(1 - gpio_output_bit_get(GPIOC, GPIO_PIN_0))); // 切换LED状态 } } ``` 在这个例子中,LED1连接到GPIOC的第0引脚,LED2连接到GPIOC的第1引脚。定时器TIM3的通道1配置为比较模式,比较值设置为5000。定时器每溢出一次,LED1的状态会切换一次,产生较慢的闪烁效果。 注意,上述代码仅供参考,具体实现可能因芯片型号、编译环境等而有所差异。请根据实际情况进行相应的修改和调试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值