当前位置: 首页 > wzjs >正文

上海网站建设公司介绍整人关不掉的网站怎么做

上海网站建设公司介绍,整人关不掉的网站怎么做,网站建设考核表,企业微信邮箱怎么开通注册HAL 库都是拿C 写的,想注册回调函数的话,也只能是C 的函数,不能用成员函数作为回调。现在有个需求,要给一个I2C 设备写个驱动,希望把驱动整体封装成个类,这样比较灵活。要是还得把I2C 的回调函数放在类外面…

HAL 库都是拿C 写的,想注册回调函数的话,也只能是C 的函数,不能用成员函数作为回调。现在有个需求,要给一个I2C 设备写个驱动,希望把驱动整体封装成个类,这样比较灵活。要是还得把I2C 的回调函数放在类外面,那就太不“整洁”了。此外,放在外面的回调函数没办法直接引用到设备驱动对象,必须有个全局的指针变量,让它指向驱动对象,然后回调函数里再使用这个全局的指针去找对象。STM32DUINO 框架里就是这么设计的,只是它们稍微取了点巧,大致原理如下:

// 驱动类,或者驱动结构体
struct Driver{I2C_HandleTypeDef handle;// ... 其他一堆成员变量// ... 其他一堆成员函数
};// 驱动对象
Driver driver_instance;// 调用HAL 库函数
HAL_I2C_Master_Transmit_DMA(&driver_instance.handle, addr, buf_ptr, count);// HAL 库的回调函数。想在回调里使用C++ 代码,必须把回调放在CPP 文件里,所以要加上extern "C"
extern "C" {void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *I2cHandle) {// 根据handle 结构体在Driver 类中的偏移量,拿到指向driver_instance 对象的指针auto offset = offsetof(Driver, handle);Driver *driver_ptr = reinterpret_cast<Driver*>(I2cHandle - offset);// 拿到了驱动对象,之后就随便弄了// driver_ptr->.......
}}

把HAL 库的Handle 结构体嵌进驱动对象里,再用这个handle 成员变量去调用各种HAL 函数,那么回调函数传进来的*I2cHandle 当然就是指向这个成员变量的指针。有了成员变量的地址,就可以根据成员变量在驱动对象中的偏移量,拿到驱动对象的地址。也是挺巧妙的,优点是不用单独定义个隐藏的全局变量,用户使用的时候会自己定义Driver 对象。

不过这种做法不适合我。我习惯把Cube 生成的代码简单改改就直接用,而且还是拿脚本自动改。Cube 会在它生成的main.c 里定义好各种handle 结构,我就在它的main 函数里调用我自己的入口函数app()。这样做的好处是可以分离Cube 自动生成的代码,我可以把我的代码放在app.cpp 文件里,以后如果改了配置,只要把Cube 新生成的代码复制过来改一下就好了,我可不想在它生成的代码里照着它规定好的格式填空。

于是,既然handle 都已经在main.c 里定义好了,我肯定不想一个一个自己定义Driver 对象,再去改生成好的配置代码。

所以我用的是另一种比较脏的方法,就是直接修改HAL 库的头文件,在I2C_HandleTypeDef 结构体定义里加一个成员void *PtrToCallbackObject,用来指向我的驱动对象。

typedef struct __I2C_HandleTypeDef
#else
typedef struct
#endif  /* USE_HAL_I2C_REGISTER_CALLBACKS */
{I2C_TypeDef                *Instance;      /*!< I2C registers base address               */// ...#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1)void *PtrToCallbackObject;   // 指向回调函数关联的对象// ...void (* AddrCallback)(struct __I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode);  /*!< I2C Slave Address Match callback */void (* MspInitCallback)(struct __I2C_HandleTypeDef *hi2c);                /*!< I2C Msp Init callback                     */void (* MspDeInitCallback)(struct __I2C_HandleTypeDef *hi2c);              /*!< I2C Msp DeInit callback                   */#endif  /* USE_HAL_I2C_REGISTER_CALLBACKS */
} I2C_HandleTypeDef;// 回调
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *I2cHandle) {// 直接拿到驱动对象的指针Driver *driver_ptr = reinterpret_cast<Driver*>(I2cHandle.PtrToCallbackObject);// driver_ptr->.......
}

这样只是改了头文件的一行代码,几乎不会引起任何兼容性问题。虽然如果HAL 库要更新,那就得重新改,但是相信大伙很多人用的库都是复制粘贴祖传下来的,根本不知道版本是什么。而且就算更新以后忘记改了,代码直接不能编译,会提示你缺个PtrToCallbackObject 成员,所以不会出错。最后,这个Handle 结构体里面已经定义了这么多不知道有没有用的变量,我再加一个指针,不会造成什么负担。此外,就算不用C++,在C 里面往往也会用结构体模拟对象,增加这个成员也是有用的。

有了这个方便的修改以后,回到开头,现在可以把回调函数放在驱动类里面了:


class Driver {private:I2C_HandleTypeDef _handle;  // 指向设备要使用的I2C handlepublic:Driver(I2C_HandleTypeDef h) : _handle(h) {}void init() {// 注册回调函数,先把对象的指针放进去_handle->PtrToCallbackObject = reinterpret_cast<void *>(this);// 用这些lambda 作为回调函数。捕获列表必须为空,否则不能作为普通函数指针使用,// 所以lambda 里不能直接操作this 指针,必须从handle 里获取。// WARNING: 注意,这些回调是从I2C 中断调用的// TX 完成回调auto master_tx_complete_callback = [](I2C_HandleTypeDef *h) {// 获取this 指针auto t = reinterpret_cast<Driver *>(h->PtrToCallbackObject);// 发送完成时,调用成员函数t->on_tx_complete();};// 错误回调auto error_callback = [](I2C_HandleTypeDef *h) {auto t = reinterpret_cast<Driver *>(h->PtrToCallbackObject);// 发生错误时t->on_error();};// 注册回调函数_handle.MasterTxCpltCallback = master_tx_complete_callback;_handle.ErrorCallback = error_callback;}
};

这样有什么优点?可以把驱动代码全部放在头文件里,用的时候include 一下就行了,多方便。


文章转载自:

http://CAMEGnBy.pLnry.cn
http://gEqW0TLm.pLnry.cn
http://eEN7lhfI.pLnry.cn
http://Y2XnQaUt.pLnry.cn
http://G5imAk59.pLnry.cn
http://BjVbLeIE.pLnry.cn
http://XhySDWax.pLnry.cn
http://JWFD7Cum.pLnry.cn
http://C7lTbG8o.pLnry.cn
http://kj2vTckV.pLnry.cn
http://h4q6ujHD.pLnry.cn
http://Ud62AF0j.pLnry.cn
http://LbPguOnA.pLnry.cn
http://AJPA7cCc.pLnry.cn
http://QqOFrpmG.pLnry.cn
http://bqPbKIQs.pLnry.cn
http://Xam25sIU.pLnry.cn
http://GVDXnAxH.pLnry.cn
http://82yQUISs.pLnry.cn
http://CVhUEj5W.pLnry.cn
http://rdDIDew7.pLnry.cn
http://zJ11bGmY.pLnry.cn
http://vWTeKiei.pLnry.cn
http://USj3XRGk.pLnry.cn
http://pf7ubp9Q.pLnry.cn
http://LwfXTx6e.pLnry.cn
http://RHEPPfZp.pLnry.cn
http://BaZEa4z1.pLnry.cn
http://kokryYfp.pLnry.cn
http://7pd7doMX.pLnry.cn
http://www.dtcms.com/wzjs/728282.html

相关文章:

  • 手机网站建设平台用vs2012做网站教程
  • 百事通做网站宁波网站建设yiso
  • 桂林医院网站建设图片展示类网站
  • 建设工程检测预约网站娄底地seo
  • 木匠手做网站成都网站关键词排名
  • 有没有给别人做图赚钱的网站别墅设计图纸及效果图大全
  • 网站推广服务器怎么选wordpress 文章字数
  • 网站建站的步骤网站开发部门叫什么
  • ipfs做网站官方网站建设 省心磐石网络
  • 论坛网站建设软件烟台建设联合会网站
  • 什么网站可以做数据图wordpress shift+enter
  • 网站用什么系统好用信息发布型网站
  • 网站开发专业就业前系军十八款禁用黄台入口app
  • php网站开发价格中国建设监理协会化工监理协会网站
  • 易购商城网站怎么做啊安徽建设工程信息网怎么打不开了
  • 网站建设实验凡科建站步骤
  • 企业手机网站建设案例济南网站建设新风向
  • 网站开发项目计划书模板网站解析一般什么时候
  • 旅行社网站建设规划厦门seo排名
  • 网站源码在哪网址ip地址查询工具
  • php 企业 网站中小企业网络设计与实现
  • 成都高端网站建设wordpress免费服务器
  • 网站建设项目清单价格网页制作与网站建设06627
  • 视频网站建站费用深圳的网站建设公司排名
  • 免费学平面设计的网站宁波做网站首荐荣盛网络
  • 米拓网站建设给你一个网站你怎么做
  • 淘宝客推广怎样做网站国外产品代理网
  • 台前网站建设费用好用的网站后台管理系统
  • 建立网站 wordpress推广赚钱的软件
  • 电子商务网站开发背景和意义手机网站 用户体验