当前位置:   article > 正文

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

stm32驱动矩阵键盘和oled

前言:

        对于刚学习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口PC0PC1PC2PC3PC4PC5PG6PG7

   

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

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

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

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

  1. GPIO_InitTypeDef GPIO_InitStructure;
  2. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOG, ENABLE);
  3. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
  4. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  5. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  6. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  7. GPIO_Init(GPIOC, &GPIO_InitStructure);
  8. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
  9. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//输入模式
  10. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  11. GPIO_Init(GPIOG,&GPIO_InitStructure);//初始化
  12. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5;
  13. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//输入模式
  14. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  15. 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);

  1. GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2);
  2. GPIO_ResetBits(GPIOC,GPIO_Pin_3);
  3. if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0)
  4. {
  5. delay_ms(10);
  6. if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0)
  7. {
  8. temp=(GPIOC->IDR&0x37)|(GPIOG->IDR&0xC0);
  9. switch(temp)
  10. {
  11. case 0xE7:Key_val=1;
  12. break;
  13. case 0xD7:Key_val=2;
  14. break;
  15. case 0xB7:Key_val=3;
  16. break;
  17. case 0x77:Key_val=4;
  18. break;
  19. default :Key_val=0;
  20. break;
  21. }
  22. }
  23. }

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


OLED显示

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

        线路连接:

OLED的IOGNDVCCDODIRESDCCS
单片机的IOGND+5VPF8PF7PF6PB13PB12

        

        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+5VGNDPC6

驱动程序讲解:

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

  1. //进行结构体声明
  2. GPIO_InitTypeDef GPIO_InitStructure;
  3. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  4. TIM_OCInitTypeDef TIM_OCInitStructure;
  5. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
  6. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  7. GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM3);
  8. //GPIO初始化
  9. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  10. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  11. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  12. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  13. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  14. GPIO_Init(GPIOC,&GPIO_InitStructure);
  15. //定时器计时初始化
  16. TIM_TimeBaseStructure.TIM_Prescaler=8399;
  17. TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
  18. TIM_TimeBaseStructure.TIM_Period=200;
  19. TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
  20. TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
  21. //输出PWM设置
  22. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  23. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  24. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
  25. TIM_OC1Init(TIM3, &TIM_OCInitStructure);
  26. //使能
  27. TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
  28. TIM_ARRPreloadConfig(TIM3,ENABLE);
  29. TIM_Cmd(TIM3, ENABLE);

HC-05蓝牙模块

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

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

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

蓝牙与单片机
蓝牙IOSTATERXDTXDGNDVCCEN
单片机IO未连PB10PB11GND+5V未连
蓝牙IOSTATERXDTXDGNDVCCEN
TTLUSBIO未连TXDRXDGND+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的初始化和中断服务函数

  1. void usart3_init(u32 bound)
  2. {
  3. NVIC_InitTypeDef NVIC_InitStructure;
  4. GPIO_InitTypeDef GPIO_InitStructure;
  5. USART_InitTypeDef USART_InitStructure;
  6. USART_DeInit(USART3); //复位串口3
  7. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); //使能GPIOB时钟
  8. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);//使能USART3时钟
  9. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_10; //GPIOB11和GPIOB10初始化
  10. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
  11. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz
  12. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
  13. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
  14. GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化GPIOB11,和GPIOB10
  15. GPIO_PinAFConfig(GPIOB,GPIO_PinSource11,GPIO_AF_USART3); //GPIOB11复用为USART3
  16. GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_USART3); //GPIOB10复用为USART3
  17. USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为9600;
  18. USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
  19. USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
  20. USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
  21. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
  22. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
  23. USART_Init(USART3, &USART_InitStructure); //初始化串口3
  24. USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断
  25. USART_Cmd(USART3, ENABLE); //使能串口
  26. NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
  27. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级2
  28. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
  29. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
  30. NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
  31. TIM7_Int_Init(100-1,8400-1); //10ms中断一次
  32. TIM_Cmd(TIM7, DISABLE); //关闭定时器7
  33. USART3_RX_STA=0; //清零
  34. }
  35. void USART3_IRQHandler(void)
  36. {
  37. u8 res;
  38. if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)//接收到数据
  39. {
  40. res =USART_ReceiveData(USART3);
  41. if((USART3_RX_STA&(1<<15))==0)//接收完的一批数据,还没有被处理,则不再接收其他数据
  42. {
  43. if(USART3_RX_STA<USART3_MAX_RECV_LEN) //还可以接收数据
  44. {
  45. TIM_SetCounter(TIM7,0);//计数器清空
  46. if(USART3_RX_STA==0)
  47. TIM_Cmd(TIM7, ENABLE); //使能定时器7
  48. USART3_RX_BUF[USART3_RX_STA++]=res; //记录接收到的值
  49. }else
  50. {
  51. USART3_RX_STA|=1<<15; //强制标记接收完成
  52. }
  53. }
  54. }
  55. }

定时器的初始化

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

连线说明

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

矩阵键盘的连线:

矩阵键盘IO口行IO4行IO3行IO2行IO1列IO1列IO2列IO3列IO4
单片机IO口PC0PC1PC2PC3PC4PC5PG6PG7

OLED屏幕的连线:

OLED的IOGNDVCCDODIRESDCCS
单片机的IOGND+5VPF8PF7PF6PB13PB12

舵机的连线:

舵机IO红线棕线黄线
单片机IO+5VGNDPC6

蓝牙的连线:

蓝牙IOSTATERXDTXDGNDVCCEN
单片机IO未连PB10PB11GND+5V未连

代码解析

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

  1. u16 key_init_44(void)//4*4矩阵键盘函数(单次按键模式)
  2. {
  3. static u8 t=1;
  4. u16 Key_val=0;
  5. u32 temp=0;
  6. gpio_init_key4();
  7. if(t)
  8. {
  9. GPIO_ResetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
  10. GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2);
  11. GPIO_ResetBits(GPIOC,GPIO_Pin_3);
  12. if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0)
  13. {
  14. delay_ms(10);
  15. if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0)
  16. {
  17. temp=(GPIOC->IDR&0x37)|(GPIOG->IDR&0xC0);
  18. switch(temp)
  19. {
  20. case 0xE7:Key_val=1;
  21. break;
  22. case 0xD7:Key_val=2;
  23. break;
  24. case 0xB7:Key_val=3;
  25. break;
  26. case 0x77:Key_val=4;
  27. break;
  28. default :Key_val=0;
  29. break;
  30. }
  31. }
  32. }
  33. GPIO_ResetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
  34. GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_3);
  35. GPIO_ResetBits(GPIOC,GPIO_Pin_2);
  36. if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0)
  37. {
  38. delay_ms(10);
  39. if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0)
  40. {
  41. temp=(GPIOC->IDR&0x3B)|(GPIOG->IDR&0xC0);
  42. switch(temp)
  43. {
  44. case 0xEB:Key_val=5;
  45. break;
  46. case 0xDB:Key_val=6;
  47. break;
  48. case 0xBB:Key_val=7;
  49. break;
  50. case 0x7B:Key_val=8;
  51. break;
  52. default :Key_val=0;
  53. break;
  54. }
  55. }
  56. }
  57. GPIO_ResetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
  58. GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_3|GPIO_Pin_2);
  59. GPIO_ResetBits(GPIOC,GPIO_Pin_1);
  60. if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0)
  61. {
  62. delay_ms(10);
  63. if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0)
  64. {
  65. temp=(GPIOC->IDR&0x3D)|(GPIOG->IDR&0xC0);
  66. switch(temp)
  67. {
  68. case 0xED:Key_val=9;
  69. break;
  70. case 0xDD:Key_val=10;
  71. break;
  72. case 0xBD:Key_val=11;
  73. break;
  74. case 0x7D:Key_val=12;
  75. break;
  76. default :Key_val=0;
  77. break;
  78. }
  79. }
  80. }
  81. GPIO_ResetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
  82. GPIO_SetBits(GPIOC,GPIO_Pin_3|GPIO_Pin_1|GPIO_Pin_2);
  83. GPIO_ResetBits(GPIOC,GPIO_Pin_0);
  84. if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0)
  85. {
  86. delay_ms(10);
  87. if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))!=0xF0)
  88. {
  89. temp=(GPIOC->IDR&0x3E)|(GPIOG->IDR&0xC0);
  90. switch(temp)
  91. {
  92. case 0xEE:Key_val=13;
  93. break;
  94. case 0xDE:Key_val=14;
  95. break;
  96. case 0xBE:Key_val=15;
  97. break;
  98. case 0x7E:Key_val=16;
  99. break;
  100. default :Key_val=0;
  101. break;
  102. }
  103. }
  104. }
  105. if(Key_val!=0)
  106. {
  107. t=0;
  108. }
  109. return Key_val;
  110. }
  111. else if(((GPIOC->IDR&0x30)|(GPIOG->IDR&0xC0))==0xF0)
  112. {
  113. t=1;
  114. }
  115. return 0;
  116. }

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

  1. u8 OLED_GRAM[144][8];
  2. //反显函数
  3. void OLED_ColorTurn(u8 i)
  4. {
  5. if(i==0)
  6. {
  7. OLED_WR_Byte(0xA6,OLED_CMD);//正常显示
  8. }
  9. if(i==1)
  10. {
  11. OLED_WR_Byte(0xA7,OLED_CMD);//反色显示
  12. }
  13. }
  14. //屏幕旋转180度
  15. void OLED_DisplayTurn(u8 i)
  16. {
  17. if(i==0)
  18. {
  19. OLED_WR_Byte(0xC8,OLED_CMD);//正常显示
  20. OLED_WR_Byte(0xA1,OLED_CMD);
  21. }
  22. if(i==1)
  23. {
  24. OLED_WR_Byte(0xC0,OLED_CMD);//反转显示
  25. OLED_WR_Byte(0xA0,OLED_CMD);
  26. }
  27. }
  28. void OLED_WR_Byte(u8 dat,u8 cmd)
  29. {
  30. u8 i;
  31. if(cmd)
  32. OLED_DC_Set();
  33. else
  34. OLED_DC_Clr();
  35. OLED_CS_Clr();
  36. for(i=0;i<8;i++)
  37. {
  38. OLED_SCLK_Clr();
  39. if(dat&0x80)
  40. OLED_SDIN_Set();
  41. else
  42. OLED_SDIN_Clr();
  43. OLED_SCLK_Set();
  44. dat<<=1;
  45. }
  46. OLED_CS_Set();
  47. OLED_DC_Set();
  48. }
  49. //开启OLED显示
  50. void OLED_DisPlay_On(void)
  51. {
  52. OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能
  53. OLED_WR_Byte(0x14,OLED_CMD);//开启电荷泵
  54. OLED_WR_Byte(0xAF,OLED_CMD);//点亮屏幕
  55. }
  56. //关闭OLED显示
  57. void OLED_DisPlay_Off(void)
  58. {
  59. OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能
  60. OLED_WR_Byte(0x10,OLED_CMD);//关闭电荷泵
  61. OLED_WR_Byte(0xAF,OLED_CMD);//关闭屏幕
  62. }
  63. //更新显存到OLED
  64. void OLED_Refresh(void)
  65. {
  66. u8 i,n;
  67. for(i=0;i<8;i++)
  68. {
  69. OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址
  70. OLED_WR_Byte(0x00,OLED_CMD); //设置低列起始地址
  71. OLED_WR_Byte(0x10,OLED_CMD); //设置高列起始地址
  72. for(n=0;n<128;n++)
  73. OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA);
  74. }
  75. }
  76. //清屏函数
  77. void OLED_Clear(void)
  78. {
  79. u8 i,n;
  80. for(i=0;i<8;i++)
  81. {
  82. for(n=0;n<128;n++)
  83. {
  84. OLED_GRAM[n][i]=0;//清除所有数据
  85. }
  86. }
  87. OLED_Refresh();//更新显示
  88. }
  89. //画点
  90. //x:0~127
  91. //y:0~63
  92. void OLED_DrawPoint(u8 x,u8 y)
  93. {
  94. u8 i,m,n;
  95. i=y/8;
  96. m=y%8;
  97. n=1<<m;
  98. OLED_GRAM[x][i]|=n;
  99. }
  100. //清除一个点
  101. //x:0~127
  102. //y:0~63
  103. void OLED_ClearPoint(u8 x,u8 y)
  104. {
  105. u8 i,m,n;
  106. i=y/8;
  107. m=y%8;
  108. n=1<<m;
  109. OLED_GRAM[x][i]=~OLED_GRAM[x][i];
  110. OLED_GRAM[x][i]|=n;
  111. OLED_GRAM[x][i]=~OLED_GRAM[x][i];
  112. }
  113. //画线
  114. //x:0~128
  115. //y:0~64
  116. void OLED_DrawLine(u8 x1,u8 y1,u8 x2,u8 y2)
  117. {
  118. u8 i,k,k1,k2,y0;
  119. if((x1<0)||(x2>128)||(y1<0)||(y2>64)||(x1>x2)||(y1>y2))return;
  120. if(x1==x2) //画竖线
  121. {
  122. for(i=0;i<(y2-y1);i++)
  123. {
  124. OLED_DrawPoint(x1,y1+i);
  125. }
  126. }
  127. else if(y1==y2) //画横线
  128. {
  129. for(i=0;i<(x2-x1);i++)
  130. {
  131. OLED_DrawPoint(x1+i,y1);
  132. }
  133. }
  134. else //画斜线
  135. {
  136. k1=y2-y1;
  137. k2=x2-x1;
  138. k=k1*10/k2;
  139. for(i=0;i<(x2-x1);i++)
  140. {
  141. OLED_DrawPoint(x1+i,y1+i*k/10);
  142. }
  143. }
  144. }
  145. //x,y:圆心坐标
  146. //r:圆的半径
  147. void OLED_DrawCircle(u8 x,u8 y,u8 r)
  148. {
  149. int a, b,num;
  150. a = 0;
  151. b = r;
  152. while(2 * b * b >= r * r)
  153. {
  154. OLED_DrawPoint(x + a, y - b);
  155. OLED_DrawPoint(x - a, y - b);
  156. OLED_DrawPoint(x - a, y + b);
  157. OLED_DrawPoint(x + a, y + b);
  158. OLED_DrawPoint(x + b, y + a);
  159. OLED_DrawPoint(x + b, y - a);
  160. OLED_DrawPoint(x - b, y - a);
  161. OLED_DrawPoint(x - b, y + a);
  162. a++;
  163. num = (a * a + b * b) - r*r;//计算画的点离圆心的距离
  164. if(num > 0)
  165. {
  166. b--;
  167. a--;
  168. }
  169. }
  170. }
  171. //在指定位置显示一个字符,包括部分字符
  172. //x:0~127
  173. //y:0~63
  174. //size:选择字体 12/16/24
  175. //取模方式 逐列式
  176. void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1)
  177. {
  178. u8 i,m,temp,size2,chr1;
  179. u8 y0=y;
  180. size2=(size1/8+((size1%8)?1:0))*(size1/2); //得到字体一个字符对应点阵集所占的字节数
  181. chr1=chr-' '; //计算偏移后的值
  182. for(i=0;i<size2;i++)
  183. {
  184. if(size1==12)
  185. {temp=asc2_1206[chr1][i];} //调用1206字体
  186. else if(size1==16)
  187. {temp=asc2_1608[chr1][i];} //调用1608字体
  188. else if(size1==24)
  189. {temp=asc2_2412[chr1][i];} //调用2412字体
  190. else return;
  191. for(m=0;m<8;m++) //写入数据
  192. {
  193. if(temp&0x80)OLED_DrawPoint(x,y);
  194. else OLED_ClearPoint(x,y);
  195. temp<<=1;
  196. y++;
  197. if((y-y0)==size1)
  198. {
  199. y=y0;
  200. x++;
  201. break;
  202. }
  203. }
  204. }
  205. }
  206. //显示字符串
  207. //x,y:起点坐标
  208. //size1:字体大小
  209. //*chr:字符串起始地址
  210. void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1)
  211. {
  212. while((*chr>=' ')&&(*chr<='~'))//判断是不是非法字符!
  213. {
  214. OLED_ShowChar(x,y,*chr,size1);
  215. x+=size1/2;
  216. if(x>128-size1) //换行
  217. {
  218. x=0;
  219. y+=2;
  220. }
  221. chr++;
  222. }
  223. }
  224. //m^n
  225. u32 OLED_Pow(u8 m,u8 n)
  226. {
  227. u32 result=1;
  228. while(n--)
  229. {
  230. result*=m;
  231. }
  232. return result;
  233. }
  234. 显示2个数字
  235. x,y :起点坐标
  236. len :数字的位数
  237. size:字体大小
  238. void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size1)
  239. {
  240. u8 t,temp;
  241. for(t=0;t<len;t++)
  242. {
  243. temp=(num/OLED_Pow(10,len-t-1))%10;
  244. if(temp==0)
  245. {
  246. OLED_ShowChar(x+(size1/2)*t,y,'0',size1);
  247. }
  248. else
  249. {
  250. OLED_ShowChar(x+(size1/2)*t,y,temp+'0',size1);
  251. }
  252. }
  253. }
  254. //显示汉字
  255. //x,y:起点坐标
  256. //num:汉字对应的序号
  257. //取模方式 列行式
  258. void OLED_ShowChinese(u8 x,u8 y,u8 num,u8 size1)
  259. {
  260. u8 i,m,n=0,temp,chr1;
  261. u8 x0=x,y0=y;
  262. u8 size3=size1/8;
  263. while(size3--)
  264. {
  265. chr1=num*size1/8+n;
  266. n++;
  267. for(i=0;i<size1;i++)
  268. {
  269. if(size1==16)
  270. {temp=Hzk1[chr1][i];}//调用16*16字体
  271. else if(size1==24)
  272. {temp=Hzk2[chr1][i];}//调用24*24字体
  273. else if(size1==32)
  274. {temp=Hzk3[chr1][i];}//调用32*32字体
  275. else if(size1==64)
  276. {temp=Hzk4[chr1][i];}//调用64*64字体
  277. else return;
  278. for(m=0;m<8;m++)
  279. {
  280. if(temp&0x01)OLED_DrawPoint(x,y);
  281. else OLED_ClearPoint(x,y);
  282. temp>>=1;
  283. y++;
  284. }
  285. x++;
  286. if((x-x0)==size1)
  287. {x=x0;y0=y0+8;}
  288. y=y0;
  289. }
  290. }
  291. }
  292. //num 显示汉字的个数
  293. //space 每一遍显示的间隔
  294. void OLED_ScrollDisplay(u8 num,u8 space)
  295. {
  296. u8 i,n,t=0,m=0,r;
  297. while(1)
  298. {
  299. if(m==0)
  300. {
  301. OLED_ShowChinese(128,24,t,16); //写入一个汉字保存在OLED_GRAM[][]数组中
  302. t++;
  303. }
  304. if(t==num)
  305. {
  306. for(r=0;r<16*space;r++) //显示间隔
  307. {
  308. for(i=0;i<144;i++)
  309. {
  310. for(n=0;n<8;n++)
  311. {
  312. OLED_GRAM[i-1][n]=OLED_GRAM[i][n];
  313. }
  314. }
  315. OLED_Refresh();
  316. }
  317. t=0;
  318. }
  319. m++;
  320. if(m==16){m=0;}
  321. for(i=0;i<144;i++) //实现左移
  322. {
  323. for(n=0;n<8;n++)
  324. {
  325. OLED_GRAM[i-1][n]=OLED_GRAM[i][n];
  326. }
  327. }
  328. OLED_Refresh();
  329. }
  330. }
  331. //配置写入数据的起始位置
  332. void OLED_WR_BP(u8 x,u8 y)
  333. {
  334. OLED_WR_Byte(0xb0+y,OLED_CMD);//设置行起始地址
  335. OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
  336. OLED_WR_Byte((x&0x0f),OLED_CMD);
  337. }
  338. //x0,y0:起点坐标
  339. //x1,y1:终点坐标
  340. //BMP[]:要写入的图片数组
  341. void OLED_ShowPicture(u8 x0,u8 y0,u8 x1,u8 y1,u8 BMP[])
  342. {
  343. u32 j=0;
  344. u8 x=0,y=0;
  345. if(y%8==0)y=0;
  346. else y+=1;
  347. for(y=y0;y<y1;y++)
  348. {
  349. OLED_WR_BP(x0,y);
  350. for(x=x0;x<x1;x++)
  351. {
  352. OLED_WR_Byte(BMP[j],OLED_DATA);
  353. j++;
  354. }
  355. }
  356. }

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

  1. void TIM3_PWM_Init(void)
  2. {
  3. GPIO_InitTypeDef GPIO_InitStructure;
  4. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  5. TIM_OCInitTypeDef TIM_OCInitStructure;
  6. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
  7. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  8. GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM3);
  9. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  10. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  11. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  12. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  13. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  14. GPIO_Init(GPIOC,&GPIO_InitStructure);
  15. TIM_TimeBaseStructure.TIM_Prescaler=8399;
  16. TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
  17. TIM_TimeBaseStructure.TIM_Period=199;
  18. TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
  19. TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
  20. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  21. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  22. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
  23. TIM_OC1Init(TIM3, &TIM_OCInitStructure);
  24. TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
  25. TIM_ARRPreloadConfig(TIM3,ENABLE);
  26. TIM_Cmd(TIM3, ENABLE);
  27. }

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

  1. void usart3_init(u32 bound)
  2. {
  3. NVIC_InitTypeDef NVIC_InitStructure;
  4. GPIO_InitTypeDef GPIO_InitStructure;
  5. USART_InitTypeDef USART_InitStructure;
  6. USART_DeInit(USART3); //复位串口3
  7. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); //使能GPIOB时钟
  8. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);//使能USART3时钟
  9. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_10; //GPIOB11和GPIOB10初始化
  10. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
  11. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz
  12. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
  13. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
  14. GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化GPIOB11,和GPIOB10
  15. GPIO_PinAFConfig(GPIOB,GPIO_PinSource11,GPIO_AF_USART3); //GPIOB11复用为USART3
  16. GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_USART3); //GPIOB10复用为USART3
  17. USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为9600;
  18. USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
  19. USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
  20. USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
  21. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
  22. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
  23. USART_Init(USART3, &USART_InitStructure); //初始化串口3
  24. USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断
  25. USART_Cmd(USART3, ENABLE); //使能串口
  26. NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
  27. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级2
  28. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
  29. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
  30. NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
  31. TIM7_Int_Init(100-1,8400-1); //10ms中断一次
  32. TIM_Cmd(TIM7, DISABLE); //关闭定时器7
  33. USART3_RX_STA=0; //清零
  34. }
  35. void USART3_IRQHandler(void)
  36. {
  37. u8 res;
  38. if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)//接收到数据
  39. {
  40. res =USART_ReceiveData(USART3);
  41. if((USART3_RX_STA&(1<<15))==0)//接收完的一批数据,还没有被处理,则不再接收其他数据
  42. {
  43. if(USART3_RX_STA<USART3_MAX_RECV_LEN) //还可以接收数据
  44. {
  45. TIM_SetCounter(TIM7,0);//计数器清空
  46. if(USART3_RX_STA==0)
  47. TIM_Cmd(TIM7, ENABLE); //使能定时器7
  48. USART3_RX_BUF[USART3_RX_STA++]=res; //记录接收到的值
  49. }else
  50. {
  51. USART3_RX_STA|=1<<15; //强制标记接收完成
  52. }
  53. }
  54. }
  55. }

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

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

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

  1. void GUI_OLED_LOCK(void)//锁屏面板初始化
  2. {
  3. OLED_Clear();
  4. OLED_ShowChinese(48,0,13,16);
  5. OLED_ShowChinese(64,0,36,16);
  6. OLED_ShowChinese(0,16,0,16);
  7. OLED_ShowChinese(16,16,1,16);
  8. OLED_ShowString(32,16,":",16);//密码开始打印位置为x=40,y=16
  9. OLED_Refresh();
  10. OLED_ShowPicture(48,4,80,8,BMP1);
  11. }
  12. void GUI_OLED_UNLOCHING(void)//进行开锁中
  13. {
  14. u8 i;
  15. double t=0.0;
  16. char buf[8];
  17. OLED_Clear();
  18. OLED_ShowChinese(32,0,2,16);
  19. OLED_ShowChinese(48,0,7,16);
  20. OLED_ShowChinese(64,0,19,16);
  21. OLED_ShowChinese(80,0,13,16);
  22. OLED_ShowChinese(0,16,29,16);
  23. OLED_ShowChinese(16,16,30,16);
  24. OLED_Refresh();
  25. for(i=0;i<80;i++)
  26. {
  27. t=t+1.25;
  28. sprintf((char *)buf,"%3.0f%%",t);
  29. OLED_DrawLine(i+32,16,i+32,32);
  30. OLED_ShowString(88,48,(uint8_t *)buf,16);
  31. OLED_Refresh();
  32. OLED_ShowPicture(48,4,80,8,BMP1);
  33. delay_ms(50);
  34. }
  35. }
  36. void GUI_OLED_UNLOCK_OK(void)//开锁成功
  37. {
  38. u8 i;
  39. double t=0.0;
  40. char buf[8];
  41. OLED_Clear();
  42. OLED_ShowChinese(32,0,19,16);
  43. OLED_ShowChinese(48,0,13,16);
  44. OLED_ShowChinese(64,0,10,16);
  45. OLED_ShowChinese(80,0,11,16);
  46. OLED_ShowChinese(0,16,31,16);
  47. OLED_ShowChinese(16,16,32,16);
  48. OLED_Refresh();
  49. for(i=0;i<80;i++)
  50. {
  51. t=t+1.25;
  52. sprintf((char *)buf,"%3.0f%%",t);
  53. OLED_DrawLine(i+32,16,i+32,32);
  54. OLED_ShowString(88,48,(uint8_t *)buf,16);
  55. OLED_Refresh();
  56. OLED_ShowPicture(43,4,85,8,BMP2);
  57. delay_ms(50);
  58. }
  59. }
  60. void GUI_OLED_UNLOCK_NO(void)//开锁失败
  61. {
  62. u8 i;
  63. double t=0.0;
  64. char buf[8];
  65. OLED_Clear();
  66. OLED_ShowChinese(32,0,19,16);
  67. OLED_ShowChinese(48,0,13,16);
  68. OLED_ShowChinese(64,0,8,16);
  69. OLED_ShowChinese(80,0,9,16);
  70. OLED_ShowChinese(0,16,25,16);
  71. OLED_ShowChinese(16,16,33,16);
  72. OLED_Refresh();
  73. for(i=0;i<80;i++)
  74. {
  75. t=t+1.25;
  76. sprintf((char *)buf,"%3.0f%%",t);
  77. OLED_DrawLine(i+32,16,i+32,32);
  78. OLED_ShowString(88,48,(uint8_t *)buf,16);
  79. OLED_Refresh();
  80. OLED_ShowPicture(48,4,80,8,BMP1);
  81. delay_ms(50);
  82. }
  83. }
  84. void GUI_OLED_UNLOCK(void)//开锁成功返回操控界面
  85. {
  86. OLED_Clear();
  87. OLED_ShowChinese(32,0,14,16);
  88. OLED_ShowChinese(48,0,15,16);
  89. OLED_ShowChinese(64,0,16,16);
  90. OLED_ShowChinese(80,0,17,16);
  91. OLED_ShowChinese(0,16,37,16);
  92. OLED_ShowChinese(16,16,38,16);
  93. OLED_ShowChinese(32,16,39,16);
  94. OLED_ShowChinese(48,16,40,16);
  95. OLED_ShowString(64,16,":",16);
  96. OLED_ShowString(0,32,"*:",16);
  97. OLED_ShowChinese(16,32,34,16);
  98. OLED_ShowChinese(32,32,35,16);
  99. OLED_ShowChinese(48,32,0,16);
  100. OLED_ShowChinese(64,32,1,16);
  101. OLED_ShowString(0,48,"#:",16);
  102. OLED_ShowChinese(16,48,13,16);
  103. OLED_ShowChinese(32,48,36,16);
  104. OLED_Refresh();
  105. }
  106. void GUI_PSSKEY(void)//按键说明界面
  107. {
  108. OLED_Clear();
  109. OLED_ShowNum(8,0,1,1,16);
  110. OLED_ShowNum(40,0,2,1,16);
  111. OLED_ShowNum(72,0,3,1,16);
  112. OLED_ShowChinese(96,0,41,16);
  113. OLED_ShowChinese(112,0,42,16);
  114. OLED_ShowNum(8,16,4,1,16);
  115. OLED_ShowNum(40,16,5,1,16);
  116. OLED_ShowNum(72,16,6,1,16);
  117. OLED_ShowChinese(96,16,43,16);
  118. OLED_ShowChinese(112,16,42,16);
  119. OLED_ShowNum(8,32,7,1,16);
  120. OLED_ShowNum(40,32,8,1,16);
  121. OLED_ShowNum(72,32,9,1,16);
  122. OLED_ShowChinese(96,32,13,16);
  123. OLED_ShowChinese(112,32,36,16);
  124. OLED_ShowString(8,48,"*",16);
  125. OLED_ShowNum(40,48,0,1,16);
  126. OLED_ShowString(72,48,"#",16);
  127. OLED_ShowChinese(96,48,3,16);
  128. OLED_ShowChinese(112,48,44,16);
  129. OLED_Refresh();
  130. }
  131. void GUI_PCHANGE(void)//密码修改界面
  132. {
  133. OLED_Clear();
  134. OLED_ShowChinese(32,0,45,16);
  135. OLED_ShowChinese(48,0,35,16);
  136. OLED_ShowChinese(64,0,0,16);
  137. OLED_ShowChinese(80,0,1,16);
  138. OLED_ShowChinese(0,16,37,16);
  139. OLED_ShowChinese(16,16,38,16);
  140. OLED_ShowChinese(32,16,39,16);
  141. OLED_ShowChinese(48,16,40,16);
  142. OLED_ShowString(64,16,":",16);
  143. OLED_ShowChinese(0,32,26,16);
  144. OLED_ShowChinese(16,32,0,16);
  145. OLED_ShowChinese(32,32,1,16);
  146. OLED_ShowString(48,32,":",16);
  147. OLED_ShowChinese(96,48,3,16);
  148. OLED_ShowChinese(112,48,44,16);
  149. OLED_Refresh();
  150. }

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

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

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

  1. while((key4_val3=key_init_44())==RESET);
  2. if(key4_val3==13)//按下*即S13键进行修改密码
  3. {
  4. GUI_PCHANGE();
  5. for(i=0;i<7;i++)
  6. {
  7. delay_ms(200);
  8. while((key4_val4=key_init_44())==RESET);
  9. if(key4_val4==13)//返回系统主界面
  10. {
  11. goto loop2;
  12. }
  13. else if(key4_val4==4)//删除
  14. {
  15. i=-1;
  16. for(j=0;j<6;j++)
  17. {
  18. keysd[j]=j+1;
  19. }
  20. key4_val4=0;
  21. GUI_PCHANGE();
  22. }
  23. else if(key4_val4==8)//清除
  24. {
  25. if(i>0)
  26. {
  27. i--;
  28. keysd[i]=i+1;
  29. OLED_ShowString((56+i*8),32," ",16);
  30. OLED_Refresh();
  31. i--;
  32. }
  33. key4_val4=0;
  34. }
  35. else if(key4_val4==16)//确认
  36. {
  37. if(i==6)
  38. {
  39. for(i=0;i<6;i++)
  40. {
  41. keysd[i]=keysa[i];
  42. }
  43. OLED_ShowChinese(0,48,10,16);
  44. OLED_ShowChinese(16,48,11,16);
  45. OLED_Refresh();
  46. goto loop2;
  47. }
  48. key4_val4=0;
  49. }
  50. else if((key4_val4!=15)&&(key4_val4!=12))//数字输入
  51. {
  52. u8 temp;
  53. if(i<6)
  54. {
  55. switch(key4_val4)
  56. {
  57. case 1:temp=1;
  58. break;
  59. case 2:temp=2;
  60. break;
  61. case 3:temp=3;
  62. break;
  63. case 5:temp=4;
  64. break;
  65. case 6:temp=5;
  66. break;
  67. case 7:temp=6;
  68. break;
  69. case 9:temp=7;
  70. break;
  71. case 10:temp=8;
  72. break;
  73. case 11:temp=9;
  74. break;
  75. case 14:temp=0;
  76. break;
  77. default:temp=10;
  78. break;
  79. }
  80. keysa[i]=temp;
  81. OLED_ShowString((56+i*8),32,"*",16);
  82. OLED_Refresh();
  83. }
  84. else
  85. {
  86. i--;
  87. }
  88. }
  89. else
  90. {
  91. i--;
  92. }
  93. key4_val4=0;
  94. }
  95. }
  96. else if(key4_val3==15)//按下#即S15键进行系统锁定
  97. {
  98. key4_val3=0;
  99. key4_val2=0;
  100. TIM_SetCompare1(TIM3,180);
  101. delay_ms(2000);
  102. TIM_SetCompare1(TIM3,100);
  103. goto loop1;
  104. }


总代码下载网址

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/302209
推荐阅读
相关标签
  

闽ICP备14008679号