这几天划水过多
这几天本着学习的态度去看RC522,NFC射频芯片
然后
无奈自己太菜了,只跑了大佬写的例程勉强可以完成读卡操作
不过也没有闲下来(不想划水),就想了想能不能用STM32内置FLASH存储NFC卡的UID信息,断电后也可以存在,这样验证NFC卡的信息也会方便很多。
基本单位换算
1 M B = 1024 K B 1MB=1024KB 1MB=1024KB |
---|
1 K B = 1024 b y t e s 1KB=1024bytes 1KB=1024bytes |
1 b y t e s = 1024 K B 1bytes=1024KB 1bytes=1024KB |
STM32中各种类型变量所占大小
这里我们随便定义几个不同类型的变量,通过debug就可以查看数据大小
数据类型 | 字节大小 |
---|---|
u c h a r uchar uchar | 1 b y t e 1byte 1byte |
c h a r char char | 1 b y t e 1byte 1byte |
u s h o r t ushort ushort | 2 b y t e s 2bytes 2bytes |
s h o r t short short | 2 b y t e s 2bytes 2bytes |
u i n t uint uint | 4 b y t e s 4bytes 4bytes |
i n t int int | 4 b y t e s 4bytes 4bytes |
f l o a t float float | 4 b y t e s 4bytes 4bytes |
d o u b l e double double | 8 b y t e s 8bytes 8bytes |
bit即为存储二进制的最小单位0和1
内置FLASH说明
野火的文档里讲解的已经很清晰了,不多说了,
芯片型号为STM32F407ZGT6
读写内部FLASH
这里需要注意的是:用户代码也存储在内置FLASH内,我们写入数据到FLASH的地址不能与程序代码存储的地址产生冲突。
野火的视频中有讲解
拿扇区 0 0 0来说
地 址 的 长 度 = 0 x 08003 F F F − 0 X 08000000 = 0 X 3 F F F 地址的长度=0x08003FFF-0X08000000=0X3FFF 地址的长度=0x08003FFF−0X08000000=0X3FFF
0 x 3 F F F = ( 0011 ) ( 1111 ) ( 1111 ) ( 1111 ) 0x3FFF=(0011)(1111)(1111)(1111) 0x3FFF=(0011)(1111)(1111)(1111) (二进制)
逢二进一,且 1 b i t 1bit 1bit对应 1 b y t e 1byte 1byte
0 x 3 F F F 0x3FFF 0x3FFF的地址长度内存储了214 = 16384 b y t e s =16384bytes =16384bytes数据
16384 / 1024 = 16 K b y t e s 16384/1024=16Kbytes 16384/1024=16Kbytes
查看.map文件
我们双击
p
r
o
j
e
c
t
project
project下面的文件夹
就会弹出
.
m
a
p
.map
.map文件
可以看出程序的加载地址为:
0
x
08000000
0x0800 0000
0x08000000
大小为:
0
x
3874
0x3874
0x3874
结尾地址:
0
x
08003874
0x0800 3874
0x08003874
可见程序并未超出扇区0的内存。
存储NFC UID数据
通过
d
e
b
u
g
debug
debug可以看出UID得数据类型和大小
一共为
8
b
i
t
∗
4
=
32
b
i
t
=
4
b
y
t
e
s
8bit*4=32bit=4bytes
8bit∗4=32bit=4bytes
我的思路是定义一个 u 8 u8 u8 P A S S [ u s e r ] [ 4 ] PASS[user][4] PASS[user][4]二维数组
一个用户存储 4 4 4个 u 8 u8 u8类型的数据既UID数据
确认身份的时候可以根据已有的 u s e r user user来遍历数组,减少了运算量。
实际运行的时候,还要注意地址的递增,
每写入4个u8数据既 4 b y t e s 4bytes 4bytes, 地址增加 0 x 04 0x04 0x04
对应的 u s e r user user也相应+1,并写入 F L A S H FLASH FLASH
思路如下
读写UID函数
#define SIZE(data) data/4+((data%4)?1:0)//以u32为单位计算个数,例->5个u8型直接当做2个u32型因为数据写入最小大小为u32
char PASS[10][4],UID2[4];
/**
**********************************
* @brief 写入UID数据
* @param
* @retval 只写入PASS中没有的UID
**********************************
*/
void Write_card(void)
{
LCD_ShowString(0,0,"writing mode",DARKBLUE);
LCD_ShowString(0,20,"set card",DARKBLUE);
if(PASS_ID()==0)//读取到卡片&&密码没有存入flash
{
if(user>=10)//容量->10
user=0;
STMFLASH_Write(FLASH_SAVE_ADDR+(0x04*user),(u32*)UID2,SIZE(sizeof(UID2)));//一个用户密码->u32 ->地址+0x04
user++;
FLASH_Write_Byte(USER_ADDR,user); //用户数量存入flash
STMFLASH_Read(FLASH_SAVE_ADDR,(u32*)PASS,sizeof(PASS)); //刷新存储密码的数组
}
}
/**
**********************************
* @brief 读取UID并进行校验
* @param
* @retval
**********************************
*/
void Read_mode(void)
{
LCD_ShowString(0,0,"reading mode",DARKBLUE);
if(READ_CARD())//如果检测到卡片
PASS_ID();
}
然后在初始化里读去数据就可以了
int main(void)
{
delay_init(168); //初始化延时函数
uart_init(9600);
Lcd_Init();
LCD_Clear(WHITE);
BACK_COLOR = WHITE;
LED_Init();
SPI2_Init();
KEY_Init();
STMFLASH_Read(FLASH_SAVE_ADDR,(u32*)PASS,PASS_SIZE);//从flash内读取密码
user=FLASH_Read_Byte(USER_ADDR); //从flash内读取用户数量
while(1)
{
i=KEY_Scan(1);
if(i!=0)
flag=i;
else
i=flag;
//保持按键值
switch(i)
{
case 1:Read_mode();break;//读卡模式
case 2:Write_card();break;//写卡模式
case 4:Erase();break; //清除扇区2 3
}
LCD_ShowNum(0,80,i,1,RED);//显示按键值
}
}
读写数据函数直接使用的正点的程序,由于正点的程序只能写入u32类型
我就自己写了读写u8类型函数
/**
**********************************
* @brief 写入flash内1个字节
* @param addr->写入地址 data->写入数据
* @retval None
**********************************
*/
void FLASH_Write_Byte(u32 addr,u8 data)
{
/*解锁->擦除->写入->上锁*/
FLASH_Unlock();
FLASH_EraseSector(STMFLASH_GetFlashSector(addr),VoltageRange_3);
FLASH_ProgramByte(addr,data);
FLASH_Lock();
}
/**
**********************************
* @brief 从flash读取一个字节
* @param addr->开始读取地址
* @retval None
**********************************
*/
u8 FLASH_Read_Byte(u32 addr)
{
char *p=(char*)addr;
u8 data;
data=*p;
return data;
}
程序比较简单,都是简单的读写
下面是遍历数组校验UID是否为已有用户的程序
u8 PASS_ID(void)
{
u8 i=0,j=0;
for(j=0;j<user;j++)
{
for(i=0;i<=3;i++)
{
if(PASS[j][i]!=UID[i])
break;
}
if(i==4)
break;
}
if(i==4)
{
LCD_ShowString(0,40,"PASS->CARD:",DARKBLUE);
LCD_ShowNum(80,40,j,1,DARKBLUE);
return 1;
}
else
{
LCD_ShowString(0,40,"ERROR",RED);
return 0;
}
}
//==============================================================================
//读取卡的类型
//读取卡的ID号
// 卡片:12AAD52D
// 卡环:EC838322
//==============================================================================
void ReaderCard(void)
{
char temp_value;
if(PcdRequest(PICC_REQALL,Temp)==MI_OK) //选卡
{
if(Temp[0]==0x04&&Temp[1]==0x00)
printf("MFOne-S50");
else if(Temp[0]==0x02&&Temp[1]==0x00)
printf("MFOne-S70");
else if(Temp[0]==0x44&&Temp[1]==0x00)
printf("MF-UltraLight");
else if(Temp[0]==0x08&&Temp[1]==0x00)
printf("MF-Pro");
else if(Temp[0]==0x44&&Temp[1]==0x03)
printf("MF Desire");
else
printf("Unknown");
if(PcdAnticoll(UID)==MI_OK) //防冲撞
{
printf("Card Id is:");
/* 获取卡值 */
Uart1_SendHexDisplay(UID[0]);
Uart1_SendHexDisplay(UID[1]);
Uart1_SendHexDisplay(UID[2]);
Uart1_SendHexDisplay(UID[3]);
printf("\r\n"); //发送换行指令
temp_value = ((UID[0]>>4)*10+(UID[0]&0x0f));
printf("管理员:%d\r\n",temp_value);
// switch(temp_value)
// {
// case 12 : printf("管理员:%d\r\n",temp_value); break;
// case 152: printf("学生 :%d\r\n",temp_value); break;
// default : printf("无效卡:%d\r\n",temp_value); break;
// }
}
}
}
u8 READ_CARD(void)
{
u8 i;
ReaderCard();
for(i=0;i<4;i++)
{
if(UID2[i]!=UID[i])
break;
}
if(i==4)
{
return 0;
}
else
{
data_re();
return 1;
}
}
debug效果
UID数据及用户数量被依次存入FLASH,断电或者复位后数据仍然存在。
上面写的知识一种思路,具体的加密什么也没有搞,更多的是对
F
L
A
S
H
FLASH
FLASH的操作和认知,关于
R
C
522
RC522
RC522还需要更多的去学习。
工程文件
提取码:eqbr