我对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毫秒才能再次返回高电平。但是,某些命令的时间更长
或如果启用了STS_DEBUG设置,如下所示:0x01
(设置加载):0x02
(低电平校准和偏移):如果启用了STS_DEBUG设置,则将上述时间增加15 ms。
其他DRDY规格:
最小时间DRDY低:1 µs
复位后最大时间DRDY为低:100毫秒
时序图是这样的:
如何实现呢?
我和朋友一起编写的代码写在这里:
#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) ;
}
}
最佳答案
不。不要只写一堆代码,然后看看它能做什么。这种shot弹枪(或者,如果您愿意,也可以是通心粉)方法是在浪费精力。
首先,删除所有这些宏。而是编写描述每个代码块用途的注释,例如SPI_Initialize()
函数中的前三个分配。
接下来,将您的规范转换为伪代码。格式没什么大不了,只是使用一些可以让您专注于目的的东西,而不是专注于如何做的细节。
datasheet表示,对于SPI,有PIC的三个输出(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
每次传输都是双向的。每当您发送数据时,您也会接收数据。数据表说,zero命令保留用于接收多个数据。因此,您只需要一个发送字节并同时接收一个字节的函数:
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微控制器的“主要操作”本质上是透明的。这需要使用命令和响应的方法稍有不同。队列(只有几个字节),但除了扫描QT1481之外,这将使PIC更加轻松地进行实际工作。)
重置后,您实际上发送0x0F,直到返回0xF0为止:
while (SPITransfer(0x0F) != 0xF0)
;
此时,您具有在C中需要实现的步骤。OP还具有用于验证其代码工作的硬件(示波器)。