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

今日尝试开发一款简单好学的 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

最后还有个稳压降压模块

硬件实物连接图:

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

代码编程主要逻辑:

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

cpp 复制代码
#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;// 无按键按下
}
cpp 复制代码
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图片...

cpp 复制代码
#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

相关推荐
zy张起灵3 小时前
48v72v-100v转12v 10A大功率转换电源方案CSM3100SK
经验分享·嵌入式硬件·硬件工程
向宇it5 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
九鼎科技-Leo6 小时前
什么是 WPF 中的依赖属性?有什么作用?
windows·c#·.net·wpf
PegasusYu6 小时前
STM32CUBEIDE FreeRTOS操作教程(九):eventgroup事件标志组
stm32·教程·rtos·stm32cubeide·free-rtos·eventgroup·时间标志组
Heaphaestus,RC7 小时前
【Unity3D】获取 GameObject 的完整层级结构
unity·c#
baivfhpwxf20237 小时前
C# 5000 转16进制 字节(激光器串口通讯生成指定格式命令)
开发语言·c#
直裾7 小时前
Scala全文单词统计
开发语言·c#·scala
ZwaterZ9 小时前
vue el-table表格点击某行触发事件&&操作栏点击和row-click冲突问题
前端·vue.js·elementui·c#·vue
lantiandianzi11 小时前
基于单片机的多功能跑步机控制系统
单片机·嵌入式硬件
文弱书生65611 小时前
输出比较简介
stm32