微型家庭中控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

最后还有个稳压降压模块

硬件实物连接图:

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

代码编程主要逻辑:

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

#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

STM32是一款由STMicroelectronics推出的32位微控制器系列,它们可以适用于广泛的应用领域,包括工业控制、汽车电子、智能家居等。STM32 Bootloader是STM32系列微控制器的引导程序,它的作用是在开机时加载应用程序或者进行固件升级。 STM32 Bootloader是一种特殊的引导加载程序,它位于微控制器的内部存储器中,并且在开机时首先运行。Bootloader通常用于加载嵌入式系统的操作系统或应用程序,或者进行固件升级、调试等操作。 在STM32微控制器中,Bootloader的实现方式可以有多种,包括从Flash存储器中加载应用程序、从外部存储器(如SD卡、串行Flash等)加载应用程序、通过串口或USB接口进行固件升级等。通过Bootloader,用户可以方便地对STM32微控制器的固件进行管理和升级,同时也可以实现一些高级功能,比如在设备上电时自动检测是否有新固件可用,并进行升级。 在使用STM32 Bootloader时,需要了解其工作原理和相应的编程方式,通常可以通过ST官方提供的工具或者第三方开发工具进行Bootloader的开发和配置。除了官方提供的Bootloader之外,用户还可以根据自己的需求开发定制的Bootloader,以满足特定的应用场景和功能需求。 总之,STM32 Bootloader在STM32微控制器的固件管理和升级方面具有重要作用,它为用户提供了方便、高效的固件管理方式,同时也为嵌入式系统的开发和维护带来了很大的便利性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NULL指向我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值