微型家庭中控STM32+C#上位机_(STM32部分)

news2024/9/24 7:20:23

今日尝试开发一款简单好学的 C8T6+C#_Winform上位机 的微型家庭中控设备的 小试验品:

这个设备将成为我毕设系统的一个小部分......

主要开发环境与工具介绍:

 单片机 STM32F103C8T6  使用标准库函数编程

 Visual Studio 2022软件  C# Winform 开发 上位机控制软件

本文主要描述一下STM32部分的实现......

STM32部分主要实现:

监控温度湿度,查看时间日期,开灯,开门,报警,串口回传信息给上位机等功能

 文章提供完整代码解释、设计点解释、测试效果图、完整工程下载

目录

STM32F103C8T6单片机部分:

使用模块与接线:

硬件实物连接图:

代码编程主要逻辑:

STM32部分功能单独展示:

STM32串口发送部分:

STM32部分整体工程下载:


STM32F103C8T6单片机部分:

 这部分就用简单的while(1)主循环加定时器中断的前后台逻辑裸机程序就能很好胜任了,

不需要什么都上操作系统(耗电)......

使用模块与接线:

使用以下传感器与显示器(包含接线):

AHT10 温湿度传感器 :

                             SCL: PB3    

                             SDA:   PB4

OLED显示器:

                             SCL: PB6   

                             SDA:   PB7

Beep蜂鸣器   :     PA0

LED 灯           :     PA1

舵机               :   PA6

按键KEY1       :    PA2

按键KEY2       :    PB15

按键KEY3       :    PB14

按键KEY4       :    PB13

最后还有个稳压降压模块

硬件实物连接图:

 直接飞线连连得了......

代码编程主要逻辑:

灯、蜂鸣器、按键的引脚初始化都只需要初始化为输入输出引脚即可

#include "headfire.h"

//蜂鸣器、灯、按键 初始化
void Beep_LED_KEY_init(void)
{
		/*定义一个GPIO_InitTypeDef类型的结构体*/
		GPIO_InitTypeDef GPIO_InitStructure;		
		/*开启LED相关的GPIO外设时钟*/
		RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA,ENABLE);
		/*开启LED相关的GPIO外设时钟*/
		RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB,ENABLE);		
		
		/*选择要控制的GPIO引脚*/
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;	
		/*设置引脚模式为通用推挽输出*/
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   
		/*设置引脚速率为50MHz */   
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
		/*调用库函数,初始化GPIO*/
		GPIO_Init(GPIOA	, &GPIO_InitStructure);
	
		/*选择要控制的GPIO引脚*/
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;	
		/*设置引脚模式为通用推挽输出*/
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   
		/*设置引脚速率为50MHz */   
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
		/*调用库函数,初始化GPIO*/
		GPIO_Init(GPIOA	, &GPIO_InitStructure);

    // 配置PA2为输入模式,无上拉/下拉  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入,你也可以选择GPIO_Mode_IPU(内部上拉)或GPIO_Mode_IPD(内部下拉)  
    GPIO_Init(GPIOA, &GPIO_InitStructure);  
  
    // 配置GPIOB13为输入模式,这里以内部上拉为例  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 内部上拉输入  
    GPIO_Init(GPIOB, &GPIO_InitStructure);  
  
    // 类似地配置GPIOB14和GPIOB15  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;  
    GPIO_Init(GPIOB, &GPIO_InitStructure); // 保持之前的模式设置(内部上拉)  
  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;  
    GPIO_Init(GPIOB, &GPIO_InitStructure); // 保持之前的模式设置(内部上拉)  
	
}




//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//0,没有任何按键按下
//1,KEY0按下
//2,KEY1按下

//4,KEY3按下 WK_UP
//注意此函数有响应优先级,KEY0>KEY1>KEY3!!
u8 KEY_Scan(u8 mode)
{	 
	static u8 key_up=1;//按键按松开标志
	if(mode)key_up=1;  //支持连按		  
	if(key_up&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0))
	{
		delay_ms(10);//去抖动 
		key_up=0;
		if(KEY1==0)return KEY1_PRES;
		else if(KEY2==0)return KEY2_PRES;
		else if(KEY3==0)return KEY3_PRES;
		else if(KEY4==0)return KEY4_PRES;
	}else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1)key_up=1; 	    
 	return 0;// 无按键按下
}
void Beep_LED_KEY_init(void);

/* 使用标准的固件库控制IO*/
#define LED(a)	if (a)	\
					GPIO_SetBits(GPIOA, GPIO_Pin_1);\
					else		\
					GPIO_ResetBits(GPIOA, GPIO_Pin_1)
/* 使用标准的固件库控制IO*/
#define Beep(a)	if (a)	\
					GPIO_SetBits(GPIOA, GPIO_Pin_0);\
					else		\
					GPIO_ResetBits(GPIOA, GPIO_Pin_0)

					
//#define KEY1 PAin(2)  //PA2
//#define KEY2 PBin(15)	//PB15 
//#define KEY3 PBin(14)	//PB14
//#define KEY4 PBin(13)	//PB13  
					
#define KEY1  GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2)  //读取按键1
#define KEY2  GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15) //读取按键2
#define KEY3  GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14) //读取按键3 
#define KEY4 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13) //读取按键4 

 
#define KEY1_PRES 	1	//KEY1按下
#define KEY2_PRES	  2	//KEY2按下
#define KEY3_PRES	  3	//KEY3按下
#define KEY4_PRES   4	//KEY4按下

u8 KEY_Scan(u8 mode);
					
					
#endif

 主函数用各种标志位等刷新OLED、按键操作等,定时器实时刷新一些数据或OLED图片...

#include "main.h"

float temp;
u8 hum;
int humm,temper;
uint16_t AHT10_cnt,AHT10_flag;
char buf[30];
uint16_t AHT10_cnt,AHT10_flag;
char buf[30];
//刷新时间标志
uint16_t TimeDisplay_cnt,TimeDisplay,BMP_Display;
u8 display;                    //切换OLED显示内容用(0:温湿度  1:时间)
u8 KEY_value;
int age=21;
u8 door_state=0;  //门状态
u8 oled_state=0;  //显示状态
u8 led_state=0;   //灯状态
u8 Beep_state=0;  //报警状态
u8 Beep_s=0;       //报警状态
u8 Beep_cnt=0;


int main(void)
{	
	init_ALL();     //初始化所有函数
  while(1)
	{	
		KEY_value=KEY_Scan(0);
		
		switch(KEY_value)
		{
			case 0:	break;
			case KEY1_PRES:	led_state++;
											if(led_state%2==1)  {	LED(1);}
											if(led_state%2==0)	{	LED(0);}
											if(led_state == 16) {led_state=2;} //防止数据异常
											break;
			case KEY2_PRES: Beep_state++;
											if(Beep_state%2==0) {	Beep_s=1;}
											if(Beep_state%2==1)	{	Beep_s=0;}
											if(Beep_state == 16) {Beep_state=2;} //防止数据异常											
											break;
			case KEY3_PRES: oled_state++;
											if(oled_state%2==0) {	OLED_Clear();Beep(1);display=1;}
											if(oled_state%2==1)	{	OLED_Clear();Beep(1);display=0;}											
											if(oled_state == 16) {oled_state=2;} //防止数据异常
											break;			
			case KEY4_PRES:	door_state++;
											if(door_state%2==0) {Beep(1);TIM_SetCompare1(TIM3,60); }
											if(door_state%2==1)	{Beep(1);TIM_SetCompare1(TIM3,260);}
											if(door_state == 16) {door_state=2;} //防止数据异常
											break;
		}
			if(Beep_s==1)
				{
					Beep(1);
				}
				else if(Beep_s==0)
				{
					Beep(0);			
				}
		if(AHT10_flag==1 && display==0)
		{
			AHT10_flag=0;
			AHT10ReadData(&temp,&hum);
			temper=temp*10;
			humm=hum;
			OLED_ShowCHinese(0,0,0);  //打印中文“温”
			OLED_ShowCHinese(16,0,2);  //打印中文“度”
		  sprintf(buf,": %d.%d",temper/10,temper%10);		
 		  OLED_ShowString(32,0,(u8 *)buf,16);	   
			
			OLED_ShowCHinese(0,2,1);  //打印中文“湿”
			OLED_ShowCHinese(16,2,2);  //打印中文“度”
		  sprintf(buf,": %d ",humm);		
 		  OLED_ShowString(32,2,(u8 *)buf,16);	     

			//打印班级姓名
			sprintf(buf,"%d ", age);	
 		  OLED_ShowString(0,5,(u8 *)buf,16);
			OLED_ShowCHinese(16,5,6);   //打印中文“通”			
			OLED_ShowCHinese(32,5,7);   //打印中文“信”		
			OLED_ShowCHinese(48,5,8);   //打印中文“杨”					
			OLED_ShowCHinese(64,5,9);   //打印中文“志”		
			OLED_ShowCHinese(80,5,10);  //打印中文“豪”		
		}
		
		else if(TimeDisplay==1 && display==1)
		{
			Time_Display(RTC_GetCounter(),&time1);
			TimeDisplay=0;
			
		}
		
		if(BMP_Display==1 && display==1)
		{
			switch(BMP_FLAG)
			{
			case 1:OLED_DrawBMP(0,0,64,8,BMP1);  break;
			case 2:OLED_DrawBMP(0,0,64,8,BMP2);  break;
			case 3:OLED_DrawBMP(0,0,64,8,BMP3);  break;
			case 4:OLED_DrawBMP(0,0,64,8,BMP4);  break;
			case 5:OLED_DrawBMP(0,0,64,8,BMP5);  break;
			case 6:OLED_DrawBMP(0,0,64,8,BMP6);  break;
			case 7:OLED_DrawBMP(0,0,64,8,BMP7);  break;
			case 8:OLED_DrawBMP(0,0,64,8,BMP8);  break;
			case 9:OLED_DrawBMP(0,0,64,8,BMP9);  break;
			case 10:OLED_DrawBMP(0,0,64,8,BMP10);  break;
			
			case 11:OLED_DrawBMP(0,0,64,8,BMP11);  break;
			case 12:OLED_DrawBMP(0,0,64,8,BMP12);  break;
			case 13:OLED_DrawBMP(0,0,64,8,BMP13);  break;
			case 14:OLED_DrawBMP(0,0,64,8,BMP14);  break;
			case 15:OLED_DrawBMP(0,0,64,8,BMP15);  break;
				
//flash不够了,只能注释掉这些内存
//			case 16:OLED_DrawBMP(0,0,64,8,BMP16);  break;
//			case 17:OLED_DrawBMP(0,0,64,8,BMP17);  break;
//			case 18:OLED_DrawBMP(0,0,64,8,BMP18);  break;
//			case 19:OLED_DrawBMP(0,0,64,8,BMP19);  break;
//			case 20:OLED_DrawBMP(0,0,64,8,BMP20);  break;		

//			case 21:OLED_DrawBMP(0,0,64,8,BMP21);  break;
//			case 22:OLED_DrawBMP(0,0,64,8,BMP22);  break;
//			case 23:OLED_DrawBMP(0,0,64,8,BMP23);  break;
//			case 24:OLED_DrawBMP(0,0,64,8,BMP24);  break;
//			case 25:OLED_DrawBMP(0,0,64,8,BMP25);  break;
//			case 26:OLED_DrawBMP(0,0,64,8,BMP26);  break;
//			case 27:OLED_DrawBMP(0,0,64,8,BMP27);  break;
//			case 28:OLED_DrawBMP(0,0,64,8,BMP28);  break;
		}
		BMP_Display=0;
		}
		
		
	}
}


//初始化所有函数:
void init_ALL(void)
{
	SysTick_Init(72);         //初始化滴答计时器
	Timer2_Init();						//初始化定时器2
	i2c_GPIO_Config();	      //IIC初始化
	OLED_Init();              //初始化OLED屏幕
	OLED_Clear();             //清空屏幕数据
	AHT10Init();              //初始化温湿度传感器
	Timer3_PWM_init(2000,719);//初始化定时器3
	Beep_LED_KEY_init();      //蜂鸣器、灯、按键 初始化
	RTC_init();
	
	LED(1);
	Beep(1);
	delay_ms(50);
	LED(0);
	Beep(0);
	TIM_SetCompare1(TIM3,60);//150是90度
	
	display=1;
}


//定时器2中断服务函数
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{		
		if(++AHT10_cnt==30)         //每300ms刷新一次温湿度数据
		{AHT10_cnt=0;AHT10_flag=1;}
				if(++TimeDisplay_cnt==10)  //每100ms定时器刷新时间
		{
			TimeDisplay_cnt=0;TimeDisplay=1;
		}
		
		if(++BMP_cnt==5)		        //定时器50ms刷新太空人图片
		{
			BMP_cnt=0;
			BMP_FLAG++;
			BMP_Display=1;
			if(BMP_FLAG==15){BMP_FLAG=1;}
		}
		
		if(++Beep_cnt==12)
		{		
				Beep(0);	
				Beep_cnt=0;
		}
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清出中断寄存器标志位,用于退出中断
	}
}


//RTC每秒进的中断服务函数
void RTC_IRQHandler(void)
{
	  if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
	  {
	    /* Clear the RTC Second interrupt */
	    RTC_ClearITPendingBit(RTC_IT_SEC);
	
//	    /* Enable time update */
//	    TimeDisplay = 1;
//	
	    /* Wait until last write operation on RTC registers has finished */
	    RTC_WaitForLastTask();
	  }
}

 

 

STM32部分功能单独展示:

KEY1    开关灯

KEY2    报警

KEY3    切换界面显示(时间界面、温湿度界面)

KEY4    驱动舵机模拟开关门

微型家庭中控设备STM32部分功能单独展示

STM32串口发送部分:

这部分的发送逻辑不是简单的发送数据就行了,这是与上位机相配合的数据包格式的发送,目前暂时不添加这个功能,等上位机写好后再编写串口回传数据的功能

STM32部分整体工程下载:

https://download.csdn.net/download/qq_64257614/89628888

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

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

相关文章

【相机与图像】2. 相机内外参的标定的代码示例

1 摄像头内参的标定 【相机标定具体操作】 使用将要标定的摄像头,以不同的角度采集棋盘格,要保证视野内出现完整的棋盘格。采集图片数量约15张左右即可。 以11*8的棋盘格为例,具体流程如下: step 1. 设置棋盘格3D点;通…

MapReduce_Writable序列化

使用序列化封装对象 将输入的csv按照员工号拆分成每个员工&#xff0c;每个员工存储为员工对象 数据处理过程 employee_noheader.csv 1,ZhangSan,101,5000 2,LiSi,102,6000 3,WangWu,101,5500 4,ZhaoLiu,103,7000 5,SunQi,102,6500pom.xml <?xml version"1.0&qu…

ctfshow-web入门-sql注入(web201-web205)系统练习sqlmap的使用

目录 1、web201 2、web202 3、web203 4、web204 5、web205 开始系统练习sqlmap的使用 1、web201 随便提交一个看下它调用的接口和请求的参数有哪些 可以看到 URL 为&#xff1a; https://32c7d026-d195-4074-a0f9-492c17dc1a2c.challenge.ctf.show/api/?id1&page1&…

微信答题小程序产品研发-前端开发

开发一款答题小程序界面&#xff0c;涉及到的技术栈&#xff0c;主要包括微信小程序的WXML、WXSS、JavaScript等。 由于时间有限&#xff0c;我先大致记录一下各个功能模块的基本开发概要&#xff0c;后面有空了再详细整理&#xff0c;分享给大家。 1. 首页 &#xff08;1&am…

Windows网络重置后无法连接网络

Windows网络重置后重启电脑无法连接到网络 打开命令提示符快捷键winR输入msconfig点击确定 在系统配置中找到服务先全部禁用&#xff0c;在全部启用&#xff0c;点击应用后重启电脑就可以了

LVS的简单配置及对Mysql主从复制的补充

Day 22 LVS的配置 环境准备 DSN() 用来解析各主机的域名和ip地址&#xff0c;配置域名解析huajuan&#xff0c;负责管理其他主机 web1--->web1.tangpin.huajuan web2--->web2.tangpin.huajuan dns--->dns.tangpin.huajuan web1(192.168.2.200) 用nginx…

解决 MacOS 连接公司 VPN 成功但是不能网络的问题

目录 解决办法2024 Mac mini 爆料 解决办法 操作比较简单&#xff0c;修改配置文件即可&#xff08;如果没有则需要手动创建&#xff09;。 sudo vim /etc/ppp/options在此文件下&#xff0c;加入 plugin L2TP.ppp&#xff1a; plugin L2TP.ppp如果文件里有l2tpnoipsec&…

基于ESP32的智能门锁系统测试

项目介绍 基于ESP32的智能门锁系统。可以运用在商务办公、家用住宅、酒店以及公租房短租公寓等领域。基于esp32的智能门锁系统是生物识别技术和嵌入式系统技术的完美结合&#xff0c;基于ESP32系统进行开发&#xff0c;同时在云端服务器搭建了MQTT服务器并连接开源的家庭自动化…

Apple Intelligence 最詳細解說

Apple Intelligence究竟是什麼&#xff1f; 顧名思義&#xff0c;Apple Intelligence就是Apple獨家開發的 AI 模型&#xff08;深度整合至 iOS 18、iPadOS 18 和 macOS Sequoia&#xff09;&#xff0c;旨在透過理解和生成語言和圖像、解讀上下文&#xff0c;並在特定App中執行…

【计算机网络】UDP实战

其实经过这几天写的几种不同的UDP的简易客户端与服务端&#xff0c;还是很有套路的&#xff0c;起手式都是非常像的。 更多的难点对我来说反而是解耦&#xff0c;各种各样的function一用&#xff0c;回调函数一调&#xff0c;呕吼&#xff0c;就会懵一下。 对于这篇文章&#x…

成功解决7版本的数据库导入 8版本数据库脚本报错问题

我 | 在这里 ⭐ 全栈开发攻城狮、全网10W粉丝、2022博客之星后端领域Top1、专家博主。 &#x1f393;擅长 指导毕设 | 论文指导 | 系统开发 | 毕业答辩 | 系统讲解等。已指导60位同学顺利毕业 ✈️个人公众号&#xff1a;热爱技术的小郑。回复 Java全套视频教程 或 前端全套视频…

大数据面试SQL(七):累加刚好超过各省GDP40%的地市名称

文章目录 累加刚好超过各省GDP40%的地市名称 一、题目 二、分析 三、SQL实战 四、样例数据参考 累加刚好超过各省GDP40%的地市名称 一、题目 现有各省地级市的gdp数据,求从高到低累加刚好超过各省GDP40%的地市名称&#xff0c;临界地市也需要。 例如&#xff1a; 浙江省…

设计模式-延迟加载(Lazy Load)

概念 一个对象&#xff0c;它虽然不包含所需要的所有数据&#xff0c;但是知道怎么获取这些数据。 加载一个对象会引起大量相关对象的加载&#xff0c;这样会损害系统的性能。延迟加载会暂时终止这个加载过程。 运行机制 四种实现延迟加载的方法&#xff1a; 延迟初始化&am…

ThreadLocal —— 让每个线程拥有自己的变量副本

在多线程编程中&#xff0c;数据共享是一个常见的话题。很多时候我们需要多个线程共享同一个数据&#xff0c;以实现数据的一致性和通信。然而&#xff0c;在一些场景下&#xff0c;我们并不希望数据被多个线程共享&#xff0c;而是希望每个线程都拥有自己独立的一份数据。这时…

【C++类和对象(中)】—— 我与C++的不解之缘(四)

前言&#xff1a; 接下来进行类和对象中的学习&#xff0c;了解类和对象的默认成员函数 一、类和对象默认成员函数 默认成员函数就是用户没有显示实现&#xff0c;编译器会自动生成的成员函数。 一个类&#xff0c;我们不显示实现的情况下&#xff0c;编译器就会默认生成一下留…

无人机开启农林植保新篇章

嘿&#xff0c;小伙伴们&#xff0c;你们知道吗&#xff1f;无人机已经悄悄在农业领域大展拳脚&#xff0c;成为现代农业的“黑科技”新宠儿啦&#xff01; 想象一下&#xff0c;广袤的田野上空&#xff0c;无人机如同勤劳的蜜蜂&#xff0c;精准高效地完成着各项任务&#xff…

unity 使用 compute shader的步骤

这里详细的记载使用步骤&#xff0c;我这个例子是让一个立方体上下不停的动 创建一个compute shader 一个普通shader 一个材质 一个C# 先挨个写上类容 这里kernel 指定main函数入口&#xff0c;RWStructuredBuffer就是数组&#xff0c;具体size是在外部指定的&#xff0c;可能…

C#使用CEFSharp获取动态网页源码

CEF 全称是Chromium Embedded Framework&#xff08;Chromium嵌入式框架&#xff09;&#xff0c;是个基于Google Chromium项目的开源Web browser控件&#xff0c;支持Windows, Linux, Mac平台。CEFSharp就是CEF的C#移植版本。 访问以下链接可以获取CEF的详细介绍 chromiumem…

c++版opencv长文指南

c版opencv长文指南 1、配置opencv库1.1 下载1.2 配置1.2.1 配置包含目录1.2.2 配置库含目录1.2.3 配置链接器1.2.4 配置系统环境变量 2、学习路线3、入门知识3.1 图像读取与显示3.2 图像色彩空间转换3.2 图像对象的创建与赋值3.2.1 图像对象的创建3.2.2 图像对象的赋值 3.3 图像…

轻松搞定小程序生成短链接/二维码,你学会了吗?

朋友们&#xff0c;大家有没有遇到过这样的困扰&#xff1a;小程序由于不是链接&#xff0c;在短信或者其他平台里根本没法推广&#xff0c;导致小程序的用户量很难涨起来。 那小程序转成链接真的就没办法实现吗&#xff1f;当然不是&#xff01; 现在有一款超实用的工具——…