c - DRDY PIC18F45K80 至 QT1481

标签 c pic spi

我也有 DRDY 的问题。我需要包括 DRDY。 DRDY 的引脚是 RD2 和 RD5。它们都是输入。

这是 DRDY 的信息。

DRDY 引脚 DRDY 是一个开漏输出(在 SPI 模式下)或双向引脚(在 UART 模式下),具有内部 20 k – 50 k 上拉电阻 电阻。
大多数通信故障都是由于未能正确遵守 DRDY 时序造成的。 串行通信节奏由该引脚控制。 DRDY 的使用对于与系统的成功通信至关重要 QT1481。在 UART 或 SPI 模式下,仅当 DRDY 返回时才允许主机执行数据传输 高的。此外,在 UART 模式下,如果 DRDY 被主机保持为低电平,QT1481 会延迟对主机的响应。
每次字节传输后,DRDY 在短暂延迟后变低,并保持低电平,直到 QT1481 准备好进行另一个字节传输。 转移。在 DRDY 被驱动为低电平之前会发生短暂的延迟,因为 QT1481 可能很忙并且需要 有限的响应时间。

DRDY 可能只会变低一微秒。从一次传输结束到 DRDY 变为低电平期间 再次回到高电平,主机不应执行另一次传输。因此,在每个字节传输之前,主机 应首先检查 DRDY 是否再次变高。 如果主机想要与 QT1481 执行字节传输,其行为应如下:
1. 在上一次传输后等待至少 100 µs(第 23 页图 3-2 中的时间 S5:保证 DRDY 继续传输) 在此 100 µs 到期之前为低)。
2. 等到 DRDY 为高电平(可能已经为高电平)。
3. 使用QT1481进行下一次传输。
在大多数情况下,DRDY 需要长达 3 ms 的时间才能再次返回高电平。但是,有些命令的时间会更长 或者如果启用了 STS_DEBUG 设置,如下所示:
0x01(设置加载):<20 毫秒
0x02(低电平校准和偏移):<20 ms
如果启用了 STS_DEBUG 设置,则在上述时间上增加 15 毫秒。 其他 DRDY 规范:
DRDY 为低电平的最短时间:1 µs
复位后 DRDY 为低电平的最长时间:100 ms

时序图是这样的:enter image description here

如何实现?

我和 friend 写的代码写在这里:

#include <xc.h>
#include "PIC.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
//#include <pic18f45k80.h>

#define MSB 1
#define LSB 0

// SPI PIN CONFIGURATION

#define SCK_TRIS TRISCbits.TRISC3 = 0 ;
#define SDO_TRIS TRISCbits.TRISC5 = 0 ;
#define SDI_TRIS TRISCbits.TRISC4 = 1 ;
#define QTA_SS_TRIS TRISDbits.TRISD4 = 0 ;
#define QTB_SS_TRIS TRISEbits.TRISE2 = 0 ;
#define QTA_SS_LAT_LOW LATDbits.LATD4 = 0 ;
#define QTA_SS_LAT_HIGH LATDbits.LATD4 = 1 ;
#define QTB_SS_LAT_LOW LATEbits.LATE2 = 0 ;
#define QTB_SS_LAT_HIGH LATEbits.LATE2 = 1 ;
#define QTA_DRDY_TRIS TRISDbits.TRISD5 = 1 ;
#define QTB_DRDY_TRIS TRISDbits.TRISD2 = 1 ;
#define QTA_DRDY_LAT_LOW LATDbits.LATD5 = 0 ;
#define QTA_DRDY_LAT_HIGH LATDbits.LAT52 = 1 ;
#define QTB_DRDY_LAT_LOW LATDbits.LAT25 = 0 ;
#define QTB_DRDY_LAT_HIGH LATDbits.LATD2 = 1 ;
#define QTB_DRDY PORTDbits.RD2 ;
#define QTA_DRDY PORTDbits.RD5 ;

// FREQUENCY SELECT

#define _XTAL_FREQ 16000000

// PIN SETUP

void PIN_MANAGER_Initialize(void)
{
    /**
    LATx registers
    */
    LATE = 0x00;
    LATD = 0x00;
    LATA = 0x00;
    LATB = 0b00010000;
    LATC = 0x00;

    /**
    TRISx registers
    */
    TRISE = 0x00;
    TRISA = 0x08;
    TRISB = 0x01;
    TRISC = 0b00010000;
    TRISD = 0xEF;

    PORTC = 0b00010010 ;

    /**
    ANSELx registers
    */
    ANCON0 = 0x00;
    ANCON1 = 0x00;

    /**
    WPUx registers
    */
    WPUB = 0x00;
    INTCON2bits.nRBPU = 1; 

}

// SPI

void SPI_Initialize(void)
{

    // SMP Middle; CKE Idle to Active; 
    SSPSTAT = 0b00000000;

    // SSPEN enabled; WCOL no_collision; CKP Idle:High, Active:Low; SSPM FOSC/4; SSPOV no_overflow; 
    SSPCON1 = 0b00111010;

    // SSPADD 0; 
    SSPADD = 0x00;

    ADCON0 = 0 ;
    ADCON1 = 0x0F ; //Makes all I/O digital

    SCK_TRIS ;
    SDO_TRIS ;
    SDI_TRIS ;
    QTA_SS_TRIS ;
    QTB_SS_TRIS ;
    QTA_DRDY_TRIS ;
    QTB_DRDY_TRIS ;
}

signed char WriteSPI( unsigned char data_out )
{
    unsigned char TempVar;
    TempVar = SSPBUF;           // Clears BF
    PIR1bits.SSPIF = 0;         // Clear interrupt flag
    SSPCON1bits.WCOL = 0;            //Clear any previous write collision
    SSPBUF = data_out;           // write byte to SSPBUF register
    if ( SSPCON1 & 0x80 )        // test if write collision occurred
        return ( -1 );              // if WCOL bit is set return negative #
    else
        while( !PIR1bits.SSPIF );  // wait until bus cycle complete
    return ( 0 );                // if WCOL bit is not set return non-negative#
}


unsigned char ReadSPI( void )
{
  unsigned char TempVar;
  TempVar = SSPBUF;        // Clear BF
  PIR1bits.SSPIF = 0;      // Clear interrupt flag
  SSPBUF = 0x00;           // initiate bus cycle
  while(!PIR1bits.SSPIF);  // wait until cycle complete
  return ( SSPBUF );       // return with byte read
}

unsigned char DataRdySPI( void )
{
  if ( SSPSTATbits.BF )
    return ( +1 );                // data in SSPBUF register
  else
    return ( 0 );                 // no data in SSPBUF register
}


// SOFTWARE EUART

void out_char(char character, char bit_order){

  uint8_t i = 0;
  RSOUT = 1 ; // MSB
  __delay_ms(1); 
  RSOUT = 0 ; // START
  __delay_us(100);
  for (i = 8; i>0; --i){
      if (bit_order){ // Bit order determines how you will put the bits, from left to right (MSB) or right to left (LSB)
        RSOUT = (character & 0x80) ? 1:0; // in MSB you compare the left-most bit doing an AND with 0x80, and put 1 if true, 0 elsewhere.
        character <<= 1; // Shift the character to the left, discrading the bit just sent
      } else {
        RSOUT = (character & 0x01); // in LSB you compare the right-most bit doing an AND with 0x01, and put 1 if true, 0 else.
        character >>= 1; // Shift the character to the right, discrading the bit just sent
      }
      __delay_us(100);
  }
  RSOUT = 1 ; // STOP

}

void out_str(char * string, uint8_t len, char bit_order){
  uint8_t i = 0;
  for (i = 0; i< len; i++){
    out_char(string[i], bit_order);
  }
}

void SYSTEM_Initialize(void)
{

    PIN_MANAGER_Initialize() ;
    SPI_Initialize() ;
}

void main(void)
{
    SYSTEM_Initialize() ;

      while (1)
      {
          QTB_SS_LAT_LOW ;         // Transmit data
          char temp ;
          WriteSPI(0x0F) ;         // Send a byte
          while(!DataRdySPI()) ;   // wait for a data to arrive
          temp = ReadSPI();        // Read a byte from the
          QTB_SS_LAT_HIGH ;        // Stop transmitting data
         __delay_us(100) ;
     }
}

最佳答案

没有。不要只是编写一堆代码,然后看看它的作用。这种霰弹枪(或者,如果你愿意的话,也可以说是“意大利面条到墙上”)的方法是浪费精力。

首先,删除所有这些宏。相反,请编写描述每个代码块用途的注释,例如 SPI_Initialize() 函数中的前三个赋值。

接下来,将您的规范转换为伪代码。格式并不重要,只需使用能让您集中精力目的的内容,而不是关注如何做到这一点的细节。

datasheet表示使用 SPI,PIC 有 3 个输出(QT1481 上的 ^SS、SCK、MOSI)和两个输入(QT1481 上的 ^DRDY 和 MISO)。我将使用这些名称作为数据线以及 PIC 上各自的 I/O 引脚名称。

PIC 上的设置阶段应该很简单:

Make ^DRDY an input
Make ^SS an output, set it HIGH

Make SCK an output, set it LOW
Make MOSI an output, set it LOW
Make MISO an input
Set up SPI using SCK, MOSI, MISO

每次传输都是双向的。每当您发送数据时,您也会收到数据。数据表称,零命令保留用于接收多个数据。所以,你只需要一个发送一个字节,同时接收一个字节的函数:

Function  SPITransfer(command):

    Make sure at least 0.1ms has passed since the previous transfer.

    Do:
        Nothing
    While (^DRDY is LOW)

    Set ^SS LOW

    response = Transfer(command)

    Set ^SS HIGH

    Return response
End Function

据我了解,对于 PIC 和正确初始化的硬件 SPI,response = Transfer(command) 行采用 C 语言

    SSPBUF = command;
    while (!DataRdySPI())
        ;
    response = SSPBUF;

您也可以对它进行位爆炸,在这种情况下它是(伪代码):

    response = 0
    For bit = 7 down to 0, inclusive:
        If (command & 128):
            Set MOSI high
        Else:
            Set MOSI low
        End If

        Set SCK low
        Sleep for a half period

        command = command / 2
        response = response * 2
        If MISO high:
            response = response + 1
        End If

        Set SCK high
        Sleep for a half period

    End For

但显然硬件 SPI 方法更好。

(当您开始工作时,您可以使用硬件 SPI,而无需定时器中断的等待循环,从而使通信对于 PIC 单片机的“主操作”来说基本上是透明的。这需要稍微不同的方法,使用命令和响应队列(几个字节),但将使 PIC 更容易执行实际工作,而不仅仅是扫描 QT1481。)

重置后,您实际上会发送 0x0F,直到收到 0xF0:

    while (SPITransfer(0x0F) != 0xF0)
        ;

此时,您已经完成了在 C 中实现所需的步骤。OP 还拥有硬件(示波器)来验证其代码是否有效。

关于c - DRDY PIC18F45K80 至 QT1481,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53394889/

相关文章:

c - 仅左移数字的一部分

c - 使用 C 将十六进制值存储到数组后打印

c++ - 从 Arduino 到 Raspberry Pi 的不可靠 SPI 字节数组传输

c - SPI头文件

raspberry-pi - e Ink 屏幕导致 Raspberry Pi 0W 重新启动

c - 为什么 C 中的空指针等于 C 中的另一个空指针?

c - 使用 c 中的 strtok() 函数从子 token 中提取 token 的问题

c - 将代码从 PIC18F2480 迁移到 PIC18F2680 单片机

c - 与 PIC18F252 上的 ADC 输出作斗争

embedded - 设置 RXIF 标志时未调用 PIC32 SPI ISR?