stm32SPI和w25q128

  • SPI

1、 SPI概念

     SPI 是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。SPI 接口主要应用在 EEPROM,FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。

     SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。

2、SPI信号线

 

SCK:时钟线(由主机产生,用于同步数据,一个脉冲传输一位数据),另名:C  SCL  SCLK

CS:使能控制端(主机控制从机),选定哪个从机可以工作

MOSI:Master Output Slave Input,主机输出,从机输入

MISO:Master Input Slave Output,主机输入,从机输出

 

 

SPI工作原理总结

  1. 硬件上为4根线。
  2. 主机和从机都有一个串行移位寄存器,主机通过向它的SPI串行寄存器写入一个字节来发起一次传输。
  3. 串行移位寄存器通过MOSI信号线将字节传送给从机,从机也将自己的串行移位寄存器中的内容通过MISO信号线返回给主机。这样,两个移位寄存器中的内容就被交换。
  4. 外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的一个字节,就必须发送一个空字符(任意字符)节来引发从机的传输。

3、SPI总线四种工作方式

SPI 模块为了和外设模块进行数据交换,根据外设模块工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。

      时序详解:

CPOL:时钟极性选择,为0时SPI总线空闲为低电平(时钟线由低电平开始),为1时SPI总线空闲为高电平(时钟线由高电平开始)

CPHA:时钟相位选择,为0时在SCK第一个跳变沿采样,为1时在SCK第二个跳变沿采样

 

  工作方式0:

  当CPHA=0、CPOL=0时SPI总线工作在方式1。MISO引脚上的数据在第一个SPSCK沿跳变之前已经上线了,而为了保证正确传输,MOSI引脚的MSB位必须与SPSCK的第一个边沿同步,在SPI传输过程中,首先将数据上线,然后在同步时钟信号的上升沿时,SPI的接收方捕捉位信号,在时钟信号的一个周期结束时(下降沿),下一位数据信号上线,再重复上述过程,直到一个字节的8位信号传输结束。

  工作方式1:

  当CPHA=0、CPOL=1时SPI总线工作在方式2。与前者唯一不同之处只是在同步时钟信号的下降沿时捕捉位信号,上升沿时下一位数据上线。

  工作方式2:

当CPHA=1、CPOL=0时SPI总线工作在方式3。MISO引脚和MOSI引脚上的数据的MSB位必须与SPSCK的第一个边沿同步,在SPI传输过程中,在同步时钟信号周期开始时(上升沿)数据上线,然后在同步时钟信号的下降沿时,SPI的接收方捕捉位信号,在时钟信号的一个周期结束时(上升沿),下一位数据信号上线,再重复上述过程,直到一个字节的8位信号传输结束。

工作方式3:

当CPHA=1、CPOL=1时SPI总线工作在方式4。与前者唯一不同之处只是在同步时钟信号的上升沿时捕捉位信号,下降沿时下一位数据上线。

 

 

4、SPI配置步骤流程图

SPI配置需要的库函数文件:stm32f4xx_spi.c

  1. 理解电路原理图

使用SPI1

SCK连接PB3

MISO连接PB4

MOSI连接PB5

CS连接PB14

 

(2)使能SPIx和IO口时钟

    RCC_AHBxPeriphClockCmd() / RCC_APBxPeriphClockCmd();

(3)初始化IO口为复用功能

    void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

(4)设置引脚复用映射:

    GPIO_PinAFConfig();

(5)初始化SPIx,设置SPIx工作模式

    void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);

(6)使能SPIx

    void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);

(7)SPI传输数据

    void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);

    uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx) ;

(8)查看SPI传输状态

   SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE);

  • W25Q128

2.1 W25Q128概念

Flash存储器属,内存器件的一种,是一种非易失性( Non-Volatile )内存。

flash闪存是非易失存储器,可以对称为块的存储器单元块进行擦写和再编程。任何flash器件的写入操作只能在空或已擦除的单元内进行,所以大多数情况下,在进行写入操作之前必须先执行擦除。

W25Q128 将 16M 的容量分为 256 个块(Block),每个块大小为 64K 字节,每个块又分为 16个扇区(Sector),每个扇区 4K 个字节。 W25Q128 的最少擦除单位为一个扇区,也就是每次必须擦除 4K 个字节。操作需要给 W25Q128 开辟一个至少 4K 的缓存区,对 SRAM (运行内存)要求比较高,要求芯片必须有 4K 以上 SRAM 才能很好的操作。 

块>扇区>页

2.2 W25Q128引脚与内部

引脚说明

 

内部

 

2.3 命令操作W25Q128

 

写使能

 

读状寄存器

 

擦除扇区

 

写数据

 

读数据

 

  • 函数说明

void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);

函数说明:SPI总线初始化

返回值:无

SPI_TypeDef* SPIx:哪个SPI外设

typedef struct

{

  uint16_t SPI_Direction;         //选择工作模式

  uint16_t SPI_Mode;            //选择主从机模式

  uint16_t SPI_DataSize;          //数据大小

  uint16_t SPI_CPOL;             //时钟极性

  uint16_t SPI_CPHA;             //时钟相位

  uint16_t SPI_NSS;              //硬件控制CS

  uint16_t SPI_BaudRatePrescaler;  //分频

  uint16_t SPI_FirstBit;            //输出高位还是低位

  uint16_t SPI_CRCPolynomial;     //CRC校验

}SPI_InitTypeDef;

SPI

#include "spi.h"

/*************************************
引脚说明
SCK连接PB3
MISO连接PB4
MOSI连接PB5
CS连接PB14
*************************************/
#if 1

void SPI1_Init(void)
{
	GPIO_InitTypeDef  	GPIO_InitStruct;
	SPI_InitTypeDef		SPI_InitStruct;
	//(2)使能SPIx和IO口时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
	

	
	//GPIO 初始化设置:要设置模式为复用功能。
	GPIO_InitStruct.GPIO_Pin	= GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;		//引脚3 4 5 
	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_AF;		//复用模式
	GPIO_InitStruct.GPIO_OType	= GPIO_OType_PP;	//推挽式
	GPIO_InitStruct.GPIO_PuPd	= GPIO_PuPd_UP;		//上拉
	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_50MHz;	//50MHZ
	GPIO_Init(GPIOB,&GPIO_InitStruct);	
	
	
	GPIO_InitStruct.GPIO_Pin	= GPIO_Pin_14;		//引脚14
	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_OUT;	//输出模式
	GPIO_InitStruct.GPIO_OType	= GPIO_OType_PP;	//推挽式输出
	GPIO_InitStruct.GPIO_PuPd	= GPIO_PuPd_UP;		//上拉
	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_50MHz;	//50MHZ
	GPIO_Init(GPIOB,&GPIO_InitStruct);	
	
	
	//(4)设置引脚复用映射:
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI1); //SCK
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_SPI1);	//MISO
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI1); //MOSI
	
	
	
	SPI_InitStruct.SPI_Direction		= SPI_Direction_2Lines_FullDuplex;	//全双工
	SPI_InitStruct.SPI_Mode				= SPI_Mode_Master;					//主机
	SPI_InitStruct.SPI_DataSize			= SPI_DataSize_8b;					//数据位8位
	SPI_InitStruct.SPI_CPHA				= SPI_CPHA_1Edge;					//时钟相位 第一边沿
	SPI_InitStruct.SPI_CPOL				= SPI_CPOL_Low;						//时钟极性 低电平
	SPI_InitStruct.SPI_FirstBit			= SPI_FirstBit_MSB;					//先发高位
	SPI_InitStruct.SPI_NSS				= SPI_NSS_Soft;						//CS端由软件控制
	SPI_InitStruct.SPI_BaudRatePrescaler= SPI_BaudRatePrescaler_16;			//分频
	SPI_InitStruct.SPI_CRCPolynomial	= 7;								//CRC校验
	//(5)初始化SPIx,设置SPIx工作模式
	SPI_Init(SPI1, &SPI_InitStruct);
	//(6)使能SPIx
	SPI_Cmd(SPI1, ENABLE);
	
	
	//不使能芯片
	F_CS = 1;

}

//SPI收发数据
u8 Spi1_Recv_Send_Byte(u8 tx_tata)
{
	u8 rx_data = 0x00;

	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
	SPI_I2S_SendData(SPI1, tx_tata);
	

	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    rx_data = SPI_I2S_ReceiveData(SPI1);

	
	return rx_data;
}

#else

void SPI1_Init(void)
{

	GPIO_InitTypeDef GPIO_InitStruct;

	//1、使能SPIx和IO口时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);

	
	GPIO_InitStruct.GPIO_Pin 	= GPIO_Pin_3 | GPIO_Pin_14|GPIO_Pin_5; 	//GPIOB 3 14 5
	GPIO_InitStruct.GPIO_Mode 	= GPIO_Mode_OUT;						//配置IO口输出
	GPIO_InitStruct.GPIO_Speed 	= GPIO_Speed_50MHz; 					//速度 50MHz
	GPIO_InitStruct.GPIO_OType 	= GPIO_OType_PP; 						//推挽复用输出
	GPIO_InitStruct.GPIO_PuPd 	= GPIO_PuPd_UP; 						//上拉
    GPIO_Init(GPIOB,&GPIO_InitStruct);
	
	
	GPIO_InitStruct.GPIO_Pin  	= GPIO_Pin_4; 			//引脚4
	GPIO_InitStruct.GPIO_Mode 	= GPIO_Mode_IN;			//输入
	GPIO_InitStruct.GPIO_PuPd 	= GPIO_PuPd_UP; 		//上拉
    GPIO_Init(GPIOB,&GPIO_InitStruct);		

	//不使能芯片
	F_CS = 1;

}

//SPI收发数据
u8 Spi1_Recv_Send_Byte(u8 tx_tata)
{
	u8 i = 0;
	u8 rx_data = 0x00;

	
	SCK  = 0;
	for(i=0; i<8; i++)
	{
		
		//准备发送的数据
		if(tx_tata & (0x01<<(7-i)))
		{
			MOSI = 1;
		}
		else
		{
			MOSI = 0;
		}
		
		delay_us(2);
		SCK  = 1;
		delay_us(2);
		//接受数据
		if(MISO == 1)
		{
			rx_data |= (0x01<<(7-i));
		}
		
		
		SCK  = 0;	
	}
	


	
	return rx_data;
}


#endif





//获取芯片生产商/设备ID
u16 W25q128_Id(void)
{
	u16 id = 0x00;
	

	//使能芯片
	F_CS = 0;
	
	//发送命令
	Spi1_Recv_Send_Byte(0x90);
	
	//发送地址
	Spi1_Recv_Send_Byte(0x00);
	Spi1_Recv_Send_Byte(0x00);
	Spi1_Recv_Send_Byte(0x00);
	
	
	//发送任意字符
	id |= Spi1_Recv_Send_Byte(0xFF)<<8;
	id |= Spi1_Recv_Send_Byte(0xFF);
	
	
	//不使能芯片
	F_CS = 1;

	return id;
}


void Write_Enable(void)
{
	//使能芯片
	F_CS = 0;
	
	//发送命令
	Spi1_Recv_Send_Byte(0x06);	
	
	//不使能芯片
	F_CS = 1;

}

u8 W25q128_status1(void)
{
	u8 status1 = 0;
	

	//使能芯片
	F_CS = 0;
	
	//发送命令
	Spi1_Recv_Send_Byte(0x05);	
	
	//发送任意字符,获取状态寄存器1的值
	status1 = Spi1_Recv_Send_Byte(0xFF);
	
	
	//不使能芯片
	F_CS = 1;

	return status1;
}

void W25q128_Sector_Erase(u32 addr)
{
	//写使能
	Write_Enable();
	
	F_CS = 0;
	
	//发送擦除命令
	Spi1_Recv_Send_Byte(0x20);
		
	//拆分地址,并发送
	Spi1_Recv_Send_Byte((addr>>16)&0xFF); 	//发送16至23位地址
	Spi1_Recv_Send_Byte((addr>>8)&0xFF); 	//发送8至15位地址
	Spi1_Recv_Send_Byte((addr)&0xFF); 		//发送0至7位地址

	F_CS = 1;	
	
	//查看是否擦除完成
	while(1)
	{
		if((W25q128_status1() & 0x01) == 0x00)
		{
			break;
		}
	
	}

}


void W25Q128_Writer_data(u32 addr,u8 *buf, u32 len)
{
	//写使能
	Write_Enable();
	
	F_CS = 0;
	
	//发送写页命令
	Spi1_Recv_Send_Byte(0x02);
		
	//拆分地址,并发送
	Spi1_Recv_Send_Byte((addr>>16)&0xFF); 	//发送16至23位地址
	Spi1_Recv_Send_Byte((addr>>8)&0xFF); 	//发送8至15位地址
	Spi1_Recv_Send_Byte((addr)&0xFF); 		//发送0至7位地址

	//发送数据
	while(len--)
	{
		Spi1_Recv_Send_Byte(*buf);
		buf++;
	}
	
	F_CS = 1;
	
	//查看是否擦除完成
	while(1)
	{
		if((W25q128_status1() & 0x01) == 0x00)
		{
			break;
		}
	
	}
	
}


void W25Q128_Read_data(u32 addr,u8 *buf, u32 len)
{
	F_CS = 0;

	//发送读数据命令
	Spi1_Recv_Send_Byte(0x03);
		
	//拆分地址,并发送
	Spi1_Recv_Send_Byte((addr>>16)&0xFF); 	//发送16至23位地址
	Spi1_Recv_Send_Byte((addr>>8)&0xFF); 	//发送8至15位地址
	Spi1_Recv_Send_Byte((addr)&0xFF); 		//发送0至7位地址

	//读取数据
	while(len--)
	{
		*buf = Spi1_Recv_Send_Byte(0xFF);
		buf++;
	}
	
	F_CS = 1;
}
#ifndef __SPI_H
#define __SPI_H

#include "stm32f4xx.h"
#include "sys.h"
#include "delay.h"

#define F_CS   PBout(14)
#define SCK     PBout(3)
#define MISO    PBin(4)
#define MOSI    PBout(5)

void SPI1_Init(void);
u16 W25q128_Id(void);
void W25q128_Sector_Erase(u32 addr);
void W25Q128_Writer_data(u32 addr,u8 *buf, u32 len);
void W25Q128_Read_data(u32 addr,u8 *buf, u32 len);

#endif
#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "tim.h"
#include "pwm.h"
#include "usart.h"
#include "sys.h"
#include "dht11.h"
#include "infrared.h"
#include "iwdg.h"
#include "iic.h"
#include "adc.h"
#include "spi.h"

u8  buffer[64] = {0};
u8  rx_buffer[64] = {0};
u8  count = 0, rx_i = 0;
u8  rx_flag = 0; //接受标志位,rx_flag = 表示数据帧完毕


void USART1_IRQHandler(void)
{
	


	//判断接收标志位是否为1
	if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		//清空接受标志位
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);	
		//接受数据 
		buffer[count++] = USART_ReceiveData(USART1);
		//判断数据是否为':',如果是':'数据帧结束
		if(buffer[count-1] == ':')
		{
			//数据赋值到rx_buffer,并过滤帧尾
			for(rx_i=0; rx_i<(count-1); rx_i++)
			{
				rx_buffer[rx_i] = buffer[rx_i];
			}
		
			//清空数组
			memset(buffer, 0, sizeof(buffer));
			
			//标志位置1
			rx_flag = 1;
			//下一帧数据从buffer[0]开始接受
			count = 0; 
					
		
		}
		
	}
}




void USART2_IRQHandler(void)
{
	
	u8 data;

	//判断接收标志位是否为1
	if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
	{
		//清空接受标志位
		USART_ClearITPendingBit(USART2, USART_IT_RXNE);	
		//接受数据 
		buffer[count++] = USART_ReceiveData(USART2);
		//判断数据是否为':',如果是':'数据帧结束
		if(buffer[count-1] == ':')
		{
			//数据赋值到rx_buffer,并过滤帧尾
			for(rx_i=0; rx_i<(count-1); rx_i++)
			{
				rx_buffer[rx_i] = buffer[rx_i];
			}
		
			//清空数组
			memset(buffer, 0, sizeof(buffer));
			
			//标志位置1
			rx_flag = 1;
			//下一帧数据从buffer[0]开始接受
			count = 0; 
					
		}
		
	}


}


void USART3_IRQHandler(void)
{
	
	u8 data;

	//判断接收标志位是否为1
	if(USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
	{
		//清空接受标志位
		USART_ClearITPendingBit(USART3, USART_IT_RXNE);	
		//接受数据 
		buffer[count++] = USART_ReceiveData(USART3);
		//判断数据是否为':',如果是':'数据帧结束
		if(buffer[count-1] == ':')
		{
			//数据赋值到rx_buffer,并过滤帧尾
			for(rx_i=0; rx_i<(count-1); rx_i++)
			{
				rx_buffer[rx_i] = buffer[rx_i];
			}
		
			//清空数组
			memset(buffer, 0, sizeof(buffer));
			
			//标志位置1
			rx_flag = 1;
			//下一帧数据从buffer[0]开始接受
			count = 0; 
					
		}
		
	}


}




int main(void)
{
	u8 write_buff[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	u8 read_buff[27];
	u16 	id;
	
	//设置NVIC分组(一个工程只能设置一个分组) 
	//第二分组;抢占优先组取值范围:0~3 响应先组取值范围:0~3
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	Led_Init();
	Delay_Init();
	Usart1_Init(115200);
	SPI1_Init();
	
	//id = W25q128_Id();
	//printf("id:%#X\r\n", id);
	//擦除第1块0扇区
	W25q128_Sector_Erase(0x010000);
	W25Q128_Writer_data(0x010000,write_buff, 26);
	delay_ms(10);
	W25Q128_Read_data(0x010000,read_buff, 26);	
	printf("read_buff:%s\r\n", read_buff);
	
	while(1)
	{
		

		delay_s(1);


	}
}

RFID

//
#include "MFRC522.h"
//test
u8  irq_regdata;
u16 wait_count;
u8  error_regdata;
u8  last_bitsdata;

//SPI3初始化
void STM32_SPI3_Init(void) 
{ 

	GPIO_InitTypeDef GPIO_InitStruct;

	//1、使能SPIx和IO口时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);

	
	GPIO_InitStruct.GPIO_Pin 	= GPIO_Pin_0| GPIO_Pin_14| GPIO_Pin_9; 	//GPIOD 0 14 9
	GPIO_InitStruct.GPIO_Mode 	= GPIO_Mode_OUT;						//配置IO口输出
	GPIO_InitStruct.GPIO_Speed 	= GPIO_Speed_50MHz; 					//速度 50MHz
	GPIO_InitStruct.GPIO_OType 	= GPIO_OType_PP; 						//推挽复用输出
	GPIO_InitStruct.GPIO_PuPd 	= GPIO_PuPd_UP; 						//上拉
    GPIO_Init(GPIOD,&GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Pin 	= GPIO_Pin_7| GPIO_Pin_13| GPIO_Pin_15;
	GPIO_Init(GPIOE,&GPIO_InitStruct);
	
	
	GPIO_InitStruct.GPIO_Pin  	= GPIO_Pin_9; 			//引脚9
	GPIO_InitStruct.GPIO_Mode 	= GPIO_Mode_IN;			//输入
	GPIO_InitStruct.GPIO_PuPd 	= GPIO_PuPd_UP; 		//上拉
  GPIO_Init(GPIOE,&GPIO_InitStruct);	
	
	
	
	GND = 0;
	VCC = 1;	

}
//
void SPI3_Send(u8 val)  
{ 

	u8 i = 0;


	SCK  = 0;
	for(i=0; i<8; i++)
	{
		
		//准备发送的数据
		if(val & (0x01<<(7-i)))
		{
			MOSI = 1;
		}
		else
		{
			MOSI = 0;
		}
		
		delay_us(2);
		SCK  = 1;
		delay_us(2);

		SCK  = 0;	
	}
	
	
	
}
//
u8 SPI3_Receive(void)  
{ 
	u8 temp = 0x00; 

	u8 i = 0;

	
	SCK  = 0;
	for(i=0; i<8; i++)
	{
		
		//输出引脚电平为0
		MOSI = 0;
		
		
		delay_us(2);
		SCK  = 1;
		delay_us(2);
		//接受数据
		if(MISO == 1)
		{
			temp |= (0x01<<(7-i));
		}
		
		
		SCK  = 0;	
	}
	
	
	
	
  return temp; 
}
//功能描述向MFRC522的某一寄存器写一个字节数据
//输入参数addr--寄存器地址val--要写入的值
void Write_MFRC522(u8 addr, u8 val) 
{
	//地址格式0XXXXXX0  
	MFRC522_CS(0);   
	SPI3_Send((addr<<1)&0x7E);  
	SPI3_Send(val);    
	MFRC522_CS(1); 
}
//功能描述从MFRC522的某一寄存器读一个字节数据
//输入参数addr--寄存器地址
//返 回 值返回读取到的一个字节数据 
u8 Read_MFRC522(u8 addr) 
{  
	u8 val;
	//地址格式1XXXXXX0   
	MFRC522_CS(0);     
	SPI3_Send(((addr<<1)&0x7E)|0x80);   
	val=SPI3_Receive();    
	MFRC522_CS(1); 
	//   
	return val;  
}
//下面两个函数只对能读写位有效
//功能描述置RC522寄存器位
//输入参数reg--寄存器地址;mask--置位值
void SetBitMask(u8 reg, u8 mask)   
{     
	u8 tmp=0;
	//     
	tmp=Read_MFRC522(reg);     
	Write_MFRC522(reg,tmp|mask);  // set bit mask 
}
//功能描述清RC522寄存器位
//输入参数reg--寄存器地址;mask--清位值
void ClearBitMask(u8 reg, u8 mask)   
{     
	u8 tmp=0;
	//     
	tmp=Read_MFRC522(reg);     
	Write_MFRC522(reg,tmp&(~mask));  //clear bit mask 
}
//功能描述开启天线,每次启动或关闭天线发射之间应至少有1ms的间隔
void AntennaOn(void) 
{  
	u8 temp;
	//   
	temp=Read_MFRC522(TxControlReg);  
	if ((temp&0x03)==0)  
	{   
		SetBitMask(TxControlReg,0x03);  
	}
}
//功能描述关闭天线,每次启动或关闭天线发射之间应至少有1ms的间隔
void AntennaOff(void) 
{  
	ClearBitMask(TxControlReg,0x03);
}
//功能描述复位MFRC522
void MFRC522_Reset(void) 
{ 
	//外复位可以不用
	MFRC522_Rst(1);
	delay_us(1);
	MFRC522_Rst(0);
	delay_us(1);
	MFRC522_Rst(1);
	delay_us(1); 
	//内复位   
	Write_MFRC522(CommandReg, PCD_RESETPHASE); 
}
//
void MFRC522_Initializtion(void) 
{
	STM32_SPI3_Init();  
	MFRC522_Reset();         
	//Timer: TPrescaler*TreloadVal/6.78MHz = 0xD3E*0x32/6.78=25ms     
	Write_MFRC522(TModeReg,0x8D);				//TAuto=1为自动计数模式,受通信协议影向。低4位为预分频值的高4位
	//Write_MFRC522(TModeReg,0x1D);				//TAutoRestart=1为自动重载计时,0x0D3E是0.5ms的定时初值//test    
	Write_MFRC522(TPrescalerReg,0x3E); 	//预分频值的低8位     
	Write_MFRC522(TReloadRegL,0x32);		//计数器的低8位                
	Write_MFRC522(TReloadRegH,0x00);		//计数器的高8位       
	Write_MFRC522(TxAutoReg,0x40); 			//100%ASK     
	Write_MFRC522(ModeReg,0x3D); 				//CRC初始值0x6363
	Write_MFRC522(CommandReg,0x00);			//启动MFRC522  
	//Write_MFRC522(RFCfgReg, 0x7F);    //RxGain = 48dB调节卡感应距离      
	AntennaOn();          							//打开天线 
}
//功能描述RC522和ISO14443卡通讯
//输入参数command--MF522命令字
//					sendData--通过RC522发送到卡片的数据
//					sendLen--发送的数据长度
//					BackData--接收到的卡片返回数据
//					BackLen--返回数据的位长度
//返 回 值成功返回MI_O
u8 MFRC522_ToCard(u8 command, u8 *sendData, u8 sendLen, u8 *backData, u16 *backLen) 
{
	u8  status=MI_ERR;
	u8  irqEn=0x00;
	u8  waitIRq=0x00;
	u8  lastBits;
	u8  n;
	u16 i;
	//根据命预设中断参数
	switch (command)     
	{         
		case PCD_AUTHENT:  		//认证卡密   
			irqEn 	= 0x12;			//    
			waitIRq = 0x10;			//    
			break;
		case PCD_TRANSCEIVE: 	//发送FIFO中数据      
			irqEn 	= 0x77;			//    
			waitIRq = 0x30;			//    
			break;      
		default:    
			break;     
	}
	//
	Write_MFRC522(ComIEnReg, irqEn|0x80);		//允许中断请求     
	ClearBitMask(ComIrqReg, 0x80);  				//清除所有中断请求位               	
	SetBitMask(FIFOLevelReg, 0x80);  				//FlushBuffer=1, FIFO初始化
	Write_MFRC522(CommandReg, PCD_IDLE); 		//使MFRC522空闲   
	//向FIFO中写入数据     
	for (i=0; i<sendLen; i++)
		Write_MFRC522(FIFODataReg, sendData[i]);
	//执行命令
	Write_MFRC522(CommandReg, command);
	//天线发送数据     
	if (command == PCD_TRANSCEIVE)					//如果是卡片通信命令,MFRC522开始向天线发送数据      
		SetBitMask(BitFramingReg, 0x80);  		//StartSend=1,transmission of data starts      
	//等待接收数据完成     
	i = 10000; //i根据时钟频率调整操作M1卡最大等待时间25ms     
	do      
	{        
		n = Read_MFRC522(ComIrqReg);
		//irq_regdata=n;	//test         
		i--;
		//wait_count=i;		//test		     
	}while ((i!=0) && !(n&0x01) && !(n&waitIRq));	//接收完就退出n=0x64
	//停止发送
	ClearBitMask(BitFramingReg, 0x80);   		//StartSend=0
	//如果在25ms内读到卡
	if (i != 0)     
	{            
		if(!(Read_MFRC522(ErrorReg) & 0x1B)) //BufferOvfl Collerr CRCErr ProtecolErr         
		{            
			if (n & irqEn & 0x01)			//                  
				status = MI_NOTAGERR;		//
			//
			if (command == PCD_TRANSCEIVE)             
			{                 
				n = Read_MFRC522(FIFOLevelReg);		//n=0x02                
				lastBits = Read_MFRC522(ControlReg) & 0x07;	//lastBits=0               
				if (lastBits!=0)                         
					*backLen = (n-1)*8 + lastBits; 
				else
					*backLen = n*8;									//backLen=0x10=16
				//
				if (n == 0)                         
				 	n = 1;                        
				if (n > MAX_LEN)         
				 	n = MAX_LEN;
				//
				for (i=0; i<n; i++)                 
					backData[i] = Read_MFRC522(FIFODataReg); 
			}
			//
			status = MI_OK;		
		}
		else
			status = MI_ERR;
	}	
	//
	Write_MFRC522(ControlReg,0x80);				//timer stops     
	Write_MFRC522(CommandReg, PCD_IDLE);	//
	//
	return status;
}
//功能描述寻卡读取卡类型号
//输入参数reqMode--寻卡方式
//					TagType--返回卡片类型
//					0x4400 = Mifare_UltraLight
//					0x0400 = Mifare_One(S50)
//					0x0200 = Mifare_One(S70)
//					0x0800 = Mifare_Pro(X)
//					0x4403 = Mifare_DESFire
//返 回 值成功返回MI_OK	
u8 MFRC522_Request(u8 reqMode, u8 *TagType)
{  
	u8  status;    
	u16 backBits;   //接收到的数据位数
	//   
	Write_MFRC522(BitFramingReg, 0x07);  //TxLastBists = BitFramingReg[2..0]   
	TagType[0] = reqMode;  
	status = MFRC522_ToCard(PCD_TRANSCEIVE, TagType, 1, TagType, &backBits); 
	// 
	if ((status != MI_OK) || (backBits != 0x10))  
	{       
		status = MI_ERR;
	}
	//  
	return status; 
}
//功能描述防冲突检测读取选中卡片的卡序列号
//输入参数serNum--返回4字节卡序列号,第5字节为校验字节
//返 回 值成功返回MI_OK
u8 MFRC522_Anticoll(u8 *serNum) 
{     
	u8  status;     
	u8  i;     
	u8  serNumCheck=0;     
	u16 unLen;
	//           
	ClearBitMask(Status2Reg, 0x08);  			//TempSensclear     
	ClearBitMask(CollReg,0x80);   				//ValuesAfterColl  
	Write_MFRC522(BitFramingReg, 0x00);  	//TxLastBists = BitFramingReg[2..0]
	serNum[0] = PICC_ANTICOLL1;     
	serNum[1] = 0x20;     
	status = MFRC522_ToCard(PCD_TRANSCEIVE, serNum, 2, serNum, &unLen);
	//      
	if (status == MI_OK)
	{   
		//校验卡序列号   
		for(i=0;i<4;i++)   
			serNumCheck^=serNum[i];
		//
		if(serNumCheck!=serNum[i])        
			status=MI_ERR;
	}
	SetBitMask(CollReg,0x80);  //ValuesAfterColl=1
	//      
	return status;
}
//功能描述用MF522计算CRC
//输入参数pIndata--要读数CRC的数据len--数据长度pOutData--计算的CRC结果
void CalulateCRC(u8 *pIndata, u8 len, u8 *pOutData) 
{     
	u16 i;
	u8  n;
	//      
	ClearBitMask(DivIrqReg, 0x04);   			//CRCIrq = 0     
	SetBitMask(FIFOLevelReg, 0x80);   		//清FIFO指针     
	Write_MFRC522(CommandReg, PCD_IDLE);   
	//向FIFO中写入数据      
	for (i=0; i<len; i++)
		Write_MFRC522(FIFODataReg, *(pIndata+i));
	//开始RCR计算
	Write_MFRC522(CommandReg, PCD_CALCCRC);
	//等待CRC计算完成     
	i = 1000;     
	do      
	{         
		n = Read_MFRC522(DivIrqReg);         
		i--;     
	}while ((i!=0) && !(n&0x04));   //CRCIrq = 1
	//读取CRC计算结果     
	pOutData[0] = Read_MFRC522(CRCResultRegL);     
	pOutData[1] = Read_MFRC522(CRCResultRegH);
	Write_MFRC522(CommandReg, PCD_IDLE);
}
//功能描述选卡读取卡存储器容量
//输入参数serNum--传入卡序列号
//返 回 值成功返回卡容量
u8 MFRC522_SelectTag(u8 *serNum) 
{     
	u8  i;     
	u8  status;     
	u8  size;     
	u16 recvBits;     
	u8  buffer[9];
	//     
	buffer[0] = PICC_ANTICOLL1;	//防撞码1     
	buffer[1] = 0x70;
	buffer[6] = 0x00;						     
	for (i=0; i<4; i++)					
	{
		buffer[i+2] = *(serNum+i);	//buffer[2]-buffer[5]为卡序列号
		buffer[6]  ^=	*(serNum+i);	//卡校验码
	}
	//
	CalulateCRC(buffer, 7, &buffer[7]);	//buffer[7]-buffer[8]为RCR校验码
	ClearBitMask(Status2Reg,0x08);
	status = MFRC522_ToCard(PCD_TRANSCEIVE, buffer, 9, buffer, &recvBits);
	//
	if ((status == MI_OK) && (recvBits == 0x18))    
		size = buffer[0];     
	else    
		size = 0;
	//	     
	return size; 
}
//功能描述验证卡片密码
//输入参数authMode--密码验证模式
//					0x60 = 验证A密钥
//					0x61 = 验证B密钥
//					BlockAddr--块地址
//					Sectorkey--扇区密码
//					serNum--卡片序列号4字节
//返 回 值成功返回MI_OK
u8 MFRC522_Auth(u8 authMode, u8 BlockAddr, u8 *Sectorkey, u8 *serNum) 
{     
	u8  status;     
	u16 recvBits;     
	u8  i;  
	u8  buff[12];    
	//验证模式+块地址+扇区密码+卡序列号     
	buff[0] = authMode;		//验证模式     
	buff[1] = BlockAddr;	//块地址     
	for (i=0; i<6; i++)
		buff[i+2] = *(Sectorkey+i);	//扇区密码
	//
	for (i=0; i<4; i++)
		buff[i+8] = *(serNum+i);		//卡序列号
	//
	status = MFRC522_ToCard(PCD_AUTHENT, buff, 12, buff, &recvBits);
	//      
	if ((status != MI_OK) || (!(Read_MFRC522(Status2Reg) & 0x08)))
		status = MI_ERR;
	//
	return status;
}
//功能描述读块数据
//输入参数blockAddr--块地址;recvData--读出的块数据
//返 回 值成功返回MI_OK
u8 MFRC522_Read(u8 blockAddr, u8 *recvData) 
{     
	u8  status;     
	u16 unLen;
	//      
	recvData[0] = PICC_READ;     
	recvData[1] = blockAddr;     
	CalulateCRC(recvData,2, &recvData[2]);     
	status = MFRC522_ToCard(PCD_TRANSCEIVE, recvData, 4, recvData, &unLen);
	//
	if ((status != MI_OK) || (unLen != 0x90))
		status = MI_ERR;
	//
	return status;
}
//功能描述写块数据
//输入参数blockAddr--块地址;writeData--向块写16字节数据
//返 回 值成功返回MI_OK
u8 MFRC522_Write(u8 blockAddr, u8 *writeData) 
{     
	u8  status;     
	u16 recvBits;     
	u8  i;  
	u8  buff[18];
	//           
	buff[0] = PICC_WRITE;     
	buff[1] = blockAddr;     
	CalulateCRC(buff, 2, &buff[2]);     
	status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 4, buff, &recvBits);
	//
	if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A))
		status = MI_ERR;
	//
	if (status == MI_OK)     
	{         
		for (i=0; i<16; i++)  //向FIFO写16Byte数据                     
			buff[i] = *(writeData+i);
		//                     
		CalulateCRC(buff, 16, &buff[16]);         
		status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 18, buff, &recvBits);           
		if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A))               
			status = MI_ERR;         
	}          
	return status;
}
//功能描述命令卡片进入休眠状态
void MFRC522_Halt(void) 
{    
	u16 unLen;     
	u8  buff[4];
	//       
	buff[0] = PICC_HALT;     
	buff[1] = 0;     
	CalulateCRC(buff, 2, &buff[2]);       
	MFRC522_ToCard(PCD_TRANSCEIVE, buff, 4, buff,&unLen);
}
//
//
#ifndef _MFRC522_H_
#define _MFRC522_H_

#include "stm32f4xx.h"
#include "delay.h"
#include "sys.h"

#define SCK     PDout(0)
#define MISO    PEin(9)
#define MOSI    PEout(7)
#define GND    	PEout(13)
#define VCC    	PDout(9)



//定义MFRC522的CS引脚操作,x=1时CS=1,x=0时CS=0
#define MFRC522_CS(x) 	x ? GPIO_SetBits(GPIOD,GPIO_Pin_14):GPIO_ResetBits(GPIOD,GPIO_Pin_14)
#define MFRC522_Rst(x) 	x ? GPIO_SetBits(GPIOE,GPIO_Pin_15):GPIO_ResetBits(GPIOE,GPIO_Pin_15)
/
//MF522命令字
/
#define PCD_IDLE              0x00               //取消当前命令
#define PCD_AUTHENT           0x0E               //验证密钥
#define PCD_RECEIVE           0x08               //接收数据
#define PCD_TRANSMIT          0x04               //发送数据
#define PCD_TRANSCEIVE        0x0C               //发送并接收数据
#define PCD_RESETPHASE        0x0F               //复位
#define PCD_CALCCRC           0x03               //CRC计算

/
//Mifare_One卡片命令字
/
#define PICC_REQIDL           0x26               //寻天线区内未进入休眠状态
#define PICC_REQALL           0x52               //寻天线区内全部卡
#define PICC_ANTICOLL1        0x93               //防冲撞
#define PICC_ANTICOLL2        0x95               //防冲撞
#define PICC_AUTHENT1A        0x60               //验证A密钥
#define PICC_AUTHENT1B        0x61               //验证B密钥
#define PICC_READ             0x30               //读块
#define PICC_WRITE            0xA0               //写块
#define PICC_DECREMENT        0xC0               //扣款
#define PICC_INCREMENT        0xC1               //充值
#define PICC_RESTORE          0xC2               //调块数据到缓冲区
#define PICC_TRANSFER         0xB0               //保存缓冲区中数据
#define PICC_HALT             0x50               //休眠

/
//MF522 FIFO长度定义
/
#define DEF_FIFO_LENGTH       64                 //FIFO size=64byte

/
//MF522寄存器定义
/
// PAGE 0
#define     RFU00                 0x00    
#define     CommandReg            0x01    
#define     ComIEnReg             0x02    
#define     DivlEnReg             0x03    
#define     ComIrqReg             0x04    
#define     DivIrqReg             0x05
#define     ErrorReg              0x06    
#define     Status1Reg            0x07    
#define     Status2Reg            0x08    
#define     FIFODataReg           0x09
#define     FIFOLevelReg          0x0A
#define     WaterLevelReg         0x0B
#define     ControlReg            0x0C
#define     BitFramingReg         0x0D
#define     CollReg               0x0E
#define     RFU0F                 0x0F
// PAGE 1     
#define     RFU10                 0x10
#define     ModeReg               0x11
#define     TxModeReg             0x12
#define     RxModeReg             0x13
#define     TxControlReg          0x14
#define     TxAutoReg             0x15
#define     TxSelReg              0x16
#define     RxSelReg              0x17
#define     RxThresholdReg        0x18
#define     DemodReg              0x19
#define     RFU1A                 0x1A
#define     RFU1B                 0x1B
#define     RFU1C             		0x1C
#define     RFU1D                 0x1D
#define     RFU1E                 0x1E
#define     SerialSpeedReg        0x1F
// PAGE 2    
#define     RFU20                 0x20  
#define     CRCResultRegH         0x21
#define     CRCResultRegL         0x22
#define     RFU23                 0x23
#define     ModWidthReg           0x24
#define     RFU25                 0x25
#define     RFCfgReg              0x26
#define     GsNReg                0x27
#define     CWGsCfgReg            0x28
#define     ModGsCfgReg           0x29
#define     TModeReg              0x2A
#define     TPrescalerReg         0x2B
#define     TReloadRegH           0x2C
#define     TReloadRegL           0x2D
#define     TCounterValueRegH     0x2E
#define     TCounterValueRegL     0x2F
// PAGE 3      
#define     RFU30                 0x30
#define     TestSel1Reg           0x31
#define     TestSel2Reg           0x32
#define     TestPinEnReg          0x33
#define     TestPinValueReg       0x34
#define     TestBusReg            0x35
#define     AutoTestReg           0x36
#define     VersionReg            0x37
#define     AnalogTestReg         0x38
#define     TestDAC1Reg           0x39  
#define     TestDAC2Reg           0x3A   
#define     TestADCReg            0x3B   
#define     RFU3C                 0x3C   
#define     RFU3D                 0x3D   
#define     RFU3E                 0x3E   
#define     RFU3F		  						0x3F

/
//和MF522通讯时返回的错误代码
/
#define MI_OK                     0
#define MI_NOTAGERR               1
#define MI_ERR                    2
//
#define MAX_LEN										18
//MFRC522 test
extern u8  irq_regdata;
extern u16 wait_count;
extern u8  error_regdata;
extern u8  last_bitsdata;
//
void Delay1_us(vu16 count);
void STM32_SPI2_Init(void);
void STM32_SPI3_Init(void);
void SPI2_Send(u8 val);
u8 SPI2_Receive(void);
void SPI3_Send(u8 val);
u8 SPI3_Receive(void);
void MFRC522_Initializtion(void);
void Write_MFRC522(u8 addr, u8 val);
u8 Read_MFRC522(u8 addr);
void SetBitMask(u8 reg, u8 mask);
void ClearBitMask(u8 reg, u8 mask);
void AntennaOn(void);
void AntennaOff(void);
void MFRC522_Reset(void);
void MFRC522_Init(void);
u8 MFRC522_ToCard(u8 command, u8 *sendData, u8 sendLen, u8 *backData, u16 *backLen);
u8 MFRC522_Request(u8 reqMode, u8 *TagType);
u8 MFRC522_Anticoll(u8 *serNum);
void CalulateCRC(u8 *pIndata, u8 len, u8 *pOutData);
u8 MFRC522_SelectTag(u8 *serNum);
u8 MFRC522_Auth(u8 authMode, u8 BlockAddr, u8 *Sectorkey, u8 *serNum);
u8 MFRC522_Read(u8 blockAddr, u8 *recvData);
u8 MFRC522_Write(u8 blockAddr, u8 *writeData);
void MFRC522_Halt(void); 
//
#endif
#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "tim.h"
#include "pwm.h"
#include "usart.h"
#include "sys.h"
#include "dht11.h"
#include "infrared.h"
#include "iwdg.h"
#include "iic.h"
#include "adc.h"
#include "spi.h"
#include "MFRC522.h"



u8  buffer[64] = {0};
u8  rx_buffer[64] = {0};
u8  count = 0, rx_i = 0;
u8  rx_flag = 0; //接受标志位,rx_flag = 表示数据帧完毕


void USART1_IRQHandler(void)
{
	


	//判断接收标志位是否为1
	if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		//清空接受标志位
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);	
		//接受数据 
		buffer[count++] = USART_ReceiveData(USART1);
		//判断数据是否为':',如果是':'数据帧结束
		if(buffer[count-1] == ':')
		{
			//数据赋值到rx_buffer,并过滤帧尾
			for(rx_i=0; rx_i<(count-1); rx_i++)
			{
				rx_buffer[rx_i] = buffer[rx_i];
			}
		
			//清空数组
			memset(buffer, 0, sizeof(buffer));
			
			//标志位置1
			rx_flag = 1;
			//下一帧数据从buffer[0]开始接受
			count = 0; 
					
		
		}
		
	}
}




void USART2_IRQHandler(void)
{
	
	u8 data;

	//判断接收标志位是否为1
	if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
	{
		//清空接受标志位
		USART_ClearITPendingBit(USART2, USART_IT_RXNE);	
		//接受数据 
		buffer[count++] = USART_ReceiveData(USART2);
		//判断数据是否为':',如果是':'数据帧结束
		if(buffer[count-1] == ':')
		{
			//数据赋值到rx_buffer,并过滤帧尾
			for(rx_i=0; rx_i<(count-1); rx_i++)
			{
				rx_buffer[rx_i] = buffer[rx_i];
			}
		
			//清空数组
			memset(buffer, 0, sizeof(buffer));
			
			//标志位置1
			rx_flag = 1;
			//下一帧数据从buffer[0]开始接受
			count = 0; 
					
		}
		
	}


}


void USART3_IRQHandler(void)
{
	
	u8 data;

	//判断接收标志位是否为1
	if(USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
	{
		//清空接受标志位
		USART_ClearITPendingBit(USART3, USART_IT_RXNE);	
		//接受数据 
		buffer[count++] = USART_ReceiveData(USART3);
		//判断数据是否为':',如果是':'数据帧结束
		if(buffer[count-1] == ':')
		{
			//数据赋值到rx_buffer,并过滤帧尾
			for(rx_i=0; rx_i<(count-1); rx_i++)
			{
				rx_buffer[rx_i] = buffer[rx_i];
			}
		
			//清空数组
			memset(buffer, 0, sizeof(buffer));
			
			//标志位置1
			rx_flag = 1;
			//下一帧数据从buffer[0]开始接受
			count = 0; 
					
		}
		
	}


}






//显示缓冲区
u8  dispnumber5buf[6];
u8  dispnumber3buf[4];
u8  dispnumber2buf[3];
//MFRC522数据区
u8  mfrc552pidbuf[18];
u8  card_pydebuf[2];
u8  card_numberbuf[5];
u8  card_key0Abuf[6]={0xff,0xff,0xff,0xff,0xff,0xff};
u8  card_writebuf[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
u8  card_readbuf[18];
//SM05-S数据区
u8  sm05cmdbuf[15]={14,128,0,22,5,0,0,0,4,1,157,16,0,0,21};


//MFRC522测试函数
void MFRC522Test(void)
{
	u8 i,j,status,card_size;
	//
	status=MFRC522_Request(0x52, card_pydebuf);			//寻卡
	//
	if(status==0)		//如果读到卡
	{
		status=MFRC522_Anticoll(card_numberbuf);			//防撞处理			
		card_size=MFRC522_SelectTag(card_numberbuf);	//选卡
		status=MFRC522_Auth(0x60, 4, card_key0Abuf, card_numberbuf);	//验卡 验密钥
		status=MFRC522_Write(4, card_writebuf);				//写卡(写卡要小心,特别是各区的块3)
		status=MFRC522_Read(4, card_readbuf);					//读卡
		//MFRC522_Halt();															//使卡进入休眠状态
		//卡类型显示
		printf("卡类型显示:%#x %#x\r\n", card_pydebuf[0], card_pydebuf[1]);
		

		//卡序列号显,最后一字节为卡的校验码
		printf("卡序列号:");
		
		for(i=0;i<5;i++)
		{
			printf("%#x ", card_numberbuf[i]);	
		}
		printf("\r\n");
		
		//卡容量显示,单位为Kbits
		printf("卡容量显示:%d Kbits\r\n", card_size);
		

		printf("读取的块数据:%");
		//读一个块的数据显示
		for(i=0;i<2;i++)		//分两行显示
		{
			for(j=0;j<9;j++)	//每行显示8个
			{
				printf("%#x ", card_readbuf[j+i*9]);
			}
		}
		
		printf("\r\n");

	}	
}


int main(void)
{

	
	//设置NVIC分组(一个工程只能设置一个分组) 
	//第二分组;抢占优先组取值范围:0~3 响应先组取值范围:0~3
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

	Delay_Init();
	Usart1_Init(115200);
	MFRC522_Initializtion();
	
	
	printf("RDID test\r\n");
	
	while(1)
	{
		
		MFRC522_Initializtion();	
		MFRC522Test();
		delay_s(1);


	}
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hqb_newfarmer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值