先叠几层甲:

学校垃圾,毕设非常的水,对于一些比较好的学校来说可能都算课程设计,代码写的比较烂,各种copy各种ctrl+cv,存在许多迷惑行为。本文仅供学习交流以及博主记录自用,很多内容是直接从论文里copy来的,如有狗屁不通,还望路过的大佬键盘之下给我留点面子(

STM32简介:

STM32是一款基于ARM Cortex-M内核的微控制器系列,由意法半导体(STMicroelectronics)开发。它被广泛应用于嵌入式系统、物联网和其他各种领域中。
在实际应用中,STM32可以用于实现各种功能,如数据采集、数据处理、通信、控制等。在嵌入式系统中,STM32可以通过各种外设实现数据输入输出、定时器计数、ADC/DAC转换、PWM输出等功能;在物联网中,STM32可以通过无线模块、传感器、控制器等实现数据采集、控制、远程监控等功能。
STM32作为一款高性能、低功耗的微控制器,具有广泛的应用前景,可以在各种领域中发挥重要作用。

这里选用STM32F407ZGT6作为控制核心(虽然可能是有亿点性能过剩了罢)

各模块简介:

MQ-2气敏传感器模块:

MQ-2 气敏传感器采用的气敏材料为二氧化锡(SnO2),在洁净空气中具有低电导率。 当传感器所在环境存在可燃气体时,传感器的电导率随空气中可燃气体浓度的增加而增加。 用一个简单的电路将电导率的变化转换成与气体浓度对应的输出信号。 MQ-2 气体传感器对液化石油气、丙烷和氢气具有高灵敏度,是检测天然气和其他可燃气体的理想选择。 该传感器可检测范围广泛的可燃气体,是一款适用于各种应用的低成本传感器。 可作为家庭和工厂的气体泄漏监测装置,适用于检测液化石油气、丁烷、丙烷、甲烷、烟雾等。
模块有 VCC、GND、AO、DO 四个引脚,其中 AO 输出模拟电压信号,电压大小与检测气体浓度有关,DO 输出开关信号,当气体浓度达到阈值时,输出低电平(0.1V),否则为高电平(5V)。

MQ-2气敏传感器示意图

火焰传感器模块:

说是火焰传感器,其实就是一个红外管外加LM393,原理是通过红外管对周围的红外辐射进行接收和检测,从而判断是否有火焰的存在。当火焰出现时,火焰会发出红外辐射,红外管可以接收到这些辐射并产生电压信号,信号经过处理后,可以控制 LM393 芯片的输出端口,输出高电平或低电平的信号。
LM393 芯片是一个双路比较器,可以将输入信号与参考电压进行比较,如果输入信号大于参考电压,则输出高电平,否则输出低电平。因此,将红外管输出的电压信号作为输入信号,设置一个适当的参考电压,就可以通过比较输出一个高电平或低电平的信号,来判断是否检测到火焰。
模块有 VCC、GND、AO、DO 四个引脚,其中 AO 输出模拟电压信号,电压大小与火光大小有关,DO 输出开关信号,当红外管接受到的红外辐射强度达到阈值时(即你家着火啦),输出低电平(0.1V),否则为高电平(5V)。

火焰传感器模块示意图

DHT11温湿度传感器模块:

DHT11是一款广泛应用于温湿度监测领域的烂大街数字温湿度传感器。由传感器元件、信号处理电路和数据传输接口组成。温度测量范围为0°C至50°C,湿度测量范围为20%至90%。使用内置的温度和湿度传感器元件来捕捉环境的温度和湿度数据,并通过单线制数字信号输出给主控制器。
模块有VCC、GND、DATA三个引脚,DATA是传感器的串行数据输出总线引脚。使用该引脚和单片机进行通信即可获取温湿度数据。

DHT11温湿度传感器模块示意图

HC-SR501人体感应模块:

HC-SR501是一种常用的人体红外感应传感器,常用于人体检测和安防应用。它能够检测到人体的红外辐射,并输出相应的信号,用于触发警报、灯光等设备。传感器上有可调节的延迟时间和灵敏度控制旋钮,说白了就是个电位器。可以根据实际需要进行调节。
模块有VCC、GND、OUT三个引脚,当有人走过传感器的感应范围时,OUT引脚输出高电平。

HC-SR501人体感应模块示意图

SIM900A通讯模块:

SIM900A是一种高性能的GSM/GPRS模块,可以通过串口与外部MCU或计算机通信,支持AT指令集,可以通过AT指令实现模块的各种功能,如拨号、短信发送、数据传输等。当然我这里就只用到了个短信发送功能。

还有些其他的模块,比如说一个tft彩屏,分辨率128*160,spi接口,驱动芯片是ST7735S。另外就是门磁开关和蜂鸣器了。

引脚分配&组装:

接线大概就跟这个图一样,仅供参考。
屏幕是SPI接口的,接到stm32的硬件spi引脚上即可。传感器和按键的输入全设置为外部中断,根据模块触发后输出的是高电平还是低电平决定检测方式是上升沿还是下降沿。

接线示意图

然后在cubeide里配置好引脚:

就比如说我这个按键,按下去是直接连到GND了,所以就设置为下降沿。

顺便配置一下时钟树,让芯片跑在最高的速度上:

画个简单的转接板(焊洞洞板太费眼了):

最后组装完就这个德行:

程序设计:

这个报警系统主要实现3个功能:温湿度、烟雾火焰等传感器数据的读取、收集;显示屏数据的处理;发送AT命令至SIM900A实现短信发送。系统上电启动后就进入到了程序的循环执行过程中。主程序流程设计如下:
(1)上电启动后,系统初始化,STM32单片机实时收集来自温湿度传感器的数据,并将温湿度信息显示在显示屏上,收集各传感器的状态,并视读取到的状态判断是否执行报警程序。
(2)如果执行报警程序,根据报警的模块显示对应的报警信息至屏幕上(例如烟雾传感器输出低电平,就显示燃气泄露报警信息和对应图标到屏幕上),并根据报警信息发送报警短信至用户手机。如果同时有多个模块报警信息,则在屏幕上轮流显示,同时,蜂鸣器鸣响,直至用户使用按钮复位报警状态。

那么就先把各模块驱动一下吧。当然像气敏传感器、火焰传感器、门磁开关、人体感应、蜂鸣器这种,无非就是个高低电平的输入输出,直接WritePin或者ReadPin就完事了,没什么好讲的。

屏幕驱动程序:

网上关于ST7735S的资料还蛮多的,原理方面这里就直接贴一篇文章了:ST7735S应用笔记 (绝对不是因为我想偷懒),
下面就直接贴代码了:

//lcd_st7735.h
#ifndef _LCD_ST7735_H_
#define _LCD_ST7735_H_

#include "main.h"

#define ST7735_RST_Pin SPI1_RST_Pin
#define ST7735_RST_GPIO_Port SPI1_RST_GPIO_Port
#define ST7735_DC_Pin SPI1_DC_Pin
#define ST7735_DC_GPIO_Port SPI1_DC_GPIO_Port
#define ST7735_CS_Pin SPI1_CS_Pin
#define ST7735_CS_GPIO_Port SPI1_CS_GPIO_Port

#define ST7735_SPI_INSTANCE hspi1

#define ST7735_XSTART 0
#define ST7735_YSTART 0
#define ST7735_WIDTH  128
#define ST7735_HEIGHT 160

#define ST7735_ROTATION 0

// Color definitions
#define ST7735_BLACK   0x0000
#define ST7735_BLUE    0x001F
#define ST7735_RED     0xF800
#define ST7735_GREEN   0x07E0
#define ST7735_CYAN    0x07FF
#define ST7735_MAGENTA 0xF81F
#define ST7735_YELLOW  0xFFE0
#define ST7735_WHITE   0xFFFF
#define ST7735_COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))

void ST7735_Init(void);
void ST7735_DrawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color);
void ST7735_FillScreen(uint16_t color);
void ST7735_DrawImage(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint8_t *image);

#endif

//lcd_st7735.c
#include "lcd_st7735.h"

#define ST7735_SLPOUT   0x11
#define ST7735_FRMCTR1  0xB1
#define ST7735_FRMCTR2  0xB2
#define ST7735_FRMCTR3  0xB3
#define ST7735_INVCTR   0xB4
#define ST7735_PWCTR1   0xC0
#define ST7735_PWCTR2   0xC1
#define ST7735_PWCTR3   0xC2
#define ST7735_PWCTR4   0xC3
#define ST7735_PWCTR5   0xC4
#define ST7735_VMCTR1   0xC5
#define ST7735_COLMOD   0x3A
#define ST7735_GMCTRP1  0xE0
#define ST7735_GMCTRN1  0xE1
#define ST7735_NORON    0x13
#define ST7735_DISPON   0x29
#define ST7735_CASET    0x2A
#define ST7735_RASET    0x2B
#define ST7735_RAMWR    0x2C
#define ST7735_INVOFF   0x20

#define ST7735_MADCTL     0x36
#define ST7735_MADCTL_MX  0x40
#define ST7735_MADCTL_MY  0x80
#define ST7735_MADCTL_MV  0x20
#define ST7735_MADCTL_RGB 0x00

void ST7735_Reset(void)
{
  ST7735_RST_GPIO_Port->BSRR=(uint32_t)ST7735_RST_Pin << 16U;
  HAL_Delay(100);
  ST7735_RST_GPIO_Port->BSRR=ST7735_RST_Pin;
  HAL_Delay(100);
}

void ST7735_WriteCommand(uint8_t cmd)
{
  ST7735_DC_GPIO_Port->BSRR=(uint32_t)ST7735_DC_Pin << 16U;
  ST7735_CS_GPIO_Port->BSRR=(uint32_t)ST7735_CS_Pin << 16U;
  HAL_SPI_Transmit(&ST7735_SPI_INSTANCE, &cmd, 1, 100);
  ST7735_CS_GPIO_Port->BSRR=ST7735_CS_Pin;
}

void ST7735_WriteData(uint8_t data)
{
  ST7735_DC_GPIO_Port->BSRR=ST7735_DC_Pin;
  ST7735_CS_GPIO_Port->BSRR=(uint32_t)ST7735_CS_Pin << 16U;
  HAL_SPI_Transmit(&ST7735_SPI_INSTANCE, &data, 1, 100);
  ST7735_CS_GPIO_Port->BSRR=ST7735_CS_Pin;
}

void ST7735_SetRotation(uint8_t rotation)
{
    uint8_t madctl = 0;

    switch (rotation)
    {
        case 0:
            madctl = ST7735_MADCTL_MX | ST7735_MADCTL_MY | ST7735_MADCTL_RGB;
            break;
        case 1:
            madctl = ST7735_MADCTL_MY | ST7735_MADCTL_MV | ST7735_MADCTL_RGB;
            break;
        case 2:
            madctl = ST7735_MADCTL_RGB;
            break;
        case 3:
            madctl = ST7735_MADCTL_MX | ST7735_MADCTL_MV | ST7735_MADCTL_RGB;
            break;
    }

    ST7735_WriteCommand(ST7735_MADCTL);
    ST7735_WriteData(madctl);
}

void ST7735_Init(void) {
  // Initialize the display
  ST7735_Reset();
  ST7735_WriteCommand(ST7735_SLPOUT);
  HAL_Delay(120);
  ST7735_WriteCommand(ST7735_FRMCTR1);
  ST7735_WriteData(0x01);
  ST7735_WriteData(0x2C);
  ST7735_WriteData(0x2D);
  ST7735_WriteCommand(ST7735_FRMCTR2);
  ST7735_WriteData(0x01);
  ST7735_WriteData(0x2C);
  ST7735_WriteData(0x2D);
  ST7735_WriteCommand(ST7735_FRMCTR3);
  ST7735_WriteData(0x01);
  ST7735_WriteData(0x2C);
  ST7735_WriteData(0x2D);
  ST7735_WriteData(0x01);
  ST7735_WriteData(0x2C);
  ST7735_WriteData(0x2D);
  ST7735_WriteCommand(ST7735_INVCTR);
  ST7735_WriteData(0x07);
  ST7735_WriteCommand(ST7735_PWCTR1);
  ST7735_WriteData(0xA2);
  ST7735_WriteData(0x02);
  ST7735_WriteData(0x84);
  ST7735_WriteCommand(ST7735_PWCTR2);
  ST7735_WriteData(0xC5);
  ST7735_WriteCommand(ST7735_PWCTR3);
  ST7735_WriteData(0x0A);
  ST7735_WriteData(0x00);
  ST7735_WriteCommand(ST7735_PWCTR4);
  ST7735_WriteData(0x8A);
  ST7735_WriteData(0x2A);
  ST7735_WriteCommand(ST7735_PWCTR5);
  ST7735_WriteData(0x8A);
  ST7735_WriteData(0xEE);
  ST7735_WriteCommand(ST7735_VMCTR1);
  ST7735_WriteData(0x0E);
  ST7735_WriteCommand(ST7735_INVOFF);
  ST7735_WriteCommand(ST7735_COLMOD);
  ST7735_WriteData(0x05);
  ST7735_WriteCommand(ST7735_CASET);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x7F);
  ST7735_WriteCommand(ST7735_RASET);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x9F);
  ST7735_WriteCommand(ST7735_GMCTRP1);
  ST7735_WriteData(0x02);
  ST7735_WriteData(0x1C);
  ST7735_WriteData(0x07);
  ST7735_WriteData(0x12);
  ST7735_WriteData(0x37);
  ST7735_WriteData(0x32);
  ST7735_WriteData(0x29);
  ST7735_WriteData(0x2D);
  ST7735_WriteData(0x29);
  ST7735_WriteData(0x25);
  ST7735_WriteData(0x2B);
  ST7735_WriteData(0x39);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x01);
  ST7735_WriteData(0x03);
  ST7735_WriteData(0x10);
  ST7735_WriteCommand(ST7735_GMCTRN1);
  ST7735_WriteData(0x03);
  ST7735_WriteData(0x1D);
  ST7735_WriteData(0x07);
  ST7735_WriteData(0x06);
  ST7735_WriteData(0x2E);
  ST7735_WriteData(0x2C);
  ST7735_WriteData(0x29);
  ST7735_WriteData(0x2D);
  ST7735_WriteData(0x2E);
  ST7735_WriteData(0x2E);
  ST7735_WriteData(0x37);
  ST7735_WriteData(0x3F);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x02);
  ST7735_WriteData(0x10);
  ST7735_WriteCommand(ST7735_NORON);
  HAL_Delay(10);
  ST7735_WriteCommand(ST7735_DISPON);
  HAL_Delay(10);

  ST7735_SetRotation(ST7735_ROTATION);
  ST7735_FillScreen(ST7735_BLACK);
  HAL_GPIO_WritePin(SPI1_BL_GPIO_Port, SPI1_BL_Pin, GPIO_PIN_SET);
}

void ST7735_SetAddressWindow(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1)
{
  x0 += ST7735_XSTART;
  y0 += ST7735_YSTART;

  x1 += ST7735_XSTART;
  y1 += ST7735_YSTART;

  ST7735_WriteCommand(ST7735_CASET);
  ST7735_WriteData(0x00);
  ST7735_WriteData(x0 + ST7735_XSTART);
  ST7735_WriteData(0x00);
  ST7735_WriteData(x1 + ST7735_XSTART);

  ST7735_WriteCommand(ST7735_RASET);
  ST7735_WriteData(0x00);
  ST7735_WriteData(y0 + ST7735_YSTART);
  ST7735_WriteData(0x00);
  ST7735_WriteData(y1 + ST7735_YSTART);
}

void ST7735_DrawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color)
{
  ST7735_SetAddressWindow(x, y, x + width - 1, y + height - 1);
  ST7735_WriteCommand(ST7735_RAMWR);
  // Write the color data
  for (uint16_t i = 0; i < width * height; i++)
  {
    ST7735_WriteData(color >> 8);
    ST7735_WriteData(color & 0xFF);
  }
}

void ST7735_FillScreen(uint16_t color)
{
  ST7735_DrawRectangle(0, 0, ST7735_WIDTH, ST7735_HEIGHT, color);
}

void ST7735_DrawImage(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint8_t *image)
{
  ST7735_SetAddressWindow(x, y, x + width - 1, y + height - 1);

  ST7735_WriteCommand(ST7735_RAMWR);
  for (uint32_t i = 0; i < width * height; i++)
  {
    ST7735_WriteData(image[i * 2]);
    ST7735_WriteData(image[i * 2 + 1]);
  }
}

然后在main.c里包含lcd_st7735.h,在while之前调用显示屏初始化函数ST7735_Init();

DHT11驱动程序:

关于dht11的通信方式可以直接去翻卖家给的资料,也可以参考这篇文章:dht11新手原理详解

//dht11.h
#ifndef __DHT11_H
#define __DHT11_H
#include "main.h"
/* DHT11 引脚 定义 */
#define DHT11_DQ_GPIO_PORT            GPIOE
#define DHT11_DQ_GPIO_PIN             GPIO_PIN_13
/* PE口时钟使能 */
#define DHT11_DQ_GPIO_CLK_ENABLE()    do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0)
/* IO操作函数 */
#define DHT11_DQ_OUT(x)   do{ x ? HAL_GPIO_WritePin(DHT11_DQ_GPIO_PORT, DHT11_DQ_GPIO_PIN, GPIO_PIN_SET) : HAL_GPIO_WritePin(DHT11_DQ_GPIO_PORT, DHT11_DQ_GPIO_PIN, GPIO_PIN_RESET); }while(0)   /* 数据端口输出 */
/* 数据端口输入 */
#define DHT11_DQ_IN       HAL_GPIO_ReadPin(DHT11_DQ_GPIO_PORT, DHT11_DQ_GPIO_PIN)
uint8_t dht11_init(void); /* 初始化DHT11 */
uint8_t dht11_check(void); /* 检测是否存在DHT11 */
uint8_t dht11_read_data(uint8_t *temp,uint8_t *humi,uint8_t *tempd,uint8_t *humid); /* 读取温湿度 */
#endif

//dht11.c
#include "dht11.h"
static void dht11_reset(void)
{
    DHT11_DQ_OUT(0); /* 拉低DQ */
    HAL_Delay(20); /* 拉低至少18ms */
    DHT11_DQ_OUT(1); /* DQ=1 */
    delay_us(30); /* 主机拉高20~40us */
}
uint8_t dht11_check(void)
{
	uint8_t retry = 0;
	uint8_t rval = 0;
	while (DHT11_DQ_IN && retry < 100) /* DHT11会拉低40~80us */
	{
        retry++;
        delay_us(1);
	}
	if (retry >= 100) /* 超时,DHT11异常 */
	{
		rval = 1;
	}
	else
	{
        retry = 0;
        while (!DHT11_DQ_IN && retry < 100) /* DHT11拉低后会再次拉高40~80us */
        	{
            	retry++;
            	delay_us(1);
        	}
        if (retry >= 100) rval = 1; /* 超时,DHT11异常 */
	}
	return rval;
}

uint8_t dht11_read_bit(void)
{
	uint8_t retry = 0;
	while (DHT11_DQ_IN && retry < 100) /* 等待变为低电平 */
	{
         retry++;
         delay_us(1);
	}
      	 retry = 0;
      	 while (!DHT11_DQ_IN && retry < 100) /* 等待变高电平 */
      	 {
      		 retry++;
      		 delay_us(1);
      	 }
      	 delay_us(40); /* 等待40us */
    if (DHT11_DQ_IN) /* 根据引脚状态返回 bit */
    {
    	return 1;
    }
    else
    {
    	return 0;
    }
}

static uint8_t dht11_read_byte(void)
{
	uint8_t i, data = 0;
	for (i = 0; i < 8; i++) /* 循环读取8位数据 */
	{
		data <<= 1; /* 高位数据先输出, 先左移一位 */
		data |= dht11_read_bit(); /* 读取1bit数据 */
	}
	return data;
}

uint8_t dht11_read_data(uint8_t *temp, uint8_t *humi,uint8_t *tempd,uint8_t *humid)
{
	uint8_t buf[5];
	uint8_t i;
    dht11_reset();
    if (dht11_check() == 0)
    {
    	for (i = 0; i < 5; i++) /* 读取40位数据 */
    	{
            buf[i] = dht11_read_byte();/* 读到的值存在buf[i]中 */
    	}
    	/* 通过校验位检查读取到的数据是否正确 */
    	if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
    	{
    		*humi = buf[0]; /* 湿度整数和小数分别在buf[0]和buf[1]中 */
    		*humid = buf[1];
    		*temp = buf[2]; /* 温度整数和小数分别在buf[2]和buf[3]中 */
    		*tempd = buf[3];
    	}
    }
    else  /* DHT11没有应答 */
    {
    	return 1;
    }
    return 0;
}

uint8_t dht11_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;
    DHT11_DQ_GPIO_CLK_ENABLE(); /* 开启DQ引脚时钟 */
    gpio_init_struct.Pin = DHT11_DQ_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD; /* 开漏输出 */
    gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 高速 */
    /* 初始化DHT11_DQ引脚 */
    HAL_GPIO_Init(DHT11_DQ_GPIO_PORT, &gpio_init_struct);
    /* DHT11_DQ引脚模式设置,开漏输出,上拉, 这样就不用再设置IO方向了, 开漏输出的时候(=1), 也可以读取外部信号的高低电平 */
    dht11_reset(); /* 复位DHT11 */
    return dht11_check(); /* 等待DHT11的回应 */
}

上述代码中dht11_read_data()需要传入用于存储温度整数、小数,湿度整数、小数数据的变量指针,这样就可以获取到温湿度数据。
如何打印在屏幕上?那当然是活字印刷啊(


const uint8_t* get_num_id(uint16_t num)
{
	switch(num)
	{
	case 0:return num_0;break;
	case 1:return num_1;break;
	case 2:return num_2;break;
	case 3:return num_3;break;
	case 4:return num_4;break;
	case 5:return num_5;break;
	case 6:return num_6;break;
	case 7:return num_7;break;
	case 8:return num_8;break;
	case 9:return num_9;break;
	default:return num_0;break;
	}
}

void draw_num(uint16_t num,uint16_t numd)
{
	uint16_t num1=(num/10)%10;
	uint16_t num2=num%10;
	ST7735_DrawImage(num1_x, num1_y, num_w, num_h, get_num_id(num1));
	ST7735_DrawImage(num2_x, num2_y, num_w, num_h, get_num_id(num2));
	ST7735_DrawImage(num3_x, num3_y, num_w, num_h, get_num_id(numd));
}

上述代码中的numx_x、y,分别是两位整数的xy坐标,还有一位小数的xy坐标。传入的num是整数,numd是小数。num_x是指向数字取模后的数组指针。
这样获取完温湿度数据之后调用draw_num()就可以把温湿度的数据打印在屏幕上。

SIM900A发送短信:

关于sim900a支持的AT命令,最好是去翻模块手册,一般卖家都会给你,不过只是发个短信其实用不了把那么长一个手册全看完,可以看看这篇文章:【STM32训练—SIM900A模块】第一篇、电脑的串口助手驱动SIM900A发送中文和英文短信
这里我们只要让stm32通过串口发送AT命令给sim900a就好了。


void sim900a_send_chinese_message(char *ucode_message,char *phonenumber)
{
	HAL_UART_Transmit(&huart1, (uint8_t*)"AT&F\r\n", strlen("AT&F\r\n")+1, 20); 
	HAL_Delay(100);
	HAL_UART_Transmit(&huart1, (uint8_t*)"AT+CMGF=1\r\n", strlen("AT+CMGF=1\r\n")+1, 20);
	HAL_Delay(100);
	HAL_UART_Transmit(&huart1, (uint8_t*)"AT+CSCS=\"UCS2\"\r\n", strlen("AT+CSCS=\"UCS2\"\r\n")+1, 20);
	HAL_Delay(100);
	HAL_UART_Transmit(&huart1, (uint8_t*)"AT+CSMP=17,167,0,8\r\n", strlen("AT+CSMP=17,167,0,8\r\n")+1, 20);
	HAL_Delay(100);
	char dispbuf[50];
	sprintf(dispbuf,"AT+CMGS=\"%s\"\r\n",phonenumber);
	HAL_UART_Transmit(&huart1, (uint8_t*)dispbuf, strlen(dispbuf)+1, 200);
	HAL_Delay(100);
	HAL_UART_Transmit(&huart1, (uint8_t*)ucode_message, strlen(ucode_message)+1, 200);
	HAL_Delay(100);
	uint8_t buf_com[1]={0x1a};
	HAL_UART_Transmit(&huart1,buf_com, sizeof(buf_com), 1000);
	MX_USART1_UART_Init();
}

使用之前要先把发送的短信内容和手机号转成Unicode编码再传入,文本转Unicode的工具一般在卖家提供的资料里都会提供。

不过sim900a有个坑,只能用移动卡,因为电信和联通的2G基站都关的差不多了,只要移动卡能够正常注册网络。而且模块对供电要求比较高,最好用独立的5V供电,别直接插核心板的5V。

主程序:

定义几个用于标志报警状态的变量,在每个模块的中断函数里写上把对应的报警状态置1的语句,按键的中断函数里写上把所有的报警状态置0的语句。
为保护隐私手机号的Unicode数据就加上*了(


  /* USER CODE BEGIN 2 */
  ST7735_Init();//显示屏初始化
  if(dht11_init()!=1)
  {
	 BEEP_ON;
	 HAL_Delay(300);
	 BEEP_OFF;
  }
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  ST7735_DrawImage(0, 0, 128, 128, wyzj_ok);//在屏幕上显示一切正常的图标(这里用的五月织姬的表情包)
  ST7735_DrawImage(bg_x, bg_y, bg_w, bg_h, ok_warn);//显示文字:一切正常
  int time=0;
  //sim900a_send_chinese_message(chsmsg1,phonenum);
  //BEEP_ON;
  while (1)
  {
	  delay_us(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  if(warn_st==0)
	  {
		  if(safed==1)
		  {
			  ST7735_DrawImage(0, 0, 128, 128, wyzj_ok);//在屏幕上显示一切正常的图标
			  ST7735_DrawImage(bg_x, bg_y, bg_w, bg_h, ok_warn);//显示文字:一切正常
			  safed=0;
		  }
		  if(time==0)
		  {
			  dht11_read_data(&temp, &humi, &tempd, &humid);//从dht11那里获取温湿度数据
			  ST7735_DrawImage(bg_x, bg_y, bg_w, bg_h, temp_bg);//打印温度:  .  ℃
			  draw_num(temp,tempd);//打印温度数据xx x
		  }
		  else if(time==1500)
		  {
			  dht11_read_data(&temp, &humi, &tempd, &humid);//从dht11那里获取温湿度数据
			  ST7735_DrawImage(bg_x, bg_y, bg_w, bg_h, humd_bg);//打印湿度:  .  %
			  draw_num(humi,humid);//打印湿度数据xx x
		  }
		  else if(time==3000)
		  {
			  ST7735_DrawImage(bg_x, bg_y, bg_w, bg_h, ok_warn);//在屏幕上显示一切正常的图标
		  }
		  else if(time==4500)
		  {
			  time=0;
			  continue;
		  }
		  time++;
	  }
	  else
	  {
		  if(door_warn_st==1)//有人撬门
		  {
			  BEEP_ON;//#define BEEP_ON HAL_GPIO_WritePin(beep_GPIO_Port, beep_Pin, GPIO_PIN_RESET)
			  ST7735_DrawImage(0, 0, 128, 128, wyzj_door);//显示有人撬门的警告图标
			  ST7735_DrawImage(bg_x, bg_y, bg_w, bg_h, door_warn);//显示有人撬门的警告文字
			  if(msg_send==1)
			  			  {
			  				  sim900a_send_chinese_message("8B66544AFF1A68C06D4B523095E87A975F00542FFF0C5EFA8BAE7ACB523B67E5770B76D163A7533A57DF60C551B5FF01",\
			  "00310037****************0310035");//发送警告短信
			  				  msg_send=0;
			  				  msg_send_ok=1;
			  			  }
			  HAL_Delay(2000);
		  }
		  if(air_warn_st==1)//煤气泄漏
		  {
			  BEEP_ON;
			  ST7735_DrawImage(0, 0, 128, 128, wyzj_air);
			  ST7735_DrawImage(bg_x, bg_y, bg_w, bg_h, air_warn);
			  if(msg_send==1)
			  			  {
			  				  sim900a_send_chinese_message("8B66544AFF1A68C06D4B523075914F3C71C36C146CC49732FF0C8BF75C3D5FEB524D5F8076D163A7533A57DF67E5770B60C551B55E7662535F0095E87A97901A98CEFF01",\
			  "00310037****************0310035");
			  				  msg_send=0;
			  				  msg_send_ok=1;
			  			  }
			  HAL_Delay(2000);
		  }
		  if(fire_warn_st==1)//火灾报警
		  {
			  BEEP_ON;
			  ST7735_DrawImage(0, 0, 128, 128, wyzj_fire);
			  ST7735_DrawImage(bg_x, bg_y, bg_w, bg_h, fire_warn);
			  if(msg_send==1)//
			  {
				  sim900a_send_chinese_message("8B66544AFF1A68C06D4B523075914F3C660E706B51FA73B0FF0C8BF75C3D5FEB524D5F8076D163A7533A57DF67E5770B60C551B5FF01",\
"00310037****************0310035");
				  msg_send=0;
				  msg_send_ok=1;
			  }
			  BEEP_OFF;
			  HAL_Delay(2000);
		  }
		  if(hu_warn_st==1)//有人活动
		  {
			  BEEP_ON;
			  ST7735_DrawImage(0, 0, 128, 128, wyzj_human);
			  ST7735_DrawImage(bg_x, bg_y, bg_w, bg_h, human_warn);
			  if(msg_send==1)
			  			  {
			  				  sim900a_send_chinese_message("8B66544AFF1A68C06D4B523067094EBA7ECF8FC776D16D4B533A57DFFF0C8BF76CE8610FFF01",\
			  "00310037****************0310035");
			  				  msg_send=0;
			  				  msg_send_ok=1;
			  			  }
			  HAL_Delay(2000);
		  }
	  }
  }
  /* USER CODE END 3 */
}

效果展示:

初始化
温湿度监测(轮播)
火灾报警
煤气泄漏报警
防盗报警

逸一时,误一世