使用PIC18F45K50进行I²C主控写操作:使SCL保持低电平

时间:2017-10-07 18:09:35

标签: pic i2c mplab pic18

我正在根据Microchip的数据表编写自己的I²C主写功能。我正在使用MPLAB X.我使用Code Configurator生成了配置,但这里有一些有趣的内容:

// 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保持时间,主模式,clokck频率约为50kHz。

我尝试按照数据表的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(Master)测试过,以确保它正常工作。

我的问题是:使用逻辑分析仪分析SDA / SCL信号,当我启动PIC时,我得到2条正确的消息,即正确的地址发送和字节传输,但在第二个SCL结束时保持低电平,这使得所有其他文字都不好(如果SCL保持低电平,则不能有正确的START条件)。顺便说一句,在第一次传输结束时,SCL保持低电平持续3ms,但是没有任何理由再次变为高电平。

这里有人能指出我做错了什么吗?我忘了什么吗?

提前完成。

最好的问候。

埃里克

PS:当用另一个Arduino作为主设备测试从设备时,一旦传输结束,SCL就会设置为高电平。

2 个答案:

答案 0 :(得分:1)

我注意到的一件事是,在发送从机地址后,您正在等待ACK(ACKSTAT),然后等待SSPIF中断标志,但是您没有在数据字节后检查SSPIF。您只是在检查ACKSTAT。也许在设置PEN以断言停止条件之前,请尝试等待并清除SSPIF?

当出现这种情况时,您是否检查过SSPCON和SSPSTAT寄存器的状态,这可能有助于缩小问题所在。

答案 1 :(得分:0)

Thanx很多你的答案!

我在加载数据字节后清除了SSP1IF,现在它工作正常!

我想我现在明白发生了什么:数据表显示ACKSTAT是唯一在SCL上升沿作出反应的寄存器位,而不是其他位的下降沿。因此,在我的代码中,我过早地生成STOP条件,这可能会使其无法运行。因此,不会产生STOP条件,SCL被拉低,并且无法启动下一次传输。

此外,当我等待STOP条件完成时,SSP1IF标志仍然设置,因此他实际上并没有等待并直接跳转到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;
}

再次为你提供帮助!

最好的问候。

埃里克