今日尝试开发一款简单好学的 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(); //初始化定时器2i2c_GPIO_Config(); //IIC初始化OLED_Init(); //初始化OLED屏幕OLED_Clear(); //清空屏幕数据AHT10Init(); //初始化温湿度传感器Timer3_PWM_init(2000,719);//初始化定时器3Beep_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