深圳比较好的网站设计公司,注册网站用于跳转虚拟货币网站违法,百度广告联盟标识,三只松鼠网络营销方案策划书前言#xff1a;本项目主要是基于freertos的小项目#xff0c;目的是为了巩固近期学习的知识#xff0c;功能较简单#xff0c;可自行扩充。
一、项目基本架构 项目基本功能#xff1a;通过STM32单片机的freertos操作系统#xff0c;将温湿度数据显示在oled屏幕上#…前言本项目主要是基于freertos的小项目目的是为了巩固近期学习的知识功能较简单可自行扩充。
一、项目基本架构 项目基本功能通过STM32单片机的freertos操作系统将温湿度数据显示在oled屏幕上并将数据通过蓝牙发送到手机上显示。
项目基本思路使用freeRTOS创建两个任务一个任务用于读取温湿度的数据然后将读取的内容放入队列当中另一个任务从队列中读取温湿度数据然后显示在屏幕上并通过串口发给蓝牙。
项目调试难题1、多任务进行时需要考虑优先级的问题防止优先级反转2、创建队列时需要使用合适的队列深度和项目大小防止队列满溢出3、在任务中使用延时时可能会导致高优先级任务阻塞从而暂时执行就绪态的低优先级任务而出现任务执行出现卡住错误。 二、项目配置
时钟树 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(j0;j8;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.hint 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(i0;i16;i){Oled_Write_Data(w1[i]);}for(i0;i16;i){Oled_Write_Data(d1[i]);}for(i0;i8;i){Oled_Write_Data(c1[i]);}//page1Oled_Write_Cmd(0xB1);Oled_Write_Cmd(0x00);Oled_Write_Cmd(0x10);for(i0;i16;i){Oled_Write_Data(w2[i]);}for(i0;i16;i){Oled_Write_Data(d2[i]);}for(i0;i8;i){Oled_Write_Data(c2[i]);}//page2Oled_Write_Cmd(0xB2);Oled_Write_Cmd(0x00);Oled_Write_Cmd(0x10);for(i0;i16;i){Oled_Write_Data(s1[i]);}for(i0;i16;i){Oled_Write_Data(d1[i]);}for(i0;i8;i){Oled_Write_Data(c1[i]);}//page3Oled_Write_Cmd(0xB3);Oled_Write_Cmd(0x00);Oled_Write_Cmd(0x10);for(i0;i16;i){Oled_Write_Data(s2[i]);}for(i0;i16;i){Oled_Write_Data(d2[i]);}for(i0;i8;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(col0x0f)); //lowOled_Write_Cmd(0x10(col4)); //high for(i((oledChar-32)*16);i((oledChar-32)*168);i){Oled_Write_Data(F8X16[i]); //写数据oledTable1}Oled_Write_Cmd(0xb0(row*2-1)); //page 1Oled_Write_Cmd(0x00(col0x0f)); //lowOled_Write_Cmd(0x10(col4)); //highfor(i((oledChar-32)*168);i((oledChar-32)*1688);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(i0;i8;i){Oled_Write_Cmd(0xb0i); //éè??ò3μ??·¨0~7?Oled_Write_Cmd(0x00); //éè????ê??????aáDμíμ??·Oled_Write_Cmd(0x10); //éè????ê??????aáD??μ??·for(n0;n128;n)Oled_Write_Data(0x00);}
}四、效果实现 四、总结
最近也是断断续续的在学习freertos知识有了STM32的HAL库开发经历及Linux的系统编程知识对freertos的学习相对没有那么吃力虽然对其中的任务、信号量、任务标志位的理解还是有点欠缺但是以后会通过动手做项目来巩固加深理解。
对于该小项目、其实还有优化的空间、比如可以通过任务标志位来进行任务的通信或者信号量互斥量来进行同步互斥也可以自行进行功能的拓展比如检测数据加入烟雾传感器ADC、二氧化碳模块等传感器通信模块换成wifi模块、4g模块屏幕换成lcd屏幕、串口屏等更高级就造个手机APP或者使用mqtt与云平台交互显示数据妥妥的一个设计就出来了哈哈。