我已经在我的 PC 上使用 Pyhton 脚本通过 UART 测试读取带有 RFID-RC522 模块的 Mifare RFID 1K 卡。现在我正在使用 STM8S103F3 通过 SPI 与相同的 RFID-RC522 (MFRC522) 接口,但是当我发送与 Python 脚本/终端相同的命令时,我遇到了无法获得 MFRC522 返回的正确值/地址的问题。这是我第一次使用 SPI,所以我怀疑自己没有正确配置 SPI 或写/读序列有问题,但我自己无法解决问题。
这是我的 main() 函数:
int main ( void ) {
initClockHSI();
initGPIO();
initUART1();
initMasterSPI();
initMFRC522();
return 0;
}
初始化函数如下:
void initClockHSI ( void ) {
CLK_DeInit(); // Deinitializes the CLK peripheral registers to their default reset
CLK_SYSCLKConfig ( CLK_PRESCALER_CPUDIV1 ); // (uint8_t)0x80 CPU clock division factors 1
CLK_SYSCLKConfig ( CLK_PRESCALER_HSIDIV1 ); // (uint8_t)0x00 High speed internal clock prescaler: 1
CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, // (uint8_t)0x01 Enable the automatic clock switching mode
CLK_SOURCE_HSI, // (uint8_t)0xE1 Clock Source HSI
DISABLE, // DISABLE = 0
CLK_CURRENTCLOCKSTATE_DISABLE); // CLK_CURRENTCLOCKSTATE_DISABLE = (uint8_t)0x00 Current clock disable
}
void initGPIO ( void ) {
// UART1:
GPIO_DeInit(GPIOD);
GPIO_Init(GPIOD, GPIO_PIN_5, GPIO_MODE_OUT_PP_HIGH_SLOW); // (uint8_t)0xD0 Output push-pull, high level, 2MHz
GPIO_Init(GPIOD, GPIO_PIN_6, GPIO_MODE_IN_PU_NO_IT); // UART1 Rx (uint8_t)0x40 Input pull-up, no external interrupt
// MFRC522:
GPIO_DeInit(GPIOC);
// MOSI:
GPIO_Init (GPIOC, GPIO_PIN_6, GPIO_MODE_OUT_PP_HIGH_SLOW);// (uint8_t)0xD0 Output push-pull, high level, 2MHz
// SCK:
GPIO_Init (GPIOC, GPIO_PIN_5, GPIO_MODE_OUT_PP_LOW_SLOW); // (uint8_t)0xC0 Output push-pull, low level, 2MHz
// MISO (Input):
GPIO_Init (GPIOC, GPIO_PIN_7, GPIO_MODE_IN_PU_NO_IT); // (uint8_t)0x40 Input pull-up, no external interrupt
GPIO_DeInit(GPIOB);
// NRSTPD:
GPIO_Init(GPIOB, GPIO_PIN_4, GPIO_MODE_OUT_PP_HIGH_SLOW); // (uint8_t)0xD0 Output push-pull, high level, 2MHz
// NSS (pulled-up externally via 10k R):
GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_OUT_PP_HIGH_SLOW); // (uint8_t)0xD0 Output push-pull, high level, 2MHz
}
void initMasterSPI ( void ) {
SPI_DeInit(); // Deinitializes the SPI peripheral registers to their default reset values
SPI_Init(SPI_FIRSTBIT_MSB, // (uint8_t)0x00 MSB bit will be transmitted first
SPI_BAUDRATEPRESCALER_16, // (uint8_t)0x18 SPI frequency = frequency(CPU)/16 == 1 MHz baud
SPI_MODE_MASTER, // (uint8_t)0x04 SPI Master configuration
SPI_CLOCKPOLARITY_LOW, // (uint8_t)0x00 Clock to 0 when idle
SPI_CLOCKPHASE_1EDGE, // (uint8_t)0x00 The first clock transition is the first data capture edge
SPI_DATADIRECTION_2LINES_FULLDUPLEX, // (uint8_t)0x00 2-line uni-directional data mode enable
SPI_NSS_SOFT, // (uint8_t)0x02 Software slave management disabled ?! isn't it enabled, when it's called SOFT ?!
0x00); // CRCPolynomial
SPI_Cmd(ENABLE); // Enables or disables the SPI peripheral; parameter can be: ENABLE or DISABLE
}
void initMFRC522 ( void ) {
char result;
// 1. hard reset MFRC522:
result = resetHardMFRC522 ();
// 3. set timer to start automatically at the end of the TRANSMISSION:
result = writeMFRC522 ( TModeReg, 0x80 ); // TModeReg = (0x2A == 42):defines settings for the internal timer; 0x80 == 1000 0000 --> MSB = 1 => timer starts automatically at the end of the TRANSMISSION in all communication modes at all speeds
}
char resetHardMFRC522 () {
unsigned int i;
// 1. Pull reset line LOW:
GPIO_WriteLow(NRSTPD_PORT, NRSTPD_PIN);
// 2. keep reset line LOW for some time; reset timing requirements: min 100ns (page 34)
for ( i = 0; i < 1000; i++) // @ 16 Mhz: 1 clock cycle == 62,5 ns;
nop();
//// 1000 == 340 - 370 us, rectangular
// 3. Pull reset line HIGH:
GPIO_WriteHigh(NRSTPD_PORT, NRSTPD_PIN);
// 4. wait for a stable oscillator; oscillator start-up time is the start up time of the crystal + 37,74µs;
for ( i = 0; i < 60000; i++) // @ 16 Mhz: 1 clock cycle == 62,5 ns; 60000 == 22,4 ms
nop(); // ;
// 5. check for wake-up procedure end (hard Power-Down mode): bit 'PowerDown' 1 --> 0:
if ( ( readMFRC522( CommandReg ) & 0x10 ) ) // if 1 returned ; 0x10 == 0001 0000 (BIt 4: PowerDown)
return ERROR; // 1
return OK; // 0 => Bit 4 (PoweDown) of CommandReg is cleared => chip should be ready to work
}
char readMFRC522 ( unsigned char address ) { // 0x01
char dataMFRC522;
// 2. Before sending data, the user must pull low an SS signal to let the slave device know it is the recipient of the message:
GPIO_WriteLow(NSS_PORT, NSS_PIN); // pull NSS line LOW before start of SPI communication
// 3. wait while SPI is busy communicating, exit when any ongoing SPI transfer has finished
while(SPI_GetFlagStatus(SPI_FLAG_BSY)) // RESET(0) or SET(1)
;
// 4. send serially the address to MFRC522 with MSB set (R mode) & LSB cleared:
SPI_SendData( ( ( address << 1 ) & 0x7E ) | 0x80 ); // highest MFRC522 address is 0x3f == 0011 1111; 0x82 == 1000 0010
// 5. check that the address is indeed sent:
while( ! SPI_GetFlagStatus(SPI_FLAG_TXE) )
;
// 6. check that data has been received:
while( ! SPI_GetFlagStatus(SPI_FLAG_RXNE) ) // data received ?
;
// 7. read the value returned serially:
dataMFRC522 = SPI_ReceiveData(); // Returns the most recent received data by the SPI peripheral; resets SPI_FLAG_RXNE
// 8. wait while SPI is busy communicating, exit when SPI transfer has finished
while(SPI_GetFlagStatus(SPI_FLAG_BSY)) // RESET(0) or SET(1)
;
// 9. raise NSS line HIGH afer end of SPI communication:
GPIO_WriteHigh(NSS_PORT, NSS_PIN);
return dataMFRC522;
}
char writeMFRC522 ( unsigned char address, unsigned char value ) {
char addressMFRC522;
// 2. Before sending data, the user must pull low an SS signal to let the slave device know it is the recipient of the message:
GPIO_WriteLow(NSS_PORT, NSS_PIN); // pull NSS line LOW before start of SPI communication
// 3. wait while SPI is busy communicating, exit when any ongoing SPI transfer has finished
while(SPI_GetFlagStatus(SPI_FLAG_BSY)) // RESET(0) or SET(1)
;
// 4. send serially the address to MFRC522 with MSB cleared (W mode) & LSB cleared:
SPI_SendData( ( address << 1 ) & 0x7E ); // highest MFRC522 address is 0x3f == 0011 1111;
// 5. check that the address is indeed sent:
while( ! SPI_GetFlagStatus(SPI_FLAG_TXE) )
;
// 6. send serially the data to MFRC522:
SPI_SendData( value );
// 7. check that the data is indeed sent:
while(!SPI_GetFlagStatus(SPI_FLAG_TXE))
;
// 8. check that data has been received as reposnse to sent address:
while( ! SPI_GetFlagStatus(SPI_FLAG_RXNE) ) // data received ?
;
// 9. read the address returned serially:
addressMFRC522 = SPI_ReceiveData(); // Returns the most recent received data by the SPI peripheral; resets SPI_FLAG_RXNE
// 10. wait while SPI is busy communicating, exit when SPI transfer has finished:
while(SPI_GetFlagStatus(SPI_FLAG_BSY)) // RESET(0) or SET(1)
;
// 11. raise NSS line HIGH afer end of SPI communication
GPIO_WriteHigh(NSS_PORT, NSS_PIN);
if ( addressMFRC522 == address )
return OK; // 0
else
return ERROR; // 1
}
我的问题出现在initMFRC522()
我的main()
函数中最后一个函数的调用中:
- 当我只执行第一部分时
resetHardMFRC522 ();
,我会在硬复位后得到 MFRC522 的 CommandRegister 的预期复位值 0x20; - 但是,当我还执行第二部分函数
result = writeMFRC522 ( TModeReg, 0x80 );
时,在硬复位后我没有得到 MFRC522 的 CommandRegister 的预期复位值 0x20,而且我没有收到与我写的返回相同的地址到(根据 MFRC522 协议)。我无法弄清楚我的问题出在哪里?我检查了 SPI 设置,但时钟极性和相位的设置似乎是正确的。引脚输入/输出方向似乎也是正确的。我想我误用/过度使用/没有正确使用 SPI 标志,或者我在读/写时没有正确的命令序列,但我无法通过阅读数据表和查看其他人的代码来弄清楚我的错误在哪里互联网 ?