XC8 收到有关 plib I2C 函数的“未定义符号”错误

2023-12-19

嘿,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++;
        }
    }
}

问题定义

这里的核心问题是,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

For the PIC12LF1552,该芯片有一个 MSSP,因此您需要复制 i2c_*.c 源并将它们连接起来,如果您的 PC 上有任何 Linux/Unix 实用程序,您可以执行以下操作:cat i2c_* > i2c.c

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

之后,您需要对 v1.21 版本的源代码进行一些修改才能与设备兼容:

  • 在您的版本的头文件中i2c.c put: #include <pic12lf1552.h>这样代码的其余部分就有了所有寄存器定义
  • Add the defines for your SDA and SCL pins in i2c.h so that OpenI2C() works or simply change OpenI2C() to be specific to the device:
    • #define I2C_SCL TRISAbits.TRISA1
    • #define I2C_SDA TRISAbits.TRISA2 OR TRISAbits.TRISA3取决于你的APFCONbits.SDSEL环境。尽管在 PIC12LF1552 上,RA3 始终设置为输入。
  • The following register fields need to be changed:
    • SSPSTATbits.R_W -> SSPSTATbits.R_nW
    • PIR1bits.SSPIF -> PIR1bits.SSP1IF
    • PIR2bits.BCLIF -> PIR2bits.BCL1IF
    • 我发现后两者很奇怪,因为数据表仍然定义了它们,而 IF 之前没有 1,但谁知道呢,也许 Microchip 有一个特殊的内部原因

毕竟,您仍然需要编写自己的包装器来执行主/从模式的基本完整函数,正如我在问题中所提到的那样。

小意见

可以说,整个过程比拔牙还糟糕。 Microchip 的社区傲慢或不屑一顾(“使用汇编”、“自己编写”等等)。 Microchip 自己的支持也无济于事。最重要的是,实际代码需要非常小的面向细节的更改,这几乎没有意义,IF -> 1IF严重地?毕竟,您需要为这些函数编写自己的包装器以进行逻辑 I2C 事务,更不用说测试整个设备以确保它不会摔倒了。难怪没有自定义布局和/或成本要求的人们会使用 Arduino。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

XC8 收到有关 plib I2C 函数的“未定义符号”错误 的相关文章

  • 为什么存在 async 关键字

    浏览 msdn 9 频道视频时 我发现以下未答复的评论 希望有人能解释一下 我不明白 async 关键字的意义 为什么不直接允许 任何时候方法返回任务时都会使用await关键字 就像迭代器一样 可以在任何返回 IEnumerable 的方法
  • 具有不同大小结构的结构数组的 malloc()

    如果每个结构都包含一个大小不同的字符串数组 那么如何正确地 malloc 一个结构数组 因此每个结构可能有不同的大小 并且不可能 realloc 结构体数量 sizeof 结构体名称 after malloc 初始大小 sizeof 结构名
  • Subversion 和 Visual Studio 项目的最佳实践

    我最近开始在 Visual Studio 中处理各种 C 项目 作为大型系统计划的一部分 该系统将用于替换我们当前的系统 该系统是由用 C 和 Perl 编写的各种程序和脚本拼凑而成的 我现在正在进行的项目已经达到了颠覆的临界点 我想知道什
  • 为什么Apache MPM prefork.c 使用互斥体来保护accept()?

    我坐下来读书Apache 的 MPM prefork c http code metager de source xref apache httpd server mpm prefork prefork c这段代码使用了一个名为accept
  • 如何尝试/捕获所有异常

    我正在完成由其他人启动的 UWP 应用程序 该应用程序经常崩溃 我总是陷入困境应用程序 at if global System Diagnostics Debugger IsAttached global System Diagnostic
  • (const T v) 在 C 中从来都不是必需的,对吗?

    例如 void func const int i 在这里 const是不必要的 因为所有参数都是按值传递的 包括指针 真的吗 C 中的所有参数确实都是按值传递 这意味着无论您是否包含该参数 实际参数都不会改变const or not 然而
  • CultureInfo 的实例(来自相同的文化)根据操作系统而变化

    我有一个网站 上面写着这样的日期 CultureInfo cultureInfo CultureInfo GetCultures CultureTypes AllCultures FirstOrDefault c gt string Equ
  • 从 C 结构生成 C# 结构

    我有几十个 C 结构 我需要在 C 中使用它们 典型的 C 结构如下所示 typedef struct UM EVENT ULONG32 Id ULONG32 Orgin ULONG32 OperationType ULONG32 Size
  • 带 If 的嵌套 For 循环的时间复杂度

    void f int n for int i 1 i lt n i if i int sqrt n 0 for int k 0 k lt pow i 3 k do something 我的思考过程 执行if语句的次数 sum i 1 to
  • 如何将带有自定义分配器的 std::vector 传递给需要带有 std::allocator 的函数?

    我正在使用外部库 pcl 因此我需要一个不会更改现有函数原型的解决方案 我正在使用的一个函数生成一个std vector
  • HttpWebRequest vs Webclient(特殊场景)

    我知道这个问题之前已经回答过thread https stackoverflow com questions 1694388 webclient vs httpwebrequest httpwebresponse 但我似乎找不到详细信息 在
  • TcpClient 在异步读取期间断开连接

    我有几个关于完成 tcp 连接的问题 客户端使用 Tcp 连接到我的服务器 在接受客户端后listener BeginAcceptTcpClient ConnectionEstabilishedCallback null 我开始阅读netw
  • 为什么 clang 使用 -O0 生成低效的 asm(对于这个简单的浮点和)?

    我正在 llvm clang Apple LLVM 版本 8 0 0 clang 800 0 42 1 上反汇编此代码 int main float a 0 151234 float b 0 2 float c a b printf f c
  • 预处理后解析 C++ 源文件

    我正在尝试分析c 使用我定制的解析器的文件 写在c 在开始解析之前 我想摆脱所有 define 我希望源文件在预处理后可以编译 所以最好的方法是运行C Preprocessor在文件上 cpp myfile cpp temp cpp or
  • OpenCV 2.4.3 中的阴影去除

    我正在使用 OpenCV 2 4 3 最新版本 使用内置的视频流检测前景GMG http docs opencv org modules gpu doc video html highlight gmg gpu 3a 3aGMG GPU算法
  • WPF。如何从另一个窗口隐藏/显示主窗口

    我有两个窗口 MainWindow 和 Login 显示登录的按钮位于主窗口 this Hide Login li new Login li Show 登录窗口上有一个检查密码的按钮 如果密码正确 我如何显示主窗口 将参数传递给 MainW
  • 初始化 LPCTSTR /LPCWSTR [重复]

    这个问题在这里已经有答案了 我很难理解并使其正常工作 基本上归结为我无法成功初始化这种类型的变量 它需要有说的内容7 2E25DC9D 0 USB003 有人可以解释 展示这种类型的正确初始化和类似的值吗 我已查看此站点上的所有帮助 将项目
  • 使用 HTMLAgilityPack 从节点的子节点中选择所有

    我有以下代码用于获取 html 页面 将网址设置为绝对 然后将链接设置为 rel nofollow 并在新窗口 选项卡中打开 我的问题是关于将属性添加到 a s string url http www mysite com string s
  • Visual Studio 2017 完全支持 C99 吗?

    Visual Studio 的最新版本改进了对 C99 的支持 最新版本VS2017现在支持所有C99吗 如果没有 C99 还缺少哪些功能 No https learn microsoft com en us cpp visual cpp
  • 受限 AppDomain 中的代码访问安全异常

    Goal 我需要在权限非常有限的 AppDomain 中运行一些代码 它不应该访问任何花哨或不安全的内容 except对于我在其他地方定义的一些辅助方法 我做了什么 我正在创建一个具有所需基本权限的沙箱 AppDomain 并创建一个运行代

随机推荐