历时一个多月的学习,掌握了HAL库的GPIO,中断,定时器最基础的外设。也学习了一些模块的使用,振动传感器,超声波传感器,舵机等等。利用开源小项目检验所学知识,熟练运用。

项目要求:几个事件触发打开垃圾桶并闪灯并蜂鸣器响,打开2秒后关闭垃圾桶,事件一:按下按钮,事件二:检测到震动,事件三:有物体靠近

思路:各个模块分别调试,最后集中在主函数main里。

1.LED,使用GPIO,输出低电平点亮,输出高电平熄灭。运用GPIO端口输出。

2.蜂鸣器,类似LED,低电平响,高电平不向。

3.按键,运用GPIO端口输入,检测按下,置一标志位,代表按下。

4.震动传感器,需要运用中断,检测到震动则在中断里配置震动标志位,配置GPIO模式为IT_Falling,意思为检测到低电平则会进入中断。

5.超声波传感器,HCSR04,用定时器来计算超声波来回的时间,进而算出距离。

6.舵机SG90,定时器输出比较,输出PWM波,控制舵机转动。

在main函数中初始化各个模块,检测到对应的打开垃圾桶条件,那么控制舵机打开垃圾桶,灯亮蜂鸣器响,否则控制舵机关闭垃圾桶。

遇到的问题

1.舵机在单独的程序中可以有效运行,但是在项目中作为一个模块使用不能有效运行。检查各个模块代码发现,舵机的定时器和超声波传感器的定时器用的同一个,这样一来,在主函数初始化的时候,后初始化的模块的定时器参数会覆盖前一个初始化的模块,导致前一个模块的定时器错误。于是改变超声波传感器的定时器,解决了问题。注意:不能改变舵机的定时器,因为舵机接线对应的端口是PA6,对应了定时器3的第一通道,而超声波传感器只是需要一个定时功能。

2.运行一段时间后,程序卡死不动。可能原因是主函数while循环里一直在检测垃圾桶开启条件,可能出问题。通过在while里延时10ms,解决此问题。

3.在垃圾桶打开时,若继续给触发开启的条件,蜂鸣器则会再次响,灯会再亮,这是不想要的。解决方法,添加垃圾桶的状态标志位,每此开启垃圾桶的时候,判断垃圾桶状态是不是关闭,若是,则打开垃圾桶。

下例部分代码:

超声波传感器模块

#include "hcsr04.h"
#include "delay.h"

TIM_HandleTypeDef tim2_handle = {0};

//定时器初始化函数
void tim2_init(void)
{
    tim2_handle.Instance = TIM2;
    tim2_handle.Init.Prescaler = 72 - 1;
    tim2_handle.Init.Period = 65536 - 1;
    tim2_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
    tim2_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    HAL_TIM_Base_Init(&tim2_handle);
}

//msp函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM2)
    {
        __HAL_RCC_TIM2_CLK_ENABLE();
    }
}

void tim2_start(void)
{
    HAL_TIM_Base_Start(&tim2_handle);
}

void tim2_stop(void)
{
    HAL_TIM_Base_Stop(&tim2_handle);
}

uint16_t tim2_get_cnt(void)
{
    return __HAL_TIM_GetCounter(&tim2_handle);
}

void tim2_set_cnt(uint16_t val)
{
    __HAL_TIM_SetCounter(&tim2_handle, val);
}

void hcsr04_gpio_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    TRIG_GPIO_CLK_ENABLE();
    ECHO_GPIO_CLK_ENABLE();
    
    //初始化Trig引脚
    gpio_initstruct.Pin = TRIG_PIN;
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;             
    gpio_initstruct.Pull = GPIO_NOPULL;                     
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;           
    HAL_GPIO_Init(TRIG_PORT, &gpio_initstruct);
    
    gpio_initstruct.Pin = ECHO_PIN;
    gpio_initstruct.Mode = GPIO_MODE_INPUT;             
    HAL_GPIO_Init(ECHO_PORT, &gpio_initstruct);
}

void hcsr04_init(void)
{
    tim2_init();
    hcsr04_gpio_init();
}

float hcsr04_get_length(void)
{
    uint16_t total_time = 0;
    float distance = 0;

    //1. Trig,给Trig端口至少10us的高电平
    TRIG_HIGH();
    delay_us(15);
    TRIG_LOW();

    //2. Echo引脚,由低电平跳转到高电平,表示开始发送波
        //波发出去的那一下,开始启动定时器
    while(ECHO_STATUS() == GPIO_PIN_RESET);
    tim2_start();
    tim2_set_cnt(0);

    //3. Echo,由高电平跳转回低电平,表示波回来了
        //波回来的那一下,我们开始停止定时器,计算出中间经过多少时间
    while(ECHO_STATUS() == GPIO_PIN_SET);
    tim2_stop();

    //4. 计算出中间经过多少时间
    total_time = tim2_get_cnt();

    //5. 距离 = 速度(343m/s) * 时间 / 2
    distance = total_time * 0.01715;
    return distance;
}
 

舵机模块

#include "sg90.h"


TIM_HandleTypeDef tim3_handle = {0};
// init函数
void tim3_init(void)
{
    TIM_OC_InitTypeDef pwm_config = {0};
    
    tim3_handle.Instance = TIM3;
    tim3_handle.Init.Prescaler = 7200 - 1;
    tim3_handle.Init.Period = 200 - 1;
    tim3_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
    HAL_TIM_PWM_Init(&tim3_handle);
    
    pwm_config.OCMode = TIM_OCMODE_PWM1;
    pwm_config.Pulse = 100;
    pwm_config.OCPolarity = TIM_OCPOLARITY_HIGH;
    HAL_TIM_PWM_ConfigChannel(&tim3_handle, &pwm_config, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&tim3_handle, TIM_CHANNEL_1);
}


//msp函数
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM3)
    {
        GPIO_InitTypeDef gpio_initstruct;
        //打开时钟
        __HAL_RCC_GPIOA_CLK_ENABLE();                           // 使能GPIOB时钟
        __HAL_RCC_TIM3_CLK_ENABLE();
        
        //调用GPIO初始化函数
        gpio_initstruct.Pin = GPIO_PIN_6;                    // 两个LED对应的引脚
        gpio_initstruct.Mode = GPIO_MODE_AF_PP;             // 推挽输出
        gpio_initstruct.Pull = GPIO_PULLUP;                     // 上拉
        gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;           // 高速
        HAL_GPIO_Init(GPIOA, &gpio_initstruct);
    }
}


//修改CCR值的函数
void tim3_compare_set(uint16_t val)
{
    __HAL_TIM_SET_COMPARE(&tim3_handle, TIM_CHANNEL_1, val);
}

void sg90_init(void)
{
    tim3_init();
}

void sg90_angle_set(uint16_t angle)
{
    uint16_t CCRx = (1.0 / 9.0) * angle + 5.0;
    tim3_compare_set(CCRx);
}
 

主函数

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "beep.h"
#include "exti.h"
#include "hcsr04.h"
#include "key.h"
#include "sg90.h"

#define OPEN 1
#define CLOSE 0

uint8_t dustbin_status = CLOSE;

void open_dustbin(void)
{
    if(dustbin_status == CLOSE)
    {
        sg90_angle_set(30);
        beep_on();
        led1_on();
        delay_ms(100);
        beep_off();
        led1_off();
        dustbin_status = OPEN;
    }
}

void close_dustbin(void)
{
    sg90_angle_set(0);
    beep_off();
    led1_off();
    dustbin_status = CLOSE;
}

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    led_init();                         /* 初始化LED灯 */
    uart1_init(115200);
    beep_init();
    exti_init();
    hcsr04_init();
    key_init();
    sg90_init();
    printf("hello world!\r\n");

    uint8_t key_num = 0;
    while(1)
    { 
        key_num = key_scan();
        if(key_num == 1 || vibrate_flag_get() == TRUE || hcsr04_get_length() < 10)
        {
            open_dustbin();
            delay_ms(2000);
            vibrate_flag_set(FALSE);
        }
        else
            close_dustbin();
        delay_ms(10);

        }

}

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐