I²;用PIC18F45K50进行C主写:保持SCL低

I²;用PIC18F45K50进行C主写:保持SCL低,pic,i2c,mplab,pic18,Pic,I2c,Mplab,Pic18,我正在根据微芯片的数据表编写自己的I²C主写函数。我使用的是MPLAB X。我使用代码配置器生成了配置,但这里有一些有趣的地方: // 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; /

我正在根据微芯片的数据表编写自己的I²C主写函数。我使用的是MPLAB X。我使用代码配置器生成了配置,但这里有一些有趣的地方:

// 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

我尝试按照数据表第238页所述的程序进行操作:

这是我的密码:

#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);
    }
}
#包括“mcc_生成的文件/mcc.h”
#包括
#定义频率16000000
#定义RTS_PIN端口dbits.RD3
#定义CTS_引脚端口dbits.RD2
#定义LED_引脚PORTAbits.RA1
#定义RX_标志PORTAbits.RA2
uint8_t c;
//为printf()定义putch()
无效putch(字符c)
{
EUSART1_写入(c);
}
真空总管(真空)
{
//初始化设备
系统初始化();
而(1)
{
//通过设置启动启用位生成启动条件
SSP1CON2bits.SEN=1;
//等待启动完成
而(!PIR1bits.SSPIF);
//旗帜
PIR1bits.SSPIF=0;
//在SSP1BUF中加载地址+RW字节
//地址=85;请求类型=WRITE(0)
SSP1BUF=0b10101010;
//等待确认
while(SSP1CON2bits.ACKSTAT);
//等待MSSP中断
而(!PIR1bits.SSPIF);
//在SSP1BUF中加载数据(0x11)
SSP1BUF=0x11;
//等待确认
while(SSP1CON2bits.ACKSTAT);
//生成停止条件
SSP1CON2bits.PEN=1;
//等待停止完成
而(!PIR1bits.SSPIF);
//旗帜
PIR1bits.SSPIF=0;
//在发送下一个字节之前,请等待1s
__延迟μms(1000);
}
}
从设备是一个Arduino,我已经用另一个Arduino(主设备)进行了测试,以确保它正常工作

我的问题是:用逻辑分析仪分析SDA/SCL信号,当我启动PIC时,我得到2条正确的消息,即正确的地址发送和字节传输,但在第二个SCL结束时保持低,这使得所有其他写入都不好(如果SCL保持低,则无法获得正确的启动条件)。顺便说一句,在第一次传输结束时,SCL保持在低电平3毫秒左右,但随后又毫无理由地变高

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

提前准备好

致以最良好的祝愿

埃里克


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

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


发生此行为时,您是否检查了SSPCON和SSPSTAT寄存器的状态,这可能有助于缩小问题所在的范围。

非常感谢您的回答

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

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

此外,当我等待STOP条件完成时,仍然设置了SSP1IF标志,因此他实际上并不等待,而是直接跳到delay()函数。我不知道在他等待时这是否重要,但如果我试图一个接一个地发送数据包,这可能会很重要

这是我写的函数,它正在工作: (顺便说一句,它最多可以占用255个数据字节)

void主写(字符大小,字符*数据)
{
//通过设置启动启用位生成启动条件
SSP1CON2bits.SEN=1;
//等待启动完成
而(!PIR1bits.SSPIF);
//旗帜
PIR1bits.SSPIF=0;
//在SSP1BUF中加载地址+RW字节
//地址=85;请求类型=WRITE(0)
SSP1BUF=0b10101010;
//等待确认
while(SSP1CON2bits.ACKSTAT);
//等待MSSP中断
而(!PIR1bits.SSPIF);
//旗帜
PIR1bits.SSPIF=0;

对于(int i=0;我只是注意到我忘了用“你好”开头我的消息,很抱歉我没有礼貌。。。
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;
}