Как получить 10-битные данные АЦП по протоколу SPI

Я делаю реализацию с одним мастером и несколькими ведомыми.
Мастер - PIC18F4550
Ведомый - PIC18F4520

К ведомому подключен потенциометр. Подчиненный преобразовывает значение потенциометра в цифровое и связывается с ведущим по протоколу SPI.

Я правильно получаю 8-битные данные (ADRESH -- по левому краю) от ведомого устройства. Но мне нужно получить 10-битные данные (ADRESH - 8 бит, ADRESL - 2 бит).

Как я могу получить 10-битные данные?

Главный код

OpenSPI(SPI_FOSC_64, MODE_01, SMPMID);   //SPI configuration

SSPCON1bits.WCOL = 0;    //Clearing SSPBUF
LATDbits.LATD0 = 0;  //Slave select
WriteSPI(0xFF);  //writing 0xFF to slave    
for(mdelay = 0; mdelay < 10; mdelay++); 
var1 = SSPBUF;
LATDbits.LATD0 = 1;
highbyte = var1;
highbyte = highbyte << 8;    //deselecting SS   
for(mdelay = 0; mdelay < 100; mdelay++);

SSPCON1bits.WCOL = 0;
LATDbits.LATD0 = 0;  //2nd time slave selct 
WriteSPI(0xAA);
for(mdelay = 0; mdelay < 10; mdelay++); 
var2 = SSPBUF;
LATDbits.LATD0 = 1;
lowbyte = var2;
for(mdelay = 0; mdelay < 100; mdelay++);

highbyte = highbyte | lowbyte;
result = highbyte;

Раб

int Count;
unsigned char ch1,ch2,data; 

ADCON0 = 0x01;   // AD Control Register 1: Enable (turn on ADC)
ADCON2 = 0x3C;   // AD Control Register 2: 20 TAD (accuracy), FOSC 4 (freq/4)
ADCON2bits.ADFM = 0;     // ADC result left justified (D10 - D2 --> ADRESH, D1 - D0 --> ADRESL) 

TRISCbits.TRISC3 = 1;    //SPI pins(PIC18F4520)
TRISCbits.TRISC4 = 1;   
TRISCbits.TRISC5 = 0;
TRISAbits.TRISA5 = 1;

TRISDbits.TRISD0 = 0;    //Configuring PORTD as output
TRISDbits.TRISD1 = 0;
TRISDbits.TRISD2 = 0;
TRISDbits.TRISD3 = 0;
TRISDbits.TRISD4 = 0;
TRISDbits.TRISD5 = 0;
TRISDbits.TRISD6 = 0;
TRISDbits.TRISD7 = 0;   

SSPSTATbits.SMP = 0;     //Configuration of SPI register
SSPSTATbits.CKE = 0;
SSPCON1bits.CKP = 0;
SSPCON1bits.SSPM3 = 0;
SSPCON1bits.SSPM2 = 1;
SSPCON1bits.SSPM1 = 0;
SSPCON1bits.SSPM0 = 0;  
SSPCON1bits.SSPEN = 1;

while(1)
{   

ADCON0bits.CHS0 = 1;     //Selecting AN0 as analog input
ADCON0bits.CHS1 = 0;
ADCON0bits.CHS2 = 0;
ADCON0bits.CHS3 = 0;
ADCON0bits.GO = 1;   //Start analog to digital conversion   
while (ADCON0bits.NOT_DONE);    
ch1 = ADRESL;   
ch2 = ADRESH;


data = SSPBUF;   //loading the SSPBUF value to some dummy varible(Previous data in SSPBUF)

//First time slave select
SSPCON1bits.WCOL = 0;    //Clearing SSPBUF register
while(PORTAbits.RA5 == 1);  //wait for slave select
SSPBUF = ch1;    //Loading ADRESH value to SSPBUF
while(SSPSTATbits.BF == 0); //wait untill the buffer is full

for(Count=0;Count<10;Count++);  //delay

//Second time slave selct
SSPCON1bits.WCOL = 0;    //Clearing SSPBUF register
while(PORTAbits.RA5 == 1);  //wait for slave select
SSPBUF = ch2;    //Loading ADRESL value to SSPBUF
while(SSPSTATbits.BF == 0); //wait untill the buffer is full

for(Count=0;Count<10;Count++);  //delay
}

Ответы (1)

Есть несколько вещей, которые кажутся мне подозрительными. На стороне ведущего я бы ввел небольшую задержку между установкой сигнала выбора ведомого и отправкой фиктивных данных (для начала передачи), хотя это может не быть проблемой. Другие вещи, которые вызывают подозрения, это то, что в вашем ведомом коде у вас сначала есть...

ch1 = ADRESL;   
ch2 = ADRESH;

но потом

SSPBUF = ch1;    //Loading ADRESH value to SSPBUF
...
SSPBUF = ch2;    //Loading ADRESL value to SSPBUF

Итак, в соответствии с вашими комментариями и кодом, который ожидает мастер, вы ожидаете получить сначала старший байт, затем младший байт, но ведомый фактически отправляет сначала ADRESL, а затем ADRESH.

Наконец, после первой передачи байта вы вводите длинную (более) задержку (mdelay<100) перед отменой SS на мастере. На ведомой стороне есть только короткая задержка, затем вы ждете повторной установки SS, который, скорее всего, все же установлен исходя из большой задержки со стороны ведущего. Затем вы устанавливаете второй байт данных и ждете установки бита BF. Я не знаком с PIC18F4550, поэтому не знаю, является ли это проблемой, но, поскольку вы никогда явно не сбрасываете бит BF, он все равно может быть установлен с первого раунда, что затем приведет к перезапуску ведомого устройства. основной цикл (после очередной небольшой задержки).