[原创] 雅特力AT32WB415外设使用 (超声波模块)

LYU4662   2022-8-8 16:46 楼主

        过上周的环境搭建完成后点亮了一个灯,这次准备进行部分外设的学习。因为之前买了一个超声波模块一直没有玩过,正好借这次机会来玩一下。虽然这个模块使用起来相对比较简单,但是在不同的平台上对于控制的方式还是有所区分的。

        们先了解一下超声波模块测距离的工作原理:超声波发射器向某一方向发射超声波,在发射时刻的同时开始计时,超声波在空气中传播,途中碰到障碍物就立即返回来,超声波接收器收到反射波就立即停止计时。超声波在空气中的传播速度为340m/s,根据计时器记录的时间t,就可以计算出发射点距障碍物的距离(s),即:s=340t/2 。更高端的雷达激光测距等也都是基于这个原理实现的测距。


        解了原理后,我们需要熟悉超声波模块的工作原理和使用方法。我使用的超声波模块型号为HY-SRF05,模块图如下    

image.png

        模块工作原理为:

     (1)采用IO触发测距,给至少10us的高电平信号;

          (2)模块自动发送8个40khz的方波,自动检测是否有信号返回;

     (3)有信号返回,通过IO输出一高电平,高电平持续的时间就是超声波从发射到返回的时间,测试距离=(高电平时间*声速(340M/S))/2;  

        使用方法为:一个控制口发一个10US以上的高电平,就可以在接收口等待高电平输出,一有输出就可以开定时器计时,当此口变为低电平时就可以读定时器的值,此时就为此次测距的时间,方可算出距离。


        于上面的情况了解,我准备通过外部中断配合定时器进行这次实验的实现。

            1、选择一个适合的例程去修改达到我们的目的,基于此我选择了外部中断的例程。这样对于我们前期的工作会减少很多,不建议一步一步来,很多时候我们会使用工具也是一种智慧。

            2、例程里使用的是PA0的外部中断来控制LED灯的亮灭,现在我们要修改外部中断的配置如下,这里主要修改了外部中断的触发模式。由原来的上升沿改为了上升和下降都出发中断,这样就可以在中断服务函数中得到高电平的时间。

            //外部中断0初始化

            void exint_line0_config(void)
            {
                exint_init_type exint_init_struct;

                crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
                crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

 

                gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOA, GPIO_PINS_SOURCE0);

                exint_default_para_init(&exint_init_struct);
                exint_init_struct.line_enable = TRUE;
                exint_init_struct.line_mode = EXINT_LINE_INTERRUPUT;
                exint_init_struct.line_select = EXINT_LINE_0;
                exint_init_struct.line_polarity = EXINT_TRIGGER_BOTH_EDGE;
                exint_init(&exint_init_struct);

 

                nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
                nvic_irq_enable(EXINT0_IRQn, 1, 0);
            }

 

            //定时器初始化,在这里配置为1s计数10000次,我们计算时间即可计算计数的个数

            void tmr1_config(void)
            {
                crm_clocks_freq_type crm_clocks_freq_struct = {0};

                /* get system clock */
                crm_clocks_freq_get(&crm_clocks_freq_struct);

                crm_periph_clock_enable(CRM_TMR1_PERIPH_CLOCK, TRUE);

                /* (systemclock / (system_core_clock/10000)) / 10000 = 1Hz(1s) */
                tmr_base_init(TMR1, 10000-1, system_core_clock/10000-1);
                tmr_cnt_dir_set(TMR1, TMR_COUNT_UP);
                tmr_clock_source_div_set(TMR1, TMR_CLOCK_DIV1);
                tmr_interrupt_enable(TMR1, TMR_OVF_INT, TRUE);
                
                nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
                nvic_irq_enable(TMR1_OVF_TMR10_IRQn, 1, 1);
            }
            

            //初始化超声波模块

            void HY_SRF05_init(void)
            {
                gpio_init_type gpio_init_struct;
                crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
                gpio_default_para_init(&gpio_init_struct);


                gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
                gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
                gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
                gpio_init_struct.gpio_pins = GPIO_PINS_1;
                gpio_init_struct.gpio_pull = GPIO_PULL_DOWN;
                gpio_init(GPIOA, &gpio_init_struct);
            }


            3、编写中断服务函数

            //定时器服务函数,理论上超声波模块不会引起定时器溢出中断,为了我们的调试方便这里我们加上溢出的LOG

            void TMR1_OVF_TMR10_IRQHandler(void)
            {
                //中断溢出标志
                if(tmr_flag_get(TMR1,TMR_OVF_FLAG) != RESET)
                {
                    at32_led_toggle(LED2);
                    printf("timer1 over flow!\r\n");
                    tmr_flag_clear(TMR1,TMR_OVF_FLAG);
                }
            }

 

            //外部中断服务函数,我们在中断之后获取电平,高电平就开始计数,低电平打印结果

            void EXINT0_IRQHandler(void)
            {
                if(exint_flag_get(EXINT_LINE_0) != RESET)
                {
                    if(gpio_input_data_bit_read(GPIOA, GPIO_PINS_0) == 1)
                    {
                        tmr_counter_value_set(TMR1, 0);//开始计数
                        tmr_counter_enable(TMR1, TRUE);
                    }
                    else
                    {
                        tmr_counter_enable(TMR1, FALSE); //停止计数
                        printf("timer1: %d\r\n",tmr_counter_value_get(TMR1)); //获取计数值
                        printf("%f m",(float)tmr_counter_value_get(TMR1)/10000 * 340 / 2);

                    }    
                    exint_flag_clear(EXINT_LINE_0);
                }
            }
            4、验证测量计时是否准确,我们可以先在循环里设置PA1以30ms的间隔进行翻转一下,然后PA1通过跳线帽连到PA0来测试计准确

            while(1)
            {
                gpio_bits_set(GPIOA, GPIO_PINS_1);    
                delay_ms(20);
                gpio_bits_reset(GPIOA, GPIO_PINS_1);    

                delay_ms(1000);
            }
image.png  

            结果非常准确的打印了计数的值,验证了通过外部中断来计算时间的可行性。

            5、接线验证,注意我这个的超声波模块为5V供电,我们接上电源、trig接到PA1、echo接到PA0。结果很成功,测试数据比较稳定。

         image.png  

 

    

 

本帖最后由 LYU4662 于 2022-8-8 16:46 编辑

回复评论 (8)

文章结构挺好,继续加油~

加油!在电子行业默默贡献自己的力量!:)
点赞  2022-8-8 17:35
引用: soso 发表于 2022-8-8 17:35 文章结构挺好,继续加油~

感谢

点赞  2022-8-8 17:40

超声波模块上用的驱动芯片是什么?

点赞  2022-8-9 08:58
引用: 秦天qintian0303 发表于 2022-8-9 08:58 超声波模块上用的驱动芯片是什么?

超声波主控和超声波控制芯片都被生产商磨掉了丝印,还有一个LM324运放在。

点赞  2022-8-9 09:27

想知道这款芯片的蓝牙性能如何。期待测评~

点赞  2022-8-9 10:32

这种模块最远能测多远啊,这个开发板就是引脚太少,已经很强悍了

点赞  2022-8-9 11:03
引用: qzc飘曳 发表于 2022-8-9 11:03 这种模块最远能测多远啊,这个开发板就是引脚太少,已经很强悍了

测距范围2-450cm 精度3mm 超声波模块主要用在小车上,起到遇到障碍物会停止的的作用

点赞  2022-8-9 13:19
引用: LYU4662 发表于 2022-8-9 09:27 超声波主控和超声波控制芯片都被生产商磨掉了丝印,还有一个LM324运放在。

这就不地道了,这种方案也不少

点赞  2022-8-9 15:49
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复