STM32C8T6+DHT11显示温湿度//通过MQTT实现开发板与阿里云服务器收发

STM32C8T6+DHT11显示温湿度/通过MQTT实现开发板与阿里云服务器收发

本教程基于韦东山百问网出的 DShanMCU-F103开发板 进行编写,需要的朋友可以在这里获取: https://item.taobao.com/item.htm?id=724601559592

配套资料获取:https://rtos.100ask.net/zh/freeRTOS/DShanMCU-F103

freeRTOS系列教程之freeRTOS入门与工程实践章节汇总: https://blog.csdn.net/qq_35181236/article/details/132842016

目录:

  1. 所需模块
  2. 接线示意图
  3. 主要代码部分

1.所需模块

  • STM32C8T6开发板

在这里插入图片描述

  • DHT11温湿度模块

在这里插入图片描述

  • OLED(0.96四针)屏幕

在这里插入图片描述

  • ESP8266WIFI模块

在这里插入图片描述

  • CH340串口模块

在这里插入图片描述

  • 多功能底板

在这里插入图片描述

再此推荐大家使用此底板,能连接很多模块,底板上面都有标注,使用起来很方便,(很适合小白)推荐给大家,开发板底板都是百问网的,推荐给大家 链接:https://item.taobao.com/item.htm?id=724601559592

效果展示给大家看一下,使用起来效果

在这里插入图片描述

2.接线示意图

  • 开发板连接ST-LINK-V2

在这里插入图片描述

  • 底板连接CH340串口模块

在这里插入图片描述

  • 底板连接ESP8266WIFI模块
ESP8266DshanMCU_F103底板
3.3V3.3V
GNDGND
RXPA2
TXPA3

3.主要代码部分

(1)首先我们先来实现STM32C8T6+DHT11通过OLED显示温湿度

底层驱动我就不放上来啦,详细代码可在文章最后Github获取

  • 首先我们先写OLED驱动程序,测试OLED

  • OLED.c 部分代码
    //7. 初始化函数
    //初始化OLED
    void OLED_Init(void)
    {   
    
        OLED_SetMemAddrMode(PAGE_ADDR_MODE);    // 0. 设置地址模式
        OLED_SetMuxRatio(0x3F);                 // 1. 设置多路复用率
        OLED_SetDispOffset(0x00);               // 2. 设置显示的偏移值
        OLED_SetDispStartLine(0x00);            // 3. 设置起始行
        OLED_SEG_REMAP();                       // 4. 行翻转
        OLED_SCAN_REMAP();                      // 5. 正常扫描
        OLED_SetComConfig(COM_PIN_SEQ, COM_NOREMAP);          // 6. COM 引脚设置
        OLED_SetContrastValue(0x7F);            // 7. 设置对比度
        ENTIRE_DISP_OFF();                      // 8. 全屏点亮/熄灭
        DISP_NORMAL();                          // 9. 显示模式
        OLED_SetDCLK_Freq(0x00, 0x08);          // 10. 设置分频系数和频率增值
        OLED_SetChargePump(PUMP_ENABLE);        // 11. 使能电荷碰撞
        
        OLED_SetComConfig(COM_PIN_ALT, COM_NOREMAP);
        
        DISP_ON();
    }
    
    //8. 基本驱动功能函数
    //设置像素显示的起始页和起始列地址
    void OLED_SetPosition(uint8_t page, uint8_t col)
    {
        OLED_SetPageAddr_PAGE(page);
        OLED_SetColAddr_PAGE(col);
    }
    
    //清屏函数
    void OLED_Clear(void)
    {
        uint8_t i = 0;
        uint8_t buf[128] = {0};
        
        for(i=0; i<8; i++)
        {
            OLED_SetPosition(i, 0);
            OLED_WriteNBytes(&buf[0], 128);
        }
    }
    
    //显示一个字符
    /*
    * x --> x坐标(0~15)
    * y --> y坐标(0~7)
    * c -->   显示的字符
    */
    void OLED_PutChar(uint8_t x, uint8_t y, char c)
    {
        uint8_t page = y;
        uint8_t col  = x*8;
        
        if (y > 7 || x > 15)
            return;
        
        OLED_SetPosition(page, col);
        OLED_WriteNBytes((uint8_t*)&ascii_font[c][0], 8);
        
        OLED_SetPosition(page + 1, col);
        OLED_WriteNBytes((uint8_t*)&ascii_font[c][8], 8);
    }
    
    //显示一个字符串
    /*x --> x坐标(0~15)
     *y --> y坐标(0~7)
     *str -->   显示的字符串
    */
    int OLED_PrintString(uint8_t x, uint8_t y, const char *str)
    {   
        int i = 0;
        while (str[i])
        {
            OLED_PutChar(x, y, str[i]);
            x++;
            if(x > 15)
            {
                x  = 0;
                y += 2;
            }
                    
            i++;
        }
        return i;
    }
    
    /*
     * 清除一行
     * x - 从这里开始
     * y - 清除这行
     */
    void OLED_ClearLine(uint8_t x, uint8_t y)
    {
        for (;x < 16; x++)
        {
            OLED_PutChar(x, y, ' ');
        }
    }
    
    /*
     *以16进制显示数值
     *x - x坐标(0~15)
     *            y - y坐标(0~7)
     *            val -   显示的数据
     *            pre -   非零时显示"0x"前缀
     */
    int OLED_PrintHex(uint8_t x, uint8_t y, uint32_t val, uint8_t pre)
    {
        uint8_t hex_tab[]={'0','1','2','3','4','5','6','7',\
                                 '8','9','a','b','c','d','e','f'};
    	int i, j;
    	char arr[11];
    
    	/* 提取数据 */
        arr[0] = '0';
        arr[1] = 'x';
        arr[10] = '\0';
    
        j = 2;
    	for (i = 7; i >= 0; i--)
    	{
            arr[j] = hex_tab[(val >> (i*4)) & 0xf];
            if ((j != 2) || (arr[j] != '0'))
            {
                j++;
            }        
    	}
        if (j == 2)
            j++;
        arr[j] = '\0';
    
        if (pre)
        {
            OLED_PrintString(x, y, arr);
            return j;
        }
        else
        {
            OLED_PrintString(x, y, arr+2);
            return j - 2;
        }
    }
    
    
    /*
     *  以10进制显示一个数值
     *  x --> x坐标(0~15)
     *            y --> y坐标(0~7)
     *            val -->   显示的数据
    */
    int OLED_PrintSignedVal(uint8_t x, uint8_t y, int32_t val)
    {
        char str[16];
        char revert_str[16];
        int i = 0, j = 0;
        int mod;
    
        if (val < 0)
        {
            str[i++] = '-';
            val = 0 - val;
        }
        else if (val == 0)
        {
            str[i++] = '0';
        }
    
        while (val)
        {
            mod = val % 10;
            revert_str[j++] = mod + '0';
            val = val / 10;
        }
    
        while (j)
        {
            str[i++] = revert_str[j-1];
            j--;
        } 
        
        str[i] = '\0';
        OLED_PrintString(x, y, str);
        return i;
    }
    
    //获得OLED的Framebuffer
     //pXres/pYres/pBpp - 用来保存分辨率、bpp
    void * OLED_GetFrameBuffer(uint32_t *pXres, uint32_t *pYres, uint32_t *pBpp)
    {
        *pXres = FRAME_WIDTH;
        *pYres = FRAME_HEIGHT;
        *pBpp  = 1;
        return oledBuffer;
    }
    
    //把Framebuffer的数据全部刷新到OLED
    void OLED_Flush(void)
    {
          uint8_t i;
          for(i=0;i<8;i++)
          {
             OLED_WriteCmd(0xb0+i); //设置行起始地址
             OLED_WriteCmd(0x00);   //设置低列起始地址
             OLED_WriteCmd(0x10);   //设置高列起始地址
             //for(n=0;n<128;n++)
             //  OLED_WriteData(oledBuffer[128*i+n]);
             OLED_WriteNBytes(&oledBuffer[128*i], 128);
        }
    }
    
    //刷新OLED的区域
    /*
     *col- OLED的列,取值范围0~127
     *row - OLED的行,取值范围0~63
     *width - 宽度
     *heigh - 高度,必须是8的整数倍
     */
    
    void OLED_FlushRegion(int col, int row, int width, int heigh)
    {
    #if 0    
          uint8_t i;
          uint8_t page = row / 8;
          
          for (i = 0; i < heigh/8; i++)
          {
             OLED_SetPosition(page+i, col);
             OLED_WriteNBytes(&oledBuffer[col + (page + i) * FRAME_WIDTH], width);
            }
    #else
        uint8_t i;
        uint8_t page = row / 8;
        uint8_t page_cnt = heigh/8;
        
        if (row % 8)
        {
            page_cnt++;
        }
    
        for (i = 0; i < page_cnt; i++)
        {
            if (page+i < 8)
            {
               OLED_SetPosition(page+i, col);
               OLED_WriteNBytes(&oledBuffer[col + (page + i) * FRAME_WIDTH], width);
            }
          }
    
    #endif
    }
    
    
    //把Framebuffer的数据全部清零
    void OLED_ClearFrameBuffer(void)
    {
        memset(oledBuffer, 0, sizeof(oledBuffer));
    }
    

    注意:本工程是通过CubeMX创建

    初始化I2C

    • 前提: 已经初始化的I2C通道
    • 本工程里已经:
    • 使用MX_I2C1_Init初始化I2C通道
    • 使用HAL_I2C_MspInit初始化I2C引脚
  • OLED.h部分
#ifndef __DRIVER_OLED_H
#define __DRIVER_OLED_H

#include "stm32f1xx_hal.h"
#include <stdint.h>

#define FRAME_WIDTH			128
#define FRAME_HEIGHT		64
#define FRAME_BUFFER_SIZE	((FRAME_WIDTH * FRAME_HEIGHT) / 8)

//初始化OLED
void OLED_Init(void);

//设置像素显示的起始页和起始列地址
void OLED_SetPosition(uint8_t page, uint8_t col);

//清屏函数
void OLED_Clear(void);

//显示一个字符
void OLED_PutChar(uint8_t x, uint8_t y, char c);

//显示一个字符串
int OLED_PrintString(uint8_t x, uint8_t y, const char *str);

///清除一行
void OLED_ClearLine(uint8_t x, uint8_t y);

//以16进制显示数值
int OLED_PrintHex(uint8_t x, uint8_t y, uint32_t val, uint8_t pre);

//获得OLED的Framebuffer
int OLED_PrintSignedVal(uint8_t x, uint8_t y, int32_t val);

//获得OLED的Framebuffer
void * OLED_GetFrameBuffer(uint32_t *pXres, uint32_t *pYres, uint32_t *pBpp);

//把Framebuffer的数据全部刷新到OLED
void OLED_Flush(void);

//刷新OLED的区域
void OLED_FlushRegion(int col, int row, int width, int heigh);

//把Framebuffer的数据全部清零
void OLED_ClearFrameBuffer(void);

//OLED测试程序
void OLED_Test(void);

#endif /* __DRIVER_OLED_H */


  • LCD.c
    //初始化LCD
    
    void LCD_Init(void)
    {
        OLED_Init();
    }
    
    
    //清屏函数
    void LCD_Clear(void)
    {
        OLED_Clear();
    }
    
    //显示一个字符
    void LCD_PutChar(uint8_t x, uint8_t y, char c)
    {
        OLED_PutChar(x, y, c);
    }
    
    
    //显示一个字符串
    int LCD_PrintString(uint8_t x, uint8_t y, const char *str)
    {
       return OLED_PrintString(x, y, str);
    }
    
    //清除一行
    void LCD_ClearLine(uint8_t x, uint8_t y)
    {
       OLED_ClearLine(x, y);
    }
    
    //以16进制显示数值
    int LCD_PrintHex(uint8_t x, uint8_t y, uint32_t val, uint8_t pre)
    {
        return OLED_PrintHex(x, y, val, pre);
    }
    
    //以10进制显示一个数值
    int LCD_PrintSignedVal(uint8_t x, uint8_t y, int32_t val)
    {
        return OLED_PrintSignedVal(x, y, val);
    }
    
    //获得LCD的Framebuffer
    void * LCD_GetFrameBuffer(uint32_t *pXres, uint32_t *pYres, uint32_t *pBpp)
    {
        return OLED_GetFrameBuffer(pXres, pYres, pBpp);
    }
    
    
    //把Framebuffer的数据全部刷新到LCD
    void LCD_Flush(void)
    {
        OLED_Flush();
    }
    
    //刷新LCD的区域
    void LCD_FlushRegion(int col, int row, int width, int heigh)
    {
        OLED_FlushRegion(col, row, width, heigh);
    }
    
    
    //把Framebuffer的数据全部清零
    void LCD_ClearFrameBuffer(void)
    {
        OLED_ClearFrameBuffer();
    }
    

    使用LCD封装OLED,以后换屏幕都可以用LCD.c调用具体的屏幕驱动

    记得要添加字库文件,然后就可以测试OLED屏幕了

    屏幕测试

    void OLED_Test(void)
    {
        OLED_Init();
    	// 清屏
    	OLED_Clear();
        
    	while (1)
    	{
    		// 在(0, 0)打印'A'
    		OLED_PutChar(0, 0, 'A');
    		// 在(1, 0)打印'Y'
    		OLED_PutChar(1, 0, 'Y');
    		// 在第0列第2页打印一个字符串"Hello World!"
    		OLED_PrintString(0, 2, "Hello World!");
    	}
    }
    

    效果展示:

    在这里插入图片描述

  • 接下来是DHT11将温湿度显示在屏幕上

  • DHT11.c 部分代码
//DHT11的初始化函数
void DHT11_Init(void)
{
	DHT11_PinCfgAsOutput();
	DHT11_PinSet(1);
	//mdelay(2000);
}


//读取DHT11的温度/湿度
int DHT11_Read(int *hum, int *temp)
{
	unsigned char hum_m, hum_n;
	unsigned char temp_m, temp_n;
	unsigned char check;	
	
	DHT11_Start();
	
	if (0 != DHT11_Wait_Ack())
	{
		//printf("dht11 not ack, err!\n\r");
		return -1;
	}

	if (0 != DHT11_WaitFor_Val(1, 1000))  /* 等待ACK变为高电平, 超时时间是1000us */
	{
		//printf("dht11 wait for ack high err!\n\r");
		return -1;
	}

	if (0 != DHT11_WaitFor_Val(0, 1000))  /* 数据阶段: 等待低电平, 超时时间是1000us */
	{
		//printf("dht11 wait for data low err!\n\r");
		return -1;
	}

	hum_m  = DHT11_ReadByte();
	hum_n  = DHT11_ReadByte();
	temp_m = DHT11_ReadByte();
	temp_n = DHT11_ReadByte();
	check  = DHT11_ReadByte();

	DHT11_PinCfgAsOutput();
	DHT11_PinSet(1);

	if (hum_m + hum_n + temp_m + temp_n == check)
	{
		*hum  = hum_m;
		*temp = temp_m;
		return 0;
	}
	else
	{
		//printf("dht11 checksum err!\n\r");
		return -1;
	}

}

这样我们DHT11也完成啦,最后我们来测试一下

  • DHT11测试代码
void DHT11_Test(void)
{
	int hum, temp;
    int len;
	
	DHT11_Init();
	
	while (1)
	{
		if (DHT11_Read(&hum, &temp) !=0 )
		{
			//printf("\n\rdht11 read err!\n\r");
			DHT11_Init();
		}
		else
		{
			LCD_PrintString(0, 0, "DHT11:");
            LCD_PrintString(0, 2, "Humidity Temp");
            len = LCD_PrintSignedVal(0, 5, hum);
            LCD_PutChar(len, 5, '%');
            LCD_PrintSignedVal(11, 5, temp);
		}
		mdelay(2000);  /* 读取周期是2S, 不能读太频繁 */
	}
}

最终效果:

在这里插入图片描述

(2)接着来实现通过MQTT实现开发板与阿里云服务器收发

由于怕篇幅太长我把这个实验放在下一章

代码获取地址:https://github.com/myj020329/MySmartHome

  • 2
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值