STM32与RC522简单公交卡系统的设计
目录
前言
系统的结构框图
引脚连接以及相关接口设计
编辑
按键初始化函数
按键扫描函数
软件流程图
调试过程
相关代码
挂失代码
具体功能描述
结论与改进
前言
本篇博客旨在给大家提供一个公交卡系统的设计思路,相关硬件以及读卡写卡的流程请参考我上一篇博客。
基于STM32的RC522模块读写数据块以及电子钱包充值扣款系统的设计
系统的结构框图
目前所用到的硬件有RC522,STM32和矩阵键盘,实物图如下:
引脚连接以及相关接口设计
RC522相关的引脚在我上一篇博客已经说过,请大家点开本博客开头的链接查看,4x4的矩阵键盘相关行我们用到的引脚是PF8,9,10,11,相关列用到的引脚是PF12,13,14,15。
按键相关代码如下:
按键初始化函数
void Matrix_ssKey_Pin_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;//行按键GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOF,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;//列按键GPIO_Init(GPIOF,&GPIO_InitStructure);
}
按键扫描函数
int Matrix_Key_Scan(void)
{u8 temp = 0;int key_val = -1;GPIO_ResetBits(GPIOF,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11); delay_us(10);temp=(GPIO_ReadInputData(GPIOF) >> 8)&0xff; if (temp == 0xf0) {delay_ms(50); GPIO_ResetBits(GPIOF,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11); delay_us(10);temp=(GPIO_ReadInputData(GPIOF) >> 8)&0xff; if (temp != 0xf0) {GPIO_Write(GPIOF,0);delay_ms(5);GPIO_Write(GPIOF,(uint16_t)(0xFE << 8)); if(((GPIO_ReadInputData(GPIOF) >> 8) & 0XF0) != 0XF0){delay_ms(20);if(((GPIO_ReadInputData(GPIOF) >> 8) & 0XF0) != 0XF0){temp=((GPIO_ReadInputData(GPIOF) >> 8) & 0XFE); switch(temp){case 0xEE: key_val = 1; break;case 0xDE: key_val = 2; break;case 0xBE: key_val = 3; break;case 0x7E: key_val = 4; break;default: key_val = -1; break;}}}GPIO_Write(GPIOF,0);delay_ms(5);GPIO_Write(GPIOF,(uint16_t)(0xFD << 8));if(((GPIO_ReadInputData(GPIOF) >> 8) & 0XF0)!= 0XF0){delay_ms(20);if(((GPIO_ReadInputData(GPIOF) >> 8) & 0XF0) != 0XF0){temp=((GPIO_ReadInputData(GPIOF) >> 8) & 0XFD);switch(temp){case 0xED: key_val = 5; break;case 0xDD: key_val = 6; break;case 0xBD: key_val = 7; break;case 0x7D: key_val = 8; break;default: key_val = -1; break;}}}GPIO_Write(GPIOF,0);delay_ms(5);GPIO_Write(GPIOF,(uint16_t)(0xFB << 8));if(((GPIO_ReadInputData(GPIOF) >> 8) & 0XF0) != 0XF0){delay_ms(20);if(((GPIO_ReadInputData(GPIOF) >> 8) & 0XF0) != 0XF0){temp=((GPIO_ReadInputData(GPIOF) >> 8) & 0XFB);switch(temp){case 0xEB: key_val = 9; break;case 0xDB: key_val = 10; break;case 0xBB: key_val = 11; break;case 0x7B: key_val = 12; break;default: key_val = -1; break;}}}GPIO_Write(GPIOF,0);delay_ms(5);GPIO_Write(GPIOF,(uint16_t)(0xF7 << 8));if(((GPIO_ReadInputData(GPIOF) >> 8) & 0XF0) !=0XF0){delay_ms(20);if(((GPIO_ReadInputData(GPIOF) >> 8) & 0XF0) != 0XF0){temp=((GPIO_ReadInputData(GPIOF) >> 8) & 0XF7);switch(temp){case 0xE7: key_val = 13; break;case 0xD7: key_val = 14; break;case 0xB7: key_val = 15; break;case 0x77: key_val = 16; break;default: key_val = -1; break;}}}}}return key_val;}
软件流程图
调试过程
我最开始设计的功能是将卡号先写好定义在数组里面,可是这样的话就没有了发卡的功能,于是我就想到设置一个空数组,读卡的时候把卡号存进这个数组里面去。随后,我在设置个人信息的功能时遇到了麻烦,我按下一个按键之后,不需要按后面三个按键他就自动跟第一个按键一样了,于是我在代码里找原因,发现原来每一次输入按键的时候都需要重新扫描,否则按键会停留在上一次的值。
在发卡和个人信息绑定设置完成后,我又要设置挂失和解除挂失功能。这个时候我又用到了一个临时数组,用来临时存放卡号。
当输入的个人信息和相应的卡匹配时,就将卡号存放在临时数组里面。
起初我只考虑了输入正确的情况,没有考虑到输入的信息错误的情况,于是我又小改了一下函数,把if改成了else if 最后如果输入的个人信息都不匹配,则打印出密码错误。
在设计卡的扣款的功能的时候,由于要扣款小数位,最开始我没有想到很好的方法怎么去设置小数位。然后我突然想到一个办法,就是用数据的第十位作为小数位,比如数据100,则实际金额为10.0。根据这个想法,我修改了代码。
将数值块的数据除以10再强制转换为double类型,这样就实现了小数的功能了。不过这样做的坏处就是整体可用金额少了十倍。
在我本来以为功能都设计的差不多的时候,我又发现了另一个问题,那就是挂失和解除挂失功能的模块,我原先把这块函数写在了读卡成功之后。实际功能为不刷卡时无法进入挂失和解除挂失模式的函数,这与实际情况不符合,我就是因为卡掉了才要进入挂失,你现在要我刷卡,我拿什么刷?于是我就把这块函数写在了读卡之前,这样,即使不刷卡,也能进入卡的挂失和解除挂失功能,更加符合实际情况。
相关代码
挂失代码
if(WK_UP==1)//进入挂失和解除挂失模式{printf("\r\n进入挂失和解除挂失模式\r\n");printf("\r\n按下S1进入挂失模式,按下S2进入解除挂失模式\r\n");while(1){key_val = Matrix_Key_Scan();if(key_val > 0 && key_val < 17){if(key_val==1)//进入挂失模式{printf("\r\n 进入挂失模式\r\n");printf("\r\n 请输入4位个人信息\r\n");while(1){key_val = Matrix_Key_Scan();if(key_val > 0 && key_val < 17)//¸个人信息第一位{if(key_val==1)card_3[0]=1;if(key_val==2)card_3[0]=2;if(key_val==3)card_3[0]=3;if(key_val==4)card_3[0]=4;if(key_val==5)card_3[0]=5;if(key_val==6)card_3[0]=6;if(key_val==7)card_3[0]=7;if(key_val==8)card_3[0]=8;if(key_val==9)card_3[0]=9;if(key_val==10)card_3[0]=0;printf("\r\n %d \r\n",card_3[0]);if(card_3[0]==0|card_3[0]==1|card_3[0]==2|card_3[0]==3|card_3[0]==4|card_3[0]==5|card_3[0]==6|card_3[0]==7|card_3[0]==8|card_3[0]==9)break;}}delay_ms(10000);while(1){key_val = Matrix_Key_Scan();if(key_val > 0 && key_val < 17)//个人信息第二位{if(key_val==1)card_3[1]=1;if(key_val==2)card_3[1]=2;if(key_val==3)card_3[1]=3;if(key_val==4)card_3[1]=4;if(key_val==5)card_3[1]=5;if(key_val==6)card_3[1]=6;if(key_val==7)card_3[1]=7;if(key_val==8)card_3[1]=8;if(key_val==9)card_3[1]=9;if(key_val==10)card_3[1]=0;printf("\r\n %d \r\n",card_3[1]);if(card_3[1]==0|card_3[1]==1|card_3[1]==2|card_3[1]==3|card_3[1]==4|card_3[1]==5|card_3[1]==6|card_3[1]==7|card_3[1]==8|card_3[1]==9)break;}}delay_ms(10000);while(1){key_val = Matrix_Key_Scan();if(key_val > 0 && key_val < 17)//个人信息第三位{if(key_val==1)card_3[2]=1;if(key_val==2)card_3[2]=2;if(key_val==3)card_3[2]=3;if(key_val==4)card_3[2]=4;if(key_val==5)card_3[2]=5;if(key_val==6)card_3[2]=6;if(key_val==7)card_3[2]=7;if(key_val==8)card_3[2]=8;if(key_val==9)card_3[2]=9;if(key_val==10)card_3[2]=0;printf("\r\n %d \r\n",card_3[2]);if(card_3[2]==0|card_3[2]==1|card_3[2]==2|card_3[2]==3|card_3[2]==4|card_3[2]==5|card_3[2]==6|card_3[2]==7|card_3[2]==8|card_3[2]==9)break;}}delay_ms(10000);while(1){key_val = Matrix_Key_Scan();if(key_val > 0 && key_val < 17)//个人信息第四位{if(key_val==1)card_3[3]=1;if(key_val==2)card_3[3]=2;if(key_val==3)card_3[3]=3;if(key_val==4)card_3[3]=4;if(key_val==5)card_3[3]=5;if(key_val==6)card_3[3]=6;if(key_val==7)card_3[3]=7;if(key_val==8)card_3[3]=8;if(key_val==9)card_3[3]=9;if(key_val==10)card_3[3]=0;printf("\r\n %d \r\n",card_3[3]);if(card_3[3]==0|card_3[3]==1|card_3[3]==2|card_3[3]==3|card_3[3]==4|card_3[3]==5|card_3[3]==6|card_3[3]==7|card_3[3]==8|card_3[3]==9)break;}}delay_ms(10000);if(((card_3[0]==card[4])&&(card_3[1]==card[5])&&(card_3[2]==card[6])&&(card_3[3]==card[7])))//如果为普通卡的信息{//创建一个临时数组来临时保存普通卡的卡号,然后将该卡卡号初始化为0card_4[0]=card[0];card[0]=0;card_4[1]=card[1];card[1]=0;card_4[2]=card[2];card[2]=0;card_4[3]=card[3];card[3]=0;printf("\r\n 普通卡挂失成功\r\n");printf("\r\n 按下S16退出\r\n");}else if(((card_3[0]==card[12])&&(card_3[1]==card[13])&&(card_3[2]==card[14])&&(card_3[3]==card[15])))//如果为学生卡的信息{//创建一个临时数组来临时保存学生卡的卡号,然后将该卡卡号初始化为0card_5[0]=card[8];card[8]=0;card_5[1]=card[9];card[9]=0;card_5[2]=card[10];card[10]=0;card_5[3]=card[11];card[11]=0;printf("\r\n 学生卡挂失成功\r\n");printf("\r\n 按下S16退出\r\n");}else if(((card_3[0]==card[20])&&(card_3[1]==card[21])&&(card_3[2]==card[22])&&(card_3[3]==card[23])))//如果为老年卡的信息{//创建一个临时数组来临时保存老年卡的卡号,然后将该卡卡号初始化为0card_6[0]=card[16];card[16]=0;card_6[1]=card[17];card[17]=0;card_6[2]=card[18];card[18]=0;card_6[3]=card[19];card[19]=0;printf("\r\n 老年卡挂失成功\r\n");printf("\r\n 按下S16退出\r\n");}else{printf("\r\n 该信息未绑定公交卡\r\n ");}}}key_val = Matrix_Key_Scan();if(key_val > 0 && key_val < 17){if(key_val==2)//进入解除挂失模式{printf("\r\n 进入解除挂失模式\r\n");printf("\r\n 请输入4为个人信息\r\n");while(1){key_val = Matrix_Key_Scan();if(key_val > 0 && key_val < 17)//个人信息第一位{if(key_val==1)card_3[0]=1;if(key_val==2)card_3[0]=2;if(key_val==3)card_3[0]=3;if(key_val==4)card_3[0]=4;if(key_val==5)card_3[0]=5;if(key_val==6)card_3[0]=6;if(key_val==7)card_3[0]=7;if(key_val==8)card_3[0]=8;if(key_val==9)card_3[0]=9;if(key_val==10)card_3[0]=0;printf("\r\n %d \r\n",card_3[0]);if(card_3[0]==0|card_3[0]==1|card_3[0]==2|card_3[0]==3|card_3[0]==4|card_3[0]==5|card_3[0]==6|card_3[0]==7|card_3[0]==8|card_3[0]==9)break;}}delay_ms(10000);while(1){key_val = Matrix_Key_Scan();if(key_val > 0 && key_val < 17)//个人信息第二位{if(key_val==1)card_3[1]=1;if(key_val==2)card_3[1]=2;if(key_val==3)card_3[1]=3;if(key_val==4)card_3[1]=4;if(key_val==5)card_3[1]=5;if(key_val==6)card_3[1]=6;if(key_val==7)card_3[1]=7;if(key_val==8)card_3[1]=8;if(key_val==9)card_3[1]=9;if(key_val==10)card_3[1]=0;printf("\r\n %d \r\n",card_3[1]);if(card_3[1]==0|card_3[1]==1|card_3[1]==2|card_3[1]==3|card_3[1]==4|card_3[1]==5|card_3[1]==6|card_3[1]==7|card_3[1]==8|card_3[1]==9)break;}}delay_ms(10000);while(1){key_val = Matrix_Key_Scan();if(key_val > 0 && key_val < 17)//个人信息第三位{if(key_val==1)card_3[2]=1;if(key_val==2)card_3[2]=2;if(key_val==3)card_3[2]=3;if(key_val==4)card_3[2]=4;if(key_val==5)card_3[2]=5;if(key_val==6)card_3[2]=6;if(key_val==7)card_3[2]=7;if(key_val==8)card_3[2]=8;if(key_val==9)card_3[2]=9;if(key_val==10)card_3[2]=0;printf("\r\n %d \r\n",card_3[2]);if(card_3[2]==0|card_3[2]==1|card_3[2]==2|card_3[2]==3|card_3[2]==4|card_3[2]==5|card_3[2]==6|card_3[2]==7|card_3[2]==8|card_3[2]==9)break;}}delay_ms(10000);while(1){key_val = Matrix_Key_Scan();if(key_val > 0 && key_val < 17)//个人信息第四位{if(key_val==1)card_3[3]=1;if(key_val==2)card_3[3]=2;if(key_val==3)card_3[3]=3;if(key_val==4)card_3[3]=4;if(key_val==5)card_3[3]=5;if(key_val==6)card_3[3]=6;if(key_val==7)card_3[3]=7;if(key_val==8)card_3[3]=8;if(key_val==9)card_3[3]=9;if(key_val==10)card_3[3]=0;printf("\r\n %d \r\n",card_3[3]);if(card_3[3]==0|card_3[3]==1|card_3[3]==2|card_3[3]==3|card_3[3]==4|card_3[3]==5|card_3[3]==6|card_3[3]==7|card_3[3]==8|card_3[3]==9)break;}}delay_ms(10000);if(((card_3[0]==card[4])&&(card_3[1]==card[5])&&(card_3[2]==card[6])&&(card_3[3]==card[7])))//如果为普通卡的个人信息{//将挂失时临时保存的普通卡重新定义card[0]=card_4[0];card[1]=card_4[1];card[2]=card_4[2];card[3]=card_4[3];printf("\r\n 普通卡解除挂失成功\r\n");printf("\r\n 按下S16退出\r\n");}else if(((card_3[0]==card[12])&&(card_3[1]==card[13])&&(card_3[2]==card[14])&&(card_3[3]==card[15])))//如果为学生卡的个人信息{//将挂失时临时保存的学生卡重新定义card[8]=card_5[0];card[9]=card_5[1];card[10]=card_5[2];card[11]=card_5[3];printf("\r\n 学生卡解除挂失成功\r\n");printf("\r\n 按下S16退出\r\n");}else if(((card_3[0]==card[20])&&(card_3[1]==card[21])&&(card_3[2]==card[22])&&(card_3[3]==card[23])))//如果为老年卡的个人信息{//将挂失时临时保存的老年卡重新定义card[16]=card_6[0];card[17]=card_6[1];card[18]=card_6[2];card[19]=card_6[3];printf("\r\n 老年卡解除挂失成功\r\n");printf("\r\n 按下S16退出\r\n");}else{printf("\r\n 该个人信息未绑定公交卡\r\n ");}}}key_val = Matrix_Key_Scan();if(key_val > 0 && key_val < 17){if(key_val==16)//按下S16退出挂失和解除挂失功能{printf("\r\n 退出挂失和解除挂失功能\r\n");break;}}}}
其他相关代码这里不再详细展示。
具体功能描述
具体实现功能为,首先进入菜单。
随机拿一张M50卡。刷卡,此卡未定义,按下KEY1进入发卡模式
此时按下S1则定义为普通卡,按下S2则定义为学生卡,按下S3则定义为老年卡。
然后输入个人信息,当卡定义完成后,按下S16按键退出发卡模式。
此时刚定义的卡是没有余额的,所以需要按下KEY0充值,每按下KEY1一次充值十元。普通卡刷卡一次扣款1.6元,学生卡刷卡一次扣款0.8元。老年卡不需要充值扣款,免费。
当用户将自己的卡遗失后,按下WK_UP键后进入卡的挂失和解除挂失功能,再按下S1进入挂失功能。
此时输入用户的个人信息后成功挂失,输入错误显示密码错误,挂失后,按下S16退出。
当用户找回自己的卡时,再次按下WK_UP键进入挂失和解除挂失功能,此时再按下S2进入解除挂失功能,此时用户输入自己的个人信息后解除挂失成功,若个人信息不匹配则显示密码错误,解除挂失成功后按下S16键退出。
可以看到,基本的功能已经演示了一遍了。(PS:串口显示有些文字有乱码,所以有些文字没显示出来。)
结论与改进
在本次设计中,我得到一个结论,想要设计一个好的系统,必须在不断的调试与改进中才能发现平时没能发现的问题,而且在写函数的时候,一定要写注释,否则到后面写多了你会发现前面写的函数你都有点忘了写的是什么了,这点我深有体会。通过这次设计,给我的收获很大,也让我成长了很多,懂得了如何自己动手去设计一款系统并且不断改进的过程。我还会不断改进这个系统,加一些能加的模块,比如显示屏和语音模块,来更加完善这个系统。 后续我会不断更新此博客,将自己的想法和改进写进此博客中,供大家学习。
有问题的小伙伴可以私信或加q1743647071,互相学习,互相进步。
STM32与RC522简单公交卡系统的设计相关推荐
- ios开发之公交卡系统的设计与实现
// // main.m // Bus-公交/*公交一卡通充值系统,有两种功能选择,第一种投入硬币或者纸币选择购票,第二种一卡通充值,充值面额是20,50,100*/ #import <Foun ...
- php公交查询系统源代码,基于Smarty公交查询系统的设计与实现(PHP,MySQL)
基于Smarty公交查询系统的设计与实现(,MySQL)(任务书,开题报告,中期报告,毕业论文11000字,程序代码,MySQL数据库,答辩PPT) 本系统主要分为前台页面.后台逻辑及数据库三大部分. ...
- 基于javaweb的公交查询系统的设计与实现(含源文件)
欢迎添加微信互相交流学习哦! 项目源码:https://gitee.com/oklongmm/biye 基于J2EE的公交查询系统的设计与实现 摘 要 公交查询系统是城市道路交通的重要组成部分,是城 ...
- Javaweb城市公交查询系统的设计与实现
Javaweb城市公交查询系统的设计与实现 摘 要 近年来, Internet推动了以互联网技术为核心的各项工作蓬勃展开,互联网的强大也大大的促进了社会的发展,整个社会信息化进程逐步加快,网络也变成了 ...
- (附源码)springboot高校学生健康打卡系统的设计与实现 毕业设计 021009
基于springboot 高校学生健康打卡系统 摘 要 2019年12月19号中国武汉发生第一例新冠病毒的到来,大家都在听从政府的号召在居家隔离,不管是在城市还是在乡镇.农村,这引起我的注目,设计一套 ...
- (附源码)springboot高校学生健康打卡系统的设计与实现 毕业设计021009
基于springboot 高校学生健康打卡系统 摘 要 2019年12月19号中国武汉发生第一例新冠病毒的到来,大家都在听从政府的号召在居家隔离,不管是在城市还是在乡镇.农村,这引起我的注目,设计一套 ...
- 基于Android公交查询系统的设计与实现(论文+程序设计源码+数据库文件)
[摘 要]随着互联网的技术的不断更新发展,人们生活节奏也在不断的加快,对于网络的依赖也越来越紧密,尤其是在等公交,经常会错过班次,但又不知道,下次班次几点发车,这样会导致乘客花掉大把时间在等待,如果可 ...
- B45 - 基于STM32单片机的家庭防火防盗系统的设计
文章目录 设计要求 实物 人脸识别模块的调试 传感器采集与显示 模块设计 温湿度模块 烟雾浓度MQ2 GSM模块 人脸识别模块 语音报警模块 资源占用 源程序 主程序 处理逻辑 AD/DA转换检测烟雾 ...
- MYSQL交通系统查询,城市公交查询系统的设计与实现(SSH,MySQL)(含录像)
城市公交查询系统的设计与实现(SSH,MySQL)(含录像)(开题报告,毕业论文15000字,程序代码,MySQL数据库,答辩PPT) 本文针对公交站的查询实际情况(百度地图),按照软件工程的结构化设 ...
最新文章
- shell脚本_查找无效网址
- 如何快捷输入函数上方的注释代码(Summary)
- Android ImageView(scaleType属性)(转)
- 【代码】synchronized是可重入锁并且多个sync代码块顺序执行
- Hibernate查询缓存
- 前端学习(1760):前端调试值之如何让浏览器阻止请求相关资源
- 利用Nmap对MS-SQLSERVER进行渗透
- mysql数据表最高速迁移,mysql的存储引擎为:myisam
- 数据在数组中存储的顺序:小端 OR 大端模式 详解
- poj 3261 Milk Patterns
- LC.234.Palindrome Linked List
- mysql创建一张日期表_MySQL创建一张日期表
- CAN(FD)收发器选型及替换指南(一)
- 涂鸦蓝牙SDK开发系列教程——4.烧录授权
- 怎么在桌面添加便签小工具,win7桌面便签小工具应该怎么添加
- 大唐凌烟阁开国廿四将
- three.js尝试(一)模拟演唱会效果
- 业务流程优化的三点思考
- CredSSP 加密数据库修正
- redis的几种常见客户端