基于STM32F103c8t6的智能垃圾桶项目

Posted 林三三三三

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于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-SR04C8T6芯片引脚
GNDGND
Vcc5V
EchoPB7
TrigPB8

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芯片引脚
GNDGND
Vcc3.3V
SCLPA5
SDAPA7

软件部分

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的智能垃圾桶项目的主要内容,如果未能解决你的问题,请参考以下文章

基于STM32F103c8t6的智能垃圾桶项目

基于stm32F103C8T6的智能门禁(毕业设计)

STM32学习笔记 二基于STM32F103C8T6和STM32CubeMX实现UART串口通信数据收发

STM32学习笔记 二基于STM32F103C8T6和STM32CubeMX实现UART串口通信数据收发

三实战小例程 基于STM32F103C8T6最小系统板和STM32CubeMX驱动WS2812B光立方

三实战小例程 基于STM32F103C8T6最小系统板和STM32CubeMX驱动WS2812B光立方