前言:

  对于刚学习STM32单片机的小伙伴,学习了理论知识和部分可驱动的模块,但是综合项目还没有触碰过多少。所以本文已最简单的模块进行简单的知识梳理和疑问解答。本文有参考其他博主内容,会在使用这些内容时附加原网址,以便向这些最牛博主学习!

实现功能:

可以使用蓝牙进行开锁,可以使用4*4矩阵键盘进行开锁。在锁定界面时可按下*号键查看按键表,在锁定界面按下#号键可进行密码输入,在锁定界面除*号和#号键以外其他按键均不起作用。当密码输入时,可有删除、清除、锁定、确认四种按键进行操作。当密码正确进入系统时,可进行系统锁定和更改密码操作。其他类似操作可在此基础上进行增加。

        注:本文将讲述了很多模块的使用方法,这些模块的使用方法都是在本人整理过之后的驱动下写的,如果有需要改动的或者移植时,请修改模块驱动程序。


目录

前言:

实现功能:

F407ZG最小系统

矩阵键盘

OLED显示

舵机

HC-05蓝牙模块

连线说明

代码解析

总代码下载网址


以下为总体展示图:


F407ZG最小系统

        作者本人采用的是正点原子的STM32F4ZGT6带SRAM版。因为带SRAM没有片选SRAM使用的IO口所以选用几个独立的IO口进行操作。选取IO口的方法为先查看数据手册还有正点原子增值资料中的IO口表格文档,查找适合本次实验所需的IO口。

        例如我需要一个USART3的串口进行蓝牙通信,我在芯片手册中查找USART3_TX/RX这两个IO口,查找到之后去IO口表格文档中查找这两个引脚对应的连接属性,经本次操作可知,USART3_TX/RX两个口完全独立并且IO口已引出,可以进行外设连接操作。

        其中相应的数据手册和IO口表格,可根据不同开发板提供的资料进行查找。


矩阵键盘

        作者本人采用的是最普通的4*4矩阵键盘,某宝几块钱就可以获取的。

        线路连接:(上四IO口为列,下四IO口为行,表格以从下到上说明)

        IO选择原因:此次程序操作了IDR和ODR寄存器,如此选择IO口,可方便寄存器的操作,以便实现代码。

线路连接列表
矩阵键盘IO口 行IO4 行IO3 行IO2 行IO1 列IO1 列IO2 列IO3 列IO4
单片机IO口 PC0 PC1 PC2 PC3 PC4 PC5 PG6 PG7

   

矩阵键盘的操作原理:上四列IO口设置为输入模式,下四行IO口设置为输出模式。由原理图可知当按下其中一个键时,其中两个IO口短接。输入一端的IO口读取到了输出一段的IO口的电平,单片机会将这一采取结果返回给程序进行判断。具体操作与代码流程如下。

1.写44KEY头文件44KEY.h的代码,其中包含两个函数一个GPIO初始化函数一个按键操作函数。

#ifndef _44KEY_H
#define _44KEY_H
#include "sys.h"
void gpio_init_key4(void);//矩阵键盘引脚初始化
u16 key_init_44(void);//4*4矩阵键盘函数(单次按键模式)
#endif

2.写44KEY.c中gpio_init_key4的函数,此函数的目的是为了初始化矩阵键盘相关的GPIO。正如本小结开头所说,其中PC的0、1、2、3设置成为了推挽输出模式,其余的PC4、5、PG6、7设置成为了输入模式。

GPIO_InitTypeDef  GPIO_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOG, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;GPIO_Init(GPIOC, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//输入模式GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉GPIO_Init(GPIOG,&GPIO_InitStructure);//初始化  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//输入模式GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉GPIO_Init(GPIOC,&GPIO_InitStructure);//初始化

        3.写44KEY.c中key_init_44的函数,此函数的目的是为了读取相关的IO口,并进行判断是哪一个按键按下的,使用的方法为扫描法。以按下S1按键为例(第一行第一列的按键)进行第一行的扫描,由于没有按键按下时列输入IO读取到的值为初始的全高(IO引脚悬空时默认为高),以此为方法进行判断。令第一行输出低电平,如果某处按键按下则对应列输入信号为低电平,其余因为没有按键按下造成短路所以依旧为高电平(IO引脚悬空时默认为高)。此时PC0、1、2、3、4、5和PG6、7的GPIO的值为1110 0111,在寄存器储存值为0xE7,则判断成功为S1按键按下。

8个IO口的储存=(GPIOC->IDR&0x37)|(GPIOG->IDR&0xC0);

        GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2);GPIO_ResetBits(GPIOC,GPIO_Pin_3);if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0){delay_ms(10);if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0){temp=(GPIOC->IDR&0x37)|(GPIOG->IDR&0xC0);switch(temp){case 0xE7:Key_val=1;break;case 0xD7:Key_val=2;break;case 0xB7:Key_val=3;break;case 0x77:Key_val=4;break;default :Key_val=0;break;}}}

      矩阵键盘部分主要参考:https://blog.csdn.net/Kevin_8_Lee/article/details/88084516


OLED显示

作者本人采用的是某宝较为便宜的0.96寸7针OLED显示使用的是SPI通信协议的。

        线路连接:

OLED的IO GND VCC DO DI RES DC CS
单片机的IO GND +5V PF8 PF7 PF6 PB13 PB12

        OLED的原理:根据所给数据的16进制数进行点亮和熄灭,例如逐列式顺式第一列点阵(一列16个点),如果给了一个16进制数为0x00ff,则表示前8个点不点亮后8个点点亮。

        取字模的方法:使用PCtoLCD2002.exe取模软件进行文字取模,主要设置如下阴码、列行式、逆向。格式处为C51的格式,其余可以不做改动。过程如下图所示。(主要生成16*16的字模,其余大小字体方法类似)

 

字模生成以后将其复制到主程序字库中,作者本人字库是放在oledfone.h头文件中定义的,其中如果字体数量超过了你能保存的大小则需要修改数组的大小。如下图所示,我定义了一个,则将代码复制于此。此字库中一共保存了50个字(每个字需要两行16进制组成,则每两个数组保存一个字)每个字的生成大小为16*16。

        取图片模的方法:使用PCtoLCD2002.exe取模软件进行图片取模,首先需要先切换到图片模式(取模软件处点击模式,选择图片模式)。

        在图片取模之前需要先对图片进行处理,首先选择一张颜色单一的图片(也就是只有深色和白色的但不能包含浅色的图片,不然识别不出来图片的质量会下降)以画图的方式打开选择重新调整大小,调整大小范围在长128宽64之内(作者本人使用的是128*64的OLED屏幕,如果其他屏幕可更改此处设置)。然后就是保存图片,保存图片的方法为点击另存为选择BMP类图片保存,然后在选择为单色图。如图所示。

        之后就是将图片在PCtoLCD2002.exe取模软件中打开进行图片取模,跟文字取模一样需要对取模方式进行一些设置,其中设置阴码、列行式、逆向,格式为C51格式并且去除两个大括号。如图所示。

        最后就是将取模成功后的图片放置到程序中,我保存在bmp.h的头文件中,方法与取字模方法相同。如图所示。

驱动程序保存在程序总代码中,如有需要请自行提取。


舵机

作者本人使用的是TD-7015MG舵机,因为手头只有这一种舵机。

定时器控制PWM输出知识参考此博客:PWM知识学习

舵机构造和简单原理参考:http://www.geek-workshop.com/thread-70-1-1.html

线路连接:

舵机IO 红线 棕线 黄线
单片机IO +5V GND PC6

驱动程序讲解:

由舵机转动的原理,我们将频率设置为50HZ即0.002秒一个周期(使用定时器),我们设置的脉冲为0.0019时为顺时针转动,设置的脉冲为0.0018时为逆时针转动,符合我们开关门锁的要求。具体代码操作如下。

    //进行结构体声明GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;TIM_OCInitTypeDef  TIM_OCInitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM3);//GPIO初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;GPIO_Init(GPIOC,&GPIO_InitStructure);//定时器计时初始化TIM_TimeBaseStructure.TIM_Prescaler=8399;TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimeBaseStructure.TIM_Period=200;TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);//输出PWM设置TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; TIM_OC1Init(TIM3, &TIM_OCInitStructure); //使能TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM3,ENABLE);TIM_Cmd(TIM3, ENABLE); 

HC-05蓝牙模块

本文作者使用的时某宝购买的HC-05蓝牙模块,如下图所示。

        原理:我们使用蓝牙模块当作媒介来使用单片机的某个串口进行串口通信。

        线路连接:(因为只使用建议的蓝牙从模式所以STATE和EN接口未连接)

蓝牙与单片机
蓝牙IO STATE RXD TXD GND VCC EN
单片机IO 未连 PB10 PB11 GND +5V 未连
蓝牙IO STATE RXD TXD GND VCC EN
TTLUSBIO 未连 TXD RXD GND +5V 未连

蓝牙模块模式设置:

蓝牙模块常用指令集
操作 指令 格式/备注
是否连接成功 AT 返回值为OK
获取串口信息 AT+UART? 返回值为串口信息
修改串口信息 AT+UART=115200,0,0 返回值为OK,修改串口波特率为115200,并且一位停止位,没有校验位
获取连接密码 AT+PSWD? 返回值为连接密码
修改连接密码 AT+PSWD=1234 返回值为OK,修改连接密码为1234
获取蓝牙设备名称 AT+NAME? 一般会获取失败
修改蓝牙设备名称 AT+NAME=BEIJING 返回值为OK,修改名字为BEIJING
修改主从模式 AT+ROLE=0 返回值为OK,设置为从模式

将蓝牙模块与TTLUSB进行连接进行蓝牙设置,蓝牙设置模式需要在蓝牙上电之前将KEY小开关按住,使KEY为高进入AT设置模式。或者在上电之后按一下KEY键进入AT模式。

        进入AT模式之后,打开XCOM.exe,进行波特率为38400和串口的设置。

逐次发送:AT、AT+NAME=BEIJING、AT+ROLE=0、AT+PSWD=1234、AT+UART=115200,0,0命令进行蓝牙模块作为从设备的设置

蓝牙模块与手机连接、代码分析

        在蓝牙模块设置好模式之后,使用手机随便打开一个蓝牙串口助手,等待搜索到蓝牙并进行连接。串口和定时器的初始化,不再过多的赘述,都是简单的配置,如果有知识不明白,可参考这位博主的文章:其他博主串口知识讲解

 以下是串口3的初始化和中断服务函数

void usart3_init(u32 bound)
{  NVIC_InitTypeDef NVIC_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;USART_DeInit(USART3);  //复位串口3RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); //使能GPIOB时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);//使能USART3时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_10; //GPIOB11和GPIOB10初始化GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHzGPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化GPIOB11,和GPIOB10GPIO_PinAFConfig(GPIOB,GPIO_PinSource11,GPIO_AF_USART3); //GPIOB11复用为USART3GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_USART3); //GPIOB10复用为USART3   USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为9600;USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    //收发模式USART_Init(USART3, &USART_InitStructure); //初始化串口3USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断  USART_Cmd(USART3, ENABLE);                    //使能串口 NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级2NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;       //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQ通道使能NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器TIM7_Int_Init(100-1,8400-1);  //10ms中断一次TIM_Cmd(TIM7, DISABLE); //关闭定时器7USART3_RX_STA=0;             //清零
}
void USART3_IRQHandler(void)
{u8 res;        if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)//接收到数据{   res =USART_ReceiveData(USART3);       if((USART3_RX_STA&(1<<15))==0)//接收完的一批数据,还没有被处理,则不再接收其他数据{ if(USART3_RX_STA<USART3_MAX_RECV_LEN)     //还可以接收数据{TIM_SetCounter(TIM7,0);//计数器清空                         if(USART3_RX_STA==0)     TIM_Cmd(TIM7, ENABLE);  //使能定时器7 USART3_RX_BUF[USART3_RX_STA++]=res;     //记录接收到的值    }else {USART3_RX_STA|=1<<15;                    //强制标记接收完成} }   }
} 

定时器的初始化

void TIM7_Int_Init(u16 arr,u16 psc)
{   NVIC_InitTypeDef NVIC_InitStructure;TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);//TIM7时钟使能    //定时器TIM7初始化TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE ); //使能指定的TIM7中断,允许更新中断TIM_Cmd(TIM7,ENABLE);//使能定时器7NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;      //子优先级1NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQ通道使能NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器}
void TIM7_IRQHandler(void)
{   if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET)//是更新中断{                USART3_RX_STA|=1<<15; //标记接收完成TIM_ClearITPendingBit(TIM7, TIM_IT_Update  );  //清除TIM7更新中断标志    TIM_Cmd(TIM7, DISABLE);  //关闭TIM7 }
}

连线说明

各模块与单片机的连接合理,并且不影响单片机其他的功能。

矩阵键盘的连线:

矩阵键盘IO口 行IO4 行IO3 行IO2 行IO1 列IO1 列IO2 列IO3 列IO4
单片机IO口 PC0 PC1 PC2 PC3 PC4 PC5 PG6 PG7

OLED屏幕的连线:

OLED的IO GND VCC DO DI RES DC CS
单片机的IO GND +5V PF8 PF7 PF6 PB13 PB12

舵机的连线:

舵机IO 红线 棕线 黄线
单片机IO +5V GND PC6

蓝牙的连线:

蓝牙IO STATE RXD TXD GND VCC EN
单片机IO 未连 PB10 PB11 GND +5V 未连

代码解析

44KEY.C代码:按照之前对4*4矩阵键盘讲解的扫描模式,完整的程序代码。其中使用了单次按键的方法,防止长按KEY产生的错误影响。

u16 key_init_44(void)//4*4矩阵键盘函数(单次按键模式)
{static u8 t=1;u16 Key_val=0;u32 temp=0;gpio_init_key4();if(t){GPIO_ResetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2);GPIO_ResetBits(GPIOC,GPIO_Pin_3);if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0){delay_ms(10);if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0){temp=(GPIOC->IDR&0x37)|(GPIOG->IDR&0xC0);switch(temp){case 0xE7:Key_val=1;break;case 0xD7:Key_val=2;break;case 0xB7:Key_val=3;break;case 0x77:Key_val=4;break;default :Key_val=0;break;}}}GPIO_ResetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_3);GPIO_ResetBits(GPIOC,GPIO_Pin_2);if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0){delay_ms(10);if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0){temp=(GPIOC->IDR&0x3B)|(GPIOG->IDR&0xC0);switch(temp){case 0xEB:Key_val=5;break;case 0xDB:Key_val=6;break;case 0xBB:Key_val=7;break;case 0x7B:Key_val=8;break;default :Key_val=0;break;}}}GPIO_ResetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_3|GPIO_Pin_2);GPIO_ResetBits(GPIOC,GPIO_Pin_1);if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0){delay_ms(10);if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0){temp=(GPIOC->IDR&0x3D)|(GPIOG->IDR&0xC0);switch(temp){case 0xED:Key_val=9;break;case 0xDD:Key_val=10;break;case 0xBD:Key_val=11;break;case 0x7D:Key_val=12;break;default :Key_val=0;break;}}}GPIO_ResetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);GPIO_SetBits(GPIOC,GPIO_Pin_3|GPIO_Pin_1|GPIO_Pin_2);GPIO_ResetBits(GPIOC,GPIO_Pin_0);if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0){delay_ms(10);if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0){temp=(GPIOC->IDR&0x3E)|(GPIOG->IDR&0xC0);switch(temp){case 0xEE:Key_val=13;break;case 0xDE:Key_val=14;break;case 0xBE:Key_val=15;break;case 0x7E:Key_val=16;break;default :Key_val=0;break;}}}if(Key_val!=0){t=0;}return Key_val;}else if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))==0xF0){t=1;}return 0;}

OLED.C代码:OLED驱动显示屏部分

u8 OLED_GRAM[144][8];//反显函数
void OLED_ColorTurn(u8 i)
{if(i==0){OLED_WR_Byte(0xA6,OLED_CMD);//正常显示}if(i==1){OLED_WR_Byte(0xA7,OLED_CMD);//反色显示}
}//屏幕旋转180度
void OLED_DisplayTurn(u8 i)
{if(i==0){OLED_WR_Byte(0xC8,OLED_CMD);//正常显示OLED_WR_Byte(0xA1,OLED_CMD);}if(i==1){OLED_WR_Byte(0xC0,OLED_CMD);//反转显示OLED_WR_Byte(0xA0,OLED_CMD);}
}void OLED_WR_Byte(u8 dat,u8 cmd)
{   u8 i;             if(cmd)OLED_DC_Set();elseOLED_DC_Clr();OLED_CS_Clr();for(i=0;i<8;i++){OLED_SCLK_Clr();if(dat&0x80)OLED_SDIN_Set();else OLED_SDIN_Clr();OLED_SCLK_Set();dat<<=1;   }                        OLED_CS_Set();OLED_DC_Set();
}//开启OLED显示
void OLED_DisPlay_On(void)
{OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能OLED_WR_Byte(0x14,OLED_CMD);//开启电荷泵OLED_WR_Byte(0xAF,OLED_CMD);//点亮屏幕
}//关闭OLED显示
void OLED_DisPlay_Off(void)
{OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能OLED_WR_Byte(0x10,OLED_CMD);//关闭电荷泵OLED_WR_Byte(0xAF,OLED_CMD);//关闭屏幕
}//更新显存到OLED
void OLED_Refresh(void)
{u8 i,n;for(i=0;i<8;i++){OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址OLED_WR_Byte(0x00,OLED_CMD);   //设置低列起始地址OLED_WR_Byte(0x10,OLED_CMD);   //设置高列起始地址for(n=0;n<128;n++)OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA);}
}
//清屏函数
void OLED_Clear(void)
{u8 i,n;for(i=0;i<8;i++){for(n=0;n<128;n++){OLED_GRAM[n][i]=0;//清除所有数据}}OLED_Refresh();//更新显示
}//画点
//x:0~127
//y:0~63
void OLED_DrawPoint(u8 x,u8 y)
{u8 i,m,n;i=y/8;m=y%8;n=1<<m;OLED_GRAM[x][i]|=n;
}//清除一个点
//x:0~127
//y:0~63
void OLED_ClearPoint(u8 x,u8 y)
{u8 i,m,n;i=y/8;m=y%8;n=1<<m;OLED_GRAM[x][i]=~OLED_GRAM[x][i];OLED_GRAM[x][i]|=n;OLED_GRAM[x][i]=~OLED_GRAM[x][i];
}//画线
//x:0~128
//y:0~64
void OLED_DrawLine(u8 x1,u8 y1,u8 x2,u8 y2)
{u8 i,k,k1,k2,y0;if((x1<0)||(x2>128)||(y1<0)||(y2>64)||(x1>x2)||(y1>y2))return;if(x1==x2)    //画竖线{for(i=0;i<(y2-y1);i++){OLED_DrawPoint(x1,y1+i);}}else if(y1==y2)   //画横线{for(i=0;i<(x2-x1);i++){OLED_DrawPoint(x1+i,y1);}}else      //画斜线{k1=y2-y1;k2=x2-x1;k=k1*10/k2;for(i=0;i<(x2-x1);i++){OLED_DrawPoint(x1+i,y1+i*k/10);}}
}
//x,y:圆心坐标
//r:圆的半径
void OLED_DrawCircle(u8 x,u8 y,u8 r)
{int a, b,num;a = 0;b = r;while(2 * b * b >= r * r)      {OLED_DrawPoint(x + a, y - b);OLED_DrawPoint(x - a, y - b);OLED_DrawPoint(x - a, y + b);OLED_DrawPoint(x + a, y + b);OLED_DrawPoint(x + b, y + a);OLED_DrawPoint(x + b, y - a);OLED_DrawPoint(x - b, y - a);OLED_DrawPoint(x - b, y + a);a++;num = (a * a + b * b) - r*r;//计算画的点离圆心的距离if(num > 0){b--;a--;}}
}//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//size:选择字体 12/16/24
//取模方式 逐列式
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1)
{u8 i,m,temp,size2,chr1;u8 y0=y;size2=(size1/8+((size1%8)?1:0))*(size1/2);  //得到字体一个字符对应点阵集所占的字节数chr1=chr-' ';  //计算偏移后的值for(i=0;i<size2;i++){if(size1==12){temp=asc2_1206[chr1][i];} //调用1206字体else if(size1==16){temp=asc2_1608[chr1][i];} //调用1608字体else if(size1==24){temp=asc2_2412[chr1][i];} //调用2412字体else return;for(m=0;m<8;m++)           //写入数据{if(temp&0x80)OLED_DrawPoint(x,y);else OLED_ClearPoint(x,y);temp<<=1;y++;if((y-y0)==size1){y=y0;x++;break;}}}
}//显示字符串
//x,y:起点坐标
//size1:字体大小
//*chr:字符串起始地址
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1)
{while((*chr>=' ')&&(*chr<='~'))//判断是不是非法字符!{OLED_ShowChar(x,y,*chr,size1);x+=size1/2;if(x>128-size1)  //换行{x=0;y+=2;}chr++;}
}//m^n
u32 OLED_Pow(u8 m,u8 n)
{u32 result=1;while(n--){result*=m;}return result;
}显示2个数字
x,y :起点坐标
len :数字的位数
size:字体大小
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size1)
{u8 t,temp;for(t=0;t<len;t++){temp=(num/OLED_Pow(10,len-t-1))%10;if(temp==0){OLED_ShowChar(x+(size1/2)*t,y,'0',size1);}else {OLED_ShowChar(x+(size1/2)*t,y,temp+'0',size1);}}
}//显示汉字
//x,y:起点坐标
//num:汉字对应的序号
//取模方式 列行式
void OLED_ShowChinese(u8 x,u8 y,u8 num,u8 size1)
{u8 i,m,n=0,temp,chr1;u8 x0=x,y0=y;u8 size3=size1/8;while(size3--){chr1=num*size1/8+n;n++;for(i=0;i<size1;i++){if(size1==16){temp=Hzk1[chr1][i];}//调用16*16字体else if(size1==24){temp=Hzk2[chr1][i];}//调用24*24字体else if(size1==32)       {temp=Hzk3[chr1][i];}//调用32*32字体else if(size1==64){temp=Hzk4[chr1][i];}//调用64*64字体else return;for(m=0;m<8;m++){if(temp&0x01)OLED_DrawPoint(x,y);else OLED_ClearPoint(x,y);temp>>=1;y++;}x++;if((x-x0)==size1){x=x0;y0=y0+8;}y=y0;}}
}//num 显示汉字的个数
//space 每一遍显示的间隔
void OLED_ScrollDisplay(u8 num,u8 space)
{u8 i,n,t=0,m=0,r;while(1){if(m==0){OLED_ShowChinese(128,24,t,16); //写入一个汉字保存在OLED_GRAM[][]数组中t++;}if(t==num){for(r=0;r<16*space;r++)      //显示间隔{for(i=0;i<144;i++){for(n=0;n<8;n++){OLED_GRAM[i-1][n]=OLED_GRAM[i][n];}}OLED_Refresh();}t=0;}m++;if(m==16){m=0;}for(i=0;i<144;i++)   //实现左移{for(n=0;n<8;n++){OLED_GRAM[i-1][n]=OLED_GRAM[i][n];}}OLED_Refresh();}
}//配置写入数据的起始位置
void OLED_WR_BP(u8 x,u8 y)
{OLED_WR_Byte(0xb0+y,OLED_CMD);//设置行起始地址OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);OLED_WR_Byte((x&0x0f),OLED_CMD);
}//x0,y0:起点坐标
//x1,y1:终点坐标
//BMP[]:要写入的图片数组
void OLED_ShowPicture(u8 x0,u8 y0,u8 x1,u8 y1,u8 BMP[])
{u32 j=0;u8 x=0,y=0;if(y%8==0)y=0;else y+=1;for(y=y0;y<y1;y++){OLED_WR_BP(x0,y);for(x=x0;x<x1;x++){OLED_WR_Byte(BMP[j],OLED_DATA);j++;}}
}

PWM.C代码:输出一个20ms为周期的PWM波,定时器产生PWM波形计算方法:84000000/(8399+1)*(199+1)=0.02。

void TIM3_PWM_Init(void)
{                            GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;TIM_OCInitTypeDef  TIM_OCInitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM3);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;GPIO_Init(GPIOC,&GPIO_InitStructure);TIM_TimeBaseStructure.TIM_Prescaler=8399;TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimeBaseStructure.TIM_Period=199;TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; TIM_OC1Init(TIM3, &TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM3,ENABLE);TIM_Cmd(TIM3, ENABLE); }  

USART3.C代码:进行串口的初始化,并使能相应的接收中断函数,来达到可接收函数解锁的目的。

void usart3_init(u32 bound)
{  NVIC_InitTypeDef NVIC_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;USART_DeInit(USART3);  //复位串口3RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); //使能GPIOB时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);//使能USART3时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_10; //GPIOB11和GPIOB10初始化GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHzGPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化GPIOB11,和GPIOB10GPIO_PinAFConfig(GPIOB,GPIO_PinSource11,GPIO_AF_USART3); //GPIOB11复用为USART3GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_USART3); //GPIOB10复用为USART3   USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为9600;USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    //收发模式USART_Init(USART3, &USART_InitStructure); //初始化串口3USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断  USART_Cmd(USART3, ENABLE);                    //使能串口 NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级2NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;       //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQ通道使能NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器TIM7_Int_Init(100-1,8400-1);  //10ms中断一次TIM_Cmd(TIM7, DISABLE); //关闭定时器7USART3_RX_STA=0;             //清零
}
void USART3_IRQHandler(void)
{u8 res;        if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)//接收到数据{   res =USART_ReceiveData(USART3);       if((USART3_RX_STA&(1<<15))==0)//接收完的一批数据,还没有被处理,则不再接收其他数据{ if(USART3_RX_STA<USART3_MAX_RECV_LEN)     //还可以接收数据{TIM_SetCounter(TIM7,0);//计数器清空                         if(USART3_RX_STA==0)     TIM_Cmd(TIM7, ENABLE);  //使能定时器7 USART3_RX_BUF[USART3_RX_STA++]=res;     //记录接收到的值    }else {USART3_RX_STA|=1<<15;                    //强制标记接收完成} }   }
} 

TIMER.C代码:USART3的定时器设置。

void TIM7_Int_Init(u16 arr,u16 psc)
{   NVIC_InitTypeDef NVIC_InitStructure;TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);//TIM7时钟使能    //定时器TIM7初始化TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE ); //使能指定的TIM7中断,允许更新中断TIM_Cmd(TIM7,ENABLE);//使能定时器7NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;      //子优先级1NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQ通道使能NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器}
void TIM7_IRQHandler(void)
{   if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET)//是更新中断{                USART3_RX_STA|=1<<15; //标记接收完成TIM_ClearITPendingBit(TIM7, TIM_IT_Update  );  //清除TIM7更新中断标志    TIM_Cmd(TIM7, DISABLE);  //关闭TIM7 }
}

GUI.C代码:通过调用OLED中的驱动函数设计出了一下OLED画面。

void GUI_OLED_LOCK(void)//锁屏面板初始化
{OLED_Clear();OLED_ShowChinese(48,0,13,16);OLED_ShowChinese(64,0,36,16);OLED_ShowChinese(0,16,0,16);OLED_ShowChinese(16,16,1,16);OLED_ShowString(32,16,":",16);//密码开始打印位置为x=40,y=16OLED_Refresh();OLED_ShowPicture(48,4,80,8,BMP1);
}
void GUI_OLED_UNLOCHING(void)//进行开锁中
{u8 i;double t=0.0;char buf[8];OLED_Clear();OLED_ShowChinese(32,0,2,16);OLED_ShowChinese(48,0,7,16);OLED_ShowChinese(64,0,19,16);OLED_ShowChinese(80,0,13,16);OLED_ShowChinese(0,16,29,16);OLED_ShowChinese(16,16,30,16);OLED_Refresh();for(i=0;i<80;i++){t=t+1.25;sprintf((char *)buf,"%3.0f%%",t);OLED_DrawLine(i+32,16,i+32,32);OLED_ShowString(88,48,(uint8_t *)buf,16);OLED_Refresh();OLED_ShowPicture(48,4,80,8,BMP1);delay_ms(50);}}
void GUI_OLED_UNLOCK_OK(void)//开锁成功
{u8 i;double t=0.0;char buf[8];OLED_Clear();OLED_ShowChinese(32,0,19,16);OLED_ShowChinese(48,0,13,16);OLED_ShowChinese(64,0,10,16);OLED_ShowChinese(80,0,11,16);OLED_ShowChinese(0,16,31,16);OLED_ShowChinese(16,16,32,16);OLED_Refresh();for(i=0;i<80;i++){t=t+1.25;sprintf((char *)buf,"%3.0f%%",t);OLED_DrawLine(i+32,16,i+32,32);OLED_ShowString(88,48,(uint8_t *)buf,16);OLED_Refresh();OLED_ShowPicture(43,4,85,8,BMP2);delay_ms(50);}
}
void GUI_OLED_UNLOCK_NO(void)//开锁失败
{u8 i;double t=0.0;char buf[8];OLED_Clear();OLED_ShowChinese(32,0,19,16);OLED_ShowChinese(48,0,13,16);OLED_ShowChinese(64,0,8,16);OLED_ShowChinese(80,0,9,16);OLED_ShowChinese(0,16,25,16);OLED_ShowChinese(16,16,33,16);OLED_Refresh();for(i=0;i<80;i++){t=t+1.25;sprintf((char *)buf,"%3.0f%%",t);OLED_DrawLine(i+32,16,i+32,32);OLED_ShowString(88,48,(uint8_t *)buf,16);OLED_Refresh();OLED_ShowPicture(48,4,80,8,BMP1);delay_ms(50);}
}
void GUI_OLED_UNLOCK(void)//开锁成功返回操控界面
{OLED_Clear();OLED_ShowChinese(32,0,14,16);OLED_ShowChinese(48,0,15,16);OLED_ShowChinese(64,0,16,16);OLED_ShowChinese(80,0,17,16);OLED_ShowChinese(0,16,37,16);OLED_ShowChinese(16,16,38,16);OLED_ShowChinese(32,16,39,16);OLED_ShowChinese(48,16,40,16);OLED_ShowString(64,16,":",16);OLED_ShowString(0,32,"*:",16);OLED_ShowChinese(16,32,34,16);OLED_ShowChinese(32,32,35,16);OLED_ShowChinese(48,32,0,16);OLED_ShowChinese(64,32,1,16);OLED_ShowString(0,48,"#:",16);OLED_ShowChinese(16,48,13,16);OLED_ShowChinese(32,48,36,16);OLED_Refresh();
}
void GUI_PSSKEY(void)//按键说明界面
{OLED_Clear();OLED_ShowNum(8,0,1,1,16);OLED_ShowNum(40,0,2,1,16);OLED_ShowNum(72,0,3,1,16);OLED_ShowChinese(96,0,41,16);OLED_ShowChinese(112,0,42,16);OLED_ShowNum(8,16,4,1,16);OLED_ShowNum(40,16,5,1,16);OLED_ShowNum(72,16,6,1,16);OLED_ShowChinese(96,16,43,16);OLED_ShowChinese(112,16,42,16);OLED_ShowNum(8,32,7,1,16);OLED_ShowNum(40,32,8,1,16);OLED_ShowNum(72,32,9,1,16);OLED_ShowChinese(96,32,13,16);OLED_ShowChinese(112,32,36,16);OLED_ShowString(8,48,"*",16);OLED_ShowNum(40,48,0,1,16);OLED_ShowString(72,48,"#",16);OLED_ShowChinese(96,48,3,16);OLED_ShowChinese(112,48,44,16);OLED_Refresh();
}
void GUI_PCHANGE(void)//密码修改界面
{OLED_Clear();OLED_ShowChinese(32,0,45,16);OLED_ShowChinese(48,0,35,16);OLED_ShowChinese(64,0,0,16);OLED_ShowChinese(80,0,1,16);OLED_ShowChinese(0,16,37,16);OLED_ShowChinese(16,16,38,16);OLED_ShowChinese(32,16,39,16);OLED_ShowChinese(48,16,40,16);OLED_ShowString(64,16,":",16);OLED_ShowChinese(0,32,26,16);OLED_ShowChinese(16,32,0,16);OLED_ShowChinese(32,32,1,16);OLED_ShowString(48,32,":",16);OLED_ShowChinese(96,48,3,16);OLED_ShowChinese(112,48,44,16);OLED_Refresh();
}

以上GUI函数设计出的画面:

MAIN.C代码:(修改密码系统部分)

思路:进入一次while函数进行一个死循环,只有当按键按下时才进行下面的操作。在下面的操作当中,合理的运用if和else if设置一个按键优先级顺序,按照这样的优先级顺序来进行按键操作。运用goto函数来进行每次按键回反的操作。

while((key4_val3=key_init_44())==RESET);
if(key4_val3==13)//按下*即S13键进行修改密码
{   GUI_PCHANGE();for(i=0;i<7;i++){delay_ms(200);while((key4_val4=key_init_44())==RESET);if(key4_val4==13)//返回系统主界面{goto loop2;}else if(key4_val4==4)//删除{i=-1;for(j=0;j<6;j++){keysd[j]=j+1;}key4_val4=0;GUI_PCHANGE();}else if(key4_val4==8)//清除{if(i>0){i--;keysd[i]=i+1;OLED_ShowString((56+i*8),32," ",16);OLED_Refresh();i--;}key4_val4=0;}else if(key4_val4==16)//确认{if(i==6){for(i=0;i<6;i++){keysd[i]=keysa[i];}OLED_ShowChinese(0,48,10,16);OLED_ShowChinese(16,48,11,16);OLED_Refresh();goto loop2;}key4_val4=0;}else if((key4_val4!=15)&&(key4_val4!=12))//数字输入{u8 temp;if(i<6){switch(key4_val4){case 1:temp=1;break;case 2:temp=2;break;case 3:temp=3;break;case 5:temp=4;break;case 6:temp=5;break;case 7:temp=6;break;case 9:temp=7;break;case 10:temp=8;break;case 11:temp=9;break;case 14:temp=0;break;default:temp=10;break;}keysa[i]=temp;OLED_ShowString((56+i*8),32,"*",16);OLED_Refresh();}else{i--;}}else{i--;}key4_val4=0;}
}
else if(key4_val3==15)//按下#即S15键进行系统锁定
{key4_val3=0;key4_val2=0;TIM_SetCompare1(TIM3,180);delay_ms(2000);TIM_SetCompare1(TIM3,100);goto loop1;
}

总代码下载网址

https://download.csdn.net/download/weixin_46619338/21772343

基于STM32F4的智能门锁超详细解析(矩阵键盘、OLED、舵机、HC-05蓝牙、F407ZG最小系统)可用于毕业设计相关推荐

  1. 基于STM32F4的智能门锁系统

    基于STM32F4的智能门锁系统 前言 一.项目背景 二.项目所预想功能 三.外置硬件准备 四.项目开发 简介及涉及协议 蓝牙模块 1.蓝牙接线图 2.使用说明: 3.蓝牙代码 USART3.C 蓝牙 ...

  2. Android技能树 — 网络小结(6)之 OkHttp超超超超超超超详细解析

    前言: 本文也做了一次标题党,哈哈,其实写的还是很水,各位原谅我O(∩_∩)O. 介于自己的网络方面知识烂的一塌糊涂,所以准备写相关网络的文章,但是考虑全部写在一篇太长了,所以分开写,希望大家能仔细看 ...

  3. 单片机数字钟(调时,调时闪烁,万年历,年月日)超详细解析

    2019/07/13 单片机数字钟(调时,调时闪烁,万年历,年月日)超详细解析 发表日期:2019/07/13 单片机开发板:巫妖王2.0, 使用同款开发板可直接上板测试 文档说明: 实现功能 : 一 ...

  4. 计算机网络之交换机的工作原理---超详细解析,谁都看得懂!!

    在了解交换机的工作原理之前,我们先要了解几个概念. 一.相关概念  1.OSI七层模型是哪七层? 自上而下分别是: 应用层 表示层 会话层 传输层 网络层 数据链路层 物理层 交换机工作在数据链路层, ...

  5. STM32项目设计:基于stm32f4的智能门锁(附项目视频全套教程、源码资料)

    文章目录 智能门锁 一.项目背景 二.项目功能要求 三.元件准备 四.项目设计 (一)原理图设计 (二)硬件设计 (三)程序设计 五.上机调试 六.知识扫盲 七.项目图片展示 智能门锁 资料链接 :智 ...

  6. VUE 钩子函数超详细解析

    点击上方蓝色字体关注我吧 一起学习,一起进步,做积极的人! 前言 Vue 实例在被创建时,会经过一系列的初始化过程,初始化过程中会运行一些函数,叫做生命周期钩子函数,通过运用钩子函数,用户在可以在Vu ...

  7. 【智能算法】粒子群算法(Particle Swarm Optimization)超详细解析+入门代码实例讲解...

    喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 01 算法起源 粒子群优化算法(PSO)是一种进化计算技术(evolutionary computation),1995 年由E ...

  8. 超详细解析python爬虫爬取京东图片

    超详细图片爬虫实战 实例讲解(京东商城手机图片爬取) 1.创建一个文件夹来存放你爬取的图片 2.第一部分代码分析 3.第二部分代码分析 完整的代码如下所示: 升级版代码: 爬取过程中首先你需要观察在手 ...

  9. Java实现图书管理系统(超详细解析)

    图书管理系统简单实现.图书管理系统基于Java,页面使用jsp实现. 用户进入登录页面,输入账号密码,系统会自动检验账号和密码是否匹配,匹配成功则进入图书管理首页.首页查看图书信息,新增图书信息,删除 ...

最新文章

  1. 后处理安装_分享UG后处理出Excel程序单的方法
  2. 五子棋html游戏代码与算法介绍
  3. 1. python 字符串简介与常用函数
  4. 内嵌iframe撑高父容器,底部有4px留白问题解决办法
  5. 通过FILETIME得到时间
  6. AndroidManifest.xml文件详解(uses-sdk)
  7. elasticsearch 工作原理_【154期】面试官:你能说说 Elasticsearch 查询数据的工作原理是什么吗?...
  8. 企业实战_19_MyCat初始化ZK并配置Mycat支持ZK
  9. 高性价比手持机有哪些
  10. PAT乙级(1016 部分A+B)
  11. leetcode刷题:最大子序积
  12. php socket发数据打印,PHP向socket服务器收发数据的方法
  13. 【转】BW的星型数据模型
  14. 遗传算法优化变分模态分解VMD包络熵和参数及MATLAB代码
  15. python 对象转json
  16. 优秀课件笔记之文件系统
  17. 地域和地方的区别_地方、地域、地区、地面、地段的区别_近义词词典_词林在线词典...
  18. Redis缓存——(分布式锁)
  19. 行云创新受邀加入信通院云原生成熟度专家组,开启业内首批云原生技术架构/应用成熟度评估测试
  20. GIC通用中断控制器

热门文章

  1. 前端中Excel的导入
  2. 2022-2-16 Leetcode986.区间列表的交集
  3. CVPR2020 论文和代码合集
  4. VOT2019——数据集
  5. C#实现获取指定文件目录下的某种格式的文件集,并移动到Bak
  6. Eclipse CDT中出现 Nothing to build for XXX 的问题
  7. oracle10 升级为11,Oracle10.2.0.4升级至Oracle11.2.0.3错误手记一则
  8. 如何用powerPCB设定4层板的层?-道合顺大数据Infinigo
  9. 2021-05-12Leetcode31.下一个排列
  10. Unity3D教程宝典之Web服务器篇