接收"未定义的符号" XC8与plib I2C功能有关的错误

时间:2014-08-10 00:56:31

标签: c pic microchip mplab xc8

嘿那里有StackOverflow!

我的问题是在下面粘贴的程序中报告错误。目标器件是 PIC12LF1552 ,它上面有一个串行外设,我假设它可以与Microchip的XC8编译器提供的库一起使用。互联网上的一些消息人士表示,只有PIC18系列中的高端设备才支持库函数,其他消息来源表示库函数工作正常。所以我决定不想从头开始重写I2C函数,也不想为这个项目编写任何数量的汇编。因此,我决定使用随附的XC8外设库。我阅读了编译器文档,了解如何获取它们(如下面的i2c.h所示)。我知道根据文档和我见过的一些例子对这些命令进行了一些错误检查,但暂时我假设主人和奴隶都表现得很完美,所以我可以把这件事搞定地面。

我已经包含了所有相关路径,这就是为什么我认为它在编译过程中得到了这么多。我在C语言和编译器的内部工作方面的知识水平非常有限,我只知道如何在基本级别使用这些工具,所以我可能会缺少一些基本的东西。

无论如何,当我在MPLABX v1.95中编译这段代码时,我得到了这个:

:0: error: undefined symbols: _AckI2C(dist/pickit3/production\strobe.X.production.obj) _ReadI2C(dist/pickit3/production\strobe.X.production.obj) _IdleI2C(dist/pickit3/production\strobe.X.production.obj) _OpenI2C(dist/pickit3/production\strobe.X.production.obj) _StopI2C(dist/pickit3/production\strobe.X.production.obj) _NotAckI2C(dist/pickit3/production\strobe.X.production.obj) _WriteI2C(dist/pickit3/production\strobe.X.production.obj) _StartI2C(dist/pickit3/production\strobe.X.production.obj)

我无法在Google,StackOverflow或其他方面找到与我的具体情况相关的任何相关内容(另一个人在从Microchip的传统C18编译器移植时遇到了类似的问题,但我已经做了所有人要解决的问题他的问题)。

所以我想,问题是,为什么我得到这个编译器错误,C语言或Microchip实现它的原因是什么导致了这个?

/* 
 * File:   i2c.h
 * Author: James
 *
 * Created on July 23, 2014, 9:02 PM
 */

#ifndef I2C_H
#define I2C_H

#ifdef  __cplusplus
extern "C" {
#endif

#ifdef  __cplusplus
}
#endif

#include <plib\pconfig.h>
#include <plib\i2c.h>

#define SLAVE_ADDRESS 0b11110000

void Connect();
void Disconnect();
void Read(unsigned char address, unsigned char * data, unsigned char length);
void Write(unsigned char address, unsigned char * data, unsigned char length);

#endif  /* I2C_H */


#include "i2c.h"

void Connect()
{
    OpenI2C(MASTER, SLEW_OFF);
}

void Disconnect()
{
    CloseI2C();
}

void Read(unsigned char address, unsigned char * data, unsigned char length)
{
    IdleI2C();                                          // Wait until the bus is idle
    StartI2C();                                         // Send START condition
    IdleI2C();                                          // Wait for the end of the START condition
    if (WriteI2C(SLAVE_ADDRESS | 0x01)) return;         // Send slave address with R/W cleared for write
    IdleI2C();                                          // Wait for ACK
    if (WriteI2C(address)) return;                      // Send register address
    IdleI2C();                                          // Wait for ACK
    for(int i = 0; i < length; i++)
    {
        data[i] = ReadI2C();                            // Write nth byte of data
        AckI2C();                                       // Wait for ACK
    }
    NotAckI2C();                                        // Send NACK
    StopI2C();                                          // Hang up, send STOP condition
}

void Write(unsigned char address, unsigned char * data, unsigned char length)
{
    IdleI2C();                                          // Wait until the bus is idle
    StartI2C();                                         // Send START condition
    IdleI2C();                                          // Wait for the end of the START condition
    if (WriteI2C(SLAVE_ADDRESS | 0x01)) return;         // Send slave address with R/W cleared for write
    IdleI2C();                                          // Wait for ACK
    if (WriteI2C(address)) return;                      // Send register address
    IdleI2C();                                          // Wait for ACK
    for(int i = 0; i < length; i++)
    {
        WriteI2C(data[i]);                              // Write nth byte of data
        IdleI2C();                                      // Wait for ACK
    }
    StopI2C();                                          // Hang up, send STOP condition
}

/* 
 * File:   main.c
 * Author: James
 *
 * Created on July 14, 2014, 11:00 PM
 */

/******************************************************************************/
/* Files to Include                                                           */
/******************************************************************************/

#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#endif

#include <stdint.h>        /* For uint8_t definition */
#include <stdbool.h>       /* For true/false definition */
#include <stdio.h>
#include <stdlib.h>
#include <pic12lf1552.h>
#include "i2c.h"

/******************************************************************************/
/* Defines                                                                    */
/******************************************************************************/

//#define SYS_FREQ        16000000L
//#define FCY             SYS_FREQ/4
#define _XTAL_FREQ      500000

__CONFIG
(
    MCLRE_ON &
    CP_OFF &
    BOREN_OFF &
    WDTE_OFF &
    PWRTE_OFF &
    FOSC_INTOSC
);

void main(void)
{
    ANSELA = 0;
    TRISA = 0b101111;
    OPTION_REG = 0b01111111;
    APFCONbits.SDSEL = 1;

    unsigned char state = 0;
    unsigned char count = 0;
    unsigned char data[8] = { 0 };

    Connect();
    Read
    (
        0x01, // System register
        data, // Data buffer
        0x01  // Read length
    );
    LATAbits.LATA4 = data[0];

    while(1)
    {
        switch (state)
        {
            case 0: // IDLE/OFF
                if (LATAbits.LATA4) LATAbits.LATA4 = 0;
                break;
            case 1: // ON
                if (!LATAbits.LATA4) LATAbits.LATA4 = 1;
                break;
            case 2: // BLINK (slow)
                LATAbits.LATA4 = !LATAbits.LATA4;
                __delay_ms(100);
                break;
            case 3: // BLINK (fast)
                LATAbits.LATA4 = !LATAbits.LATA4;
                __delay_ms(50);
                break;
            case 4: // BEAT DETECT
                LATAbits.LATA4 = PORTAbits.RA5;
                break;
            default:
                state = 0;
                break;
        }

        if (TMR0 > 0)
        {
            while (count < 20)
            {
                if (!PORTAbits.RA2) count = 0;
                __delay_ms(10);
                count++;
            }
            TMR0 = 0;
            state++;
        }
    }
}

2 个答案:

答案 0 :(得分:2)

问题定义

这里的核心问题是Microchip XC8外设库与其前身C18外设库一样,不支持PIC18系列之外的微控制器。因此,有一大堆头文件可以正确配置外设,所有寄存器宏都是PIC18专用的,尽管有很多相似之处。

解决方案/解决方法

但是,由于Microchip在此目录中提供了外围库的源:/path/to/xc8/install/directory/version/sources/pic18/plib

特别是在我的情况下,对于Windows x64机器上的i2c源: C:\Program Files (x86)\Microchip\xc8\v1.21\sources\pic18\plib\i2c

对于 PIC12LF1552 ,芯片有一个MSSP,因此您需要复制i2c _ * .c源并连接它们,如果您的PC上有任何Linux / Unix实用程序,则可以这样做:cat i2c_* > i2c.c

现在,首先,要么删除文件中定义的所有I2C版本,要么更简单地,进入当前构建配置文件下的xc8编译器设置并设置以下定义宏:I2C_V1 < / p>

之后,您需要从v1.21版本的源代码中进行一些修改,以便与设备兼容:

  • 在您的i2c.c版本的标头文件中放置:#include <pic12lf1552.h>,以便其余代码具有所有寄存器定义
  • i2c.h中添加SDA和SCL引脚的定义,以便OpenI2C()可以工作或者只是将OpenI2C()更改为特定于设备:
    • #define I2C_SCL TRISAbits.TRISA1
    • #define I2C_SDA TRISAbits.TRISA2TRISAbits.TRISA3取决于您的APFCONbits.SDSEL设置。虽然在PIC12LF1552上,RA3始终设置为输入。
  • 需要更改以下注册字段:
    • SSPSTATbits.R_W -> SSPSTATbits.R_nW
    • PIR1bits.SSPIF -> PIR1bits.SSP1IF
    • PIR2bits.BCLIF -> PIR2bits.BCL1IF
    • 后两个我觉得奇怪,因为数据表仍然在IF之前没有定义它们,但谁知道,也许Microchip有一个特殊的内部原因

在完成所有这些之后,你仍然需要编写自己的包装器来执行主/从模式的基本完全形成的功能,正如我在我的问题中所做的那样。

小意见

这整个过程比拔牙更糟糕,可以这么说。 Microchip的社区是傲慢或不屑一顾(“使用汇编”,“自己写”,等等)。 Microchip自己的支持也无济于事。除此之外,实际代码需要非常小的面向细节的更改,几乎没有任何意义,IF -> 1IF认真对待?在完成所有这些之后,您需要为这些函数编写自己的包装器以进行逻辑I2C事务,更不用说测试整个设备以确保它不会落在它的脸上。难怪没有自定义布局和/或成本要求的人使用Arduinos。

答案 1 :(得分:0)

  • 考虑采用重写i2c lib代码的方法 MC plib代码作为起点。它可能比做一个快 转换。另外,考虑另一个编译器,如来自CCS的编译器 - 他们可能拥有一个更强大,文档齐全的图书馆(有任何人 试过这个?)

    是的,MC的文档有时令人沮丧。不知道为什么十亿美元合作。不能做得更好。并非所有函数和宏都是 记录,有时候这些例子不太现实,比如 i2c eeprom代码的示例。

    我也遇到了这个lib的问题,因为代码使用了阻塞IO调用,并且无法从总线问题中恢复。示例:我 我正在制作一块用i2c设备测试PCB的测试设备。 但是如果连接在plib操作期间被中断,那么 plib代码无法再访问PIC18 i2c端口。这是 一件测试装置是不可接受的。