门锁系统——屏幕显示

2023-11-01 00:31
文章标签 系统 屏幕显示 门锁

本文主要是介绍门锁系统——屏幕显示,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

接上篇1.门锁系统——项目简介_only_print的博客-CSDN博客

本节主要先简单实现屏幕的显示功能,以供后期的显示需要。

设想先实现上部为显示整个信息,下部显示密码的选项。

目录

显示部分

程序设计

触摸部分

CobeMX设置

程序设计


显示部分

本实验采用的是2.8寸TFTLCD,有关LCD的基本操作过程可以参考我之前的博客:使用FSMC连接TFT LCD_only_print的博客-CSDN博客

接下来我们就基于这个地方开始进行开发。

CobeMX中的设置已经完成,直接进入程序

程序设计

为了整个项目的整洁,我们将自己实现的LCD相关程序放在一个新的文件中,在文件目录下创建一个新的文件夹,在其中创建一个bsp_LCD.c和bsp_LCD.h文件,将其分别添加到文件目录中。

然后就可以初步实现显示功能了,先在下方显示LCD的数字显示功能,具体功能实现下:

// 画出下方的屏幕中按键void LCD_Partition(void){uint16_t i,x= 0,y = 170;POINT_COLOR=RED;LCD_Fill(x,y,x+240,y+150,WHITE);/* 此处就是画一些条条框框来放置相应的UI值 */LCD_DrawRectangle(x,y,x+240,y+150); //画竖线                                    LCD_DrawRectangle(x+80,y,x+160,y+150); LCD_DrawRectangle(x,y+30,x+240,y+60);LCD_DrawRectangle(x,y+90,x+240,y+120);POINT_COLOR=BLUE;LCD_ShowString(x+4,y+7,80,16,16,(uint8_t *)"Del FinPt");// 删除指纹按键  LCD_ShowString(x+4+80,y+7,80,16,16,(uint8_t *)"Cge PasWd");// 修改密码LCD_ShowString(x+4+80*2,y+7,80,16,16,(uint8_t *)"Cre FinPt");// 新建指纹按键  for(i=1;i<10;i++)//数字键盘{// 显示1至9LCD_ShowNum(x+36+((i-1)%3)*80,y+7+30*(((i-1)/3)+1),i,1,16);}// 显示剩下的# 0 *LCD_ShowString(36, y+7+30*4, 8,16,16, (uint8_t *)"*");  // 这个按键用来触摸时,删除错误的按键。LCD_ShowNum(80+36, y+7+30*4, 0, 1, 16);LCD_ShowString(160+36, y+7+30*4, 8,16,16,(uint8_t *)"#");  // 这个按键用来触摸时,提交密码。}

再显示上方的按键功能信息,这部分留于以后模块实现时完成这部分二级菜单,具体实现如下:

// 绘制上方的部分,这部分用来展示按键的作用/* 按键的作用key1-密码设置key2-指纹设置key3-卡片设置key4-忘记密码*/void Key_Press(void){LCD_ShowString(10,0, 240,16,16,(uint8_t*)"[1] Password settings");LCD_ShowString(10,20,240,16,16, (uint8_t*)"[2] Fingerprint settings");LCD_ShowString(10,40,240,16,16, (uint8_t*)"[3] IDCard settings");LCD_ShowString(10,60, 240,16,16,(uint8_t*)"[4] Forgot password");}

最后为了方便将之前的两个初始化添加到一个初始化函数中:

// 屏幕显示初始化函数void Bsp_Lcd_Init(void){LCD_Partition();Key_Press();}

将函数在bsp_lcd.h中声明,在主函数中调用即可。

然后将各个按键的作用分别定义为函数:

// 触摸设置void Touch_Set(void){// 清除y方向上从0到80的区域LCD_Fill(0, 0, 280, 80, WHITE);// 最上方显示选择的按键LCD_ShowString(10,0, 240,16,16,(uint8_t*)"[1] Touch settings");// 触摸校正函数,在touch.c中定义TouchCalibrate();// 显示完成后重新显示主界面HAL_Delay(2000);Bsp_Lcd_Init();}// 指纹设置void Finger_Set(void){LCD_Fill(0, 0, 280, 80, WHITE);LCD_ShowString(10,0,240,16,16, (uint8_t*)"[2] Fingerprint settings");// 画出按键对应的选项uint16_t x= 0,y = 20;POINT_COLOR=RED;  // 将颜色设置为红色/* 此处就是画一些条条框框来放置相应的UI值 */LCD_DrawRectangle(x,y,x+120,y+60);   // 画矩形                                   LCD_DrawRectangle(x+120,y,x+240,y+60);POINT_COLOR=BLUE;  // 将颜色设置为蓝色// 设置方框内显示内容LCD_ShowString(x+20,y+10,80,16,16,(uint8_t *)"View the");LCD_ShowString(x+20,y+30,80,16,16,(uint8_t *)"password");  // 查看密码(将密码发送到手机上)LCD_ShowString(x+20+120,y+10,80,16,16,(uint8_t *)"Change the");LCD_ShowString(x+20+120,y+30,80,16,16,(uint8_t *)"password");  // 修改密码}// 卡片设置void IDCard_Set(void){LCD_Fill(0, 0, 280, 80, WHITE);LCD_ShowString(10,0,240,16,16, (uint8_t*)"[3] IDCard settings");// 画出按键对应的选项uint16_t x= 0,y = 20;POINT_COLOR=RED;  // 将颜色设置为红色/* 此处就是画一些条条框框来放置相应的UI值 */LCD_DrawRectangle(x,y,x+120,y+60);   // 画矩形                                   LCD_DrawRectangle(x+120,y,x+240,y+60);POINT_COLOR=BLUE;  // 将颜色设置为蓝色// 设置方框内显示内容LCD_ShowString(x+20,y+10,80,16,16,(uint8_t *)"View the");LCD_ShowString(x+20,y+30,80,16,16,(uint8_t *)"password");  // 查看密码(将密码发送到手机上)LCD_ShowString(x+20+120,y+10,80,16,16,(uint8_t *)"Change the");LCD_ShowString(x+20+120,y+30,80,16,16,(uint8_t *)"password");  // 修改密码}// 密码设置void Password_Set(void){LCD_Fill(0, 0, 280, 100, WHITE);LCD_ShowString(10,0, 240,16,16,(uint8_t*)"[4] Password settings");// 画出按键对应的选项uint16_t x= 0,y = 20;POINT_COLOR=RED;  // 将颜色设置为红色/* 此处就是画一些条条框框来放置相应的UI值 */LCD_DrawRectangle(x,y,x+239,y+60);   // 画矩形                                   POINT_COLOR=BLUE;  // 将颜色设置为蓝色// 设置方框内显示内容LCD_ShowString(x+20,y+10,240,16,16,(uint8_t *)"View the password");LCD_ShowString(x+20,y+30,240,16,16,(uint8_t *)"Please check your phone");  // 查看密码(将密码发送到手机上)}

注意:这里的函数只是初步的设置,在之后需要为各个函数添加自己相应的函数操作.。

触摸部分

显示完成后,就需要可以触摸实现第一种解锁方式了

基本原理:

    电阻触摸屏的主要部分是一块与显示器表面非常配合的电阻薄膜屏,这是一种多层的复合薄膜,它以一层玻璃或硬塑料平板作为基层,表面涂有一层透明氧化金属(透明的导电电阻)导电层,上面再盖有一层外表面硬化处理、光滑防擦的塑料层、它的内表面也涂有一层涂层、在他们之间有许多细小的(小于 1/1000 英寸)的透明隔离点把两层导电层隔开绝缘 当手指触摸屏幕时,两层导电层在触摸点位置就有了接触,电阻发生变化,在 X Y 两个方向上产生信号,然后送触摸屏控制器。控制器侦测到这一接触并计算出(XY)的位置,再根据获得的位置模拟鼠标的方式运作。这就是电阻技术触摸屏的最基本的原理,具体情况如下图所示:

 24CXX系列芯片属于EEPROM(Electrically Erasable Programmable read only memory)掉电可擦可编程只读存储器,是一种掉电后数据不丢失(不挥发)存储芯片。

该系列芯片由美国Mcrochip公司出品,1-512K位的支持I2C总线数据传送协议的串行CMOS E2PROM,可用电擦除,可编程自定时写周期(包括自动擦除时间不超过10ms,典型时间为5ms)的。串行E2PROM一般具有两种写入方式,一种是字节写入方式,还有另一种页写入方式。允许在一个写周期内同时对1个字节到一页的若干字节的编程写入,1页的大小取决于芯片内页寄存器的大小。其中,AT24C01具有8字节数据的页面写能力,AT24C02/04/08/16具有16字节数据的页面写能力,AT24C32/64具有32字节数据的页面写能力。

CobeMX设置

这一块需要用到之前的按键和24C02芯片(EEPROM),这个芯片的作用是用来储存屏幕的校准信息和密码的。这个芯片是我这块开发板自带的,这个每个开发板可能不太一样,需要根据自己的板子来使用,但是实现的功能都一样,是为了在掉电后还可以储存信息。

触摸是使用SPI方式进行通讯的,这里选择软件触发方式,同时提供4个按键的GPIO设置:

这里的KEY经过测试,只有这样才能正常使用。

在使用软件模拟SPI时需要使用到微秒级延时,这里需要打开TIM7,并设置为71分频,具体操作如图:

接下来配置EEPROM,这块需要选择I2C方式通信,这里因为我的开发板中设计的接口只能选择I2C2(如果发现自己的屏幕数据在复位后无法保存,大概率是I2C接口选择错误),选择模式为I2C模式。

这些配置完成后就可以生成代码了。

程序设计

这部分我们仍然需要创建文件夹来存放EEPROM,KEY和触摸的程序,分别创建24C02_EEPROM,KEY和touch文件,在其中创建相应的.c和.h文件,添加到主函数中。

在key.c中我们实现按键的识别功能:

// 轮询4个按键,返回按键值KEYS ScanKeys(uint32_t timeout){KEYS key = KEY0;// 按下按键1if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET){HAL_Delay(10);if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET){key = KEY1;}}else if(HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET){HAL_Delay(10);if(HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET){key = KEY2;}}else if((HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin) == GPIO_PIN_RESET)){HAL_Delay(10);if((HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin) == GPIO_PIN_RESET)){key = KEY3;}}else if((HAL_GPIO_ReadPin(KEY4_GPIO_Port, KEY4_Pin) == GPIO_PIN_SET)){HAL_Delay(10);if((HAL_GPIO_ReadPin(KEY4_GPIO_Port, KEY4_Pin) == GPIO_PIN_SET)){key = KEY4;}}return key;}

相应的在key.h中需要设置一些对应的定义:

#include "main.h"// 按键的枚举变量typedef enum{KEY0 = 0,   // 没有按键按下KEY1,KEY2,KEY3,    KEY4,} KEYS;
#define KEY_WAIT_ALWAYS   0  // 作为ScanKeys的输入参数,表示一直等待按键输入KEYS ScanKeys(uint32_t timeout);

这样对按键的识别就完成了,接下来我们需要对按键做出反应,在主函数中对按键做出反应:

KEYS curKey;/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while(1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */curKey=ScanKeys(KEY_WAIT_ALWAYS);switch(curKey){case  KEY0:break;case       KEY1:{Touch_Set();break;}case       KEY2:{Finger_Set();break;}case       KEY3:{IDCard_Set();break;}// 修改密码case       KEY4:{Password_Set();break;}}//end switchHAL_Delay(300);}

switch函数中的各个函数组成在上边的显示部分中.

接下来我们对触摸做出反应,触摸函数实际上就是将按下屏幕的位置进行计算,然后得出坐标.这部分函数有很多实现的方法,这里只是其中的一种,这些函数厂商会提供,可以直接复制厂商的,这里我就不进行详细讲解了,剩下的自己识别部分我们再详细说明:

#include "touch.h"#include "tim.h"#include      "touch.h"#include      "lcd.h"#include "24C02_EEPROM.h"/* 触摸校正因数设置 */#define LCD_ADJX_MIN (10)                      //读取四个点的最小X值#define LCD_ADJX_MAX (240 -  LCD_ADJX_MIN) //读取四个点的最大X值#define LCD_ADJY_MIN (10)                      //读取四个点的最小Y值#define LCD_ADJY_MAX (320 - LCD_ADJY_MIN) //读取四个点的最大Y值#define LCD_ADJ_X (LCD_ADJX_MAX - LCD_ADJY_MIN)//读取方框的宽度#define LCD_ADJ_Y (LCD_ADJY_MAX - LCD_ADJY_MIN)//读取方框的高度#define TOUCH_READ_TIMES 5     //一次读取触摸值的次数#define TOUCH_X_CMD      0xD0  //读取X轴命令#define TOUCH_Y_CMD      0x90  //读取Y轴命令#define TOUCH_MAX        20    //预期差值#define TOUCH_X_MAX      4000  //X轴最大值#define TOUCH_X_MIN      100   //X轴最小值#define TOUCH_Y_MAX      4000  //Y轴最大值#define TOUCH_Y_MIN      100   //Y轴最小值//电阻屏SPI接口的基本输入输出#define MISO_Read()             HAL_GPIO_ReadPin(T_MISO_GPIO_Port,T_MISO_Pin)#define MOSI_Out0()              HAL_GPIO_WritePin(T_MOSI_GPIO_Port,T_MOSI_Pin,GPIO_PIN_RESET)#define MOSI_Out1()              HAL_GPIO_WritePin(T_MOSI_GPIO_Port,T_MOSI_Pin,GPIO_PIN_SET)#define SCK_Out0()         HAL_GPIO_WritePin(T_SCK_GPIO_Port,T_SCK_Pin,GPIO_PIN_RESET)#define SCK_Out1()         HAL_GPIO_WritePin(T_SCK_GPIO_Port,T_SCK_Pin,GPIO_PIN_SET)#define TCS_Out0()          HAL_GPIO_WritePin(TP_CS_GPIO_Port,TP_CS_Pin,GPIO_PIN_RESET)#define TCS_Out1()          HAL_GPIO_WritePin(TP_CS_GPIO_Port,TP_CS_Pin,GPIO_PIN_SET)#define TOUCH_AdjDelay500ms()  HAL_Delay(500)TouchPointDef TouchPoint;   //触摸点数据TouchParaDef TouchPara;     //触摸屏校正参数,全局静态变量//SPI写数据//向触摸屏写入1byte数据//num:要写入的数据void TOUCH_Write_Byte(uint8_t num){ uint8_t count=0;for(count=0;count<8;count++) {       if(num & 0x80)MOSI_Out1();elseMOSI_Out0();num<<=1;   SCK_Out0();Delay_us(1);SCK_Out1();        //上升沿有效}}//SPI读数据 ,软件模拟SPI//从触摸屏IC读取adc值//CMD:指令//返回值:读到的数据        uint16_t TOUCH_Read_AD(uint8_t CMD){      uint8_t count=0;uint16_t Num=0;SCK_Out0(); //TCLK=0;            //先拉低时钟MOSI_Out0();      //TDIN=0;           //拉低数据线TCS_Out0();         //TCS=0;             //选中触摸屏ICTOUCH_Write_Byte(CMD);//发送命令字Delay_us(6); //delay_us(6);     //ADS7846的转换时间最长为6usSCK_Out0(); //TCLK=0;Delay_us(1); //delay_us(1);SCK_Out1(); //TCLK=1;                   //给1个时钟,清除BUSYDelay_us(1); //delay_us(1);SCK_Out0(); //TCLK=0;for(count=0;count<16;count++)//读出16位数据,只有高12位有效{                            Num<<=1;    SCK_Out0(); //TCLK=0;     //下降沿有效Delay_us(1); //delay_us(1);SCK_Out1(); //TCLK=1;if (MISO_Read()) //if(DOUT)Num++;}Num>>=4;               //只有高12位有效.TCS_Out1();         //TCS=1;              //释放片选return(Num);  }uint16_t TOUCH_ReadData(uint8_t cmd){uint8_t i, j;uint16_t readValue[TOUCH_READ_TIMES], value;uint32_t totalValue;/* 读取TOUCH_READ_TIMES次触摸值 */for(i=0; i<TOUCH_READ_TIMES; i++){   /* 打开片选 *///       TCS_Out0();         //TCS=0;/* 在差分模式下,XPT2046转换需要24个时钟,8个时钟输入命令,之后1个时钟去除 *//* 忙信号,接着输出12位转换结果,剩下3个时钟是忽略位 */   readValue[i]=TOUCH_Read_AD(cmd); // 发送命令,选择X轴或者Y轴//        TCS_Out1();          //TCS=1;}/* 滤波处理 *//* 首先从大到小排序 */for(i=0; i<(TOUCH_READ_TIMES - 1); i++){for(j=i+1; j<TOUCH_READ_TIMES; j++){/* 采样值从大到小排序排序 */if(readValue[i] < readValue[j]){value = readValue[i];readValue[i] = readValue[j];readValue[j] = value;}}}/* 去掉最大值,去掉最小值,求平均值 */j = TOUCH_READ_TIMES - 1;totalValue = 0;for(i=1; i<j; i++)     //求y的全部值{totalValue += readValue[i];}value = totalValue / (TOUCH_READ_TIMES - 2);return value;}//返回值为0表示有触摸操作uint8_t TOUCH_ReadXY(uint16_t *xValue, uint16_t *yValue){  uint16_t xValue1, yValue1, xValue2, yValue2;xValue1 = TOUCH_Read_AD(TOUCH_X_CMD);yValue1 = TOUCH_Read_AD(TOUCH_Y_CMD);xValue2 = TOUCH_Read_AD(TOUCH_X_CMD);yValue2 = TOUCH_Read_AD(TOUCH_Y_CMD);/* 查看两个点之间的采样值差距 */if(xValue1 > xValue2)*xValue = xValue1 - xValue2;else*xValue = xValue2 - xValue1;if(yValue1 > yValue2)*yValue = yValue1 - yValue2;else*yValue = yValue2 - yValue1;/* 判断采样差值是否在可控范围内 */if((*xValue > TOUCH_MAX+0) || (*yValue > TOUCH_MAX+0)) return 0xFF;/* 求平均值 */*xValue = (xValue1 + xValue2) / 2;*yValue = (yValue1 + yValue2) / 2;/* 判断得到的值,是否在取值范围之内 */if((*xValue > TOUCH_X_MAX+0) || (*xValue < TOUCH_X_MIN)|| (*yValue > TOUCH_Y_MAX+0) || (*yValue < TOUCH_Y_MIN))return 0xFF;elsereturn 0;      //读取成功,有触控操作}uint8_t TOUCH_ReadAdjust(uint16_t x, uint16_t y, uint16_t *xValue, uint16_t *yValue){uint8_t i;uint32_t timeCont=0;/* 读取校正点的坐标 */LCD_Clear(WHITE);LCD_DrowSign(x, y, RED);i = 0;while(1){if(!TOUCH_ReadXY(xValue, yValue)){i++;if(i > 10)         //延时一下,以读取最佳值{LCD_DrowSign(x, y, WHITE);return 0;}}timeCont++;/* 超时退出 */if(timeCont > 0xFFFFFFFE){LCD_DrowSign(x, y, WHITE);return 0xFF;}}}//触摸屏校准,依次在LCD的4个角上显示十字符号,用户点击后获取输出,计算触摸屏参数void TOUCH_Adjust(void){uint16_t px[2], py[2], xPot[4], yPot[4];float xFactor, yFactor;/* 读取第一个点 */if(TOUCH_ReadAdjust(LCD_ADJX_MIN, LCD_ADJY_MIN, &xPot[0], &yPot[0]))return;TOUCH_AdjDelay500ms();/* 读取第二个点 */if(TOUCH_ReadAdjust(LCD_ADJX_MIN, LCD_ADJY_MAX, &xPot[1], &yPot[1]))return;TOUCH_AdjDelay500ms();/* 读取第三个点 */if(TOUCH_ReadAdjust(LCD_ADJX_MAX, LCD_ADJY_MIN, &xPot[2], &yPot[2]))return;TOUCH_AdjDelay500ms();/* 读取第四个点 */if(TOUCH_ReadAdjust(LCD_ADJX_MAX, LCD_ADJY_MAX, &xPot[3], &yPot[3]))return;TOUCH_AdjDelay500ms();/* 处理读取到的四个点的数据,整合成对角的两个点 */px[0] = (xPot[0] + xPot[1]) / 2;py[0] = (yPot[0] + yPot[2]) / 2;px[1] = (xPot[3] + xPot[2]) / 2;py[1] = (yPot[3] + yPot[1]) / 2;/* 求出比例因数 */xFactor = (float)LCD_ADJ_X / (px[1] - px[0]);yFactor = (float)LCD_ADJ_Y / (py[1] - py[0]);/* 求出偏移量 */TouchPara.xOffset = (int16_t)LCD_ADJX_MAX - ((float)px[1] * xFactor);TouchPara.yOffset = (int16_t)LCD_ADJY_MAX - ((float)py[1] * yFactor);/* 将比例因数进行数据处理,然后保存 */TouchPara.xFactor = xFactor ;TouchPara.yFactor = yFactor ;TouchPara.isSaved = TOUCH_PARA_SAVED;}uint8_t TOUCH_Scan(void){if(TOUCH_ReadXY(&TouchPoint.Vx, &TouchPoint.Vy)) //没有触摸return 0xFF;/* 根据物理坐标值,计算出彩屏坐标值 */TouchPoint.Lcdx = TouchPoint.Vx * TouchPara.xFactor + TouchPara.xOffset;TouchPoint.Lcdy = TouchPoint.Vy * TouchPara.yFactor + TouchPara.yOffset;/* 查看彩屏坐标值是否超过彩屏大小 */if(TouchPoint.Lcdx > 240)TouchPoint.Lcdx = 240;if(TouchPoint.Lcdy > 320)TouchPoint.Lcdy = 320;return 0;  }void TOUCH_ScanAfterINT(void)    // T_PEN中断后读取{TouchPoint.Vx = TOUCH_ReadData(TOUCH_X_CMD);TouchPoint.Vy = TOUCH_ReadData(TOUCH_Y_CMD);/* 根据物理坐标值,计算出彩屏坐标值 */TouchPoint.Lcdx = TouchPoint.Vx * TouchPara.xFactor + TouchPara.xOffset;TouchPoint.Lcdy = TouchPoint.Vy * TouchPara.yFactor + TouchPara.yOffset;/* 查看彩屏坐标值是否超过彩屏大小 */if(TouchPoint.Lcdx > 240)TouchPoint.Lcdx = 240;if(TouchPoint.Lcdy > 320)TouchPoint.Lcdy = 320;}uint16_t LCD_CurX=0;      //当前位置Xuint16_t LCD_CurY=0;      //当前位置Yvoid ShowTouchPara(void)//显示触摸屏参数{uint16_t  IncY=16;   //Y间距LCD_ShowString(10,0,240,16,16,(uint8_t*)"**Parameters of touch screen:");LCD_ShowString(0,16,240,16,16,(uint8_t*)"xOffset= ");LCD_ShowChar(80, 16,TouchPara.xOffset,16,0);LCD_ShowString(0,32,240,16,16,(uint8_t*)"yOffset= ");LCD_ShowChar(80, 32,TouchPara.yOffset,16,0);LCD_ShowString(0,32+IncY,240,16,16,(uint8_t*)"xFactor= ");LCD_ShowxNum(80, 32+IncY,TouchPara.xFactor, 4,16,0);LCD_ShowString(0,32+IncY+IncY,240,16,16,(uint8_t*)"yFactor= ");LCD_ShowxNum(80, 32+IncY+IncY,TouchPara.yFactor, 4,16,0);}void TouchCalibrate(void)//进行触摸屏测试,获取参数{LCD_ShowString(10,0,240,16,16,(uint8_t*)"**Touch screen calibration");LCD_ShowString(10,16,240,16,16,(uint8_t*)"A red cross will display on");LCD_ShowString(10,32,240,16,16,(uint8_t*)"the 4 corners of LCD. ");LCD_ShowString(10,48,240,16,16,(uint8_t*)"Touch red cross one by one.");LCD_ShowString(10,64,240,16,16,(uint8_t*)"Press any key to start...");HAL_Delay(3000);TOUCH_Adjust(); //触摸屏校正时会清屏EP24C_WriteLongData(TOUCH_PARA_ADDR, &TouchPara.isSaved, sizeof(TouchPara));LCD_CurY=40;ShowTouchPara();//显示触摸屏参数LCD_ShowString(10,80,240,16,16,(uint8_t*)"Press any key to enter GUI");HAL_Delay(3000);}

在这些函数之后,我们需要对之前的屏幕下方的按键部分进行识别,这些按键分为数字和命令,所以得分成两个单独的函数,这些函数的实现部分,我在注释中有详细说明,但是这个是之前写的,实现的逻辑不太好,但是还能用,也就不太想改了(就是懒):

// a用来储存当前的数字,c用来检测位置uint8_t a,c = 0;extern uint8_t Password[6];// 位置和第几个数字对应uint8_t a_c(uint8_t x){if(c == 0)return 0;if(c == 1)return 20;if(c == 2)return 40;if(c == 3)return 60;if(c == 4)return 80;if(c == 5)return 100;if(c == 6)  // 密码过长了LCD_ShowString(10,130,240,16,16,(uint8_t*)"The password is too long!");HAL_Delay(3000);LCD_Fill(10,130, 240, 170, WHITE);return 0;}// 定义一个储存密码的数组uint8_t PasswordIn[6];// 这个函数用来检测触摸的位置以及做出反应uint8_t Touch_Num(void){// 返回值uint8_t i;if(TOUCH_Scan() == 0)  // 触摸屏扫描{// 1if(TouchPoint.Lcdx < 80 && TouchPoint.Lcdy > 200&&TouchPoint.Lcdy<230){a = a_c(c);PasswordIn[c] = 1;LCD_ShowNum(a, 150, 1, 1, 16);c+=1;i = 1;return i;}// 2else if(TouchPoint.Lcdx<160&&TouchPoint.Lcdy > 200&&TouchPoint.Lcdy<230&&TouchPoint.Lcdx>80){a = a_c(c);PasswordIn[c] = 2;LCD_ShowNum(a, 150, 2, 1, 16);c+=1;i = 2;return i;}// 3else if(TouchPoint.Lcdx>160&&TouchPoint.Lcdy > 200&&TouchPoint.Lcdy<230){a = a_c(c);PasswordIn[c] = 3;LCD_ShowNum(a, 150, 3, 1, 16);c+=1;i = 3;return i;}// 4else if(TouchPoint.Lcdx< 80&&TouchPoint.Lcdy > 230&&TouchPoint.Lcdy<260){a = a_c(c);PasswordIn[c] = 4;LCD_ShowNum(a, 150, 4, 1, 16);c+=1;i = 4;return i;}// 5else if(TouchPoint.Lcdx<160&&TouchPoint.Lcdy > 230&&TouchPoint.Lcdy<260&&TouchPoint.Lcdx>80){a = a_c(c);PasswordIn[c] = 5;LCD_ShowNum(a, 150, 5, 1, 16);c+=1;i = 5;return i;}// 6else if(TouchPoint.Lcdx>160&&TouchPoint.Lcdy > 230&&TouchPoint.Lcdy<260){a = a_c(c);PasswordIn[c] = 6;LCD_ShowNum(a, 150, 6, 1, 16);c+=1;i = 6;return i;}// 7else if(TouchPoint.Lcdx<80&&TouchPoint.Lcdy>260&&TouchPoint.Lcdy<290){a = a_c(c);PasswordIn[c] = 7;LCD_ShowNum(a, 150, 7, 1, 16);c+=1;i = 7;return i;}// 8else if(TouchPoint.Lcdx<160&&TouchPoint.Lcdx>80&&TouchPoint.Lcdy>260&&TouchPoint.Lcdy<290){a = a_c(c);PasswordIn[c] = 8;LCD_ShowNum(a, 150, 8, 1, 16);c+=1;i = 8;return i;}// 9else if(TouchPoint.Lcdx>160&&TouchPoint.Lcdy>260&&TouchPoint.Lcdy<290){a = a_c(c);PasswordIn[c] = 9;LCD_ShowNum(a, 150, 9, 1, 16);c+=1;i = 9;return i;}// *——表示输入错误,重新输入上一位else if(TouchPoint.Lcdx<80&&TouchPoint.Lcdy>290){c-=1;a = a_c(c);LCD_Fill(a, 150, a+20, 166, WHITE);i = 0;return i;}// 0else if(TouchPoint.Lcdx<160&&TouchPoint.Lcdx>80&&TouchPoint.Lcdy>290){a = a_c(c);PasswordIn[c] = 0;LCD_ShowNum(a, 150, 0, 1, 16);c+=1;i = 0;return i;}// #——表示确定密码输入else if(TouchPoint.Lcdx>160&&TouchPoint.Lcdy>290){c = 0;for(uint8_t i = 0;i<6;i++){// 输出密码错误if(PasswordIn[i] != Password[i]){LCD_ShowString(10,130,240,16,16,(uint8_t*)"The password is incorrect!");HAL_Delay(3000);LCD_Fill(0,130, 239, 170, WHITE);return 0;}}// 密码正确LCD_ShowString(10,130,240,16,16,(uint8_t*)"The password is correct!");HAL_Delay(3000);LCD_Fill(0,130, 239, 170, WHITE);}}return 0;}// 触摸位置是命令的位置void TOUCH_Command(void){// 删除指纹if(TouchPoint.Lcdx < 80 && TouchPoint.Lcdy > 170&&TouchPoint.Lcdy<200){// 请选择想删除的指纹LCD_ShowString(10,100,240,16,16,(uint8_t*)"Please select the fingerprint!");HAL_Delay(3000);LCD_Fill(0,100, 240, 170, WHITE);// 这个函数用来检测触摸的位置以及做出反应uint8_t i = Touch_Num();// 删除想要删除的指纹IDif(i>0){//                  Del_FR(i);}}// 修改密码else if(TouchPoint.Lcdx<160&&TouchPoint.Lcdy > 170&&TouchPoint.Lcdy<200&&TouchPoint.Lcdx>80){LCD_ShowString(10,100,240,16,16,(uint8_t*)"Please enter previous password!");//           c = 0;for(c = 0;c<6;){Touch_Num();HAL_Delay(200);}for(uint8_t i = 0;i<6;i++){// 输入密码错误if(PasswordIn[i] != Password[i]){LCD_ShowString(10,130,240,16,16,(uint8_t*)"The password is incorrect!");HAL_Delay(3000);LCD_Fill(0, 130,240, 165, WHITE);  //清除信息显示区return;}}// 密码正确LCD_ShowString(10,130,240,16,16,(uint8_t*)"The password is correct!");HAL_Delay(3000);LCD_Fill(0, 130,240, 165, WHITE);  //清除信息显示区// 输出请输入新密码LCD_ShowString(10,130,240,16,16,(uint8_t*)"Please enter a new password!");for(c = 0;c<6;){//                  c = 0;Touch_Num();HAL_Delay(200);}LCD_Fill(0, 130,240, 146, WHITE);  //清除信息显示区// 输出密码修改成功LCD_ShowString(10,130,240,16,16,(uint8_t*)"The password is OK!");HAL_Delay(3000);LCD_Fill(0, 130,240, 165, WHITE);  //清除信息显示区EP24C_WriteLongData(PASSWORD_PARA_ADDR, PasswordIn,sizeof(PasswordIn));c = 0;}// 新建指纹else if(TouchPoint.Lcdx>160&&TouchPoint.Lcdy > 170&&TouchPoint.Lcdy<200){// 请选择新建指纹的位置LCD_ShowString(10,100,240,16,16,(uint8_t*)"Select the new fingerprint");HAL_Delay(3000);LCD_Fill(0,100, 240, 170, WHITE);// 这个函数用来检测触摸的位置以及做出反应uint8_t i = Touch_Num();if(i>0){// 录入指纹ID//                  Add_FR(i);}}}void Touch_Point(void)  // 将之前的函数进行合并,主函数中只需要调用这个函数就足够了.{if(TOUCH_Scan() == 0)  // 触摸屏扫描{TOUCH_Command();Touch_Num();}}// 微秒级延时(上边会用到)void Delay_us(uint16_t delay){__HAL_TIM_DISABLE(&htim7);__HAL_TIM_SET_COUNTER(&htim7,0);  // 设置计数值初值__HAL_TIM_ENABLE(&htim7);uint16_t curCnt = 0;while(1)  // 开始计数{curCnt = __HAL_TIM_GET_COUNTER(&htim7);if(curCnt>delay)break;}__HAL_TIM_DISABLE(&htim7);}

Touch.c所对应的touch.h中的程序如下:

#ifndef __TOUCH_H#define __TOUCH_H #include "main.h"#include      "lcd.h"// 微秒级延时void Delay_us(uint16_t delay);/* 定义数据类型 */// 触摸点数据结构体定义typedef struct{uint16_t Vx; //XPT2046输出的X轴电压值uint16_t Vy; //XPT2046输出的Y轴电压值uint16_t Lcdx;     //计算的LCD坐标Xuint16_t Lcdy;     //计算的LCD坐标Y} TouchPointDef;extern TouchPointDef TouchPoint; //触摸点数据全局变量// 电阻触摸屏校正参数, 需要保存到EEPROMtypedef struct{uint8_t isSaved;    // 参数是否已保存到EEPROMint16_t xOffset;   //偏移量int16_t yOffset;float xFactor;             //相乘因子float yFactor;} TouchParaDef;extern TouchParaDef TouchPara;     //触摸屏校准参数全局变量#define TOUCH_PARA_SAVED      'S'    //表示触摸校准参数准备好了#define TOUCH_PARA_ADDR        80    //校正参数在24C02中的首地址,必须是页的起始地址,也就是8的整数倍//触摸屏校正,会清除屏幕,依次在屏幕四个角上显示红色十字符号,点击进行测试。//计算的校准参数保存在变量TouchPara里,并保存到EEPROMvoid TOUCH_Adjust(void);//触摸屏扫描,返回值为0表示有触摸操作,触摸点保存到变量TouchPoint里uint8_t TOUCH_Scan(void);void TOUCH_ScanAfterINT(void);   //T_PEN中断后读取// 新定义的两个函数//显示触摸屏参数,即全局变量TouchPara的数据void ShowTouchPara(void);//进行触摸屏测试,内部会调用TOUCH_Adjust()void TouchCalibrate(void);// 这个函数用来检测触摸的位置以及做出反应void Touch_Point(void);#endif /* __TOUCH_H */

在上边的函数中使用的EEPROM,这些使用的地方实际上就是将屏幕的坐标存入只读存储器中.接下来就进入24C02.c文件中,这个文件主要定义存储的实现过程,具体这些实现方法如下程序,这些也是厂商提供:

#include "24C02_EEPROM.h"#define   EP24C_TIMEOUT      200  //超时等待时间,单位:节拍数#define   EP24C_MEMADD_SIZE  I2C_MEMADD_SIZE_8BIT  //存储器地址大小,8位地址//检查设备是否准备好 I2C 通信,返回HAL_OK 表示OKHAL_StatusTypeDef EP24C_IsDeviceReady(void){uint32_t  Trials=10;  //尝试次数HAL_StatusTypeDef result=HAL_I2C_IsDeviceReady(&I2C_HANDLE,DEV_ADDR_24CXX,Trials,EP24C_TIMEOUT);return result;}//向任意地址写入1字节的数据,memAddr 是存储器内部地址,byteData 是需要写入的1字节数据HAL_StatusTypeDef EP24C_WriteOneByte(uint16_t memAddress, uint8_t byteData){HAL_StatusTypeDef result=HAL_I2C_Mem_Write(&I2C_HANDLE,DEV_ADDR_24CXX, memAddress, EP24C_MEMADD_SIZE, &byteData, 1,EP24C_TIMEOUT);return result;}//从任意地址读出1字节的数据,memAddr 是存储器内部地址,byteData是读出的1字节数据HAL_StatusTypeDef EP24C_ReadOneByte(uint16_t memAddress, uint8_t byteData){HAL_StatusTypeDef result=HAL_I2C_Mem_Read(&I2C_HANDLE,DEV_ADDR_24CXX, memAddress, EP24C_MEMADD_SIZE, &byteData, 1,EP24C_TIMEOUT);return result;}//连续读取数据,任意地址,任意长度,不受页的限制HAL_StatusTypeDef EP24C_ReadBytes(uint16_t memAddress, uint8_t *pBuffer,uint16_t bufferLen){if (bufferLen>MEM_SIZE_24CXX)   //超过总存储容量return HAL_ERROR;HAL_StatusTypeDef result=HAL_I2C_Mem_Read(&I2C_HANDLE,DEV_ADDR_24CXX,memAddress,EP24C_MEMADD_SIZE,pBuffer,bufferLen,EP24C_TIMEOUT);return result;}//限定在一个页内写入连续数据,最多 8 字节。从任意起始地址开始,但起始地址+数据长度不能超过页边界HAL_StatusTypeDef EP24C_WriteInOnePage(uint16_t memAddress, uint8_t *pBuffer,uint16_t bufferLen){if (bufferLen>MEM_SIZE_24CXX)   //超过总存储容量return HAL_ERROR;HAL_StatusTypeDef result=HAL_I2C_Mem_Write(&I2C_HANDLE,DEV_ADDR_24CXX,memAddress,EP24C_MEMADD_SIZE,pBuffer,bufferLen,EP24C_TIMEOUT);      return result;     }//写任意长的数据,可以超过8字节,但数据地址必须从页首开始,即8XN。自动分解为多次写入HAL_StatusTypeDef EP24C_WriteLongData(uint16_t memAddress, uint8_t *pBuffer,uint16_t bufferLen){if (bufferLen>MEM_SIZE_24CXX)   //超过总存储容量return HAL_ERROR;HAL_StatusTypeDef result=HAL_ERROR;if (bufferLen<=PAGE_SIZE_24CXX)  //不超过1个page,直接写入后退出{result=HAL_I2C_Mem_Write(&I2C_HANDLE,DEV_ADDR_24CXX,memAddress,EP24C_MEMADD_SIZE,pBuffer,bufferLen,EP24C_TIMEOUT);      return result;}uint8_t *pt=pBuffer;  //临时指针,不能改变传入的指针uint16_t pageCount=bufferLen/PAGE_SIZE_24CXX;   //Page个数for(uint16_t i=0;i<pageCount;i++)  //一次写入一个page 的数据{result=HAL_I2C_Mem_Write(&I2C_HANDLE,DEV_ADDR_24CXX,memAddress,EP24C_MEMADD_SIZE,pt, PAGE_SIZE_24CXX,EP24C_TIMEOUT);  pt += PAGE_SIZE_24CXX;memAddress += PAGE_SIZE_24CXX;HAL_Delay(5);   //必须有延时,以等待页写完if (result != HAL_OK)return result;}uint16_t leftBytes=bufferLen%PAGE_SIZE_24CXX; //余数if (leftBytes>0)   //写入剩余的数据result=HAL_I2C_Mem_Write(&I2C_HANDLE,DEV_ADDR_24CXX,memAddress,EP24C_MEMADD_SIZE,pt, leftBytes,EP24C_TIMEOUT);   return result;     }

对应的.h文件程序:

#ifndef __24C02_EEPROM_H#define __24C02_EEPROM_H#include "main.h"#include "i2c.h"#define    I2C_HANDLE     hi2c2  // I2C接口外设对象变量#define    DEV_ADDR_24CXX 0x00A0  // 24c02的写地址#define    PASSWORD_PARA_ADDR        16    //密码在24C02中的首地址,必须是页的起始地址,也就是8的整数倍#define    PAGE_SIZE_24CXX  0x0008  // 24c02的page大小为8字节#define    MEM_SIZE_24CXX  (uint16_t)256  // 24c02总容量为256字节//检查设备是否准备好 I2C 通信,返回HAL_OK 表示OKHAL_StatusTypeDef EP24C_IsDeviceReady(void);//向任意地址写入1字节的数据,memAddr 是存储器内部地址,byteData 是需要写入的1字节数据HAL_StatusTypeDef EP24C_WriteOneByte(uint16_t memAddress, uint8_t byteData);//从意地址读出1字节的数据,memAddr 是存储器内部地址,byteData是读出的1字节数据HAL_StatusTypeDef EP24C_ReadOneByte(uint16_t memAddress, uint8_t byteData);//连续读取数据,任意地址,任意长度,不受页的限制HAL_StatusTypeDef EP24C_ReadBytes(uint16_t memAddress, uint8_t *pBuffer, uint16_t bufferLen);//限定在一个页内写入连续数据,最多 8 字节。从任意起始地址开始,但起始地址+数据长度不能超过页边界HAL_StatusTypeDef EP24C_WriteInOnePage(uint16_t memAddress, uint8_t *pBuffer,uint16_t bufferLen);//写任意长的数据,可以超过8字节,但数据地址必须从页首开始,即8XN。自动分解为多次写入HAL_StatusTypeDef EP24C_WriteLongData(uint16_t memAddress, uint8_t *pBuffer,uint16_t bufferLen);#endif /* __24C02_EEPROM_H */

这些完成后,我们就可以将之前的密码存入rom中了(下面的部分在main.c中):

//====1. 读取保存在EEPROM中的电阻触摸屏参数EP24C_ReadBytes(TOUCH_PARA_ADDR, &TouchPara.isSaved, sizeof(TouchPara));if (TouchPara.isSaved ==TOUCH_PARA_SAVED)LCD_ShowString(10,80,240,12,12,(uint8_t*)"Touch-Res has been calibrated");elseLCD_ShowString(10,80,240,12,12,(uint8_t*)"Touch-Res has not been calibrated");// 向EEPROM中写入初始密码//    EP24C_WriteLongData(PASSWORD_PARA_ADDR, Password,sizeof(Password));// 从EEPROM中读取密码EP24C_ReadBytes(PASSWORD_PARA_ADDR,Password,sizeof(Password));// 检验读取的密码//    for(uint8_t i = 0;i<6;i++)//    {//           LCD_ShowxNum(10,80,Password[i],1,16,0);//           HAL_Delay(500);//    }

至此就完成了屏幕和密码部分的所有操作,但是这些操作在主函数中实现的效率不高,所以我们将主函数中的内容转到freertos中.

打开CobeMX,找到FREERTOS,选择模式为:CMSIS_V2.然后先创建两个任务,分别为Key和Touch,这里设置Key的优先级高于Touch,具体设置如图:

设置完成后,这里需要将SYS的时钟更改为TIM6, 因为之前没有使用FreeRTOS时HAL时钟默认是SysTick,但是现在FreeRTOS使用了SysTick,所以我们要为HAL时钟重新配置基础时钟.完成时钟配置后生成代码.

将之前main.c中的while循环的key相关代码放入Key的for循环中,将触摸相关的代码放入Touch的循环中,

现在main函数中的代码如下:

int main(void){/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_FSMC_Init();MX_I2C2_Init();MX_TIM7_Init();/* USER CODE BEGIN 2 */LCD_Init();// 屏幕显示初始化Bsp_Lcd_Init();//====1. 读取保存在EEPROM中的电阻触摸屏参数EP24C_ReadBytes(TOUCH_PARA_ADDR, &TouchPara.isSaved, sizeof(TouchPara));if (TouchPara.isSaved ==TOUCH_PARA_SAVED)LCD_ShowString(10,80,240,12,12,(uint8_t*)"Touch-Res has been calibrated");elseLCD_ShowString(10,80,240,12,12,(uint8_t*)"Touch-Res has not been calibrated");// 向EEPROM中写入初始密码//    EP24C_WriteLongData(PASSWORD_PARA_ADDR, Password,sizeof(Password));// 从EEPROM中读取密码EP24C_ReadBytes(PASSWORD_PARA_ADDR,Password,sizeof(Password));// 检验读取的密码//    for(uint8_t i = 0;i<6;i++)//    {//           LCD_ShowxNum(10,80,Password[i],1,16,0);//           HAL_Delay(500);//    }/* USER CODE END 2 *//* Init scheduler */osKernelInitialize();  /* Call init function for freertos objects (in freertos.c) */MX_FREERTOS_Init();/* Start scheduler */osKernelStart();/* We should never get here as control is now taken by the scheduler *//* Infinite loop *//* USER CODE BEGIN WHILE */while(1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */}

Freertos.c中各个函数如下:

void Key(void *argument){/* USER CODE BEGIN Key */KEYS      curKey;/* Infinite loop */for(;;){curKey=ScanKeys(KEY_WAIT_ALWAYS);switch(curKey){case  KEY0:break;case       KEY1:{Touch_Set();break;}case       KEY2:{Finger_Set();break;}case       KEY3:{IDCard_Set();break;}// 修改密码case       KEY4:{Password_Set();break;}}//end switchvTaskDelay(300);}/* USER CODE END Key */}/* USER CODE BEGIN Header_Touch *//*** @brief Function implementing the Task_Touch thread.* @param argument: Not used* @retval None*//* USER CODE END Header_Touch */void Touch(void *argument){/* USER CODE BEGIN Touch *//* Infinite loop */for(;;){Touch_Point();vTaskDelay(300);}/* USER CODE END Touch */}

当然在这之前需要添加这些函数的头文件:

#include "bsp_lcd.h"#include "24C02_EEPROM.h"#include "bsp_key.h"#include "touch.h"

至此,有关屏幕的部分已经全部完成了.

这篇关于门锁系统——屏幕显示的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/319199

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

基于 YOLOv5 的积水检测系统:打造高效智能的智慧城市应用

在城市发展中,积水问题日益严重,特别是在大雨过后,积水往往会影响交通甚至威胁人们的安全。通过现代计算机视觉技术,我们能够智能化地检测和识别积水区域,减少潜在危险。本文将介绍如何使用 YOLOv5 和 PyQt5 搭建一个积水检测系统,结合深度学习和直观的图形界面,为用户提供高效的解决方案。 源码地址: PyQt5+YoloV5 实现积水检测系统 预览: 项目背景