当前位置:   article > 正文

基于stm32f103c8t6的智能垃圾桶_智能垃圾桶 csdn

智能垃圾桶 csdn

这个垃圾桶的功能效果和51的那个一样,但是实现的方式不一样,都可以由距离,震动,按键触发垃圾桶开盖子。

一、硬件介绍

名称图片功能
超声波模块避障模式时测量距离。这个模块具体的简绍可以看http://t.csdnimg.cn/uFgqP
舵机与超声波模块配合使用,使超声波向前左右扭头测距。可以用PWM波形来控制它的转动角度。
振动传感器单片机供电5V, GND接单片机 ,电源指示灯亮。发生震动时,信号指示灯会亮,同时AO口输出低电平。无震动时,信号指示灯不亮,同时AO口输出高电平。
蜂鸣器单片机供电3.3V, GND接单片机. 。单片机引脚·发出低电平时蜂鸣器报警,高电平时,蜂鸣器不叫。

二、代码部分

代码分了两部分,一部分是手写的(手写的我用淡蓝色的标记了),一部分是在stm32cube上设置后,软件生成的。

#include "main.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
#define OPEN 1
#define CLOSE 0
/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
char flag = CLOSE;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
//使用TIM2来做us级延时函数
void TIM2_Delay_us(uint16_t n_us)
{
    /* 使能定时器2计数,HAL库没有us函数,因此要自己写,我们把PSC的只改成71,就可以实现1us计数一次,原因在下面我会说 */
    __HAL_TIM_ENABLE(&htim2);
    __HAL_TIM_SetCounter(&htim2, 0);
    while(__HAL_TIM_GetCounter(&htim2) < ((1 * n_us)-1) );
    /* 关闭定时器2计数 */
    __HAL_TIM_DISABLE(&htim2);
}

double get_distance()
{
        int cnt=0;//数值代表时间
        //1. Trig ,给Trig端口至少10us的高电平,,让超声波模块开始工作
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);//拉高
        TIM2_Delay_us(15);
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);//拉低

        //2. echo由低电平跳转到高电平,表示开始发送波
        //波发出去的那一下,开始启动定时器
        while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) == GPIO_PIN_RESET);//等待输入电平拉高
        HAL_TIM_Base_Start(&htim2);
        __HAL_TIM_SetCounter(&htim2,0);//每一次开始测距时,把定时器二的CNT清零

        //3. 由高电平跳转回低电平,表示波回来了
        while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) == GPIO_PIN_SET);//等待输入电平变低
        //波回来的那一下,我们开始停止定时器
        HAL_TIM_Base_Stop(&htim2);

        //4. 计算出中间经过多少时间
        cnt = __HAL_TIM_GetCounter(&htim2);

        //5. 距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
        return (cnt*0.034); //单位换算后面我写的有
}

void openStatusLight()
{
    //点亮LED1
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
}

void closeStatusLight()
{
    //熄灭LED1
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
}

void initSG90_0()
{
    HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_4); //启动定时器4
    __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 5); //__HAL_TIM_SetCompare,
在运行时设置TIM捕获比较寄存器值,这里CCR=5,将舵机置为0度
}

void openDusbin()
{
    if(flag == CLOSE)
    {
        flag = OPEN;
        __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 15); //将舵机置为90度
        HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_RESET);
        HAL_Delay(100);
        HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_SET);
    }
    HAL_Delay(2000);
}

void closeDusbin()
{
    __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 5); //将舵机置为0度
    flag = CLOSE;
    HAL_Delay(150);
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if(GPIO_Pin == GPIO_PIN_0 || GPIO_Pin == GPIO_PIN_5)
    {
        if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET ||   //按键
            HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_5) == GPIO_PIN_RESET)    // 震动传感器
        {
            openStatusLight();
            openDusbin();
        }
    }
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
    float distance;
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_TIM4_Init();
  /* USER CODE BEGIN 2 */
    initSG90_0();
    HAL_NVIC_SetPriority(SysTick_IRQn,0,0);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
        //超声波测距
        distance = get_distance();
        if(distance < 10){
            //点亮LED1
      openStatusLight();
            //开盖
            openDusbin();
        }else{
            //熄灭LED1
            closeStatusLight();
            //关盖
            closeDusbin();
        }
  }

  /* USER CODE END 3 */
}

三、stm32cube上的设置

   SYS里,debug选择Serial Wire为st-link下载器用。RCC里,选择High Speed Clock(HSE),配置为Crystal/Ceramic Resonator,然后在Clock Configuration里按下图配置

GPIO的配置如下

PA0对应单片机按键1   PB4对应蜂鸣器   PB5接振动传感器  PB6接Trig   PB7接Echo   PB8对应单片机LED1  PB9接舵机

        PA0和PB5要作为外部触发中断使用,当按键按下,来一个低电平给单片机PA0,触发中断,垃圾桶打开;当发生震动,传感器来一个低电平给单片机PB5,触发中断,垃圾桶打开。

超声波配置

测距需要时间,还需速度,声波的速度是340m/s,换算单位就是0.034cm/us。时间怎么计算呢?

这时候就需要用定时器了,将定时器2如下图设置

时钟源来自系统的72MHz,分频器PSC设置为71,自动重装使能。

关于时基单元的PSC,CNT和ARR,我说说我的理解

    对于预分频器PSC,它就是一个改变计数时间寄存器,在你不分频(即PSC=0)的时候以72MHz/(0+1)的频率计数;当你的PSC=71时,你要以72MHz/(71+1)的频率计数,也就是每隔1us计数一次,CNT加一。自动装载寄存器ARR是你设置的计数上限,达到这个值之后就要将CNT置零。

   所以所谓的定时中断,不过是你通过改变PSC来改变计一个数的时间,然后输入ARR的值再规定记到多少个数字停止。就比如你要定时1s中断,你就可以改变PSC的值,使CNT每隔20毫秒加一,将ARR设置为49,打开中断通道,这样过20ms*(49+1)就实现1s可以计时了。ARR之所以要加以是因为0到49有50个数。

回到定时器2,我们将它的PSC=71,这样就可以实现1us记一个数了,定时器2的CNT每加一就代表时间增加1us。至于ARR,我们不用管,在有限距离内,ARR不会爆表。(为什么不会爆表,可以看一下这里http://t.csdnimg.cn/wbIWW).

     接着说舵机,图上的舵机的驱动频率是50Hz,周期也是就20ms。舵机想要改变角度,就要控制一个钟期内高电平的占用时间,也就是我们说的占空比。

一个周期内,高电平占用时间对应的旋转角度

回到定时器4,配置如下图

对于时基单元的配置我不说了,无论你想咋配置,只要能配制出20ms就行。关于PWM Generation下面的东西,大家可以出一下手册,了解一下,中文手册在255页。

我要说的是角度的事,按照我上面写的ARR=199,也就是说,ARR从0到199,计数200次后就要自动变成0。

在PWM模式1:在向上计数时,一旦 CNT < CCRx 时输出为有效电平,否则为无效电平; 在向 下计数时,一旦 CNT > CCRx 时输出为无效电平即低电平,否则为有效电平。说白了就是CCR是个门槛,是高低电平的分水岭。

这里的,你可以发现CCR越接近ARR,一个周期里,高电平持续时间越长。所以高电平的持续时间与CCR的值成正比,如果ARR=CCR,则整个周期都是高电平。要想舵机达到0度,则要有持续时间0.5ms的高电平,则ARR从0到199共200份,CCR要占到5份,其余的角度以此类推。

四、其它

   这就要说一个很傻逼的事了,是振动传感器的,本来在51上面,他的灵敏度是可以的,但是我也没想到到了32上,原来的灵敏度就不行了。等我把程序写好,硬件安好后,舵机就像神经了一样,不受控制过两秒自己动,过两秒自己动,刚开始我以为是我代码有问题,导致死机了,后来我一点一点排查,我发现把振动传感器控制开盖去掉就好了,我才意识到是震动传感器出了问题。但说实话,我也没想到是灵敏度的问题,知道我看见震动模块的灯一直闪,我才有意无意的调了一下灵敏度,没想到竟然阴差阳错好了。折磨了我快3个小时,如果你做的话,引以为戒吧。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/560119
推荐阅读
相关标签
  

闽ICP备14008679号