基于freertos的温湿度蓝牙系统

前言:本项目主要是基于freertos的小项目,目的是为了巩固近期学习的知识,功能较简单,可自行扩充。

一、项目基本架构

项目基本功能:通过STM32单片机的freertos操作系统,将温湿度数据显示在oled屏幕上,并将数据通过蓝牙发送到手机上显示。

项目基本思路:使用freeRTOS创建两个任务,一个任务用于读取温湿度的数据,然后将读取的内容放入队列当中,另一个任务从队列中读取温湿度数据,然后显示在屏幕上并通过串口发给蓝牙。

项目调试难题:1、多任务进行时,需要考虑优先级的问题,防止优先级反转;2、创建队列时需要使用合适的队列深度和项目大小,防止队列满溢出;3、在任务中使用延时时,可能会导致高优先级任务阻塞,从而暂时执行就绪态的低优先级任务,而出现任务执行出现卡住错误。

DHT11电容式温湿度传感器模块 温湿度检测系统解决方案 温湿度传感器品牌 型号 报价

 

Buy HC 08 Bluetooth BLE Serial Port Module at Best Price | Robu

显示屏模块_0.96寸oled显示屏arduino12864oled模块iic0.96寸oled - 阿里巴巴

 

 

二、项目配置

时钟树

 

1、任务的创建(这里确保读取温湿度任务的优先级高于显示温湿度任务的优先级即可)

2、队列的创建(这里项目的大小我设置为uint64_t,因为温湿度以及校验位有5个字节,共40位bit数据

 3、IIC设置(这里MOde选择iic即可,下面涉及到主从模式,这里并没有用到)

 4、串口(串口选择串口一,MODE选择异步通信)

 5、gpio设置(细心会发现并没有DHT11的数据引脚,因为该引脚既需要当输入引脚又需要当输出引脚,这里需要我们手动在代码设置即可)

 三、代码实现

1、温湿度读取任务

/* USER CODE END Header_StartDht11Task */
void StartDht11Task(void const * argument)
{/* USER CODE BEGIN StartDht11Task */BaseType_t status;/* Infinite loop */for(;;){//不断读取温湿度数据Read_Data_From_DHT();//这里需要加段延时等待数据读取稳定,否则可能会出现卡住的现象。osDelay(500);//将读取到的数据丢到队列里面去status = xQueueSend(Dht11QueueHandle,datas,0);//将该任务暂时挂起,防止该任务一直执行。osThreadSuspend(dht11TaskHandle);//判断写入队列状态if(status == pdTRUE){printf("写入成功\r\n");}else{printf("写入失败\r\n");}osDelay(1000);}/* USER CODE END StartDht11Task */
}

2、温湿度显示任务

void StartReadDht11Task(void const * argument)
{/* USER CODE BEGIN StartReadDht11Task */uint8_t dht[5] = {0};//队列数据缓冲区BaseType_t status;char message[32] = {'\0'};/* Infinite loop */for(;;){//高优先级任务调用osDelay函数会使任务阻塞,从而执行低优先级任务,加入延时可保证队列的写入先执行。osDelay(1000);//将队列里面的数据读取出来status = xQueueReceive(Dht11QueueHandle,dht,100);//将接收温湿度数据的任务恢复,方便下次接收。osThreadResume(dht11TaskHandle);if(status == pdTRUE){printf("读取成功\r\n");printf("Temp: %d.%d ", dht[2], dht[3]);//温度printf("Humi: %d.%d\r\n", dht[0], dht[1]);//湿度memset(message,'\0',sizeof(message));sprintf(message,"%d.%d",dht[0], dht[1]);Oled_Show_Str(2,40,message);memset(message,'\0',sizeof(message));sprintf(message,"%d.%d",dht[2], dht[3]);Oled_Show_Str(1,40,message);}else{printf("读取失败\r\n");}osDelay(2000);}/* USER CODE END StartReadDht11Task */
}

3、DHT11

void delay_us(uint16_t cnt)
{uint8_t i;while(cnt){for (i = 0; i < 10; i++){}cnt--;}
}
//设置引脚模式
void DHT_GPIO_Init(uint32_t Mode)
{GPIO_InitTypeDef GPIO_InitStruct = {0};__HAL_RCC_GPIOB_CLK_ENABLE();//用外设需要打开对应时钟GPIO_InitStruct.Pin = GPIO_PIN_5;GPIO_InitStruct.Mode = Mode;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
//DHT11初始化
void DHT11_Start(void)
{DHT_GPIO_Init(GPIO_MODE_OUTPUT_PP);//配置为输出引脚DHT_HIGHT;DHT_LOW;HAL_Delay(30);DHT_HIGHT;DHT_GPIO_Init(GPIO_MODE_INPUT);//配置为输入引脚while(DHT_VALUE);while(!DHT_VALUE);while(DHT_VALUE);
}
//读取DHT11数据
void Read_Data_From_DHT(void)
{int i;//轮int j;//每一轮读多少次char tmp;char flag;DHT11_Start();//判断硬件是否存在DHT_GPIO_Init(GPIO_MODE_INPUT);配置为输入引脚for(i= 0;i < 5;i++){for(j=0;j<8;j++){while(!DHT_VALUE);//等待卡g点delay_us(40);if(DHT_VALUE == 1){flag = 1;while(DHT_VALUE);}else{flag = 0;}tmp = tmp << 1;tmp |= flag;}datas[i] = tmp;}
}

4、串口重定向

int fputc(int ch, FILE *f){unsigned char temp[1] = {ch};HAL_UART_Transmit(&huart1,temp,1,0xffff);return ch;
}

打开USB MicroLIB选项

5、OLED

#include "oled.h"
#include "oledfont.h"
#include "i2c.h"int i =0;
char w1[16] = {0x10,0x60,0x02,0x8C,0x00,0x00,0xFE,0x92,0x92,0x92,0x92,0x92,0xFE,0x00,0x00,0x00};//温上半部分
char w2[16] = {0x04,0x04,0x7E,0x01,0x40,0x7E,0x42,0x42,0x7E,0x42,0x7E,0x42,0x42,0x7E,0x40,0x00};//温下办部分char d1[16] = {0x00,0x00,0xFC,0x24,0x24,0x24,0xFC,0x25,0x26,0x24,0xFC,0x24,0x24,0x24,0x04,0x00};//度上半部分
char d2[16] = {0x40,0x30,0x8F,0x80,0x84,0x4C,0x55,0x25,0x25,0x25,0x55,0x4C,0x80,0x80,0x80,0x00};//度下办部分char s1[16] = {0x10,0x60,0x02,0x8C,0x00,0xFE,0x92,0x92,0x92,0x92,0x92,0x92,0xFE,0x00,0x00,0x00};//湿上半部分
char s2[16] = {0x04,0x04,0x7E,0x01,0x44,0x48,0x50,0x7F,0x40,0x40,0x7F,0x50,0x48,0x44,0x40,0x00};//湿下办部分
char c1[8]  = {0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00};//冒号上半部分
char c2[8]  = {0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00};//冒号下半部分void Oled_Write_Cmd(uint8_t dataCmd)//写命令
{HAL_I2C_Mem_Write(&hi2c1,0x78,0x00,I2C_MEMADD_SIZE_8BIT,&dataCmd,1,0xff);
}
void Oled_Write_Data(uint8_t dataData)//写数据
{HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x40, I2C_MEMADD_SIZE_8BIT,&dataData, 1, 0xff);
}
//oled屏初始化
void Oled_Init(void){Oled_Write_Cmd(0xAE);//--display offOled_Write_Cmd(0x00);//---set low column addressOled_Write_Cmd(0x10);//---set high column addressOled_Write_Cmd(0x40);//--set start line addressOled_Write_Cmd(0xB0);//--set page addressOled_Write_Cmd(0x81); // contract controlOled_Write_Cmd(0xFF);//--128Oled_Write_Cmd(0xA1);//set segment remapOled_Write_Cmd(0xA6);//--normal / reverseOled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)Oled_Write_Cmd(0x3F);//--1/32 dutyOled_Write_Cmd(0xC8);//Com scan directionOled_Write_Cmd(0xD3);//-set display offsetOled_Write_Cmd(0x00);//Oled_Write_Cmd(0xD5);//set osc divisionOled_Write_Cmd(0x80);//Oled_Write_Cmd(0xD8);//set area color mode offOled_Write_Cmd(0x05);//Oled_Write_Cmd(0xD9);//Set Pre-Charge PeriodOled_Write_Cmd(0xF1);//Oled_Write_Cmd(0xDA);//set com pin configuartionOled_Write_Cmd(0x12);//Oled_Write_Cmd(0xDB);//set VcomhOled_Write_Cmd(0x30);//Oled_Write_Cmd(0x8D);//set charge pump enableOled_Write_Cmd(0x14);//Oled_Write_Cmd(0xAF);//--turn on oled panel}
//温湿度初始化
void Oled_Meg_Slow(void)
{//page0Oled_Write_Cmd(0xB0);Oled_Write_Cmd(0x00);Oled_Write_Cmd(0x10);for(i=0;i<16;i++){Oled_Write_Data(w1[i]);}for(i=0;i<16;i++){Oled_Write_Data(d1[i]);}for(i=0;i<8;i++){Oled_Write_Data(c1[i]);}//page1Oled_Write_Cmd(0xB1);Oled_Write_Cmd(0x00);Oled_Write_Cmd(0x10);for(i=0;i<16;i++){Oled_Write_Data(w2[i]);}for(i=0;i<16;i++){Oled_Write_Data(d2[i]);}for(i=0;i<8;i++){Oled_Write_Data(c2[i]);}//page2Oled_Write_Cmd(0xB2);Oled_Write_Cmd(0x00);Oled_Write_Cmd(0x10);for(i=0;i<16;i++){Oled_Write_Data(s1[i]);}for(i=0;i<16;i++){Oled_Write_Data(d1[i]);}for(i=0;i<8;i++){Oled_Write_Data(c1[i]);}//page3Oled_Write_Cmd(0xB3);Oled_Write_Cmd(0x00);Oled_Write_Cmd(0x10);for(i=0;i<16;i++){Oled_Write_Data(s2[i]);}for(i=0;i<16;i++){Oled_Write_Data(d2[i]);}for(i=0;i<8;i++){Oled_Write_Data(c2[i]);}}
void Oled_Show_Char(char row,char col,char oledChar){ //row*2-2unsigned int  i;Oled_Write_Cmd(0xb0+(row*2-2));                           //page 0Oled_Write_Cmd(0x00+(col&0x0f));                          //lowOled_Write_Cmd(0x10+(col>>4));                            //high  for(i=((oledChar-32)*16);i<((oledChar-32)*16+8);i++){Oled_Write_Data(F8X16[i]);                            //写数据oledTable1}Oled_Write_Cmd(0xb0+(row*2-1));                           //page 1Oled_Write_Cmd(0x00+(col&0x0f));                          //lowOled_Write_Cmd(0x10+(col>>4));                            //highfor(i=((oledChar-32)*16+8);i<((oledChar-32)*16+8+8);i++){Oled_Write_Data(F8X16[i]);                            //写数据oledTable1}       
}/******************************************************************************/
// 函数名称:Oled_Show_Char 
// 输入参数:oledChar 
// 输出参数:无 
// 函数功能:OLED显示单个字符
/******************************************************************************/
//指定行列显示字符串
void Oled_Show_Str(char row,char col,char *str){while(*str!=0){Oled_Show_Char(row,col,*str);str++;col += 8;   }       
}
//清屏函数
void Oled_Screen_Clear(void){int i,n;Oled_Write_Cmd (0x20); //set memory addressing modeOled_Write_Cmd (0x02); //page addressing modefor(i=0;i<8;i++){Oled_Write_Cmd(0xb0+i); //éè??ò3μ??·£¨0~7£?Oled_Write_Cmd(0x00); //éè????ê??????aáDμíμ??·Oled_Write_Cmd(0x10); //éè????ê??????aáD??μ??·for(n=0;n<128;n++)Oled_Write_Data(0x00);}
}

四、效果实现

 四、总结

最近也是断断续续的在学习freertos知识,有了STM32的HAL库开发经历及Linux的系统编程知识,对freertos的学习相对没有那么吃力,虽然对其中的任务、信号量、任务标志位的理解还是有点欠缺,但是以后会通过动手做项目来巩固加深理解。

对于该小项目、其实还有优化的空间、比如可以通过任务标志位来进行任务的通信或者信号量互斥量来进行同步互斥,也可以自行进行功能的拓展,比如检测数据加入烟雾传感器(ADC)、二氧化碳模块等传感器,通信模块换成wifi模块、4g模块,屏幕换成lcd屏幕、串口屏等,更高级就造个手机APP或者使用mqtt与云平台交互显示数据,妥妥的一个设计就出来了哈哈。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/21666.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue响应数据为二维码如何渲染到页面

在postman测试请求后发现响应数据为一个二维码图片,不是链接,如何解决? 然后如果在vue中使用请求还会报Uncaught (in promise) SyntaxError: Unexpected token o in JSON at position 1的错误。这个就是使用了JSON.parse导致的响应格式不对)&#xff0c;使用JSON.stringify解决…

Spring Boot集成单元测试调用dao,service

文章目录 Spring Boot集成单元测试调用dao&#xff0c;service1 添加相关依赖2 新建测试类 Spring Boot集成单元测试调用dao&#xff0c;service 1 添加相关依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-st…

奥威BI—数字化转型首选,以数据驱动企业发展

奥威BI系统BI方案可以迅速构建企业级大数据分析平台&#xff0c;可以将大量数据转化为直观、易于理解的图表和图形&#xff0c;推动和促进数字化转型的进程&#xff0c;帮助企业更好地了解自身的运营状况&#xff0c;及时发现问题并采取相应的措施&#xff0c;提高运营效率和质…

程序员的帝路应该是肉身成圣

标题听着贼中二&#xff0c;没办法哥们实在想不到啥好的标题&#xff0c;只是看到这个讨论程序员身体健康的话题啊情不自禁想到中学时期看过的一本修仙小说《遮天》小说内容忘记的差不多了&#xff0c;印象最深的就是各种体质&#xff0c;荒古圣体、先天霸体、混沌体等等&#…

【无公网IP】在公网环境下Windows远程桌面Ubuntu 18.04

【无公网IP】在公网环境下Windows远程桌面Ubuntu 18.04 文章目录 *【无*公网IP】在公网环境下Windows远程桌面Ubuntu 18.04一、 同个局域网内远程桌面Ubuntu1. 更新软件仓库2. 安装支持包3. 安装XFCE4桌面环境4. 安装XRDP5. 环境设置5.1 XFCE桌面配置5.2 在配置文件中&#xff…

[JAVAee]锁策略

目录 乐观锁与悲观锁 乐观锁 乐观锁的冲突检测 悲观锁 读锁与写锁 重量级锁与轻量级锁 重量级锁 轻量级锁 自旋锁 公平锁与非公平锁 可重入锁与不可重入锁 乐观锁与悲观锁 乐观锁 在乐观锁中,假设数据并不会发生冲突,在正式提交数据时会对数据进行冲突检测,如果发…

小白入门Java第一天

当你对 Java语言有了一些了解后&#xff0c;你就可以开始着手学习Java了。 作为你的Java 学习第一天&#xff0c;所需掌握内容如下述目录&#xff1a; 文章目录 1. 注释1. 三种注释1.1 单行注释1.2 多行注释1.3 文档注释 2. 标识符和关键字2.1 标识符的组成&#xff1a;2.2 那…

Smarty

一.知识 1.PHP Smarty模版注入 二.实例 {{system(ls /)}}{{system(cat /flag)}}

从零搭建一个react + electron项目

最近打算搭建一个react electron的项目&#xff0c;发现并不是那么傻瓜式 于是记录一下自己的实践步骤 通过create-react-app 创建react项目 npx create-react-app my-app 安装electron依赖 npm i electron -D暴露react项目的配置文件&#xff08;这一步看自己需求&#xff0c…

《Flask Web 开发指南 pt.2》

在编写 Flask 程序的时候&#xff0c;你需要注意你的程序文件不要命名为 flask.py&#xff0c;建议命名为 app.py 或者 wsgi.py 但如果你的程序不是叫 app.py 或者 wsgi.py&#xff0c;那么你就需要设置环境变量 FLASK_APP 的值为程序名字 设置环境变量有两种方法&#xff0c;在…

url重定向

不安全的url跳转 不安全的url跳转问题可能发生在一切执行了url地址跳转的地方。 如果后端采用了前端传进来的(可能是用户传参,或者之前预埋在前端页面的url地址)参数作为了跳转的目的地,而又没有做判断的话 就可能发生"跳错对象"的问题。 url跳转比较直接的危害是…

SpringBoot整合邮件服务

SpringBoot整合邮件服务 发送邮件应该是网站的必备功能之一&#xff0c;什么注册验证&#xff0c;忘记密码或者是给用户发送营销信息。最早期的时候我们会 使用 JavaMail 相关 api 来写发送邮件的相关代码&#xff0c;后来 Spring 推出了 JavaMailSender 更加简化了邮件发送的…

API是什么?

API是什么&#xff1f; API&#xff08;Application Programming Interface,应用程序编程接口&#xff09;是一些预先定义的函数&#xff0c;目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力&#xff0c;而又无需访问源码&#xff0c;或理解内部工作机制…

SSM(Vue3+ElementPlus+Axios+SSM前后端分离)【三】

文章目录 SSM(Vue3ElementPlusAxiosSSM前后端分离)--基础环境搭建【三】项目介绍项目功能/界面● SSM 整合项目界面 配置Spring 和MyBatis , 并完成整合 SSM(Vue3ElementPlusAxiosSSM前后端分离)–基础环境搭建【三】 项目介绍 项目功能/界面 ● SSM 整合项目界面 配置Sprin…

回调函数的简单用例

列举项目中一个简单的回调函数用例 ①用MsgInterface_t定义一个结构体s_Lin_MsgInterface&#xff0c;包含两个回调函数成员&#xff1a; ②确定结构体下的回调函数成员的参数&#xff1a; ③传入实参&#xff0c;确定结构体下的回调函数成员的函数名&#xff1a; ④最终回…

【数据结构与算法——TypeScript】算法的复杂度分析、 数组和链表的对比

【数据结构与算法——TypeScript】 算法的复杂度分析 什么是算法复杂度(现实案例)&#xff1f; ❤️‍&#x1f525; 前面已经解释了什么是算法&#xff1f; 其实就是解决问题的一系列步骤操作、逻辑。 ✅ 对于同一个问题&#xff0c;我们往往有很多种解决思路和方法&#x…

Jenkins工具系列 —— Jenkins 安装并启动

文章目录 安装涉及相关链接选择安装Jenkins版本安装JenkinsJenkins web页面启动卸载Jenkins 安装涉及相关链接 Jenkins官网&#xff1a; https://www.jenkins.io/zh/ Jenkins下载安装步骤&#xff1a; https://www.jenkins.io/zh/download/ 安装各种版本OpenJDK&#xff1a; h…

weui cells 如何去掉边框

问题&#xff1a;weui cells 如何去掉边框 解决&#xff1a; cells通过before,after实现边框&#xff0c;不显示的话&#xff0c;在引用的页面wxss加上&#xff1a; .weui-cells:before,.weui-cells:after {border: none; }

3分钟白话RocketMQ系列—— 核心概念

白话3分钟&#xff0c;快速了解RocketMQ基础&#xff0c;包括适用场景&#xff0c;以及基本概念。 看完如果不了解&#xff0c;欢迎来打我。 关键字摘要 低延迟、高可用、高可靠、高并发 的消息中间件适合在线业务分为producer、consumer、nameserver、broker等角色另外还有主…

过程:从虚拟机上添加 git 并成功提交到 GitLab 的全过程

Ⅰ、准备工作&#xff1a; 1、Git 查看&#xff1a; 其一、命令&#xff1a;git --version // 此时就能在虚拟机环境下看到 git 的版本为: git version 2.41.0 其二、如何在虚拟机上安装 git &#xff1a; A、命令 &#xff1a; sudo apt-get install git B、然后再输入虚…