• [技术干货] C++ 调用C#的DLL
    理论知识在C++中直接调用C#并传递String^(这看起来像是C++/CLI中的托管字符串类型)和C#对象是比较复杂的,因为C++和C#是两种不同的编程语言,运行在不同的运行时环境中。但是,你可以通过几种方法来实现这种交互:使用C++/CLI作为桥梁: 你可以使用C++/CLI来编写一个包装器类,该类可以在C++和C#之间传递数据。C++/CLI允许你在C++代码中使用.NET类型,并可以很容易地与C#代码交互。**使用P/Invoke或C++/CX (COM)**: 如果你的C#代码暴露为COM组件或DLL(使用C++/CX或P/Invoke),则可以从C++代码中调用它。但是,这通常不直接支持传递C#对象;你可能需要将这些对象序列化为字节数组或其他可以在两种语言之间传递的类型。**使用IPC (进程间通信)**: 你可以使用命名管道、WCF、TCP/IP套接字或其他IPC机制在C++和C#进程之间传递数据。这允许你在两个独立的进程中进行通信,每个进程都可以使用它自己的语言运行时。使用C#的DLLImport: 如果你的C++代码是编译为DLL的,并且你希望从C#中调用它,你可以使用C#的DllImport属性来导入C++函数。但是,这通常只适用于简单的C函数,而不是C++类或对象。对于你的情况,一个使用C++/CLI作为桥梁的简单示例可能如下所示:代码实战C#代码 (YourCSharpLibrary.dll)public class YourCSharpClass { public string YourMethod(string input) { // ... 处理输入并返回结果 ... return "Processed: " + input; } }C++/CLI代码 (YourBridge.dll)// YourBridge.cpp #include "YourBridge.h" #using "YourCSharpLibrary.dll" as_friend YourCSharpClass^ CreateCSharpObject() { return gcnew YourCSharpClass(); } String^ CallCSharpMethod(YourCSharpClass^ obj, String^ input) { return obj->YourMethod(input); }C++代码 (调用C++/CLI)// YourNativeCppCode.cpp #include <iostream> #include <msclr/marshal_cppstd.h> // 用于字符串转换(如果需要) #using "YourBridge.dll" int main() { YourCSharpClass^ obj = CreateCSharpObject(); String^ csharpString = gcnew String("Hello from C++"); String^ result = CallCSharpMethod(obj, csharpString); // 如果需要,将String^转换为std::string msclr::auto_gcroot<System::String^> resultWrapped(result); std::string stdResult = msclr::interop::marshal_as<std::string>(resultWrapped); std::cout << "Result from C#: " << stdResult << std::endl; return 0; }请注意,这个示例假设你已经有了C#库(YourCSharpLibrary.dll)和C++/CLI桥接库(YourBridge.dll)。C++/CLI桥接库负责在C++和C#之间转换和管理对象。在C++代码中,你通过C++/CLI桥接库来创建C#对象、调用C#方法,并在需要时转换数据类型。注意C# 是托管对象,C++ 是非托管对象,在参数传递的时候有很多限制。例如,不能把C#的托管对象传给C++的线程,这点一定要注意甄别
  • [技术干货] C++ 在类中创建并使用线程
    thread库在C++中,你可以使用<thread>库来在类中创建线程。然而,直接在类的成员函数中启动线程可能不是一个好主意,因为线程的生命周期和对象的生命周期可能会变得难以管理。但你可以通过在类的成员函数或成员变量中封装线程创建的逻辑来实现这一功能。简单线程示例以下是一个简单的示例,展示了如何在C++类的成员函数中启动一个线程:#include <iostream> #include <thread> #include <chrono> class MyClass { public: MyClass() : threadPtr(nullptr) {} // 启动线程的成员函数 void startThread() { // 检查线程是否已经在运行 if (threadPtr == nullptr) { // 使用lambda表达式捕获this指针,以便在线程中访问类的成员 threadPtr = std::make_unique<std::thread>([this]() { this->runInThread(); }); } else { std::cout << "Thread is already running!" << std::endl; } } // 线程执行的函数 void runInThread() { for (int i = 0; i < 5; ++i) { std::cout << "Running in thread: " << i << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); } } // 等待线程完成 void joinThread() { if (threadPtr != nullptr && threadPtr->joinable()) { threadPtr->join(); threadPtr.reset(); // 释放线程对象 } } private: std::unique_ptr<std::thread> threadPtr; // 使用unique_ptr管理线程对象的生命周期 }; int main() { MyClass obj; obj.startThread(); // 启动线程 // 让主线程等待一段时间,以便观察子线程的输出 std::this_thread::sleep_for(std::chrono::seconds(6)); obj.joinThread(); // 等待线程完成 return 0; }在这个示例中,MyClass类有一个成员变量threadPtr,它是一个std::unique_ptr<std::thread>类型,用于管理线程对象的生命周期。startThread成员函数检查线程是否已经在运行,如果没有,则创建一个新线程来执行runInThread成员函数。joinThread成员函数用于等待线程完成并释放线程对象。注意,在捕获this指针时要小心,因为如果对象在线程执行期间被销毁,这可能会导致未定义的行为。在这个示例中,我们通过使用std::unique_ptr来确保线程对象在线程完成后被正确销毁。线程传参如果你需要在startThread函数中传递一些参数到线程执行的函数中,你可以通过几种方式来实现。以下是一个示例,展示了如何使用std::bind或lambda表达式来传递参数:使用std::bind#include <iostream> #include <thread> #include <chrono> #include <functional> class MyClass { public: MyClass() : threadPtr(nullptr) {} // 启动线程的成员函数,接受一个int参数 void startThread(int param) { // 检查线程是否已经在运行 if (threadPtr == nullptr) { // 使用std::bind将参数绑定到成员函数上 threadPtr = std::make_unique<std::thread>(std::bind(&MyClass::runInThread, this, param)); } else { std::cout << "Thread is already running!" << std::endl; } } // 线程执行的函数,接受一个int参数 void runInThread(int param) { for (int i = 0; i < 5; ++i) { std::cout << "Running in thread with param: " << param << ", count: " << i << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); } } // 等待线程完成 void joinThread() { if (threadPtr != nullptr && threadPtr->joinable()) { threadPtr->join(); threadPtr.reset(); // 释放线程对象 } } private: std::unique_ptr<std::thread> threadPtr; // 使用unique_ptr管理线程对象的生命周期 }; int main() { MyClass obj; obj.startThread(42); // 启动线程并传递参数42 // 让主线程等待一段时间,以便观察子线程的输出 std::this_thread::sleep_for(std::chrono::seconds(6)); obj.joinThread(); // 等待线程完成 return 0; }使用Lambda表达式// ... 省略其他部分 ... void startThread(int param) { // 检查线程是否已经在运行 if (threadPtr == nullptr) { // 使用lambda表达式捕获this指针和param参数 threadPtr = std::make_unique<std::thread>([this, param]() { this->runInThread(param); }); } else { std::cout << "Thread is already running!" << std::endl; } } // ... 省略其他部分 ... int main() { MyClass obj; obj.startThread(42); // 启动线程并传递参数42 // ... 省略其他部分 ... }在这两个示例中,我们都修改了startThread函数以接受一个int参数,并将该参数传递给线程执行的函数runInThread。在第一个示例中,我们使用std::bind来绑定参数和成员函数,而在第二个示例中,我们使用lambda表达式来捕获参数并调用成员函数。两种方法都可以实现相同的效果。
  • [问题求助] 【MDC300】在mini0上运行编译生成文件报错
    运行了MDC300sample-1.0.107.2中的Ascendcl_sample,模型推理和编译都没有问题,把最终生成的编译文件bin,模型文件model,图片image发到mini上面运行,结果报错。
  • [问题求助] iot studio软件按照步骤安装,编译显示Arm-none-eabi-gcc:致命错误:没有输入文件编译终止。
    iot studio软件按照步骤安装,编译显示Arm-none-eabi-gcc:致命错误:没有输入文件编译终止。
  • [常见FAQ] 选手程序输出异常
    本地和判题器交互正常,有最终得分。但是线上提交显示:选手程序输出异常。
  • [问题求助] atlas 300,在开发环境中(x86),安装样例中samples/cplusplus/common/acllite库时,make报错
    报错如下:/usr/bin/ld: cannot find -lavdevice /usr/bin/ld: cannot find -lavfilter collect2: error: ld returned 1 exit status make: *** [out/x86_64/libacllite.so] Error 1 在路径下THIRDPART_PATH,目前只有安装好的ffmpeg包,/usr/local/Ascend/thirdpart/aarch64/ffmpeg/环境变量如下:开发端--x86export INSTALL_DIR=/usr/local/Ascend/ascend-toolkit/latest export INSTALL_DIR_ARM=/usr/local/Ascend/ascend-toolkit/ascend-toolkit_arm/latest/aarch64-linux export PATH=$PATH:/usr/local/bin/cmake:${INSTALL_DIR}/atc/ccec_compiler/bin:${INSTALL_DIR}/atc/bin:${INSTALL_DIR}/bin:${INSTALL_DIR}/compiler/ccec_compiler/bin export LD_LIBRARY_PATH=${INSTALL_DIR}/acllib/lib64:${INSTALL_DIR}/atc/lib64:/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/runtime/lib64/stub:$LD_LIBRARY_PATH export ASCEND_OPP_PATH=${INSTALL_DIR}/opp export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest/aarch64-linux export PYTHONPATH=${INSTALL_DIR}/atc/python/site-packages:${INSTALL_DIR}/opp/built-in/op_impl/ai_core/tbe:$PYTHONPATH export TOOLCHAIN_HOME=${INSTALL_DIR}/toolkit export ASCEND_HOME_PATH=${INSTALL_DIR} export DDK_PATH=/usr/local/Ascend/ascend-toolkit/latest/arm64-linux export NPU_HOST_LIB=${DDK_PATH}/runtime/lib64/stub export CPU_ARCH=`arch` export THIRDPART_PATH=/usr/local/Ascend/thirdpart/${CPU_ARCH} 
  • [问题求助] 在arm中,将数据写入device时,报错malloc device data buffer failed, aclRet is 107002
    报错代码如下:void* AtlasEngine::CopyDataToDevice(void* data, uint32_t dataSize, aclrtMemcpyKind policy) {    void* buffer = nullptr;    aclError aclRet = aclrtMalloc(&buffer, dataSize, ACL_MEM_MALLOC_HUGE_FIRST);    if (aclRet != ACL_SUCCESS) {        ERROR_LOG("malloc device data buffer failed, aclRet is %d", aclRet);        return nullptr;    }根据错误码,也检查了context,返回的是create context success,是创建成功的;aclrtSetDevice(deviceId_);也是成功的, ret = aclrtCreateContext(&context_, deviceId_);    if (ret != ACL_SUCCESS) {        ERROR_LOG("acl create context failed, deviceId = %d, errorCode = %d",            deviceId_, static_cast<int32_t>(ret));        return FAILED;    }    INFO_LOG("create context success");
  • [技术干货] 64位MFC调用32位DLL
    当64位MFC应用程序调用32位DLL时,你可以通过创建一个中间层Wrapper DLL来实现。下面是一个简单的示例,演示如何从64位MFC应用程序调用32位DLL的函数:假设你有一个32位DLL,其中包含一个名为MyFunction的函数,它接受一个整数参数并返回一个整数。你想从64位MFC应用程序中调用这个函数。首先,创建一个新的64位DLL项目(Wrapper DLL),用于与32位DLL进行交互。在这个64位DLL项目中,编写一个导出函数,该函数将调用32位DLL的函数。下面是一个简单的例子:// WrapperDLL.h #pragma once #ifdef WRAPPERDLL_EXPORTS #define WRAPPERDLL_API __declspec(dllexport) #else #define WRAPPERDLL_API __declspec(dllimport) #endif extern "C" WRAPPERDLL_API int CallMyFunction(int value);// WrapperDLL.cpp #include "WrapperDLL.h" #include "windows.h" typedef int(*MYFUNCTION)(int); int CallMyFunction(int value) { HINSTANCE hDLL = LoadLibrary(L"path_to_32bit_dll.dll"); if (hDLL != NULL) { MYFUNCTION myFunction = (MYFUNCTION)GetProcAddress(hDLL, "MyFunction"); if (myFunction != NULL) { int result = myFunction(value); FreeLibrary(hDLL); return result; } FreeLibrary(hDLL); } return -1; }在这个示例中,我们创建了一个名为CallMyFunction的导出函数。该函数加载32位DLL,并使用GetProcAddress函数获取MyFunction函数的地址。然后,我们将参数传递给32位DLL的函数,并返回结果。接下来,编译这个Wrapper DLL项目,并生成一个64位的DLL文件。然后,在你的64位MFC应用程序中,你可以通过调用CallMyFunction函数来间接调用32位DLL的函数。例如:// MFCAppDlg.cpp (64位MFC应用程序的对话框类文件) #include "WrapperDLL.h" // ... void CMFCAppDlg::OnBnClickedButton1() { int result = CallMyFunction(42); // 处理结果... }这里,我们在MFC应用程序中的按钮单击事件处理程序中调用了CallMyFunction函数,将参数值 42 传递给32位DLL的函数。你可以根据需要使用返回的结果。需要确保在编译64位MFC应用程序和Wrapper DLL时,使用相应的64位编译器选项。此外,还需要将32位DLL的路径替换为你自己的实际路径。这只是一个简单的示例,具体的实现可能因实际情况而有所不同。你可能需要根据32位DLL的特定函数和参数来进行更多的调整和适配。
  • [常见FAQ] C++如何Debug
    文档里说的调试器太简单了   能细说吗?解锁新知识
  • [问题求助] 按照样例操作,执行bash sample_build.sh的时候,编译出错,新人求指导
    正在学习Atlas 200 DK,用了分设环境,CANN是6.0.RC1,固件与驱动版本是1.0.13.alpha,目前卡在开发环境,试了两个C++的检测样例,都是成功模型转换,但在运行提供的bash sample_build.sh编译的时候,都报同样的错,想请教一下有经验的大佬
  • [开发资源] Restful 接口API开发文档
    使用restful接口进行对接和开发时,可以参考附件文档中的说明进行开发20221019:更新最新版本(10-10号发布)
  • [问题求助] 请求文档链接
    请问谁有《IPC V200R003C00 智能元数据结构设计说明书》?谢谢!
  • [问题求助] 捉虫,输入0D/1DTensor,1D张量时shape为1,获取不到(或不正确)获取那唯一元素的值,后来分int64,int32尝试获取了也不行
    固定值的Tensor输入可行,这两种用例随机范围0-10输入,不行原因设备日志显示,在于超时​UT增加用例input_int64_data_type_float,input_int64_data_type_default会有出现过超时bad_alloc,或段错误(调试时是获取不正确,n过大如下):@莫晓忧,有空麻烦上仓帮忙看一下实现和用例两个文件。感谢涛哥和各位版主了!尝试了memcpy_s,5个输入int64ut用例失败。但改上面两个随机Tensor用例为Int32输入,这两个随机x输入用例st设备本地测试也不通过,所以应该只能是cann仓的问题
  • [API使用] 请问想在Qt项目中使用mindspore lite进行推理有没有示例可以参考?
    如题,想在自己的Qt项目中加入mindspore lite的API进行推理,有没有什么示例可以参考?
  • [技术干货] 基于CC2530(ZigBee)设计的景观照明控制系统+配套手机APP
    一、环境介绍编译集成开发环境: IARMCU: CC2530(ZigBee)编程语言: C语言手机APP: 采用QT设计,程序支持跨平台编译运行(Android、IOS、Windows、Linux都可以编译运行,对应平台上QT的环境搭建,之前博客已经发了文章讲解)硬件包含: 3套CC2530开发板(1个协调器、2个节点)、1个ESP8266串口WIFI、1个DHT11温湿度传感器、1个RGB多彩灯、1个BH1750光强度检测传感器.资料包里包含了: CC2530协调器源码、2个节点源码、手机APP源码、Windows上位机源码、手机APP可执行文件、IAR下载器驱动、IAR资料等等。二、功能介绍这是基于CC2530设计的景观照明控制系统,一共包含了3个CC2530节点(就是3块CC2530开发板)。下面将这个3个CC2530开发板称为A、B、C节点。A节点: 当做协调器、可以接收BC节点上传的数据;A模块配了一个ESP8266 WIFI模块,可以连接手机APP,将BC节点上传温湿度数据再上传给手机APP显示。如果A节点在一定时间内没有收到B、C节点的数据,就会通知手机APP,告诉用户,B、C节点已经掉线。B节点: 作为RGB多彩灯+温湿度检测节点,会根据当前温湿度调整当前RGB灯的颜色,用于告诉景区的游客,当前景区的温湿度情况,采集的温湿度也会通过CC2530传递给A节点。C节点: 光照强度检测+LED灯节点。 这里的LED灯就是模拟景区的路灯,手机APP可以控制LED灯的开关,如果是白天的时候,LED灯会自动关掉,天气变暗,自动打开。也可以设计时间,定时关灯。三、相关的硬件介绍3.1 DTH11 温湿度传感器DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性和卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,使其成为该类应用中,在苛刻应用场合的最佳选择。产品为4针单排引脚封装,连接方便。3.2 ESP8266 WIFIESP8266系列无线模块是高性价比WIFI SOC模组,该系列模块支持标准的IEEE802.11b/g/n协议,内置完整的TCP/IP协议栈。用户可以使用该系列模块为现有的设备添加联网功能,也可以构建独立的网络控制器。能卓越ESP8266EX 芯片内置超低功耗 Tensilica L106 32 位 RISC 处理器,CPU 时钟速度最⾼可达 160 MHz,⽀持实时操作系统 (RTOS) 和 Wi-Fi 协议栈,可将⾼达 80% 的处理能⼒应用于编程和开发。高度集成ESP8266 芯片高度集成天线开关、射频巴伦、功率放大器、低噪声接收放大器、滤波器等射频模块。模组尺寸小巧,尤其适用于空间受限的产品设计。认证齐全RF 认证:SRRC、FCC、CE-RED、KCC、TELEC/MIC、IC 和 NCC 认证;环保认证:RoHS、REACH;可靠性认证:HTOL、HTSL、μHAST、TCT、ESD。丰富的产品应用ESP8266 模组既可以通过 ESP-AT 指令固件,为外部主机 MCU 提供 Wi-Fi 连接功能;也可以作为独立 Wi-Fi MCU 运行,用户通过基于 RTOS 的 SDK 开发带 Wi-Fi 连接功能的产品。用户可以轻松实现开箱即用的云连接、低功耗运行模式,以及包括 WPA3 在内的 Wi-Fi 安全支持等功能。3.3 CC2530CC2530 是用于2.4-GHz IEEE 802.15.4、ZigBee 和RF4CE 应用的一个真正的片上系统(SoC)解决方案。它能够以非常低的总的材料成本建立强大的网络节点。CC2530 结合了领先的RF 收发器的优良性能,业界标准的增强型8051 CPU,系统内可编程闪存,8-KB RAM 和许多其它强大的功能。CC2530 有四种不同的闪存版本:CC2530F32/64/128/256,分别具有32/64/128/256KB 的闪存。CC2530 具有不同的运行模式,使得它尤其适应超低功耗要求的系统。运行模式之间的转换时间短进一步确保了低能源消耗。CC2530F256 结合了德州仪器的业界领先的黄金单元ZigBee 协议栈(Z-Stack™),提供了一个强大和完整的ZigBee 解决方案。CC2530F64 结合了德州仪器的黄金单元RemoTI,更好地提供了一个强大和完整的ZigBee RF4CE 远程控制解决方案。3.4 RGB多彩灯颜色:全彩 红绿蓝三基色亮度:高亮电压:5V输入:数字电平三基色原理显示多重颜色通过PWM端口控制实现全彩显示3.5 BH1750** bh1750 是16位数字输出型,环境光强度传感器。**四、节点硬件+手机APP介绍4.1 C节点: 光敏传感器+LED灯控制4.2 B节点: 多彩灯+温湿度4.3 A节点: WIFI + APP4.4 手机APP界面效果五、手机APP上位机源码六、CC2530节点源码节点源码较多,下面就贴一些关键代码。6.1 uart.c#include "uart.h" /* 函数功能:串口0初始化 */ void Init_Uart0(void) { PERCFG&=~(1<<0); //串口0的引脚映射到位置1,即P0_2和P0_3 P0SEL|=0x3<<2; //将P0_2和P0_3端口设置成外设功能 U0BAUD = 216; //32MHz的系统时钟产生115200BPS的波特率 U0GCR&=~(0x1F<<0);//清空波特率指数 U0GCR|=11<<0; //32MHz的系统时钟产生115200BPS的波特率 U0UCR |= 0x80; //禁止流控,8位数据,清除缓冲器 U0CSR |= 0x3<<6; //选择UART模式,使能接收器 } /* 函数功能:UART0发送字符串函数 */ void UR0SendString(u8 *str) { while(*str!='') { U0DBUF = *str; //将要发送的1字节数据写入U0DBUF while(UTX0IF == 0);//等待数据发送完成 UTX0IF = 0; //清除发送完成标志,准备下一次发送 str++; } } /* 函数功能: 模仿printf风格的格式化打印功能 */ char USART0_PRINT_BUFF[200]; //格式化数据缓存数据 void USART0_Printf(const char *format,...) { char *str=NULL; /*1. 格式化转换*/ va_list ap; // va_list---->char * va_start(ap,format); //初始化参数列表 vsprintf(USART0_PRINT_BUFF, format, ap); //格式化打印 va_end(ap); //结束参数获取 /*2. 串口打印*/ str=USART0_PRINT_BUFF;//指针赋值 while(*str!='') { U0DBUF=*str; //发送一个字节的数据 str++; //指针自增,指向下一个数据 while(UTX0IF == 0);//等待数据发送完成 UTX0IF = 0; //清除发送完成标志,准备下一次发送 } }6.2 DHT11.c#include "dht11.h" #include "delay.h" #define DATA_PIN P0_7 //温湿度定义 uchar ucharFLAG,uchartemp; uchar shidu_shi,shidu_ge,wendu_shi,wendu_ge=4; uchar ucharT_data_H,ucharT_data_L,ucharRH_data_H,ucharRH_data_L,ucharcheckdata; uchar ucharT_data_H_temp,ucharT_data_L_temp,ucharRH_data_H_temp,ucharRH_data_L_temp,ucharcheckdata_temp; uchar ucharcomdata; //延时函数 void Delay_us() //1 us延时 { asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); } void Delay_10us() //10 us延时 { #if 0 Delay_us(); Delay_us(); Delay_us(); Delay_us(); Delay_us(); Delay_us(); Delay_us(); Delay_us(); Delay_us(); Delay_us(); #else int i = 10; while(i--); #endif } void Delay_ms(unsigned int Time)//n ms延时 { unsigned char i; while(Time--) { for(i=0;i<100;i++) Delay_10us(); } } //温湿度传感 void COM(void) // 温湿写入 { uchar i; for(i=0;i<8;i++) { ucharFLAG=2; while((!DATA_PIN)&&ucharFLAG++); Delay_10us(); Delay_10us(); Delay_10us(); uchartemp=0; if(DATA_PIN)uchartemp=1; ucharFLAG=2; while((DATA_PIN)&&ucharFLAG++); if(ucharFLAG==1)break; ucharcomdata<<=1; ucharcomdata|=uchartemp; } } void DHT11(void) //温湿传感启动 { DATA_PIN=0; Delay_ms(19); //>18MS DATA_PIN=1; P0DIR &= ~0x80; //重新配置IO口方向 Delay_10us(); Delay_10us(); Delay_10us(); Delay_10us(); if(!DATA_PIN) { ucharFLAG=2; while((!DATA_PIN)&&ucharFLAG++); ucharFLAG=2; while((DATA_PIN)&&ucharFLAG++); COM(); ucharRH_data_H_temp=ucharcomdata; COM(); ucharRH_data_L_temp=ucharcomdata; COM(); ucharT_data_H_temp=ucharcomdata; COM(); ucharT_data_L_temp=ucharcomdata; COM(); ucharcheckdata_temp=ucharcomdata; DATA_PIN=1; uchartemp=(ucharT_data_H_temp+ucharT_data_L_temp+ucharRH_data_H_temp+ucharRH_data_L_temp); if(uchartemp==ucharcheckdata_temp) { ucharRH_data_H=ucharRH_data_H_temp; ucharRH_data_L=ucharRH_data_L_temp; ucharT_data_H=ucharT_data_H_temp; ucharT_data_L=ucharT_data_L_temp; ucharcheckdata=ucharcheckdata_temp; } wendu_shi=ucharT_data_H/10; wendu_ge=ucharT_data_H; shidu_shi=ucharRH_data_H/10; shidu_ge=ucharRH_data_H; } else //没用成功读取,返回0 { wendu_shi=0; wendu_ge=0; shidu_shi=0; shidu_ge=0; } P0DIR |= 0x80; //IO口需要重新配置 }6.3 BH1750.c#include "bh1750.h" u8 Read_BH1750_Data() { unsigned char t0; unsigned char t1; unsigned char t; u8 r_s=0; IIC_Start(); //发送起始信号 IIC_WriteOneByteData(0x46); r_s=IIC_GetACK();//获取应答 if(r_s)USART0_Printf("error:1 "); IIC_WriteOneByteData(0x01); r_s=IIC_GetACK();//获取应答 if(r_s)USART0_Printf("error:2 "); IIC_Stop(); //停止信号 IIC_Start(); //发送起始信号 IIC_WriteOneByteData(0x46); r_s=IIC_GetACK();//获取应答 if(r_s)USART0_Printf("error:3 "); IIC_WriteOneByteData(0x01); r_s=IIC_GetACK();//获取应答 if(r_s)USART0_Printf("error:4 "); IIC_Stop(); //停止信号 IIC_Start(); //发送起始信号 IIC_WriteOneByteData(0x46); r_s=IIC_GetACK();//获取应答 if(r_s)USART0_Printf("error:5 "); IIC_WriteOneByteData(0x10); r_s=IIC_GetACK();//获取应答 if(r_s)USART0_Printf("error:6 "); IIC_Stop(); //停止信号 DelayMs(300); //等待 IIC_Start(); //发送起始信号 IIC_WriteOneByteData(0x47); r_s=IIC_GetACK();//获取应答 if(r_s)USART0_Printf("error:7 "); t0=IIC_ReadOneByteData(); //接收数据 IIC_SendACK(0); //发送应答信号 t1=IIC_ReadOneByteData(); //接收数据 IIC_SendACK(1); //发送非应答信号 IIC_Stop(); //停止信号 t=(((t0<<8)|t1)/1.2); return t; }