我正试图配置PIC24FJ512GA610使用SPI与ADC模块接口。 因此,我将其配置为两线模式(只有SCK和SDI,CS由端口控制)。 下面是我用来配置SPI的相关代码。 一个头文件包含了大部分定义。
// SPI3 is used to read from 22-bit ADC tied to RTDs
// SPI3CON1L
#define SPI3EN 0<<15 // SPI Enable Pin
// unimplemented
#define SPI3SIDL 0<<13 // Stop when CPU is in idle mode
#define SPI3DSSDO 1<<12 // Disable SDO (no data sent to ADC module)
#define SPI3MODE1 0<<11 // Data mode: (0,0) transmits 8-bits
#define SPI3MODE0 0<<10 //
#define SPI3SMP 1<<9 // Sampling phase: samples at the end of output data time
#define SPI3CKE 0<<8 // Transmits on transition from idle to active
#define SPI3SSEN 0<<7 // only used in slave mode
#define SPI3CKP 0<<6 // clock idle state is low, active state is high
#define SPI3MSTEN 1<<5 // Master mode enabled
#define SPI3DISSDI 0<<4 // Disable SDI (no data received the board))
#define SPI3DISSCK 0<<3
#define SPI3MCLKEN 1<<2
#define SPI3SPIFE 0<<1
#define SPI3ENHBUF 0<<0
#define SPI3CON1L_MASK (SPI3EN | SPI3SIDL | SPI3DSSDO | SPI3MODE1 | SPI3MODE0 | SPI3SMP |\
SPI3CKE | SPI3SSEN | SPI3CKP | SPI3MSTEN | SPI3DISSDI | SPI3DISSCK | SPI3MCLKEN |\
SPI3SPIFE | SPI3ENHBUF )
// SPI3CON1H
#define AUDEN3 0<<15 // Audio codec enable
#define SPI3SGNEXT 0<<14 // Sign Extend Enable
#define IGNROV3 0<<13 // Ignore Receive Overflow
#define IGNTUR3 0<<12 // Ignore Transmit Underrun
#define AUDMONO3 0<<11 // Audio data format
#define URDTEN3 0<<10 // Transmit underrun data enable
#define AUDMOD31 0<<9 // Audio protocol mode select
#define AUDMOD30 0<<8 //
#define FRMEN3 1<<7 // Framed SPI support
#define FRMSYNC3 0<<6 // Frame sync pulse direction control
#define FRMPOL3 0<<5 // Frame sync/slave select polarity bit
#define MSSEN3 0<<4 // Master mode slave select enable
#define FRMSYPW3 0<<3 // Frame sync pulse width bit
#define FRMCNT32 0<<2 // Frame sync pulse counter bits
#define FRMCNT31 0<<1 //
#define FRMCNT30 0<<0 //
#define SPI3CON1H_MASK (AUDEN3 | SPI3SGNEXT | IGNROV3 | IGNTUR3 | AUDMONO3 | URDTEN3 | AUDMOD31 |\
AUDMOD30 | FRMEN3 | FRMSYNC3 | FRMPOL3 | MSSEN3 | FRMSYPW3 | FRMCNT32 |\
FRMCNT31 | FRMCNT30 )
配置SPI的函数在其他地方找到。
void SPI3Init(void)
// SPI 3 is the thermocouple interface chip or
// the external adc interface for the cryostat
// **************************************
{
#if PROCESSOR == __PIC24FJ512GA610__
// Used for SPI communication to read RTDs through ADC
IEC3bits.SPI3RXIE = 0; // disable all SPI3 interrupts
IEC5bits.SPI3TXIE = 0;
IEC5bits.SPI3IE = 0;
SPI3BUFL = 0; // clear buffer
SPI3BUFH = 0;
OSCCONbits.IOLOCK = 0;
RPINR28bits.SDI3R = 30; // assign SPI3 SDI to pin 52 (RP30)
// RPINR28bits.SCK3R = 15; // assign SPI3 SCK to pin 53 (RP15)
RPOR7bits.RP15R = 24; // Set SCK pin to SPI3 SCK OUT (function 24)
RPOR8bits.RP16R = 23; // Map SDO to N/C pin 51 (function 23)
OSCCONbits.IOLOCK = 1;
SPI3CON1Lbits.SPIEN = 0; // disable the port
SPI3IMSKH = 0; // disable all interrupts
SPI3CON1L = 0; // disable SPI
SPI3CON1H = 0; // turn off AUDEN & FRMEN
SPI3BRGL = 832; // 3=16mhz / (2* (3+1)) = 2mhz, 7=16/2(7+1) = 1mhz, 832 -> 9600 )
SPI3CON1L = SPI3CON1L_MASK; // Write config masks
SPI3CON1H = SPI3CON1H_MASK;
SPI3CON2L = 7; // 8 bit data
SPI3STATLbits.SPIROV = 0; // clear any overflow status
SPI3CON1Lbits.SPIEN = 1; // enable the port
SPI3BUFL = 0;
ADC_CS_HIGH;
ADC_CS_LOW;
ADC_CS_HIGH;
#endif
return;
}
实际上读取ADC会调用这个函数三次(每8位分辨率调用一次)
unsigned char Read_SPI3()
{
unsigned char ioByte = 0;
if(SPI3STATLbits.SPIROV)
SPI3STATLbits.SPIROV = 0; // clear overflow
SPI3BUFL = ioByte; // CLK out data on falling edge
while(!SPI3STATLbits.SPIRBF)
;
ioByte = SPI3BUFL; // CLK in data on rising edge
return ioByte;
}
我这一两天一直在看我的代码,在网上梳理了一下,想不通我到底做错了什么。 在SCK线上放一个范围,说明串行时钟没有运行。 我已经确认配置位被成功写入。 谁能告诉我可能出了什么问题?
一些想法。
有了这个
RPOR7bits.RP15R = 24;
你把SCLK引脚映射到了RF8上。但你必须把这个引脚切换到输出。
TRISFbits.TRISF8 = 0;
而你必须把这个引脚切换到数字式的
ANSELFbits.ANSELF8 = 0;
SDO引脚也是如此。
正如 @Dan 已经提到的,你需要一个PPS的解锁序列。请参考第163页的 数据表
您用来解锁引脚选择器的语句。
OSCCONbits.IOLOCK = 0;
并不是Microchip所要求的
因为 OSCCON 寄存器中的所有可写位都是 "受保护 "的,必须使用内置的编译器扩展命令来更改这些位。
解锁 PPS 的命令如下。
__builtin_write_OSCCONL(OSCCON & _OSCCON_IOLOCK_MASK);
锁定PPS的命令是这样的:
__builtin_write_OSCCONL(OSCCON | _OSCCON_IOLOCK_MASK);
根据你对配置字的设置 PPS可能被配置成无法解锁的状态 一旦被锁定,PPS就需要上电复位才能解锁