1

我已经在我的 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 标志,或者我在读/写时没有正确的命令序列,但我无法通过阅读数据表和查看其他人的代码来弄清楚我的错误在哪里互联网 ?
4

1 回答 1

0

问题是,当尝试读取寄存器值时,我需要在寄存器地址本身之后通过 MOSI 发送第二个虚拟字节,因为返回的第一个字节是无意义字节,而真正的寄存器内容作为第二个字节返回这需要一个 CLK 信号(它本身是由发送的第二个虚拟字节生成的)。这与使用 UART 相比有所不同,但我在解释数据表时得到了一些帮助 :-)

于 2020-12-07T15:59:15.000 回答