基于stm32f103c8t6的智能垃圾桶

您所在的位置:网站首页 智能垃圾桶简介20字 基于stm32f103c8t6的智能垃圾桶

基于stm32f103c8t6的智能垃圾桶

2024-07-12 14:00| 来源: 网络整理| 查看: 265

这个垃圾桶的功能效果和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个小时,如果你做的话,引以为戒吧。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3