基于STM32F103c8t6的智能垃圾桶项目
Posted 林三三三三
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于STM32F103c8t6的智能垃圾桶项目相关的知识,希望对你有一定的参考价值。
基于STM32F103c8t6的智能垃圾桶项目
写在前头
本人新手小白,写这个文章完全是纪念自己第一个小项目,如有不足之处还请多多指教,谢谢!
先上图。
软件配置
本文主要用的编译软件为keil5,软件配置的部分可参考以下文章(文章也包括了烧录的部分)。《Keil5配置STM32F103C8T6》
硬件部分
以STM32F103c8t6的最小系统板为核心,配合HC-SR04超声波模块、SG90舵机以及一个0.96寸的IIC接口的OLED显示屏。当然还有若干的杜邦线及一个垃圾桶模型,模块固定部分可自行发挥。
1. 主控芯片
以STM32F103c8t6芯片为核心的最小系统板,实物图就如下所示,来源是淘宝。
关于STM32F103c8t6芯片本文就不加以介绍,可参考以下文章。《STM32F103C8T6初学笔记》
2. HC-SR04超声波模块
模块简介
HC-SR04超声波模块常用于机器人避障、物体测距、液位检测、公共安防、停车场检测等场所。HC-SR04超声波模块主要是由两个通用的压电陶瓷超声传感器,并加外围信号处理电路构成的。如图:
模块参数
1) 模块主要参数
① 使用电压:DC—5V
② 静态电流:小于2mA
③ 电平输出:高5V
④ 电平输出:底0V
⑤ 感应角度:不大于15度
⑥ 探测距离:2cm-450cm
⑦ 高精度 可达0.2cm
2) 模块引脚
超声波模块有4个引脚,分别为Vcc(电源+)、GND(接地)、 Trig(控制端)、 Echo(接收端);其中Vcc接上5V电源,GND接地, Trig(控制端)控制发出的超声波信号,Echo(接收端)接收反射回来的超声波信号。
工作原理
a.单片机引脚触发Trig测距,给至少 10us 的高电平信号;
b.模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;
c.有信号返回,通过 IO 输出一高电平,并单片机定时器计算高电平持续的时间;
d.超声波从发射到返回的时间.
计算公式:测试距离=(高电平时间*声速(340M/S))/2;
简单来说,就是超声波模块发出声波信号,同时定时计数器器开始计时,声波信号在遇到障碍物后返回。采集到返回的声波信号后,模块输出一个高电平信号,相应配合的定时计数器停止计时,最后通过超声波在空气中的传递规律公式计算出障碍物的距离。
GPIO配置
HC-SR04 | C8T6芯片引脚 |
---|---|
GND | GND |
Vcc | 5V |
Echo | PB7 |
Trig | PB8 |
3. SG90舵机
模块简介
舵机是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。目前,在高档遥控玩具,如飞机、潜艇模型,遥控机器人中已经得到了普遍应用。如图:
模块参数
1) 模块主要参数
① 死区设定:7us (7MHZ)
② 工作电压:4.8V-6V
③ 位置等级:1024级
④ 脉冲控制精度为2us
⑤ 尺寸:21.5mmX11.8mmX22.7mm
⑥ 重量:9克 (1kg=1公斤=2斤)
⑦ 无负载速度:0.12秒/60度(4.8V) 0.002s/度
⑧ 堵转扭矩:1.2-1.4公斤/厘米(4.8V)
⑨ 使用温度:-30~~+60摄氏度
2) 模块引脚
SG90模块有三个引脚,信号引脚(橙色)、Vcc(红色)及GND(棕色);在使用过程中,信号引脚与单片机输出PWM信号的引脚相连接,Vcc与电源+5V相连接,GND接地。
工作原理
SG90的工作原理是采用PWM控制的方式来进行舵机的操纵,主要是让板子产生一个20ms的脉冲信号,以0.5ms到2.5ms的高电平来控制舵机的角度。以180度角度伺服为例,那么对应的控制关系如下:
0.5ms-------------0度; 2.5% 对应函数中占空比为250
1.0ms------------45度; 5.0% 对应函数中占空比为500
1.5ms------------90度; 7.5% 对应函数中占空比为750
2.0ms-----------135度; 10.0% 对应函数中占空比为1000
2.5ms-----------180度; 12.5% 对应函数中占空比为1250
详细的舵机使用原理可参考《舵机使用基础(SG90模拟舵机和MG90S数字舵机为例)》
GPIO配置
SG90舵机 | C8T6芯片引脚 |
---|---|
GND(棕色) | GND |
Vcc(红色) | 5V |
信号线(橙色) | PA1 |
3. OLED显示屏
模块简介
OLED,即有机发光二极管( Organic Light Emitting Diode)。 OLED 由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。如图:
模块参数
1) 模块主要参数
① 尺寸:0.96 (inch)
② 工作电压:3.3V/5V
③ 高分辨率: 128x64
④ 有效显示区域: 21.744x10.864(mm)
⑤ 模块尺寸: 27.3x27.8(mm)
⑥ 视角:>160°
⑦ 重量:15克
⑧ OLED驱动芯片:SSD1306
⑨ 功耗: 全亮约为25mA,全灭约为1.5mA
⑩ 使用温度:-20~~+70摄氏度
数据来源LCD wiki
2) 模块引脚
0.96寸OLED显示屏(IIC)有四个引脚,GND (接地)、 Vcc (电源+)、SCL OLED 的 D0 脚、SDA OLED 的 D1 脚。在使用过程中,Vcc接电源+3.3V(或+5V),GND接地, D0引脚,在 IIC 通信中为时钟管脚,D1引脚,在 IIC 通信中为数据管脚,接相应的GPIO口。
工作原理
本屏所用的驱动 IC 为 SSD1306;其具有内部升压功能;当然了本屏也可以选用外部升压,具体的请详查数据手册。SSD1306 控制器用1bit控制一个像素点显示。所以每个像素点只能显示黑白两色。其显示的RAM总共分为8页,每页有8行,每行128个像素点。设置像素点数据时,需要指定页地址,再分别指定列低地址跟列高地址,所以每次同时设置垂直方向的8个像素点。为了能够灵活控制任意任意位置的像素点,软件上先设置一个设置一个和RAM一样大小的全局一维数组,先将像素点数据设置到全局数组中,此过程采用或、与操作保证之前写入全局数组的数据不受破坏,然后将全局数组的数据写入到显示RAM中,这样就可以通过OLED显示出来了。
GPIO配置
OLED显示屏 | C8T6芯片引脚 |
---|---|
GND | GND |
Vcc | 3.3V |
SCL | PA5 |
SDA | PA7 |
软件部分
HC-SR04超声波代码
#include "hc-sr04.h"
uint count = 0;
// Set NVIC
void NVIC_Config(void){
NVIC_InitTypeDef NVIC_InitStructer;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructer.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructer.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructer.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructer.NVIC_IRQChannel = TIM2_IRQn;
NVIC_Init(&NVIC_InitStructer);
}
/*HC-SR04 GPIO TIM3*/
void HC_SR04_init(void){
GPIO_InitTypeDef GPIO_InitStructer;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructer;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/*TRIG PB8*/
GPIO_InitStructer.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructer.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructer.GPIO_Pin = HCSR04_TRIG;
GPIO_Init(HCSR04_PORT, &GPIO_InitStructer);
/*ECOH PB7*/
GPIO_InitStructer.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_InitStructer.GPIO_Pin = HCSR04_ECHO;
GPIO_Init(HCSR04_PORT, &GPIO_InitStructer);
/*定时器TIM3初始化*/
TIM_DeInit(TIM3);
TIM_TimeBaseInitStructer.TIM_Period = 999; //计数到1000为1ms
TIM_TimeBaseInitStructer.TIM_Prescaler = 71; //1M的计数频率 1us计数
TIM_TimeBaseInitStructer.TIM_ClockDivision = TIM_CKD_DIV1; //不分频
TIM_TimeBaseInitStructer.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructer);
TIM_ClearFlag(TIM3, TIM_FLAG_Update); // 清除中断更新
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); // 打开定时器更新中断
NVIC_Config();
TIM_Cmd(TIM3, DISABLE);
}
/*测距部分*/
float Count_Dist(void)
{
float distance = 0, sum = 0;
uint16_t time;
uint i = 0;
while(i < 5)
{
GPIO_SetBits(HCSR04_PORT, HCSR04_TRIG);
delay_us(20);
GPIO_ResetBits(HCSR04_PORT, HCSR04_TRIG);
while(GPIO_ReadInputDataBit(HCSR04_PORT, HCSR04_ECHO) == 0);//回响信号出现
TIM_Cmd(TIM3, ENABLE); //打开定时器
i += 1;
while(GPIO_ReadInputDataBit(HCSR04_PORT, HCSR04_ECHO) == 1); //回响信号消失
TIM_Cmd(TIM3,DISABLE); //关闭定时器
time = TIM_GetCounter(TIM3); //获取TIM3计数值
distance = (time + count*1000)/58.0; //通过回响计算距离
sum = distance + sum; //五次结果相加
TIM3->CNT = 0; //TIM3清零
count = 0; //中断溢出次数清零
delay_ms(10);
}
distance = sum/5; //取5次的平均值
return distance;
}
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //??????
count++;
}
}
SG90舵机代码
#include "sg90.h"
void SG90_pwm_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* 开启时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
/* 配置GPIO 选择GPIOA_1 */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;// PA1
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure);
//TIM2定时初始化
TIM_TimeBaseInitStructure.TIM_Period = 199; //PWM 频率=72000/(199+1)=36Khz
TIM_TimeBaseInitStructure.TIM_Prescaler = 7199;//设置TIM2预分频
TIM_TimeBaseInitStructure.TIM_ClockDivision = 0;//时钟分割:TDTS = Tck_tim
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM2向上计数
TIM_TimeBaseInit(TIM2, & TIM_TimeBaseInitStructure);
//PWM初始化
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//PWM使能输出
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OC2Init(TIM2,&TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);//使能TIM2在CCR1上的预装载寄存器
TIM_Cmd(TIM2,ENABLE);//使能TIM2外设
}
显示屏代码
由于显示屏的代码过于冗长,可参考中景园电子的0.96寸显示屏代码,这里对本项目修改的部分进行演示。首先讲解汉字取模的过程:
① 打开取模软件,然后模式选择字符模式,然后点击选项
② 汉字取模设置如下,点击确定
③ 在红框内输入要取模的汉字,然后点击生成字模
讲完怎么取模后,针对本项目需要的字进行取模。
显示屏主要显示垃圾桶的状态及障碍物的距离,因此需要显示的文字为“垃圾桶:开关距离为:”。
{0x20,0x20,0x20,0xFF,0x20,0x20,0x10,0x90,0x11,0x16,0x10,0x10,0xD0,0x10,0x00,0x00},
{0x10,0x30,0x10,0x0F,0x08,0x48,0x40,0x41,0x5E,0x40,0x70,0x4E,0x41,0x40,0x40,0x00},/*"垃",0*/
/* (16 X 16 , ?? )*/
{0x20,0x20,0x20,0xFF,0x20,0x22,0x02,0xFE,0x02,0x02,0x62,0x5A,0x46,0xC0,0x00,0x00},
{0x08,0x18,0x08,0x07,0x44,0x34,0x8E,0x81,0x46,0x28,0x10,0x28,0x46,0x81,0x80,0x00},/*"圾",1*/
/* (16 X 16 , ?? )*/
{0x10,0x90,0xFF,0x90,0x10,0xE2,0x22,0x2A,0x2A,0xF2,0x2A,0x26,0x22,0xE0,0x00,0x00},
{0x06,0x01,0xFF,0x00,0x01,0xFF,0x09,0x09,0x09,0x7F,0x09,0x49,0x89,0x7F,0x00,0x00},/*"桶",2*/
/* (16 X 16 , ?? )*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*":",3*/
/* (16 X 16 , ?? )*/
{0x80,0x82,0x82,0x82,0xFE,0x82,0x82,0x82,0x82,0x82,0xFE,0x82,0x82,0x82,0x80,0x00},
{0x00,0x80,0x40,0x30,0x0F,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00},/*"开",4*/
/* (16 X 16 , ?? )*/
{0x00,0x00,0x10,0x11,0x16,0x10,0x10,0xF0,0x10,0x10,0x14,0x13,0x10,0x00,0x00,0x00},
{0x81,0x81,0x41,0x41,0x21,0x11,0x0D,0x03,0x0D,0x11,0x21,0x41,0x41,0x81,0x81,0x00},/*"关",5*/
/* (16 X 16 , ?? )*/
{0x00,0x3E,0x22,0xE2,0x22,0x3E,0x00,0xFE,0x22,0x22,0x22,0x22,0x22,0xE2,0x02,0x00},
{0x20,0x3F,0x20,0x1F,0x11,0x11,0x00,0x7F,0x44,0x44,0x44,0x44,0x44,0x47,0x40,0x00},/*"距",6*/
/* (16 X 16 , ?? )*/
{0x04,0x04,0x04,0xF4,0x84,0xD4,0xA5,0xA6,0xA4,0xD4,0x84,0xF4,0x04,0x04,0x04,0x00},
{0x00,0xFE,0x02,0x02,0x12,0x3A,0x16,0x13,0x12,0x1A,0x32,0x42,0x82,0x7E,0x00,0x00},/*"离",7*/
/* (16 X 16 , ?? )*/
{0x00,0x20,0x22,0x2C,0x20,0x20,0xE0,0x3F,0x20,0x20,0x20,0x20,0xE0,0x00,0x00,0x00},
{0x80,0x40,0x20,0x10,0x08,0x06,0x01,0x00,0x01,0x46,0x80,0x40,0x3F,0x00,0x00,0x00},/*"为",8*/
/* (16 X 16 , ?? )*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*":",9*/
/* (16 X 16 , ?? )*/
根据需要的文字,写入部分显示屏的代码:
void LEDSHOW1(void)
{
OLED_ShowChinese(18,8,0,16);//垃
OLED_ShowChinese(36,8,1,16);//圾
OLED_ShowChinese(54,8,2,16);//桶
OLED_ShowChinese(72,8,3,16);//:
OLED_ShowChinese(18,40,6,16);//距
OLED_ShowChinese(36,40,7,16);//离
OLED_ShowChinese(54,40,8,16);//为
OLED_ShowChinese(72,<以上是关于基于STM32F103c8t6的智能垃圾桶项目的主要内容,如果未能解决你的问题,请参考以下文章
STM32学习笔记 二基于STM32F103C8T6和STM32CubeMX实现UART串口通信数据收发
STM32学习笔记 二基于STM32F103C8T6和STM32CubeMX实现UART串口通信数据收发