打印
[CW32F030系列]

【CW32F030CxTx StartKit开发板】利用超声波传感器实现智能灯控

[复制链接]
1364|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 zealsoft 于 2024-6-29 19:00 编辑

#有奖活动#
感谢21ic和武汉芯源提供的测试机会。
在上一篇帖子中介绍了CW32F030CxTxStartKit 评估板的环境构建。本次介绍如何利用超声波传感器实现人来灯亮,人走灯灭的智能灯控。

1、超声波传感器
HC-SR04是一款广泛使用的超声波测距模块,特别适用于机器人、无人车等领域。它利用超声波的发射和接收原理,通过测量超声波从发射到接收的时间来计算物体与传感器之间的距离。
HC-SR04的工作原理基于超声波的发射和接收。它主要由两个压电陶瓷片组成,其中一个用于发射超声波(T),另一个用于接收反射回来的超声波信号(R)。工作时,Trig引脚(触发端)发送一个10us的高电平信号,模块内部随后发出8个40KHZ的周期电平信号,并自动检测是否有信号返回。当有信号返回时,Echo引脚(接收端)会输出一个高电平信号,其脉冲宽度与所测距离成正比。
2、硬件连线
CW32F030CxTxStartKit 评估板把所有I/O口都引出来了,有个好处就是可以方便地进行接口之间的连接,做各种测试。我们把PA01连接到Trig引脚,将PA02连接到Echo引脚。同时将HC-SR04的VCC和GND引导开发板的VDD和GND上。

3. 程序开发
3.1 超声波测距
使用HC-SR04时,只需提供一个10uS以上的脉冲触发信号,模块内部将自动发出超声波并检测回波。通过测量Echo引脚高电平持续的时间,结合声速(340m/s),即可计算出物体与传感器之间的距离。具体计算公式为:距离 = (高电平时间 * 声速) / 2。
在程序中我们开启了BTIM1定时器,并在其中断函数中进行计时,从而用于测量Echo引脚高电平持续的时间。主要的程序代码如下:
//UARTx
#define  DEBUG_USARTx                   CW_UART1
#define  DEBUG_USART_CLK                RCC_APB2_PERIPH_UART1
#define  DEBUG_USART_APBClkENx          RCC_APBPeriphClk_Enable2
#define  DEBUG_USART_BaudRate           9600
#define  DEBUG_USART_UclkFreq           8000000

//UARTx GPIO
#define  DEBUG_USART_GPIO_CLK           RCC_AHB_PERIPH_GPIOA
#define  DEBUG_USART_TX_GPIO_PORT       CW_GPIOA
#define  DEBUG_USART_TX_GPIO_PIN        GPIO_PIN_8
#define  DEBUG_USART_RX_GPIO_PORT       CW_GPIOA
#define  DEBUG_USART_RX_GPIO_PIN        GPIO_PIN_9

//GPIO AF
#define  DEBUG_USART_AFTX               PA08_AFx_UART1TXD()
#define  DEBUG_USART_AFRX               PA09_AFx_UART1RXD()

#define LED_GPIO_PORT CW_GPIOB
#define LED_GPIO_PINS GPIO_PIN_8 | GPIO_PIN_9

#define SetTrig()    PA01_SETHIGH()
#define ResetTrig()  PA01_SETLOW()
#define ReadEcho()   GPIO_ReadPin(CW_GPIOA, GPIO_PIN_2)

/******************************************************************************
* Global variable definitions (declared in header file with 'extern')
******************************************************************************/
extern unsigned int time;

/******************************************************************************
* Local type definitions ('typedef')
******************************************************************************/

/******************************************************************************
* Local function prototypes ('static')
******************************************************************************/

/******************************************************************************
* Local variable definitions ('static')                                      *
******************************************************************************/
void RCC_Configuration(void);
void GPIO_Configuration(void);
void UART_Configuration(void);
unsigned int Measure_Distance(void);

#ifdef __GNUC__
    /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
    set to 'Yes') calls __io_putchar() */
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
    #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */

BTIM_TimeBaseInitTypeDef BTIM_TimeBaseInitStruct;
               
/******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/

/*****************************************************************************
* Function implementation - global ('extern') and local ('static')
******************************************************************************/


void BTIM_Init(void)
{
        RCC_APBPeriphClk_Enable2(RCC_APB2_PERIPH_BTIM, ENABLE);  //使能APB外设时钟
        
        BTIM_TimeBaseInitTypeDef BTIM_Initstruct;
        BTIM_Initstruct.BTIM_Mode = BTIM_Mode_TIMER;  //工作模式-->定时模式
        BTIM_Initstruct.BTIM_OPMode = BTIM_OPMode_Repetitive;//连续计数模式
        BTIM_Initstruct.BTIM_Period = 80-1;  //计数重载周期,16bit自动重载寄存器ARR,ARR的值最大为65535
        BTIM_Initstruct.BTIM_Prescaler = BTIM_PRS_DIV8;        //预分频
        BTIM_TimeBaseInit(CW_BTIM1, &BTIM_Initstruct);
        //定时时长=预分频/计数器时钟源频率*(计数重载周期+1),即T=8/64000000*800s=10us
        BTIM_ITConfig(CW_BTIM1, BTIM_IT_OV, ENABLE); //设置ARR溢出引发中断
        BTIM_Cmd(CW_BTIM1, ENABLE); //BTIM使能
        NVIC_EnableIRQ(BTIM1_IRQn);//中断使能
}

/**
* [url=home.php?mod=space&uid=247401]@brief[/url] 配置RCC
*
*/
void RCC_Configuration(void)
{
        //SYSCLK = HSI = 8MHz = HCLK = PCLK
    RCC_HSI_Enable(RCC_HSIOSC_DIV6);
    //外设时钟使能
    RCC_AHBPeriphClk_Enable(DEBUG_USART_GPIO_CLK, ENABLE);
    __RCC_BTIM_CLK_ENABLE();
                DEBUG_USART_APBClkENx(DEBUG_USART_CLK, ENABLE);
}


/**
* [url=home.php?mod=space&uid=247401]@brief[/url] 配置GPIO
*
*/
void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    RCC_HSI_Enable(RCC_HSIOSC_DIV6);
    __RCC_GPIOB_CLK_ENABLE();
    GPIO_InitStruct.IT = GPIO_IT_NONE;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pins = LED_GPIO_PINS;
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
    GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct);

    __RCC_GPIOA_CLK_ENABLE();
    GPIO_InitStruct.IT = GPIO_IT_NONE;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pins = GPIO_PIN_1; // Trig引脚初始化
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
    GPIO_Init(CW_GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pins = GPIO_PIN_2; // Echo引脚初始化
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT_PULLDOWN;
    GPIO_InitStruct.IT   = GPIO_IT_NONE;
    GPIO_Init(CW_GPIOA, &GPIO_InitStruct);
        
           GPIO_InitTypeDef GPIO_InitStructure;
    //UART TX RX 复用
    DEBUG_USART_AFTX;
    DEBUG_USART_AFRX;
    GPIO_InitStructure.Pins = DEBUG_USART_TX_GPIO_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
    GPIO_InitStructure.Pins = DEBUG_USART_RX_GPIO_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
    GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
}

unsigned int Measure_Distance(void) //测距
{
        unsigned int distance=0;
        
        SetTrig();     //10us的脉冲触发信号
        delay10us(1);
        ResetTrig();
        while(ReadEcho() == 0); //等待Echo输出高电平
        time = 0;               //开始记录回波信号脉宽
        while(ReadEcho() == 1); //等待Echo输出低电平           
        distance = time * 1.7;//根据声速和时间计算距离,即distance=time*340/2/100
        /*
                        关于分辨力(mm):
                                        定时器每次对time加1是10us,10us=0.01ms,340m/s=340mm/ms
                                        计算距离时,最小分辨力为:0.01(ms) * 340(mm/ms) / 2 = 1.7(mm)
                                        小于模块标准精度3mm,故测距结果十分精准
        */
        return distance; //返回距离,单位mm
}
在interrupts_cw32f030.c中加入如下代码:
unsigned int time = 0;

/**
* [url=home.php?mod=space&uid=247401]@brief[/url] This funcation handles BTIM1
*/
void BTIM1_IRQHandler(void)
{
    /* USER CODE BEGIN */
                if(BTIM_GetITStatus(CW_BTIM1,BTIM_IT_OV))  
                {
                        BTIM_ClearITPendingBit(CW_BTIM1,BTIM_IT_OV); //清除标志位
                        time++;
                }
                /* USER CODE END */
}
3.2 LED控制
我们在while循环中不断进行测距工作,当发现测量的距离值小于100mm,就认为有人靠近,从而打开LED灯,否则就关闭LED灯。
代码如下:
  unsigned int distance;
    while (1)
    {
                                distance = Measure_Distance();
                                printf("Distance is : %dmm\r\n", distance);
                          if(distance > 100)
                                {
                                                GPIO_WritePin(LED_GPIO_PORT, LED_GPIO_PINS, GPIO_Pin_RESET);
                                }
                                else
                                {
                                                GPIO_WritePin(LED_GPIO_PORT, LED_GPIO_PINS, GPIO_Pin_SET);
                                }
                                delay1ms(500);
    }
完整的代码可以点此下载: hrsr04.zip (1.49 MB)
4. 演示视频
演示视频已经发在B站了:【CW32+超声波传感器实现智能灯控】

使用特权

评论回复
沙发
AdaMaYun| | 2024-7-9 13:58 | 只看该作者
超声波的测量精度大概是多少?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

6

帖子

1

粉丝