这个项目也是我给别人代做的,大家先看一下视频,了解一下这个项目
客户要求基本是这样的:现在大学的教室门口不都贴着课程表嘛,然后每个学期都要换,上面有这个学期要上的课,每一个格子里有课程名字,上课老师,课程开始和结束的周数,例如周一第一节课1-8周高等数学,9-16周概率论这样子,但是每个学期都需要取出来换,所以客户想让我做一个可以自动从网络获取课程表的设计,要自动从网络获取就必须要爬虫呗,用Python爬虫我还是会的,毕竟也参加过数学建模,学过Python,但是硬件方面我只会STM32,不会树莓派啊,所以我给他提了另外一个方案。
那就是把课程啊,教室啊什么的信息都放到内存卡里,然后把设备固定到墙上,这样每个学期只需要拔出内存卡把里面的文件更新一下再插回去不就行了,然后不用STM32计时,用机智云自动获取网络时间,这样时间不就不会错了,然后计算出当前是第几周,根据周数显示课表(因为有的课不在当前周可以不用显示),然后用机智云设置远程操作与监控。
设计一个APP给老师用,设置上“正在考试”功能,开启功能课表消失,显示正在考试,然后其他在找教室自习的同学看到后就不会有闯进教室的尴尬了;“课程顺延”功能,开启后课表消失,显示课程已顺延,这样学生就不用在教室白白等了;“调课功能”,当前教室要是多媒体坏了或者房顶漏水,老师可以提前设置要更换的教室,学生在看到后直接去调课的教室;“当前教室”功能,开启后当前教室的课程表消失,显示正在上课,上什么课,上课老师是谁,也是放止不是本班的学生进错了教室,导致尴尬,同时自动开启打卡功能,学生进教室之前打卡,老师的APP界面显示当前已打卡的学生人数。
在听到我的方案之后说比他想的更周全,然后果断选择了使用我的方案。
好,废话不多说了,我们来说一下这个项目,STM32连接机智云与修改开源APP的教程在我的博客里都有,不会的小伙伴看以去看我的博客学习。
功能就如视频中那样,现在粘贴核心部分的源码,已经详细注释
show.c
extern int students; extern int classnum; FIL fil; FRESULT res; UINT bww; FIL fil_date; FRESULT res_date; UINT bww_date; char buf[200]; char buf_date[11]; int currentoday; int weeks; int group; int current_class; //读取SD卡内容,将信息存储到buf,计算本学期本教室共有几节课 void Show_SDIO(void) { int n=0; char str; int len = 0; res=f_open (&fil,"0:/table.txt", FA_READ); //打开文件 f_read (&fil, buf,200,&bww); //读取文件并将值存入buf f_close(&fil);//关闭文件 res_date=f_open (&fil_date,"0:/date.txt", FA_READ); //打开文件 f_read (&fil_date, buf_date,200,&bww_date); //读取文件并将值存入buf f_close(&fil_date);//关闭文件 for(n=0;n>=0;n++)//统计文件中共有多少值 { str = buf[n]; if(str=='\0') { len = n; //printf("Space:%d\r\n",len); break; } } //printf("Buff:%s",(u8 *)buf); group = len/9;//计算本学期本教室一周要上多少课 } void Show_Week(int month,int day)//显示当前周数 { int daytime=0; int today = 0; int i,j; int days[12]={31,28,31,30,31,30,31,31,30,31,30,31}; int current_month,current_day; current_month=(buf_date[4]-'0')*10+(buf_date[5]-'0'); current_day=(buf_date[6]-'0')*10+(buf_date[7]-'0'); current_class=(buf_date[8]-'0')*100+(buf_date[9]-'0')*10-(buf_date[10]-'0'); for(i=current_month-1;i<month-1;i++) { daytime=daytime+days[i]; } for(j=0;j<month-1;j++) { today += days[j]; } daytime += day;//计算从开学到现在一共多少天 today += day;//计算从2018.1.1周一开始一共经过了多少天 printf("today:%d",today); currentoday = today%7;//计算当前周几 daytime -= current_day; weeks = daytime/7+1;//计算开学到现在当前周数 Show_Str_Mid(364,30,"第 周",24,72); LCD_ShowxNum(388,30,weeks,2,24,0);//LCD显示周数 if(currentoday==0)//显示当前周几 { Show_Str_Mid(290,0,"周日",24,48); }else if(currentoday==1) { Show_Str_Mid(290,0,"周一",24,48); }else if(currentoday==2) { Show_Str_Mid(290,0,"周二",24,48); }else if(currentoday==3) { Show_Str_Mid(290,0,"周三",24,48); }else if(currentoday==4) { Show_Str_Mid(290,0,"周四",24,48); }else if(currentoday==5) { Show_Str_Mid(290,0,"周五",24,48); }else if(currentoday==6) { Show_Str_Mid(290,0,"周六",24,48); } } void Show_Table(void)//显示课表 { char str1,str2,str3; int x,y,x0,y0; int m=0,m0,n0; for(x=0;x<8;x++)//绘制表格 { LCD_DrawRectangle(x*100,60,100+x*100,100); for(y=0;y<5;y++) { LCD_DrawRectangle(x*100,100+y*70,100+x*100,170+y*70); } } printf("Group:%d\r\n",group); for(m=0;m<group;m++) { str1=buf[0+m*9];str2=buf[1+m*9]; m0 = (buf[2+m*9]-'0')*10+(buf[3+m*9]-'0'); n0 = (buf[4+m*9]-'0')*10+(buf[5+m*9]-'0'); str3 = buf[8+m*9]; printf("m:%d,n:%d\r\n",m0,n0); if(str1=='1')//按照周几第几节课将课程名称填入对应位置 { x0=100; }else if(str1=='2') { x0=200; }else if(str1=='3') { x0=300; }else if(str1=='4') { x0=400; }else if(str1=='5') { x0=500; }else if(str1=='6') { x0=600; }else if(str1=='7') { x0=700; } if(str2=='1') { y0=127; }else if(str2=='2') { y0=197; } else if(str2=='3') { y0=267; } else if(str2=='4') { y0=337; } else if(str2=='5') { y0=407; } if(weeks>=m0&&weeks<=n0) { printf("OK\r\n"); if(str3=='1') { Show_Str_Mid(x0,y0-8,"复变函数与",16,100); Show_Str_Mid(x0,y0+8,"积分变换",16,100); }else if(str3=='2') { Show_Str_Mid(x0,y0-8,"数学物理方法",16,100); Show_Str_Mid(x0,y0+8,"与特殊函数",16,100); }else if(str3=='3') { Show_Str_Mid(x0,y0,"高等数学2-2",16,100); }else if(str3=='4') { Show_Str_Mid(x0,y0,"电磁学",16,100); }else if(str3=='5') { Show_Str_Mid(x0,y0,"单片机原理",16,100); }else if(str3=='6') { Show_Str_Mid(x0,y0,"通信原理",16,100); } } } //LCD显示课表基本内容 Show_Str_Mid(100,68,"周一",24,100); Show_Str_Mid(200,68,"周二",24,100); Show_Str_Mid(300,68,"周三",24,100); Show_Str_Mid(400,68,"周四",24,100); Show_Str_Mid(500,68,"周五",24,100); Show_Str_Mid(600,68,"周六",24,100); Show_Str_Mid(700,68,"周日",24,100); Show_Str_Mid(0,123,"第一节",24,100); Show_Str_Mid(0,193,"第二节",24,100); Show_Str_Mid(0,263,"第三节",24,100); Show_Str_Mid(0,333,"第四节",24,100); Show_Str_Mid(0,403,"第五节",24,100); } //LCD显示课程顺延 void Show_Deferred(void) { Show_Str_Mid(280,250,"课程顺延",24,240); Show_Str_Mid(280,280,"暂停授课",24,240); } //显示正在考试 void Show_Examination(void) { Show_Str_Mid(280,250,"正在考试",24,240); } //显示调课 void Show_Lecture(int classroom) { Show_Str_Mid(280,250,"已调课至",24,240); Show_Str_Mid(280,280,"明理楼",24,240); Show_Str_Mid(370,310,"理 ",24,60); LCD_ShowxNum(394,310,classroom,3,24,0); } //显示正在上课 void Show_Class(int classroom) { int x0 = 325,y0 = 140; char str1,str2,str3; int m=0,m0,n0; Show_Str_Mid(280,220,"第 节课",24,240);//显示当前是第几节课 LCD_ShowxNum(376,220,classnum,2,24,0); Show_Str_Mid(280,250,"正在上课",24,240); Show_Str_Mid(280,280,"请刷卡",24,240); Show_Str_Mid(370,310,"理 ",24,60);//显示当前教室 LCD_ShowxNum(394,310,classroom,3,24,0); Show_Str_Mid(346,340,"已到 人",24,108);//显示已到学生人数 //LCD_ShowxNum(394,340,students,3,24,0); for(m=0;m<group;m++)//显示当前上课的详细内容 { str1=buf[0+m*9];str2=buf[1+m*9]; m0 = (buf[2+m*9]-'0')*10+(buf[3+m*9]-'0'); n0 = (buf[4+m*9]-'0')*10+(buf[5+m*9]-'0'); str3 = buf[8+m*9]; printf("m:%d,n:%d\r\n",m0,n0); if((str1-'0')==currentoday&&(str2-'0')==classnum&&weeks>=m0&&weeks<=n0) { if(weeks>=m0&&weeks<=n0) { printf("OK\r\n"); if(str3=='1') { Show_Str_Mid(x0,y0-12,"复变函数与",24,150); Show_Str_Mid(x0,y0+12,"积分变换",24,150); Show_Str_Mid(x0,y0+36,"老师:牛鹏斌",24,150); }else if(str3=='2') { Show_Str_Mid(x0,y0-12,"数学物理方法",24,150); Show_Str_Mid(x0,y0+12,"与特殊函数",24,150); Show_Str_Mid(x0,y0+36,"老师:牛鹏斌",24,150); }else if(str3=='3') { Show_Str_Mid(x0,y0,"高等数学2-2",24,150); Show_Str_Mid(x0,y0+24,"老师:肖润梅",24,150); }else if(str3=='4') { Show_Str_Mid(x0,y0,"电磁学",24,150); Show_Str_Mid(x0,y0+24,"老师:王 萍",24,150); }else if(str3=='5') { Show_Str_Mid(x0,y0,"单片机原理",24,150); Show_Str_Mid(x0,y0+24,"老师:张 昊",24,150); }else if(str3=='6') { Show_Str_Mid(x0,y0,"通信原理",24,150); Show_Str_Mid(x0,y0+24,"老师:孙慧萍",24,150); } } } } }
main.c
/* 用户区当前设备状态结构体*/ dataPoint_t currentDataPoint; //WIFI连接状态 //wifi_sta 0: 断开 // 1: 已连接 u8 wifi_sta=0; //协议初始化 void Gizwits_Init(void) { TIM3_Int_Init(9,7199);//1MS系统定时 usart3_init(9600);//WIFI初始化 memset((uint8_t*)¤tDataPoint, 0, sizeof(dataPoint_t));//设备状态结构体初始化 gizwitsInit();//缓冲区初始化 } int main(void) { u8 key_num; u8 key; u8 status=0; extern int students; extern int students_flag; extern int months,days; extern int current_class; u8 wifi_con=0;//记录wifi连接状态 1:连接 0:断开 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2 delay_init(); //初始化延时函数 uart_init(115200); //初始化串口1波特率为115200,用于支持USMART BEEP_Init(); //初始化蜂鸣器 //OUTPUT_Init(); //输出模块初始化 InitRc522(); //初始化射频卡模块 KEY_Init(); //按键初始化 LCD_Init(); //LCD初始化 Gizwits_Init(); //协议初始化 //W25QXX_Init(); //初始化W25Q128 tp_dev.init(); //初始化触摸屏 usmart_dev.init(72); //初始化USMART //my_mem_init(SRAMIN); //初始化内部内存池 exfuns_init(); //为fatfs相关变量申请内存 f_mount(fs[0],"0:",1); //挂载SD卡 f_mount(fs[1],"1:",1); //挂载FLASH. LCD_Display_Dir(1);//设置横屏 POINT_COLOR=RED;//红色字体 while(font_init()) //检查字库 { LCD_ShowString(60,50,240,16,16,"Font Error!"); delay_ms(200); LCD_Fill(60,50,240,66,WHITE);//清除显示 delay_ms(200); } while(SD_Init())//检测不到SD卡 { Show_Str_Mid(50,30,"SD卡异常",24,96); delay_ms(500); Show_Str_Mid(50,30,"请检查",24,96); delay_ms(500); } /* if(res==0X0D)//FLASH磁盘,FAT文件系统错误,重新格式化FLASH { LCD_ShowString(450,30,200,16,16,"Flash Disk Formatting..."); //格式化FLASH res=f_mkfs("1:",1,4096);//格式化FLASH,1,盘符;1,不需要引导区,8个扇区为1个簇 if(res==0) { f_setlabel((const TCHAR *)"1:ALIENTEK"); //设置Flash磁盘的名字为:ALIENTEK LCD_ShowString(450,30,200,16,16,"Flash Disk Format Finish"); //格式化完成 }else LCD_ShowString(450,30,200,16,16,"Flash Disk Format Error "); //格式化失败 delay_ms(1000); } */ Show_SDIO();//读取SD卡内容,将信息存储到buf,计算本学期本教室共有几节课 if(!(tp_dev.touchtype&0x80))//如果是电阻屏 { Show_Str_Mid(0,30,"是否进行触摸屏校准",16,240); POINT_COLOR=BLUE; Show_Str_Mid(0,60,"是:KEY2 否:KEY0",16,240); while(1) { key_num=KEY_Scan(0); if(key_num==KEY0_PRES) break; if(key_num==KEY2_PRES) { LCD_Clear(WHITE); TP_Adjust(); //屏幕校准 TP_Save_Adjdata();//保存校准参数 break; } } } POINT_COLOR=BLACK;//字体更新为黑色 printf("--------机智云IOT-智能教务显示系统----------\r\n"); printf("KEY1:AirLink连接模式\t KEY_UP:复位\r\n\r\n"); while(1) { if(wifi_con!=wifi_sta)//判断是否已连接WIFI { wifi_con=wifi_sta; wifi_con?Show_Str_Mid(600,0,"WIFI已连接",24,200):Show_Str_Mid(600,0,"WIFI未连接",24,200); } Show_Str_Mid(398,0,"明理楼 理 ",24,240); LCD_ShowxNum(506,0,current_class,3,24,0); gizwitsGetNTP();//请求NTP网络时间 currentDataPoint.valueStudents = students;//学生人数上报 if(currentDataPoint.valueClassroom==Classroom_VALUE4)//如果310教室上课 { RC522_Handel();//刷卡 LCD_ShowxNum(394,340,students,3,24,0); //LCD显示人数 } gizwitsHandle((dataPoint_t *)¤tDataPoint);//协议处理 if(wifi_sta&&status==0)//开机连接WIFI后显示当前的周数以及本周的课表,此程序只执行一次,防止循环执行覆盖其他命令页面 { Show_Week(months,days);//显示周数 Show_Table();//根据SD卡内容显示课表 status=1; } key = KEY_Scan(0);//读取按键值 if(key==KEY0_PRES) { } if(key==KEY1_PRES)//KEY1按键 { printf("WIFI进入AirLink连接模式\r\n"); gizwitsSetMode(WIFI_AIRLINK_MODE);//Air-link模式接入 } if(key==WKUP_PRES)//KEY_UP按键 { printf("WIFI复位,请重新配置连接\r\n"); gizwitsSetMode(WIFI_RESET_MODE);//WIFI复位 wifi_sta=0;//标志wifi已断开 } delay_ms(200);//延时200ms } }
gizwits_product.c
int8_t gizwitsEventProcess(eventInfo_t *info, uint8_t *gizdata, uint32_t len) { uint8_t i = 0; dataPoint_t *dataPointPtr = (dataPoint_t *)gizdata; moduleStatusInfo_t *wifiData = (moduleStatusInfo_t *)gizdata; protocolTime_t *ptime = (protocolTime_t *)gizdata; #if MODULE_TYPE gprsInfo_t *gprsInfoData = (gprsInfo_t *)gizdata; #else moduleInfo_t *ptModuleInfo = (moduleInfo_t *)gizdata; #endif if((NULL == info) || (NULL == gizdata)) { return -1; } for(i=0; i<info->num; i++) { switch(info->event[i]) { case EVENT_Examination: currentDataPoint.valueExamination = dataPointPtr->valueExamination; GIZWITS_LOG("Evt: EVENT_Examination %d \n", currentDataPoint.valueExamination); if(0x01 == currentDataPoint.valueExamination)//如果正在考试开关打开 { //user handle LCD_Clear(WHITE);//清屏 Show_Examination();//显示正在考试 } else//正在考试开关关闭 { LCD_Clear(WHITE);//清屏 Show_Table();//显示课表 } break; case EVENT_Deferred: currentDataPoint.valueDeferred = dataPointPtr->valueDeferred; GIZWITS_LOG("Evt: EVENT_Deferred %d \n", currentDataPoint.valueDeferred); if(0x01 == currentDataPoint.valueDeferred)//如果正在课程顺延打开 { //user handle LCD_Clear(WHITE);//清屏 Show_Deferred();//显示考试顺延 } else { LCD_Clear(WHITE);//清屏 Show_Table();//显示课表 } break; case EVENT_Classroom: currentDataPoint.valueClassroom = dataPointPtr->valueClassroom; GIZWITS_LOG("Evt: EVENT_Classroom %d\n", currentDataPoint.valueClassroom); switch(currentDataPoint.valueClassroom) { case Classroom_VALUE0://当前教室为None students_flag=1; students = 0;//学生人数清空 LCD_Clear(WHITE);//清屏 Show_Table();//显示课表 //user handle break; case Classroom_VALUE1: //user handle break; case Classroom_VALUE2: //user handle break; case Classroom_VALUE3: //user handle break; case Classroom_VALUE4://选择310教室 students_flag=1; students = 0;//学生人数清空 LCD_Clear(WHITE);//清屏 Show_Class(310);//显示310教室详细情况 //user handle break; case Classroom_VALUE5: //user handle break; case Classroom_VALUE6: //user handle break; case Classroom_VALUE7: //user handle break; default: break; } break; case EVENT_Lecture: currentDataPoint.valueLecture = dataPointPtr->valueLecture; GIZWITS_LOG("Evt: EVENT_Lecture %d\n", currentDataPoint.valueLecture); switch(currentDataPoint.valueLecture) { case Lecture_VALUE0://调课选择None LCD_Clear(WHITE);//清屏 Show_Table();//显示课表 //user handle break; case Lecture_VALUE1://调课选择307 LCD_Clear(WHITE);//清屏 Show_Lecture(307);//显示调课至307 //user handle break; case Lecture_VALUE2://同上 LCD_Clear(WHITE); Show_Lecture(308); //user handle break; case Lecture_VALUE3: LCD_Clear(WHITE); Show_Lecture(309); //user handle break; case Lecture_VALUE4: LCD_Clear(WHITE); Show_Lecture(310); //user handle break; case Lecture_VALUE5: LCD_Clear(WHITE); Show_Lecture(311); //user handle break; case Lecture_VALUE6: LCD_Clear(WHITE); Show_Lecture(312); //user handle break; case Lecture_VALUE7: LCD_Clear(WHITE); Show_Lecture(313); //user handle break; default: break; } break; case WIFI_SOFTAP: break; case WIFI_AIRLINK: break; case WIFI_STATION: break; case WIFI_CON_ROUTER: break; case WIFI_DISCON_ROUTER: break; case WIFI_CON_M2M:wifi_sta=1;//wifi设备已连接//第二处,添加 break; case WIFI_DISCON_M2M:wifi_sta=0;//wifi设备断开//第三处,添加 break; case WIFI_RSSI: GIZWITS_LOG("RSSI %d\n", wifiData->rssi); break; case TRANSPARENT_DATA: GIZWITS_LOG("TRANSPARENT_DATA \n"); //user handle , Fetch data from [data] , size is [len] break; case WIFI_NTP: //获取网络时间 GIZWITS_LOG("WIFI_NTP : [%d-%d-%d %02d:%02d:%02d][%d] \n",ptime->year,ptime->month,ptime->day,ptime->hour,ptime->minute,ptime->second,ptime->ntp); //显示年月日 LCD_ShowxNum(20,0,ptime->year,4,24,0); LCD_ShowChar(68,0,'-',24,0); LCD_ShowxNum(80,0,ptime->month,2,24,0); LCD_ShowChar(104,0,'-',24,0); LCD_ShowxNum(126,0,ptime->day,2,24,0); //显示时分秒 LCD_ShowxNum(180,0,ptime->hour,2,24,0); LCD_ShowChar(204,0,':',24,0); LCD_ShowxNum(216,0,ptime->minute,2,24,0); LCD_ShowChar(240,0,':',24,0); LCD_ShowxNum(252,0,ptime->second,2,24,0); //显示周几 Show_Week(ptime->month,ptime->day); months = ptime->month; days = ptime->day; currentmin = ptime->hour*60+ptime->minute; //计算当前是第几节课 if(currentmin>=(8*60)&¤tmin<=(9*60+50)) { classnum = 1; }else if(currentmin>=(10*60+10)&¤tmin<=(12*60)) { classnum = 2; }else if(currentmin>=(14*60+30)&¤tmin<=(16*60+20)) { classnum = 3; }else if(currentmin>=(16*60+30)&¤tmin<=(18*60+20)) { classnum = 4; }else if(currentmin>=(19*60)&¤tmin<=(21*60+50)) { classnum = 5; } break; case MODULE_INFO: GIZWITS_LOG("MODULE INFO ...\n"); #if MODULE_TYPE GIZWITS_LOG("GPRS MODULE ...\n"); //Format By gprsInfo_t #else GIZWITS_LOG("WIF MODULE ...\n"); //Format By moduleInfo_t GIZWITS_LOG("moduleType : [%d] \n",ptModuleInfo->moduleType); #endif break; default: break; } } return 0; }
硬件连接如下
左侧的电路是我设计的备用电源系统,经12V电源升压到24V后带动继电器动作,电池正极接常闭触点,这样在有点的时候继电器常开触点闭合,常闭触点断开,电池不给单片机供电,如果突然断电,常开触点断开,常闭触点闭合,电池供电电路接通,通过5V稳压模块稳定输出5V电源供单片机使用,达到备用电源的作用。在有电时,电池通过TP4056电源模块充电,模块自带过充保护,在锂电池充满电后就不在继续充电,达到保护电池的目的
源代码里忘了放内存卡里的文件了,首先是本学期课程表的TXT文件
table.txt
110108001110916002120116003210116004310116003320116005350108001350916002410116006420116004510108001510916002530116003
每九个数字一组,以“110108001”为例,从左到右,"1"代表周一,“1”代表第一节课,“01”代表这节课的开始的周数,“08”代表这节课结束的周数,“001”代表课程代码,对照如下
001复变函数与积分变换
002数学物理方法与特殊函数
003高等数学2-2
004电磁学
005单片机原理
006通信原理
然后是本学期开学日期以及教室号的TXT文件
date.txt
20180304310“20180304”代表开学的日期,要用这个计算当前的周数,“310”代表当前教室是310教室
至此,教程结束,谢谢大家,也欢迎大家关注我的个人技术与资源分享公众号“linkutures”