基于stm32f103c8t6的智能垃圾桶 |
您所在的位置:网站首页 › 智能垃圾桶简介20字 › 基于stm32f103c8t6的智能垃圾桶 |
这个垃圾桶的功能效果和51的那个一样,但是实现的方式不一样,都可以由距离,震动,按键触发垃圾桶开盖子。 一、硬件介绍 名称图片功能超声波模块![]() ![]() ![]() ![]() 二、代码部分 代码分了两部分,一部分是手写的(手写的我用淡蓝色的标记了),一部分是在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如下图设置
关于时基单元的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 |