2017-10-07 108 views
1

根據Microchip數據手冊,我正在編寫自己的I²C主控寫入功能。我使用的MPLAB X.我生成與代碼配置的配置,但這裏有一個有趣的位:I²C主控寫入PIC18F45K50:保持SCL低電平

// R_nW write_noTX; P stopbit_notdetected; S startbit_notdetected; BF RCinprocess_TXcomplete; SMP Standard Speed; UA dontupdate; CKE disabled; D_nA lastbyte_address; 
SSP1STAT = 0x80; 
// SSPEN enabled; WCOL no_collision; CKP Idle:Low, Active:High; SSPM FOSC/4_SSPxADD_I2C; SSPOV no_overflow; 
SSP1CON1 = 0x28; 
// SBCDE disabled; BOEN disabled; SCIE disabled; PCIE disabled; DHEN disabled; SDAHT 100ns; AHEN disabled; 
SSP1CON3 = 0x00; 
// Baud Rate Generator Value: SSP1ADD 80; 
SSP1ADD = 0x50; 


// clear the master interrupt flag 
PIR1bits.SSP1IF = 0; 
// enable the master interrupt 
PIE1bits.SSP1IE = 1; 

所以:標準速度,100ns的保持時間,主模式,約50kHz的頻率clokck。

我試圖遵循的程序中描述的數據表的P238: http://ww1.microchip.com/downloads/en/DeviceDoc/30000684B.pdf

這是我的代碼:

#include "mcc_generated_files/mcc.h" 
#include <stdio.h> 

#define _XTAL_FREQ 16000000 
#define RTS_PIN  PORTDbits.RD3 
#define CTS_PIN  PORTDbits.RD2 
#define LED_PIN  PORTAbits.RA1 
#define RX_FLAG  PORTAbits.RA2 

uint8_t c; 

// Define putch() for printf()) 
void putch(char c) 
{ 
    EUSART1_Write(c); 
} 

void main(void) 
{ 
// Initialize the device 
SYSTEM_Initialize(); 

    while (1) 
    { 
     // Generate a START condition by setting Start Enable bit 
     SSP1CON2bits.SEN = 1; 
     // Wait for START to be completed 
     while(!PIR1bits.SSPIF); 
     // Clear flag 
     PIR1bits.SSPIF = 0; 
     // Load the address + RW byte in SSP1BUF 
     // Address = 85 ; request type = WRITE (0) 
     SSP1BUF = 0b10101010; 
     // Wait for ack 
     while (SSP1CON2bits.ACKSTAT); 
     // Wait for MSSP interrupt 
     while (!PIR1bits.SSPIF); 
     // Load data (0x11) in SSP1BUF 
     SSP1BUF = 0x11; 
     // Wait for ack 
     while (SSP1CON2bits.ACKSTAT); 
     // Generate a STOP condition 
     SSP1CON2bits.PEN = 1; 
     // Wait for STOP to be completed 
     while(!PIR1bits.SSPIF); 
     // Clear flag 
     PIR1bits.SSPIF = 0; 

     // Wait for 1s before sending the next byte 
     __delay_ms(1000); 
    } 
} 

從屬裝置是我與另一個Arduino的(主),以測試一個Arduino確保它正常工作。

我的問題是:用邏輯分析器分析SDA/SCL信號,當我啓動PIC時,我得到2個正確的消息,這是正確的地址發送和字節傳輸,但在第二個SCL結束時保持低電平,這會使所有其他寫入都不正確(如果SCL保持低電平,則不能有適當的START條件)。順便說一句,在第一次傳輸結束時,SCL保持低電平,等待3ms,但之後沒有任何原因再次變爲高電平。

任何人都可以在這裏指出我做錯了什麼?我忘了什麼嗎?

Thanx提前。

此致敬禮。

埃裏克

PS:測試與其他的Arduino從作爲主站時,SCL是一旦傳輸結束設置爲高。

+0

只注意到我忘了,開始我消息「你好」,遺憾的是缺乏禮貌...... – ricothebrol

回答

1

我注意到的一件事是發送從地址後,您正在等待ACK(ACKSTAT),然後等待SSPIF中斷標誌,但是在數據字節後沒有檢查SSPIF。你只是檢查ACKSTAT。在設置PEN來斷言停止條件之前,可能試着等待並清除SSPIF?

發生此問題時是否檢查了SSPCON和SSPSTAT寄存器的狀態,這可能有助於縮小問題的位置。

0

非常感謝您的回答!

我加載數據字節後清零了SSP1IF,現在工作正常!

我想我現在明白髮生了什麼:數據表指示ACKSTAT是唯一的寄存器位,它在SCL的上升沿發生反應,而不是其他位的下降沿。所以在我的代碼中,我過早地產生了停止條件,這可能會使其不起作用。因此,不會產生停止條件,SCL卡住低電平,並且下一次傳輸無法啓動。此外,當我等待STOP條件完成時,SSP1IF標誌仍然置1,因此他實際上並沒有等待並直接跳轉到delay()函數。無論如何,我不知道這個問題是否重要,但如果我曾試圖一個接一個地發送數據包,那麼這個問題可能會很重要。

所以,我在這裏是我寫的功能,這是工作: (順便說一句可能需要多達255個數據字節)

void MasterWrite(char _size, char* _data) 
{ 
    // Generate a START condition by setting Start Enable bit 
    SSP1CON2bits.SEN = 1; 
    // Wait for START to be completed 
    while(!PIR1bits.SSPIF); 
    // Clear flag 
    PIR1bits.SSPIF = 0; 
    // Load the address + RW byte in SSP1BUF 
    // Address = 85 ; request type = WRITE (0) 
    SSP1BUF = 0b10101010; 
    // Wait for ack 
    while (SSP1CON2bits.ACKSTAT); 
    // Wait for MSSP interrupt 
    while (!PIR1bits.SSPIF); 
    // Clear flag 
    PIR1bits.SSPIF = 0; 

    for (int i=0; i<_size; i++) 
    { 
     // Load data in SSP1BUF 
     SSP1BUF = *(_data+i); 
     // Wait for ack 
     while (SSP1CON2bits.ACKSTAT); 
     // Wait for MSSP interrupt 
     while (!PIR1bits.SSPIF); 
     // Clear flag 
     PIR1bits.SSPIF = 0; 
    } 

    // Generate a STOP condition 
    SSP1CON2bits.PEN = 1; 
    // Wait for STOP to be completed 
    while(!PIR1bits.SSPIF); 
    // Clear flag 
    PIR1bits.SSPIF = 0; 
} 

感謝名單了很多再次感謝您的幫助!

此致敬禮。

埃裏克