从事化妆品研发怎么样嵌入式研发三年遇到些问题还不能解决是不是没法从事化妆品研发怎么样些类工作了

查看: 17266|回复: 123
不知有没有人对C++开发STM32感兴趣的,来讨论些问题
因为一开始我自学的就是C++,后来玩单片机以后才使用C语言来开发东西,也写过一些程序了,
但是感觉就是,C语言没有C++那么方便,最近才在学STM32,看到ARM编译器能够支持C++,挺爽的,就开始尝试把实验代码的工程改成C++的方式
出现了一些问题,我不太会查资料,网上讨论这个的也比较少,所以就发个帖子大家一起讨论下
先上我改成C++的工程(MDK下,测试可以运行了的):
点击此处下载
(原文件名:stm32_cppTest.zip)
先说一下,为什么要用C++,(说的可能不太清楚,对没学过C++的哥们就不好意思啊呃。。。)
1. 最简单的,函数重载, 这个语法特性就比C语言的好,还有运算符重载,这些都可以让代码变得更直观
2. 命名空间,C语言写大程序一般每个模块都会有个前缀,但是写起来麻烦,其实有时候在一个地方只会用到
一个模块的内容,所以用using xxx::xxx感觉会比较方便些。
3. 类的支持,尤其是成员函数什么的使用起来方便,还有constructor,不用每次手动调用初始化。
4.inline关键字,可以解决宏的一些缺陷
5.引用参数的支持,比直接使用指针省事放心些
6.至少,网上说的,C++具有C的全部优点
然后再提一下我遇到的问题,有的已经解决,有的还没解决:
1. 以前的库函数怎么使用?
在函数声明前加上 extern &C& 就可以了,因为C++支持函数重载之类的东东,所以生成的目标代码的名字和C会有些不同,用extern &C&强制成C语言的名字规则。现在新版本的库好像已经加上了,这里顺便问一下,新版本的库在官网的哪里下载?我不要一点就直接弹出下载的链接
新版的库的头文件前面是
#ifdef __cplusplus
extern &C& {
#ifdef __cplusplus
2. 中断函数进不去呀?
中断函数定义前也要加上 extern &C&
3. 对库里面定义的结构体有警告: warning:&&#368-D: class &&unnamed&& defines no constructor to initialize the following:
我用这段代码屏蔽了中间警告
#ifdef __cplusplus
extern &C& {
//消除 warning:&&#368-D: class &&unnamed&& defines no constructor to initialize the following:
#pragma diag_remark 368
#ifdef __cplusplus
//恢复368号警告
#pragma diag_default 368
还有些没解决的问题
4. 定义全书类变量后会有错误:
..\output\stm32test.axf: Error: L6218E: Undefined symbol __cpp_initialize__aeabi_ (referred from anon$$obj.o).
& & & & A()
& & & & & & & & int x,
& & & & & & & & x = 5;
& & & & & & & & y = 7;
& & & & & & & & x =
& & & & & & & & y = x + 8;
5. C++有 new 关键字,类似C的malloc,但是这个是需要有内存管理提供动态内存的,这个在一个没有操作系统的MCU上咋整呀?
暂时想到的就这么多
补充内容 ( 13:43):
C++版的代码已经从61楼开始会逐步更新
补充内容 ( 14:17):
外部中断实验,65楼。
补充内容 ( 14:17):
独立看门狗实验,66楼。
再提下中断函数定义的
看到网上好像是可以用类成员函数(非static)来做中断服务程序的(自己搜索),
没仔细研究,感觉不太靠谱,因为类成员函数(非static)调用的时候会默认传个
this指针,中断函数是不接收参数的,不知道这个怎么搞。。。。有经验的能不能发表下意见?
我认为有些底层的东西是不可能都用面向对象的方式的,用C++只不过是想利用一些方便的语法特性,
如果真要实现那种类成员函数做中断响应的,估计看 MFC 的源码可以解决这些问题,在VS2010目录下不知哪个文件。。。
malloc和new并不是由操作系统管理,而是由C/C++运行时库管理,这个就放心的用吧。
我一年半以前想学C++,用C++开发单片机。后来搁置下来了。现在重新拾起。
我认为用C++的特性写程序会更好。尤其用OOP的思想组织程序。
但一提到C++,马上有人批评它的虚函数等,认为C++效率低,庞大。批评的人思维模式好像是用C++就要用C++的全部的特性。
我认为结合单片机和工程的要求,只用C++适用于单片机的部分特性。
欢迎大家多发表意见。给我等入门者多些启发。
回复【2楼】lcofjp 卡尔夫
-----------------------------------------------------------------------
话是这样说,
比如说C51的,KEIL有提供malloc,但前提是需要你给个内存池给它去初始化的(init_mempool),在裸机的场合,有些东西是要自己操心的
不知道ARM上的C++用的内存池我要怎么提供给它
补充一点,
STM32的一个头文件里有typedef ... bool的,C++已经内建了bool了,所以注释掉即可
回复【3楼】guolun
-----------------------------------------------------------------------
&但一提到C++,马上有人批评它的虚函数等&
效率低可以不使用虚函数的,
而且,在需要用到这些特性的场合,就算是自己写代码去实现,也好不到那哪里去,一切都是有代价的
在单片机上开发不像是PC上开发,确实不能把C++在PC上的使用方法全部搬到单片机上,就算是C语言也是这样的
但是总有一些有用的东西的
本人愚见:
不考虑效率 java&&更好。
回复【7楼】bbs2009
本人愚见:
不考虑效率 java&&更好。
-----------------------------------------------------------------------
但是我不什么你在说啥?我帖子里可没有提到不考虑效率呀?
C++是可以内联汇编的,Java就不行了吧?效率一般是不用考虑的,
但是有些地方是不得不考虑的,比如IO驱动还带大量数据传输的,这个时候才要重视程序的效率问题
回复【7楼】bbs2009&&
本人愚见:
不考虑效率 java&&更好。
-----------------------------------------------------------------------
C#也不错!!!
而且还真有人这么干来着!!!他在CSDN上写了一系列用C#编写STM32程序的例子,直接搜“STM32 .NET”就能找到。。。。
回复【9楼】XIVN1987 小显
-----------------------------------------------------------------------
真不知道你们俩这样说是啥意思
ARM9好像是可以支持JAVA的,WinCE也是可以利用C#做应用开发的
我只是想讨论C++开发STM32的问题。。。咋谈起这个来了。。。
(PS: C#开发STM32,有点新奇,可惜我不会C#)
我认为没必要标榜自己是用C开发还是用C++开发...
首先是C是C++的一个子集...另外是C构成了C++...只不过是C编辑器级别的宏替换....
需要性能的时候C都不好使 需要直接上汇编...
inline是C++的啊? KEIL下有 __inline...
类并不是C++的优点...实际用来起来...结构体会更方便些...只不过都是动态绑定...
void func(int x,int y) 在c++中是替换成 void void_func_int_int(int x, int y)实现重载
new就是 a=(a*)malloc(sizeof(a)); a-&a(); 也是宏替换...如果没有a()...有一部替换完不成...就有警报了
C++的真正价值是STL...那个真是开发神器...不用重复发明轮子了...
回复【11楼】adce
-----------------------------------------------------------------------
&我认为没必要标榜自己是用C开发还是用C++开发... &
我没有在标榜C++开发,只是遇到了些问题,毕竟不可能只是把.c文件改成.cpp就了事了的,希望大家一起讨论下
“inline是C++的啊? KEIL下有 __inline... ”
谢谢指出,试了下,在C环境下确实可以用__inline,不过以前玩C51的时候确实没这东西。。。
“类并不是C++的优点...实际用来起来...结构体会更方便些...”
那要看场合了,比如说有些结构体是需要有默认值的,用C的结构体的话需要手动去初始化,
“C++的真正价值是STL...那个真是开发神器...不用重复发明轮子了...”
对STL不太熟,如果能把一些有用的部分移植到ARM上也是很不错的。嗯,C++能够支持模板,
这也是更我喜欢C++的原因之一,要是能支持lambda表达式之类的特性就更酷了~
回复【11楼】adce
-----------------------------------------------------------------------
&void func(int x,int y) 在c++中是替换成 void void_func_int_int(int x, int y)实现重载 &
学MFC的时候,看孙鑫讲动态链接库那里有简单的讲到符号的问题,我记得好像不完全是这样的,
我不想去关心这些东西,要的只是语法上的支持
如果在C语言里这样来定义函数,那个代码的可读性不是一般的差的
“new就是 a=(a*)malloc(sizeof(a)); a-&a(); 也是宏替换...”
这些是C++的基础知识,我明白,我现在想知道的就是怎么提供一个内存块给系统去 new,
因为是在STM32上做裸机开发,内存怎么配置是要自己操心的
&如果没有a()...有一部替换完不成...就有警报了&
不明白你想说什么,我上面提到的问题的意思是说全局类变量的话链接会出错,但是如果是局部变量的话,就没问题。
回复【12楼】Pony279 霍斯
-----------------------------------------------------------------------
Boost Lambda
C语言入门中!
回复【13楼】Pony279 霍斯
-----------------------------------------------------------------------
你误解了...我不是说C可以用那种方式代替重载...
而是在解释为什么不加extern &C&就找不到函数...
每个编译器的实现方法都不一样...不过类似....
原始的malloc就是找一块空地方...然后占用...free后就释放...
频繁的malloc和free最后就会使内存全是小块不连续的空间(就是碎片)...然后没有内存...malloc失败...跑飞...
单片机开发中一般不用malloc/free 要用也是用OS提供的malloc和free....
可以看freeRTOS的heap_x.c....
还真有玩家搞这个。
就不扯c和c++的什么效率问题了,玩玩可以,就不用当真了。
单片机处理能力有限,不是用来搞数据库的。楼主玩玩就行了,没推广价值。
回复【16楼】adce
-----------------------------------------------------------------------
&频繁的malloc和free最后就会使内存全是小块不连续的空间(就是碎片)...然后没有内存...malloc失败...跑飞...
单片机开发中一般不用malloc/free 要用也是用OS提供的malloc和free.... &
确实用的比较少,因为C++直接就提供了new关键字,所以我想解决使用上的问题
以前在C51上是需要先传个比较大的数组给init_mempool函数去初始化,然后才能malloc的,不知道现在要咋整。。。
是不是直接跟STM32的启动代码有关?好像有配置heap的部分(PS:我对汇编不熟。。。没仔细研究。。。)
很短时间就有很多跟帖,大家继续踊跃发言。我在入门中,只能看你们探讨。
回复【17楼】learner123
还真有玩家搞这个。
就不扯c和c++的什么效率问题了,玩玩可以,就不用当真了。
单片机处理能力有限,不是用来搞数据库的。楼主玩玩就行了,没推广价值。
-----------------------------------------------------------------------
为什么没有推广价值?C++是C的升级版呀,(++是自增操作符),
“单片机处理能力有限,”不代表不适合用C++,
我上面也说了,用C++只是为了利用它的一些方便的语法特性,同时也不会损失效率
C++的一些损失效率的地方,不喜欢的话同样也可以不使用。
回复【11楼】adce
-----------------------------------------------------------------------
&new就是 a=(a*)malloc(sizeof(a)); a-&a(); &
补充一下,其实也不能完全这样说,因为
“Operators new and delete are exclusive of C++. They are not available in the C language. But using pure C language and its library, dynamic memory can also be used through the functions malloc, calloc, realloc and free, which are also available in C++ including the &cstdlib& header file (see cstdlib for more info).
The memory blocks allocated by these functions are not necessarily compatible with those returned by new, so each one should be manipulated with its own set of functions or operators.”(引自/doc/tutorial/dynamic/)
回复【18楼】Pony279 霍斯
-----------------------------------------------------------------------
这个不知道...得重定向new吧...
可以研究研究RT-Thread,不是说那个是C++开发的么...应该有办法解决吧....
晕啊...文字_狱啊...我的意思是new和malloc一样原理申请内存....
如果C能这样代替new的话编译器都不用换了 直接#define得了....
回复【22楼】adce
-----------------------------------------------------------------------
好的,谢谢你的建议
(PS:现在裸机都还是三脚猫。。。上OS估计会比较痛苦。。。)
回复【22楼】adce
-----------------------------------------------------------------------
呵呵,我不是在钻牛角尖,没有恶意,只是怕不知道的人看到了还真以为是这么回事
new的一种教学实现的确是那个样子...
但是C++不保证new一定用malloc...也就是free释放new出来的东西可能会有错误...
C++的new至少有3种实现....
我问了一下身边的人....
在STM32中用需要重载new和delete....
自己写内存管理....碎片回收...可以参考FreeRTOS的heap_2.c
头文件在&NEW&里....
事实上c++和c根本不是子集关系,楼主有兴趣看看编译器对c++的实现。语法兼容,低层差别挺大。效率问题也正由此而来,建议楼主先做点单片机的项目,而不是跑几个例子就知道为什么c++搞单片机意义不大。
至于很多语法糖,恐怕对实际项目意义不大
当然,单片机的速度和资源相比过去是大了,但应用方向决定它不可能像pc那样搞
回复【26楼】learner123
-----------------------------------------------------------------------
&楼主有兴趣看看编译器对c++的实现。语法兼容,低层差别挺大。&
编译器的事情,我可不想去掺和。而且,目前为止,看反汇编出来的情况,我还没发现明显的效率差距。
(PS:老是挠头想着程序怎样能少执行少一两条指令,恐怕自己的工作效率会比较悲剧,花的时间比别人多,效果又不一定好)
&至于很多语法糖,恐怕对实际项目意义不大&
这个我并不这么认为,至少我是有这样的需要
如果你说C++不适合在传统的51上搞,我可以勉强同意。
但是你说C++不适合在ARM上搞,我不同意。如果真的不适合,那么ARM公司应该把Keil软件的项目属性配置对话框那里的&C/C++&标题改成&C&
回复【26楼】learner123
-----------------------------------------------------------------------
&当然,单片机的速度和资源相比过去是大了,但应用方向决定它不可能像pc那样搞&
这个确实是有道理,但是Java也有应用在嵌入式领域也是个事实,还有C#,也有应用在嵌入式领域的,
C++同样也可以,从来也没人说要把PC上的方式照搬到嵌入式系统中,任何东西都有它的利弊,灵活运用才是最重要的
如果速度真的那么重要,那应该用汇编。若干年前刚出现C语言的时候,估计有很多玩汇编的哥们都看不起这玩意儿吧
New delete这些可以绕过
Template可以不用
ARM下C++编译和效率不用考虑
楼主应该是看重了c++的某些语法上的便利性而选择它的
如果你选择了它,那么你就要自己建立一个体系来维持它
你得在你耗费的精力和其带来的便利之间找到平衡
回复【29楼】xrr1017
-----------------------------------------------------------------------
&楼主应该是看重了c++的某些语法上的便利性而选择它的&
差不多可以这么说,因为可以利用一些面向对象的方法的同时(当然不可能全盘都面向对象)又可以在必要的时候顾及底层的驱动(至少可以inline asm)
&你得在你耗费的精力和其带来的便利之间找到平衡&
确实,不过我还是个学生,也没做什么商业项目的,单片机可以算是业余爱好了,业余爱好者们都喜欢折腾的,不是么
http://andybrown.me.uk/ws//stm32plus-a-c-library-for-stm32-development/
这个就是用C++ 用的红牛的板子
回复【31楼】tanghong668
-----------------------------------------------------------------------
谢谢楼上提供的链接!!!
原来new可以这么搞的(软件仿真会跳进重载的函数里),自己只要提供malloc和free以及堆的一些初始化就行了
/*&&* Implement C++ new/delete operators using the heap&&*/
void *operator new(size_t size)
{& &return malloc(size); }
void *operator new[](size_t size)
{& &return malloc(size); }
void operator delete(void *p)
{& &free(p); }
void operator delete[](void *p)
{& &free(p); }&&
确实是25楼说的那样,也要谢谢 adce 网友!
回复【31楼】tanghong668
-----------------------------------------------------------------------
看了看开发板的源码。。。发现我以前在51上写的FAT。。。弱爆了。。。
C++的特性在MCU开发中确实有它的用武之地,比如需要涉及到GUI的领域,就算是用C,也一样要用大量的结构体和函数指针来模拟面向对象的实现过程,否则代码的复杂度和可维护性都会是一场噩梦。单片机上的跑C++,尤其是动态内存分配一定要小心,毕竟MCU裸跑的程序没有堆栈、内存管理等机制。尤其是堆栈资源严重紧张,一旦爆栈,死机是肯定的。总的来说,我认为C++只有部分特性能适合裸机,它的完整特性必须在现代OS的支持下才能得到发挥。
话说还有个问题没解决,
定义全局类变量后会有错误:
..\output\stm32test.axf: Error: L6218E: Undefined symbol __cpp_initialize__aeabi_ (referred from anon$$obj.o).
y = x + 8;
};& && &&&
在MDK的文档里有提到,不些地方不太理解,改天再研究
回复【35楼】Pony279 霍斯
-----------------------------------------------------------------------
没遇见过...
全局类变量是在main()之行前就要被创建的....
应该是在代码main()之前标出来吧...编译器找不到....
要么加extern标出全局类....要么加static让他静态化....
我还是没有解决中断函数的写法问题。
楼主为啥不用IAR呢?
另外对32楼的new的实现,没有调用对象的构造函数啊,我觉得这是跟C内存分配最大的区别之处。
一直在用C++
成员函数作为中断服务完全可以
但没必要,新建一个无类的CPP文件作为硬件与软件的中间层即可
直接在类里写中断函数,影响移植性
回复【39楼】kevin_ares
-----------------------------------------------------------------------
&成员函数作为中断服务完全可以&
如果我建立了两个对象,你觉得发生中断后硬件会让哪个对象去响应中断?
回复【38楼】nicksean 不务正业
-----------------------------------------------------------------------
一直习惯MDK。。。
&另外对32楼的new的实现,没有调用对象的构造函数啊&
我试了,会的,这个是编译器做的事情
回复【36楼】adce
-----------------------------------------------------------------------
&要么加extern标出全局类....&
这个可以,不过。。。加extern不是标出全局类的吧?这个是用来声明,它是外部的一个全局变量。。。
“要么加static让他静态化.... ”
试了,不行
回复【37楼】guolun
-----------------------------------------------------------------------
中断函数的名字是固定的(只要你用的启动代码是IDE给的),
你需要在前面加上 extern &C&,你可以下载我的代码看看,cpp_test.cpp文件里有个定时器中断函数
extern &C& void TIM1_UP_IRQHandler()
回复【36楼】adce
-----------------------------------------------------------------------
这个问题已经解决了,
原来是因为我在 项目属性 那里选择了 Use MicroLIB
当时选择这个是因为不选的话片子不能启动,不知道为什么,然后在网上找解决方案,找到有两种,我当时贪快,就直接设置属性了。
继续补充,如果不用微库,然后又使用了printf,程序就不能正常启动,按照网上的解决方案,我在随便一个.cpp文件里加了下面的代码
#pragma import(__use_no_semihosting)&&
extern &C& void _sys_exit(int x)&&
& & & & x =&&
namespace std
& & & & struct __FILE&&
& & & & {&&
& & & & & & & &&&
& & & & & & & & /* Whatever you require here. If the only file you are using is */&&
& & & & & & & & /* standard output using printf() for debugging, no file handling */&&
& & & & & & & & /* is required. */&&
& & & & & & & & };&&
& & & & & & & & /* FILE is typedef’ d in stdio.h. */&&
& & & & FILE __
回复【39楼】kevin_ares&&
一直在用c++
成员函数作为中断服务完全可以
但没必要,新建一个无类的cpp文件作为硬件与软件的中间层即可
直接在类里写中断函数,影响移植性
-----------------------------------------------------------------------
能否给出一个完整的例子,想知道如何用成员函数做中断服务。
回复【45楼】Pony279 Pony279
-----------------------------------------------------------------------
加了那段代码后,可以使用标准库,但是全局类变量又不能使用了。。。
..\output\stm32test.axf: Error: L6915E: Library reports error: __use_no_semihosting was requested, but _ttywrch was referenced
不知怎么改了下又可以了。。。有些问题真不知道神马原因。。。
正在学习中,这个想法很不错
mark&&等待楼主补充。很期待。
mark 最近正研究着c++
ecos就是c++的,也没问题吧。
主要是看怎么使用特定语言的特性了,还有就是系统的资源状况考虑使用什么样的方式更好。
直到47楼,主要问题已经解决了
下面继续补充:
关于内联函数,
经过测试,原来编译器是这么搞的:
在一个.c文件里如果被引用2次或以上,就会自动生成一个函数
(估计它是想节省代码的,事实上,对于我上面写的宏,如果参数是常量,它传递参数 + 跳转指令 + 返回指令的代码量已经多于常量优化后的代码量了。。。我晕。。。)
如果在一个模块里,这个内联函数只被引用一次,就不会生成函数。。。看来编译器来是比较傻逼的。。。
不过这个应该不是编译器不能解决的问题,只是需要时间去进步罢了。
继续补充:
看了MDK的文档,关于inline的说明,可以使用__forceinline而不是inline,这样的话就可以更好的优化了。
奇怪。。。上不了图片了。。。我抄上来好了:
在MDK文档的 Differences in behavior between C++, C90, C99, and GNU C90 complier modes 一节中有提到,
__forceinline behaves like __inline, except that the complier tries harder to do the inlining.
(在MDK文档中搜inlin,很容易找到说明的。)
可以统一的定义 #define inline __forceinline
不知道这样做合不合适,其实写inline的人理应知道那代码通过内联以后会更好的,
如果强制内联被滥用,就悲剧了。
起始能玩嵌入式的,大家玩起C语言都是高端人士,我们什么都能制造
回复【54楼】ewindiy 疯沁
-----------------------------------------------------------------------
C++能做到的都能用C语言来完成,C语言能做的都能用汇编来完成,看个人喜好。
现在遇到一个问题:
上面说的强制内联,确实是当某些参数为编译期常量的时候,生成的代码量小,速度快
但是,谁也不能保证用户会规规矩矩的用,上个月学习Java的时候,老师是这么比喻的“你一个人不犯法,社会就和谐了吗?”
所以,必须想个办法强制参数为编译期的常量,
可是,就算函数的参数类型定义为const也不行啊,大家有没有什么更好的解决办法啊?
我做过实验,我的gpio模块的SetMode函数,只要那个pin参数是一个变量,就会生成200+字节的代码。。。肿么办啊。。。
(PS: 在很多地方使用enum类型是一个很好的方案,但是这里的pin。。。比较麻烦啊。。。)
点击此处下载
(原文件名:stm32_cppTest.zip)
方案有了,通过继承的方式,
父类子类的数据成员是一样的
但是父类给最少的功能函数,保证速度,子类给多一些功能,
SetMode函数通过重载的方式去支持子类,但是,这个重载的函数不能inline,因为对于变量参数,生成的代码量比较大。
点击此处下载
(原文件名:stm32_cppTest.zip)
只是做好了GPIO部分的寄存器封装,函数重载多了,文档写起来比来比较麻烦啊。。。
说一下我上传的代码的使用吧,我这里只是为了示例用C++怎么写,所以以后就不会再在这里上传代码了,因为基本问题都已经解决了。
也许我示例的不好,因为我不是软件大牛。。。也请大家包涵。。。:
其实下面的示例也主要用了函数重载,至于C++的模板,大家可以看MYLIB文件夹下的template.h里面的内容
其它的比较简单,我只说SetMode函数的使用:
(如果我这里说的都不能满足你的需求,可能就需要你直接看函数原型,或者,自己去写个函数出来了。)
第一种最简单的适应大部分情况的用法,也就是代码执行速度最快代码的用法
把PA0设置为推挽输出, 速度50M:
SetMode(GPIOA, Pin(0), OUTPUT, PUSH_PULL, _50M);
对于输出,默认是开漏10M速度输出,如果后面的两个参数不写,则取默认值。
(PS:上面那句,生成代码量为12字节)
把PA0-PA7设置为推挽输出, 速度2M:
SetMode(GPIOA, Pin(7,0),OUTPUT,OPEN_DRAIN,_2M);
这名话生成的代码量是,8字节(因为编译器会视情况自动优化)
把PA9设置为上拉输入:
SetMode(GPIOA,Pin(9),INPUT,PULL,UP);
上面的代码,生成的代码量是16字节,因为设置上拉还要写BSRR寄存器来间接写ODR。
对于输入,默认参数上拉,所以也可以这么写:
SetMode(GPIOA,Pin(9),INPUT);
还有一种情况,
还有一种输出的情况,就是特殊功能输出,比较使用硬件串口之类的:
SetMode(GPIOA,Pin(3),AF_OUTPUT,PUSH_PULL,_50M);
上面的函数生成的代码量都是比较少的, Pin是一个类,虽然生成一个类的对象会调用构造函数之类的,
但是因为比较短,都被编译器优化掉了。至于为什么我会用类的对象,因为,这样,在使用的过程中不容易出错,
强制成一种类型,代码的阅读性和可维护性也有所提高。有兴趣的朋友,也可以用C语言来实现一次,帮我对比看看
C语言是不是真的效率比较高,还是说,其实效率上没什么区别?
好了,废话说多了,上面的使用是有点限制的,因为我只能同时设置一个引脚或者几个连续的引脚的模式,
那么怎么同时设置几个同端口但是编号不连续的引脚的模式呢?
通过继承的方式,我又写了一个类,Pins提供了这种支持,但是,由于编译器还是比较傻逼的,
生成的代码量比较大,超过200字节了,所以我使用非内联的方式,
把PA9和PA2设置为下拉输入:
SetMode(GPIOA, Pins(9)+Pins(2), PULL,DOWN);
这条语句生成的代码是40字节,呵呵,实在是有点多啊,加上函数本身,刚刚测试了,原来有400字节啊,,,
多得有点恐怖,,,还好,其实这种方式是不常用的,哈哈。
但是其实呢,对于实现上面的内容,SetMode函数也有更加高效用法,只是使用直接比较复杂,所以我就没写出来,
如果有特殊要求,再去看吧,我想一般都是没有这种必要了。
不明白,既然是C++了,为什么不采用如“PA0-&SetMode(...)”的形式,将每个管脚定义为一个类,这样用起来更像C++了。
建议去http://mbed.org/看看。它的软件就是基于C++的,用起来很方便,虽然免费但不开源,只能用NXP的Cortex-M3。
回复【58楼】yzhu
-----------------------------------------------------------------------
你说得有道理,
只是官方库已经定义了GPIOA等等结构体,如果我再定义个PA0,等等,
可能真的不那么容易让用户去掌握,而且,如果采用那种定义,不知效率会不会有所影响。
当然,其实C++语言的拓展性是很好的,想要按你那种思路来写,随时都可以拓展,因为C++灵活强大啊。
我也想过另一种方案,直接修改官方库的结构体的定义,增加一些成员函数,这样用起来也许会爽一点,不知楼上觉得怎样?
谢谢你提供的链接,我去了解一下。
论坛升级的这段时间里我继续写了一些代码,后来也采用了58楼的方案,现在把代码上传,供大家参考。以后会继续上传。
实验内容主要以正点原子的《STM32不完全手册》为参考,因为我用的STM32开发板是正点原子赠送的,呵呵
不过代码会和书上的有些不同,实验内容也不完全相同,
而且,序号比较后的相对之前的代码是比较完善的,所以后面的代码,和前面的代码,不一定兼容的,不要把各工程的代码到处复制搞混了就行。
我也是新手,凡事总有个发展的过程的。
这里我只介绍最后一个,之前的代码的简单说明可以看这里,
代码里面没有使用官方的固件库函数,但是用到了官方库的头文件,而且我做了修改。
最后一个实验是使用串口的文本输入输出流,类似c++的cin,cout,
代码中定义了pa0, pa1, ..., pa15, pb0, pb1, ...
然后如果要定义pa0为输出的话,就可以直接写
pa0.Config(OUTPUT);& & //呵呵,用起来还是比较方便的。
然后就是主函数代码了,底层代码我就不贴了~
#include &sys.h&
#include &IOStream.h&
int main(void)
& & & & sys.Init();
& & & & us
& & & & scb.SetPriorityGrouping(GRP4_SUB4);
& & & & nvic.Config(USART1_IRQn, ENABLE, 0, 0);
& & & & rcc.Enable(IOPAEN);& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & // PA使能
& & & & pa9.Config(AF_OUTPUT, PUSH_PULL);& & & & & & & & & & & & & & & & & & & & & & & & // 串口输出脚配置
& & & & pa10.Config(INPUT);& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & // 串口输入
& & & & rcc.Enable(USART1EN);& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & // 使能串口
& & & & usart1.Config(9600);& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & // 配置串口的参数
& & & & usart1.Transmitter(ENABLE);& & & & & & & && & & & & & & & & & & & & & & & & & & & & & & & & & // 使能串口发送
& & & & usart1.Receiver(ENABLE);& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & // 使能串口接收
& & & & usart1.Interrupt(ReceivedInt_OverRunErrInt, ENABLE);& & & & // 使能接收中断
& & & & char str[20];
& & & & while(1)
& & & & & & & & output& & & & &&&\n请输入一个单词吧 :&;
& & & & & & & & input& & & & &&
& & & & & & & & output& & & & &&&\n你输入的单词是:&&&str&&'\n';
然后是软件仿真的结果,实际测试也是通过的:
另外一点,题外话,MDK的configuration wizard 好有爱啊,我在我的 iostream.cpp 里有这一段代码:
如果我点了上面的 configuration wizard,就可以图形化地进行配置了,好好玩啊~
原理是什么?呵呵,请点击上面的help键,
咱们搞技术的,一定要会看文档。
补充内容 ( 13:47):
下一个实验:65楼
本帖子中包含更多资源
才可以下载或查看,没有帐号?
楼主很强大,作为一个学C的人我一直困惑c++在单片机上如何运用,什么东西应该定义为类,什么时候谁继承于谁等问题
正在看楼主的例子,先感谢楼主
我记得以前有论坛的网友说打算把ST库转换成类库,不知道现在怎么样了
exilefox 发表于
楼主很强大,作为一个学C的人我一直困惑c++在单片机上如何运用,什么东西应该定义为类,什么时候谁继承于谁 ...
我也是想把ST库全部转为C++的类库,
不过ST库比较庞大,STM32很多外设我都没有接触过,所以干脆就边学习,边积累了
有些地方现在还是比较简陋的,比如串口,官方的参考手册上还有智能卡模式,结合DMA的方式等等,我都没有去考虑,
因为比较不熟,把后面的慢慢积累后再回来看看,或许这些也都不是什么问题了。
本帖最后由 Pony279 于
12:40 编辑
对子,说明一下,
最后一个工程代码里面因为我要测试FIFO类用来支持输入输出流,所以编译器的优化等级设置到了最低,避免编译器把我的测试代码给优化了
所以生成的代码量有4k+,就不要真的以为C++效率很低了,很多地方编译器是会自动优化的
把优化等级设置到默认即可,生成的代码量大概是2k+
本帖子中包含更多资源
才可以下载或查看,没有帐号?
这个实验是外部中断实验,比较简单,看正点原子的STM32不完全手册就懂了,我也不需要解释了,
直接贴代码,初始化流程应该是一目了然的
#include &sys.h&
#include &led.h&
// 外部中断0 服务程序
ARMAPI void EXTI0_IRQHandler(void)
& & & & Delay_ms(10);& & & & // 消抖
& & & & if(pa0 == 1)
& & & & & & & & led0.Toggle();
& & & & & & & & led1.Toggle();
& & & & exti.ClearPending(Line0);
ARMAPI void EXTI15_10_IRQHandler(void)
& & & & Delay_ms(10);& & & & // 消抖
& & & & if(pa13 == 0)
& & & & & & & & led0.Toggle();
& & & & else if( pa15 == 0)
& & & & & & & & led1.Toggle();
& & & & exti.ClearPending(Line13|Line15);
int main(void)
& & & & sys.Init();& & & & & & & & // 系统初始化
& & & & us
& & & & //& & & & scb.SetPriorityGrouping(GRP4_SUB4);& & & & // 这个在sys.Init()里已经做了初始化了
& & & & nvic.Config(EXTI0_IRQn, ENABLE);
& & & & nvic.Config(EXTI15_10_IRQn, ENABLE);
& & & & rcc.Enable(IOPAEN);& & & & & & & & // 开PA时钟
& & & & rcc.Enable(AFIOEN);& & & & & & & & // 开AFIO时钟
& & & & afio.Map(EXTI_LINE0, PORTA);
& & & & afio.Map(EXTI_LINE13, PORTA);
& & & & afio.Map(EXTI_LINE15, PORTA);
& & & & pa0.Config(INPUT, PULL, DOWN); & & & & // PA0下拉输入
& & & & pa13.Config(INPUT, PULL, UP);& & & & // PA13上拉输入
& & & & pa15.Config(INPUT, PULL, UP);
& & & & exti.FallingTrigger(Line13 | Line15, ENABLE); //下降沿中断
& & & & exti.RisingTrigger(Line0, ENABLE);//上升沿中断
& & & & exti.Interrupt(Line0 | Line13| Line15, ENABLE);& & & & //开启EXTI0, EXTI13, EXTI15的中断
& & & & led0.Init();& & & & & & & & // LED初始化
& & & & led1.Init();& & & & & & & & // LED初始化
& & & & while(1)
补充内容 ( 14:16):
呵呵,没人关注啊,还是补充一下,下一个实验,66楼。
本帖子中包含更多资源
才可以下载或查看,没有帐号?
这个实验是独立看门狗实验,功能和正点原子的《STM32不完全手册》中的独立看门狗实验描述的差不多。
复位后延时1s,然后点亮LED,启动看门狗,如果0.8s内没有按KEY2(外部中断0,PA0),看门狗就会把片子复位。
所以如果不停的按KEY2(外部中断0,PA0),在外部中断0的中断函数里会不停的喂狗,所以灯会一直亮。否则,灯会闪烁。
因为上一个实验做了外部中断实验,所以就直接用外部中断来读按键了。
贴上代码:
#include &sys.h&
#include &led.h&
// 外部中断0 服务程序, KEY2
ARMAPI void EXTI0_IRQHandler(void)
& & & & Delay_ms(10);& & & & // 消抖
& & & & if(pa0 == 1)
& & & & & & & & iwdg.Feed();
& & & & exti.ClearPending(Line0);
int main(void)
& & & & sys.Init();& & & & & & & & // 系统初始化
& & & & us
& & & & ///////////外部中断的初始化///////////
& & & & nvic.Config(EXTI0_IRQn, ENABLE);
& & & & rcc.Enable(IOPAEN);& & & & & & & & // 开PA时钟
& & & & rcc.Enable(AFIOEN);& & & & & & & & // 开AFIO时钟
& & & & afio.Map(EXTI_LINE0, PORTA);
& & & & pa0.Config(INPUT, PULL, DOWN); & & & & // PA0下拉输入
& & & & exti.RisingTrigger(Line0, ENABLE);
& & & & exti.Interrupt(Line0 , ENABLE);& & & & //开启EXTI0, EXTI13, EXTI15的中断
& & & & //////////////////////////////////////
& & & & led0.Init();& & & & & & & & // LED0初始化
& & & & led1.Init();& & & & & & & & // LED1初始化
& & & & Delay_ms(1000);& & & & & & & & //延时1s点亮LED
& & & & led0.Switch(ENABLE);
& & & & led1.Switch(ENABLE);
& & & & // 重载值 0xfff, 对40kHz进行8分频,在LIS理想40kHz下,每0.8ms需要喂狗一次。
& & & & iwdg.Config(0xfff, 8);
& & & & iwdg.Start();
& & & & while(1)
& & & & {}
上传工程代码:
本帖子中包含更多资源
才可以下载或查看,没有帐号?
C++玩IO口,串口就是爽。
uc_cpp 发表于
C++玩IO口,串口就是爽。
本来我是想用标准库的cin 和 cout的,
不过不知怎么用,就自己临时写了一个简陋的,呵呵
一直都想转到C++
以前读过一个300多页的PDF将嵌入式C++,哪些特性开销大,哪些特性没开销等等
从那个文件来看,C++完全可以获得与C相同的性能,在某些场合比C都要快
mcu用C++就是爽
Pony279 发表于
本来我是想用标准库的cin 和 cout的,
不过不知怎么用,就自己临时写了一个简陋的,呵呵 ...
cin,cout一般不用。
自己写个串口类,重载&&就行了。
有时间想学习学习!
使用C++只做过上位机,用在单片机上没有试过!
不知道效率咋样!!
syuanwang 发表于
一直都想转到C++
以前读过一个300多页的PDF将嵌入式C++,哪些特性开销大,哪些特性没开销等等
从那个文件来 ...
哪本资料?能否推荐一下 : )
一直都是用C写MCU的程序,C++到是没用过,不知道有没有这方面的资料。分析一下其优缺点。关注中。
本帖最后由 Pony279 于
10:20 编辑
yuzr 发表于
一直都是用C写MCU的程序,C++到是没用过,不知道有没有这方面的资料。分析一下其优缺点。关注中。 ...
截取《C和C++嵌入式系统编程》(英文版是Programming Embedded Systems in C and C++ - O'REILLY)一书中的部分内容供楼上参考,
我们要讨论的设备驱动的例子是用来控制80199EB 处理器的一个时钟/ 计数
器单元。我选择用C++ 来实现这个程序——并且本书所有剩下的例子部将用C++
来实现。尽管C++ 在访问硬件寄存器方面没有提供比C 更多的附加帮助,但是
在对于这种类型的抽象方面有很多好的理由使用它。最明显的是,C++ 类与任何
C 特性或者编程技巧相比,允许我们更完全地隐藏实际的便件接口。比如,可以
加入一个构造函数,在每一次新的时钟对象被声明的时候自动地设置硬件。这
省去了应用软件对初始比例程的显式调用的需要。此外,有可能把对应于设备
寄存器的数据结构隐藏在相关类的私有部分。这有助于防止应用程序员从程序
的其他部分意外的读写设备案存器。
限制C++ 的影响
在决定写这本书的时候我面临的一个最大的问题是:是否把C++ 加入到讨论
中去。尽管我熟悉C++ ,但是我不得不用C 和汇编来写几乎所有我的嵌入式软
件。而且在嵌入式软件界对于C++ 是否值得所产生的性能损失的问题存有很大
的争议。一般认为C++ 程序会产生更大的代码,这些代码执行起来比完全用C
写的程序要慢。然而,C++ 给于程序员很多好处,并且我想在这本书中讨论一些
这样的好处。因此,我最终决定把C++ 加入到讨论中来,但是在我的例子中只
是使用那些性能损失最小的特性。
我相信很多的读者在他们自己的嵌入式系统编程的时候会面对相同的问题。
在结束这本书之前。我想简单地评判一下每一种我使用过的C++ 特性。并且提
醒你一些我没有使用过的比较昂贵的特性。
当然,并不是每一件 C++ 引入的事情都是昂贵的。很多老的 C++ 编译器并入
了一个叫作C.front的技术,这项技术把 C++ 的程序变成C,并且把结果供给标
准的C 编译器。这个事实暗示这两种语言之间的句法差别很小,或与运行代价
无关( 注2) 。只有最新的C++ 特性,如模板,不能够用这种方式处理。
比如,类的定义是完全有益的。公有和私有成员数据及函数的列表与一个
struct 及函数原型的列表没有大的差别。然而,C++ 编译器能够用public 和
private关键字决定,哪一个方法调用和数据访问是允许的或者是不允许的。因
为这个决定在编译的时候完成,所以运行时不会付出代价。单纯的加入类既不
会影响代码的大小,又不会影响你的程序的效率。
默认参数值也是没有损失的。编译器只是加入代码使得在每次函数被无参数
调用的时候传递一个默认的值。类似地,函数名的重载也是编译时的修改。具
有相同名字但是不同参数的函数在编译过程中分别分配了一个唯一的名字。每
次函数名出现在程序中的时候编译器就替换它,然后连接器正确的把它们匹配
起来。我没有在我的例子中使用C++ 的这一特性,但是我这幺做过而没有影响
操作符的重载是另一个我使用过但是没有包括在例子中的特性。无论何时编
译器见到这样一个操作符,它只是用合适的函数调用来替换它。因此,在下面
列出的代码,最后两行是等价的,性能的损失很容易明白:
Complex a, b,
c = operator+(a, b)
// The traditional way: Function Call
// The C++ way: Operator Overloading
构造函数和析构函数也有一点与它们相关的损失。这些特殊的方法去分别保
证每次这种类型的对象在创建或者超出了范围时被调用。然而,这个小量的开
销是为减少错误而支付的一个合理代价。构造函数完整地删除了一个C 语言编
程中与未初始化数据结构编程错误有关的类。这个特性也被证明是有用的,因
为她隐藏了那些与像Timer 和Ta s k这样复杂的类相关的笨拙初始化顺序。
虚拟函数也具有一个合理的代价收益比。不要深究太多的关于什么是虚拟函
数的细节,让我们只是说一下没有它们多态性就是不可能的。而没有多态性,
C++ 就不可能是一个真正的面向对象的语言。虚拟函数唯一一个明显的代价是在
调用虚拟函数之前附加了一个存储查询。普通的函数和方法调用是不受影响的。
就我的体验来说太昂贵的C++ 特性有模板、异常事件及运行类型识别。这三个
特性都对代码的大小有负面的影响,而且异常事件和运行时类型识别还会增加
执行时间。在决定是否使用这些特性之前,你可能要做一些实验来看看它们会
怎么样影响你自己的应用程序的大小及速度。
嵌入式的C++ 标准
你可能想知道为什么 C++语言的创造者加入了如此多的昂贵的——就执
行时间和代码大小来说——特性。你并不是少数,全世界的人都在对同样的
一件事情困惑——特别是用 C++做嵌入式编程的用户们。很多这些昂贵的特
性是最近添加的,它们既不是绝对的必要也不是原来 C++规范的一部分。这
些特性一个接着一个的被添加到正在进行着的“标准化”进程中来。
在1996年,一群日本的芯片厂商联台起来定义了一个C++语言和库的子
集,它更加适合嵌入式软件开发。他们把他们新的工业标准叫作嵌入式C++。
令人惊奇的是,在它的初期,它就在C++用户群中产生了很大的影响。
作为一个C++标准草案的合适子集,嵌入式C++省略了很多不限制下层语
言可表达性的任何可以省略的东西。这些被省略的特性不仅包括像多重继承
性、虚拟基类、运行时类型识别和异常处理等昂贵的特性,而且还包括了一
些最新的添加特性,比如:模板、命名空问、新的类型转换等。所剩下的是
一个 C++的简单版本,它仍然是面向对象的并且是 C 的一个超集,但是它具
有明显更少的运行开销和更小的运行库。
很多商业的C++编译器已经专门地支持嵌入式C++标准。个别其他的编译器允
许手工的禁用具体的语言特性,这样就使你能够模仿嵌入式 C++或者创建你
的很个性化的C++语言。
虽然书上说模板是有一定的开销,不过我用的倒是挺爽的
具体可以看我上传的代码中 封装寄存器操作的实现 和 template.h 中的内容。
另外,效率都是经过测试的,直接被编译器自动优化了。
不过如果模板被滥用的话,确实会成为一场灾难。
之前我也有想过用c++
我一直都是使用 IAR C++来编写STM32的固件。
我的做法是,抛弃ST公司自带的库,采用自己编写的C++库(除了仅有的一个xx_MAP.h文件是ST的,其它的全部是自己定义和编写的)。
后来,包括应用库,例如LED,LCD,KEY,USB,GAP,等等,都是采用C++来写。
其主要原因还是我比较喜欢RAD快速开发模式。
例如,要编写一个USB应用,只需要很简单的继承USB类,再加入自己的应用就可以了。
aleyn 发表于
我一直都是使用 IAR C++来编写STM32的固件。
我的做法是,抛弃ST公司自带的库,采用自己编写的C++库(除了 ...
呵呵,村长光临啊~
曾经看过村长在别的帖子里上传的GPIO代码,
谢谢你的建议。
我也是抛弃ST公司自带的库,边学习边积累,呵呵
Pony279 发表于
截取《C和C++嵌入式系统编程》(英文版是Programming Embedded Systems in C and C++ - O'REILLY)一书中 ...
谢谢您的解答,我也去买本《C和C++嵌入式系统编程》来看看。
aleyn 发表于
我一直都是使用 IAR C++来编写STM32的固件。
我的做法是,抛弃ST公司自带的库,采用自己编写的C++库(除了 ...
村长境界比较高,
呵呵,我主要是看着C++在语法上提供的便利和面象对象才使用C++的,
对于RAD开发模型,我就不了解了...
本帖最后由 Pony279 于
17:41 编辑
这次不是新的实验,还是按键中断,提一个使用比较方便的地方,pa0, pa1, ..., 之类的定义吧,
之前类型转换操作符没重载好,编译器给我报个错说什么cv-qualifiers...不懂,刚刚把两个成员函数改成静态的,就编译成功了,
具体的实现的使用方法是这样的:
bool a = pa0;& && & //读PA0引脚的电平
pa1 =& && && && &//PA1脚输出a。
这种简单的IO操作,在51上简直就是家常便饭
因为STM32的读和写是分开两个寄存器的,想把读和写操作做到像51那样方便,
统一成一个名字,在C语言下确实有点无能为力了,
而C++提供了一种运算符重载的机制,就可以很好的解决这个问题,
于是我就在代码里定义了pa0 ---- pd15 的引脚,
每个引脚都可以像上面那样使用,还算是比较方便的了,
当然,如果一个引脚不是配置成开漏(外接上拉)的方式, (如) a = pa0;&&pa0 =&&这两种使用方式是不允许同存在的。
实现机制并不难,核心还是运算符重载,
比如上面的 bool a = pa0 就是利用了重载的 bool()操作符,
而下一句 pa1 = a 就是利用了重载的 = 操作符
因为每个引脚的操作都是有很多共同的特点的,所以我使用了模板来实现。
我把实现的代码简要的写出来,完整的代码可以自己下载来参考。
// 用来给模板提供端口信息的类
& & & & class CPort_InfoA{public:& & & & enum{PORT = (uint32_t)GPIOA};& & & & };
& & & & class CPort_InfoB{public:& & & & enum{PORT = (uint32_t)GPIOB};& & & & };
//用来给模板提供引脚号信息的类
& & & & class CPin_Info0{public:& & & & enum{PIN = Pin0};& & & & };
& & & & class CPin_Info1{public:& & & & enum{PIN = Pin1};& & & & };
& & & & template&class CPort_Info, class CPin_Info&
& & & & class CPin
& & & & protected:
& & & & & & & & // 注意一定要定义为static的,否则 bool() 运算符重载编译不通过。
& & & & & & & & static finline GPIO_TypeDef* GetPort()& & & & & & & & {return (GPIO_TypeDef*)(CPort_Info::PORT);}
& & & & & & & & static GPIO_Pin GetPin()& & & & & & & & & & & & & & & & & & & & {return (GPIO_Pin)(CPin_Info::PIN);}& & & & & & & &
& & & & public:
& & & & & & & & void finline Config(const GPIO_Input input, const InputStyle style = PULL,const InputPull pull_way = UP)
& & & & & & & & & & & & & & & & & & & & & & & & {GetPort()-&Config(GetPin(), input, style, pull_way);}
& & & & & & & & void finline Config(const _Output output, const OutStyle style = OPEN_DRAIN,const OutSpeed speed = SPEED_10M )
& & & & & & & & & & & & & & & & & & & & & & & & {GetPort()-&Config(GetPin(), output, style, speed);}
& & & & & & & & finline CPin& operator &&(bool val)& & & & & & & & & & & & {GetPort()-&Write(GetPin(), val);return *}
& & & & & & & & finline CPin& operator =(bool val)& & & & & & & & & & & & { GetPort()-&Write(GetPin(), val);return * }
& & & & & & & & //& & & & 读引脚,如果引脚为高电平,则读到非零值,否则读到0
& & & & & & & & finline CPin& operator &&(bool& val)& & & & {val = GetPort()-&Read(GetPin());return *}& & & &
& & & & & & & & finline CPin& operator &&(int& val)& & & & & & & & {val = GetPort()-&Read(GetPin());return *}
& & & & & & & & finline CPin& operator &&(u16& val)& & & & & & & & {val = GetPort()-&Read(GetPin());return *}
& & & & & & & & finline CPin& operator &&(u32& val)& & & & & & & & {val = GetPort()-&Read(GetPin());return *}
& & & & & & & &
& & & & & & & & finline operator bool() const& & & & {return GetPort()-&Read(GetPin());}
& & & & };
& & & & extern CPin&CPort_InfoA, CPin_Info0&& & & & pa0;
& & & & extern CPin&CPort_InfoA, CPin_Info1&& & & & pa1;
& & & & extern CPin&CPort_InfoB, CPin_Info0&& & & & pb0;
& & & & extern CPin&CPort_InfoB, CPin_Info1&& & & & pb1;
& && &&&类中是没有数据成员的,所以只声明不定义pa0也行,但是需要编译器的优化等级调高点,才不会报错,
& && &&&或者,随便在一个文件里定义定义一来就行了。
& && &&&这部分的具体代码可参考 myfwlib 文件夹中的 GPIO_CPin.h 和 GPIO_CPin.cpp 中的内容。
& && &&&实验还是按键中断实验,不过对部分名字做了修改,不和原来的代码兼容
& && &&&因为标准库里也有个iostream,我怕搞混了,所以就给自己的iostream里的内容加了个命名空间,namespace nstd,非标准,哈哈,因为只有我在用~
本帖子中包含更多资源
才可以下载或查看,没有帐号?
本帖最后由 Pony279 于
22:33 编辑
发现我之前的方式效率稍低一些,
虽然以前测试的时候对比过位带的方式,但是发现位带的代码会略多一点,
估计是用位带的操作的宏的时候编译器会产生一些常量,看上去吃了点flash。但是使用的多了,确实是位带的方式效率高。
我反汇编对比了《STM32不完全手册》书上提供的位带操作的宏,和我之前的引脚操作的方式,发现位带的操作方式速度是比较快的,所以我把楼上的代码改成位带操作去实现了。
基本原理差不多的,具体的就自己看了。
示例代码是很简单的闪烁灯,,,我发现我测试啥都喜欢来个闪烁灯
#include &sys.h&
int main(void)
& & & & sys.Init();
& & & & rcc.Enable(PERIPH_GPIOA);
& & & & pa8.Config(OUTPUT, PUSH_PULL);
& & & & while(1)
& & & & & & & & Delay_ms(1000);
& & & & & & & & pa8 = !pa8;& && && && &// led 取反,这句话用起来有点像用51单片机的感觉,好亲切
本帖子中包含更多资源
才可以下载或查看,没有帐号?
我也用C++开发过东西,但个人感觉C++是一门被过度设计的语言,他的许多特性只适合被拿来欣赏而不是使用,也不是谁都驾驭的了,对MCU程序设计来说更是,累己又累人。
cheh 发表于
我也用C++开发过东西,但个人感觉C++是一门被过度设计的语言,他的许多特性只适合被拿来欣赏而不是使用,也 ...
呵呵,我倒觉得C++给我提供了很多方便
膜拜中。。。
我一直用C++开发ARM, 不过一直使用ADS, 在MDK上,C++的虚函数没发使用,只好在ADS上玩了。
liyong2000 发表于
我一直用C++开发ARM, 不过一直使用ADS, 在MDK上,C++的虚函数没发使用,只好在ADS上玩了。&&...
ADS在win7下老是崩溃。。。我对ADS比较反感。。。
这个实验是窗口看门狗实验。。。
吐糟一下STM32的WWDG,设计的实在不咋的,
1. 不如独立看门狗,WWDG还可以由RCC控制,想关就关(实验代码里有这个演示)
2. 这个可能是我自己的问题,有经验的帮我看看。手册上说WWDG的计数器达到0x40就会产生中断,而这个时候计数器的值肯定是在窗口中。但是测试结果发现,不在窗口中的时候也可以进入中断的。
3. 居然可以中断喂狗。。。这样简单的功能,随便用个定时器+几行代码也能做到。。。要这狗来干啥。。。
另外发现软件仿真不了,参考网上的资料,说是MDK不能仿真硬件复位。MDK真不厚道,不能仿真的东西也搞上去,这个是坑人么。。。
吐糟归吐糟,实验还是要做的。。。
实验的功能是,上电复位后,
延时 1s&&--------&&两个 LED 亮 ---------1s --------两个LED灭 -------- 放狗开中断 --------进入死循环延时 10s
在中断中,如果发现看门狗计数器在窗口内,喂狗,翻转LED1,否则不喂狗,翻转LED0。
延时10s后,通过RCC 把狗收了,延时1s,发现系统没复位,发条串口信息,over
上主函数代码,
#include &sys.h&
#include &iostream.H&
ARMAPI void WWDG_IRQHandler()
& & & & if(wwdg.IsInWindow())& & & & // 如果计数器的值在指定的窗口中
& & & & & & & & wwdg.Reflash();& & & & & & & & // 喂狗
& & & & & & & & pd2 = !pd2;
& & & & else
& & & & & & & & pa8 = !pa8;& & & & & & & & // 程序虽然会跳进这里。。。奇怪。。。
& & & & wwdg.ClearPending();
int main(void)
& & & & sys.Init();
& & & & scb.SetPriorityGrouping(GRP4_SUB4);& & & & & & & & // 4个组优先级,4个子优先级
& & & & nvic.Config(wwdg, ENABLE);& & & & & & & & & & & & & & & & // 使能窗口听门狗的中断
& & & & rcc.Enable(gpioa);& && &&&//这个的配置和以前不同了哦,具体实现利用的是函数重载,看GPIO_TypeDef的定义就知道了。感觉这样用方便些。
& & & & rcc.Enable(gpiod);
& & & & // 两个LED对应引脚的配置
& & & & pa8.Config(OUTPUT, PUSH_PULL);
& & & & pd2.Config(OUTPUT, PUSH_PULL);
& & & & // 两个LED灭
& & & & pa8 = 1;
& & & & pd2 = 1;
& & & & Delay_ms(1000);
& & & & // 两个LED翻转
& & & & pa8 = !pa8;
& & & & pd2 = !pd2;
& & & & Delay_ms(1000);
& & & & // 两个LED翻转
& & & & pa8 = !pa8;
& & & & pd2 = !pd2;
& & & & Delay_ms(1000);
& & & & rcc.Enable(wwdg);
& & & & wwdg.SetTimerBase(PCLK1_DIV_4096_DIV_8);& & & & //设置窗口看门狗的时钟
& & & & wwdg.SetWindow(0x7f);& & & & & & & & & & & & // 窗口值
& & & & wwdg.Start();& & & & & & & & & & & & & & & & & & & & // 启动窗口看门狗
& & & & wwdg.Reflash();& & & & & & & & & & & & & & & & & & & & // 刷新窗口看门狗的计数器
& & & & wwdg.EWI_Enable();& & & & & & & & & & & & & & & & // 使能窗口看门狗的中断
& & & & while(1)
& & & & & & & & for(u8 i = 10; i--)
& & & & & & & & & & & & Delay_ms(1000);
& & & & & & & & rcc.Disable(wwdg);
& & & & & & & & Delay_ms(1000);
& & & & & & & & output&&&TMD, 系统没有复位,WWDG还是可以关闭的。。。&&&
& & & & & & & & while(1);
本帖子中包含更多资源
才可以下载或查看,没有帐号?
有些手机和平板有在运行的时候自由设置CPU频率的功能,昨天心血来潮也做了一个,
实验现象就是,LED闪烁,闪烁的频率会不断变化
#include &sys.h&
#include &iostream.H&
// 应用程序中修改 CPU 频率的实验
int main(void)
& & & & sys.Init();
& & & & pa8.Config(OUTPUT);
& & & & while(1){
& & & & & & & & // 使用 HSE 作为系统时钟
& & & & & & & & rcc.SysclkConfig(HSE_AS_SYSCLK);
& & & & & & & & for(u8 i = 0; i & 4; i++)
& & & & & & & & {
& & & & & & & & & & & & Delay_ms(100);
& & & & & & & & & & & & pa8 = !pa8;
& & & & & & & & }
& & & & & & & &
& & & & & & & & // 使用 HSI 作为系统时钟
& & & & & & & & rcc.SysclkConfig(HSI_AS_SYSCLK);
& & & & & & & & for(u8 i = 0; i & 4; i++)
& & & & & & & & {
& & & & & & & & & & & & Delay_ms(100);
& & & & & & & & & & & & pa8 = !pa8;
& & & & & & & & }
& & & & & & & &
& & & & & & & & // 后面的是使用PLL输出作为系统时钟
& & & & & & & & for(u8 pll = 2; pll &= 9; pll++)
& & & & & & & & {
& & & & & & & & & & & & rcc.SysclkConfig(PLL_AS_SYSCLK, HSE_DIV_1, pll);& & & & // PLL时钟源为 HSE
& & & & & & & & & & & & for(u8 i = 0; i & 4; i++)
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & Delay_ms(100);
& & & & & & & & & & & & & & & & pa8 = !pa8;
& & & & & & & & & & & & }
& & & & & & & & }
& & & & & & & &
& & & & & & & & for(u8 pll = 2; pll &= 16; pll++)
& & & & & & & & {
& & & & & & & & & & & & rcc.SysclkConfig(PLL_AS_SYSCLK, HSI_DIV_2, pll);& & & & // PLL 时钟源为HSI
& & & & & & & & & & & & for(u8 i = 0; i & 4; i++)
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & Delay_ms(100);
& & & & & & & & & & & & & & & & pa8 = !pa8;
& & & & & & & & & & & & }
& & & & & & & & }
本帖子中包含更多资源
才可以下载或查看,没有帐号?
戒骄戒躁,潜心学习!!!
还没玩到那种程度呢
本人现在32位单机都用c++来写程序!
Pony279 ,好,看了你的代码,感觉不错,我现在32位机全都用c++来编写了,希望多多交流,MCU(处理器) 发展日新月异,资源越发丰富,软件开发效率、维护成了主要矛盾,用c++有着无与伦比的优势,只有真正在项目中用过了,才真正了解在嵌入式系统中为什么要用c++,怎么去用c++,和c到底差了多少,为什么可以使用继承(但不能乱用),模板.....我保证用过了一次,c++就会根植于你心里,你会断然接受它! 我从前也是极力反对单片机使用c++开发......现在32位机基本都用它了...
不错,学习一下,我也觉得C++会方便很多,未来的嵌入式开发肯定会用C++或JAVA
这个不错啊,记号一下
Pony279 发表于
回复【54楼】ewindiy 疯沁
-----------------------------------------------------------------------
我认为应该考虑用template,这可是C++的利器呀,特别是模板元编程。我曾经发贴推荐一个 C++ template做的固件库,不过那个是用C++ 11 标准写的,MDK只支持 C++03 不过思想是一致的。
说实话,c++我也想用,但问题不少,虚函数支持是个大问题。gui必用虚函数,不然无意义。
一直都是在VC下用C++开发的。
mark,通帖好东西啊
阿莫电子论坛, 原"中国电子开发网"

我要回帖

更多关于 嵌入式研发工程师 的文章

 

随机推荐