OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 32799|回复: 72

不知有没有人对C++开发STM32感兴趣的,来讨论些问题

[复制链接]

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
发表于 2012-3-9 16:27:12 | 显示全部楼层 |阅读模式

注1:以下的内容本来是我在ourdev上发表的帖子。因为昨天在这里发了一个关于宏的帖子,提到一点C++,看到有网友感兴趣
转到这边来了,因为部分内容已经和网友讨论过,所以我对原来的内容也做了一点修改 。
注2:如果有网友只学过C没学习过C++的,没关系,因为C++你已经算是会了一半了,看到不懂的概念,比如C++的函数重载,直接百度,谷歌,你绝对能很快掌握!


因为一开始我自学的就是C++,后来玩单片机以后才使用C语言来开发东西,也写过一些程序了,
但是我的体会就是,C语言没有C++那么方便,最近才在学STM32,看到ARM编译器能够支持C++,挺爽的,就开始尝试把实验代码的工程改成C++的方式
出现了一些问题,我不太会查资料,网上讨论这个的也比较少,所以就发个帖子大家一起讨论下

先说一下,为什么要用C++,(说的可能不太清楚,对没学过C++的哥们就不好意思啊呃。。。)
1. 最简单的,函数重载, 这个语法特性就比C语言的好,还有运算符重载,这些都可以让代码变得更直观(这个等下我用我刚刚拓展的代码来演示一下)
2. 命名空间,C语言写大程序一般每个模块都会有个前缀,但是写起来麻烦,其实有时候在一个地方只会用到一个模块的内容,所以用using xxx::xxx感觉会比较方便些。
3. 类的支持,尤其是成员函数什么的使用起来方便,还有constructor,不用每次手动调用初始化。
(关于这个还是有一点问题我没有解决的,好像是全部类变量的初始化问题,我比较健忘,记不清了)
4.inline关键字,可以解决宏的一些缺陷 (有热心网友指出,用C也有__inline关键字)
5.引用参数的支持,比直接使用指针省事放心些
6.模板的支持,(这个在我之前发过的一个关于宏的帖子里有提到一点,也有提供代码,这个帖子的附件里面也有代码)
7.至少,网上说的,C++具有C的全部优点
关于我上面说的优点,也有网友对我的观点不屑,
有的说C++效率低下(关于这个我并不理解,因为我反汇编看过,没有明显的区别,除非你使用了继承多态的特性可能会有问题,
但是,在有些地方就需要使用这些特性,特别是在比较大的系统里,比如GUI,就算是用C语言去模拟面象对象的实现过程效率也是差不多的)
还有网友称C++的一些语法特性为语法糖,没多大用处(呵呵,这个就看个人喜好了,就像学过汇编的哥们可能就喜欢写汇编,不喜欢用C语言一样)

我也不打算说服所有的人,我只是希望有兴趣的人能和我一起交流意见,我之前发了那个帖子之后,就有一位华工刚毕业的师兄感兴趣,通过邮件和我交流
只可惜那个时候我一直没什么时间继续解决那些问题。趁这个下午有点时间,我就改了一下之前的代码,再到这里发帖,希望有兴趣的人能一起交流。


下面是我遇到的一些问题,有的已经解决,有的还没解决:

1. 以前的库函数怎么使用?
在函数声明前加上 extern "C" 就可以了,因为C++支持函数重载之类的东东,所以生成的目标代码的名字和C会有些不同,用extern "C"强制成C语言的名字规则。
现在新版本的库好像已经加上了,这里顺便问一下,新版本的库在官网的哪里下载?我不要一点就直接弹出下载的链接

新版的STM32的库的头文件前面是
#ifdef __cplusplus
extern "C" {
#endif

后面
#ifdef __cplusplus
}
#endif
这就是为了兼容C++的。

2. 中断函数进不去呀?
中断函数定义前也要加上 extern "C"。中断函数,名字已经固定了(在你使用MDK给的启动代码的情况下),
而C++对函数的生成的目标代码的命名方式和C语言不一样(为了支持重载),
然后我是以这种方式来解决的,
#define ARMAPI extern "C"    
ARMAPI void EXTI15_10_IRQHandler(void)
{
...    
}



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
#endif

...
...

#ifdef __cplusplus
//恢复368号警告
#pragma diag_default 368
}

4. C++有 new 关键字,类似C的malloc,但是这个是需要有内存管理提供动态内存的,这个在一个没有操作系统的MCU上咋整呀?
其实关于使用C++的,国外已经有成功的例子了(只是IDE用的不是MDK。。。),我从网友提供的链接去下载了源代码:
http://andybrown.me.uk/ws/2011/12/28/stm32plus-a-c-library-for-stm32-development/ 
(PS:看了他们的代码库,我发现我以前写的文件系统实在是弱啊。。。没关系,会继续完善的)

人家是这么搞的,利用函数重载,重载了new操作符,(软件仿真会跳进重载的函数里)
,自己只要提供malloc和free以及堆的一些初始化就行了(这个一般要上了OS才有内存管理的吧。。。)

/*  * 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); }  



还有些没解决的问题

5. 定义全局类变量后会有错误:
..\output\stm32test.axf: Error: L6218E: Undefined symbol __cpp_initialize__aeabi_ (referred from anon$$obj.o).
class A
{
public:
A()
{
int x, y;
x = 5;
y = 7;
x = y;
y = x + 8;
}
};       
A a;

有些地方可能不清楚,原帖子在这个链接:
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=5401612&bbs_page_no=1&search_mode=3&search_text=Pony279&bbs_id=9999

然后是我刚刚做的设置IO口模式的几个函数的测试代码,因为实现代码比较长,我不会帖上来,
在附件里面有完整的代码,测试代码在gpio_test_120309a.cpp文件里,相关的代码全部在 MYLIB文件夹里面也有。
(自己在学习的时候整理的函数都在那里面,其实内容比较少。。。)
我这里只是为了演示使用的便利性的提高和代码的阅读性的提高。

SetMode函数实现是利用了函数重载的,和默认参数。如果不知道什么是重载的,先不要去想语法,直接看代码,看得懂不?
int main(void)
{
 {using namespace gpio;    //在这个代码block里面使用gpio的命名空间。

 SetMode(GPIOA, Pin(0), OUTPUT);        //设置PA0为输出模式,有默认参数 开漏输出, 这里没有写出来
 SetMode(GPIOA, Pin(1), OUTPUT, OPEN_DRAIN, _50M);
 SetMode(GPIOA, Pin(2), OUTPUT, PUSH_PULL, _50M);
 SetMode(GPIOA, Pin(3), INPUT);        //有默认参数,上拉输入,没有写出来。
 SetMode(GPIOA, Pin(8), INPUT, PULL, DOWN); 
 SetMode(GPIOB, in(3),  INPUT);
 SetMode(GPIOB, Pin(8), INPUT, PULL, DOWN);
 }
 //仿真结果和预期一致。
 while(1); 
}

函数重载是语法上允许同名函数的存在,但是需要这两个函数的参数列表是不同的,使用的时候,编译器会知道你要调用的是哪个函数。
在写代码的时候对于一个同样功能但是参数类型不同的函数,如果需要起不同的名字,不论是写代码还是读代码都会比较痛苦的,

我上面好像提了几次代码的阅读性的问题,因为我一直很重视代码的阅读性,这一点从我之前发的那个关于宏的帖子大家也可以知道。
因为,我想老鸟应该有体会,其实程序猿花在读代码上的时间,是远大于写代码的时间的。

好像扯远了。。。就先到这里吧。。。


2012.3.26 补充:
http://www.openedv.com/posts/list/3210.htm



stm32_cppTest.zip

1.43 MB, 下载次数: 1447

https://github.com/roxma
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-3-9 17:21:45 | 显示全部楼层
我也是学的c++.现在完全c了....
倒是c++还给老师了...
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-9 17:25:27 | 显示全部楼层
补充一下,以前用的是STM32最小系统板,照着不完全手册做,用printf函数的时候出了点问题,
百度后得知微库片子才能跑程序,不太理解,但是使用了微库以后就有上面的第5个问题。

现在用ALIENTEK MiniSTM32开发板下载测试,没有出现问题。。。
搞不清楚以前是什么原因。。。

那好像现在敢没啥问题要解决的了。。。 

还有

STM32的一个头文件里有typedef ... bool的,C++已经内建了bool了,所以注释掉即可
https://github.com/roxma
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-3-9 17:27:08 | 显示全部楼层
看我们的usart.c就知道原因了.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-9 17:27:31 | 显示全部楼层
回复【2楼】正点原子:
---------------------------------

因为一直以来嵌入式的编程主流都是C吧。
https://github.com/roxma
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-3-9 17:29:00 | 显示全部楼层
确实.从学51开始,人家就不支持C++,后面的AVR,也是.最后到STM32,虽说KEIL支持CPP,但是已经没有欲望去整了...
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-9 17:45:51 | 显示全部楼层
回复【6楼】正点原子:
---------------------------------

我没学过AVR,接触51的时间也不长,偶尔还得用一下VC来写上位机,所以对C++一直都很感兴趣

不过其实C++能做的全部都可以用C语言来实现,
只是我比较喜欢那种语法上提供的便利而已,有一句话是说,“让编译器成为程序员的奴隶”,
利用C++的语法可以让编译器去帮程序员做很多重复的工作

也有网友说这方面用java,C#什么的更好,
但是就算是可以,执行效率也太低了,在stm32上搞这个的实在是有点难以接受


https://github.com/roxma
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-9 18:09:17 | 显示全部楼层
看到网上有人在STM32上用C#的,确实挺牛的,不过我也只能膜拜一下,效仿就没多大意义了。。。
https://github.com/roxma
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-3-9 18:14:53 | 显示全部楼层
回复【8楼】Pony279:
---------------------------------
没必要搞这么多,弄一种最习惯的就OK了.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-9 18:34:48 | 显示全部楼层
回复【4楼】正点原子:
---------------------------------
嗯,看了,我测试C++的代码用的是以前从网上抄的usart,

翻了一下我的测试代码里的usart.c代码。。。里面没有那段解决printf使用问题的代码,

下载到板子上又正常。。。

然后才发现原来是我不知什么时候,把解决printf使用问题的那段代码挪到sys.c里去了。。。

记性差的悲剧啊。。。
https://github.com/roxma
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-9 19:51:29 | 显示全部楼层
补充:
关于内联函数,
经过测试,原来编译器是这么搞的:

在一个.c文件里如果被引用2次或以上,就会自动生成一个函数
(估计它是想节省代码的,事实上,对于我上面写的宏,如果参数是常量,它传递参数 + 跳转指令 + 返回指令的代码量已经多于常量优化后的代码量了。。。我晕。。。)
如果在一个模块里,这个内联函数只被引用一次,就不会生成函数。。。看来编译器来是比较傻逼的。。。
不过这个应该不是编译器不能解决的问题,只是需要时间去进步罢了。
https://github.com/roxma
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-9 20:07:01 | 显示全部楼层
继续补充:
看了MDK的文档,关于inline的说明,可以使用__forceinline而不是inline,这样的话就可以更好的优化了。



https://github.com/roxma
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-9 20:10:35 | 显示全部楼层
可以统一的定义 #define inline __forceinline
不知道这样做合不合适,其实写inline的人理应知道那代码通过内联以后会更好的,
如果强制内联被滥用,就悲剧了。
https://github.com/roxma
回复 支持 反对

使用道具 举报

27

主题

274

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
472
金钱
472
注册时间
2011-11-2
在线时间
11 小时
发表于 2012-3-9 20:17:57 | 显示全部楼层
是高手啊,加油哈,估计你是前人了,我们这些后人都是吃现成的。。。
回复 支持 反对

使用道具 举报

12

主题

216

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
313
金钱
313
注册时间
2011-4-7
在线时间
3 小时
发表于 2012-3-9 20:31:30 | 显示全部楼层
学习了!!
回复 支持 反对

使用道具 举报

11

主题

49

帖子

0

精华

初级会员

Rank: 2

积分
118
金钱
118
注册时间
2012-2-17
在线时间
0 小时
发表于 2012-3-9 20:35:35 | 显示全部楼层
目前,还只是葵花第一层,膜拜
那些年,我们一起走过的日子...
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-9 21:47:42 | 显示全部楼层
我还是采用宏定义来了,不过不直接改inline,而是定义一个宏finline,在需要强制内联的时候就用这个宏了。
#define finline __forceinline

就到这里吧,解决了上面说的问题,基本上应该是足够了,以后遇到问题了再回来补充。

代码我就不上传了,留意一下前面讲的内联自己做修改吧。
https://github.com/roxma
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-10 14:56:29 | 显示全部楼层
对了,我上面一直在说。。。
只要**参数是常数,那么效率就会比较高。。。
但是。。。谁能保证用户不会传个变量进去导致效率低下呢?

记得上个月在在学习Java的时候讲师是这么比喻的:你一个人不犯法,这个社会就和谐了?

那该怎么办呢?
我的想法是:强制参数为const,如果用户想要传递变量进去?对不起。。。我没有提供这样的函数给你,自己写去吧。

代码修改后再上传。
https://github.com/roxma
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-10 17:25:10 | 显示全部楼层
回复【18楼】Pony279:
---------------------------------
我的C++语法没学好。。。
声明为const也不能强制参数为常量的,只是声明了const在函数内部不能修改这个变量了。。。
使用枚举是比较好的办法,之前也是这样的。
https://github.com/roxma
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-11 01:42:42 | 显示全部楼层

仅完善了一下GPIO部分的寄存器封装
其实用起来还是比较好用的,但是函数重载多了,我也不知怎么写说明文档了,所以又不太好用了。。。



 

stm32_cppTest.zip

1.43 MB, 下载次数: 758

https://github.com/roxma
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-11 12:20:40 | 显示全部楼层
 说一下之前我上传的代码的使用吧,我这里只是为了示例用C++怎么写,所以以后就不会再在这里上传代码了,因为基本问题都已经解决了。
也许我示例的不好,因为我不是软件大牛。。。也请大家包涵。。。
其实下面的示例也主要用了函数重载,至于C++的模板,大家可以看MYLIB文件夹下的template.h里面的内容

其它的比较简单,我只说SetMode函数的使用:
(如果我这里说的都不能满足你的需求,可能就需要你直接看函数原型,或者,自己去写个函数出来了。)
第一种最简单的适应大部分情况的用法,也就是代码执行速度最快代码的用法
把PA0设置为推挽输出, 速度50M
SetMode(GPIOA, in(0), OUTPUT, USH_PULL, _50M);
对于输出,默认是开漏10M速度输出,如果后面的两个参数不写,则取默认值。
(PS:上面那句,生成代码量为12字节)
把PA0-PA7设置为推挽输出, 速度2M
SetMode(GPIOA, in(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);

上面的函数生成的代码量都是比较少的, in是一个类,虽然生成一个类的对象会调用构造函数之类的,
但是因为比较短,都被编译器优化掉了。至于为什么我会用类的对象,因为,这样,在使用的过程中不容易出错,
强制成一种类型,代码的阅读性和可维护性也有所提高。有兴趣的朋友,也可以用C语言来实现一次,帮我对比看看
C语言是不是真的效率比较高,还是说,其实效率上没什么区别?

好了,废话说多了,上面的使用是有点限制的,因为我只能同时设置一个引脚或者几个连续的引脚的模式,
那么怎么同时设置几个同端口但是编号不连续的引脚的模式呢?
通过继承的方式,我又写了一个类,Pins提供了这种支持,但是,由于编译器还是比较傻逼的,
生成的代码量比较大,超过200字节了,所以我使用非内联的方式,
把PA9和PA2设置为下拉输入
SetMode(GPIOA, ins(9)+Pins(2), INPUT,PULL,DOWN);
这条语句生成的代码是40字节,呵呵,实在是有点多啊,加上函数本身,刚刚测试了,原来有400字节啊,,,
因为编译器以为那是变量,所以傻逼的没有做多少优化,以至于。。。。。。。
多得有点恐怖,,,还好,其实这种方式是不常用的,哈哈。


但是其实呢,对于实现上面的内容,SetMode函数也有更加高效用法,只是使用直接比较复杂,所以我就没写出来,
如果有特殊要求,再去看吧,我想一般都是没有这种必要了。
https://github.com/roxma
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-3-11 12:25:25 | 显示全部楼层
很有研究代码的精神啊。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-11 12:30:26 | 显示全部楼层
回复【22楼】正点原子:
---------------------------------
毕竟单片机不是PC机啊,
在PC上编程的时候,随便就申请个上K的空间来用了,
学习51后才发现,原来这是多么奢侈啊。。。
就算是STM32,也不能用K级的空间来挥霍,,,
https://github.com/roxma
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-3-11 12:37:52 | 显示全部楼层
那是,越低级的单片机,越能锻炼勤俭节约的品质。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-11 13:17:19 | 显示全部楼层
上面说的SetMode用起来不知道会不会比较麻烦,
还有另一种方案就是,
直接修改官方库的结构体的定义,增加一些成员函数,这样用起来也许会爽一点吧,,,

不过之前写的函数我也不打算删改,就像Windos下的VC++编程一样,发展到了MFC,你可以用MFC里的类,
一样也可以用以前C语言的API函数,有一句话是这么说的:“经常修改的代码不是好代码”
所以,要改的话一般是基于原来的基础去拓展,而不是反复的改,因为,反复的改是很容易出bug的,
就算没有BUG,对于使用者来说也是一种痛苦。


PS:周末快结束了,,赶作业的时间到了。。。以后我再试试吧。。。
https://github.com/roxma
回复 支持 反对

使用道具 举报

38

主题

248

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
463
金钱
463
注册时间
2011-2-11
在线时间
12 小时
发表于 2012-3-11 14:26:22 | 显示全部楼层
不大了解c++,总觉得c++很多特性都不是为了嵌入式设计的。
c一开始未必是面向嵌入式领域设计的语言,但现在看来,它确实是最贴切的。
c++的那么多特性反倒是支持应用开发的。
Openedv大力支持的开源RTOS  --Trochili RTOS(飞鸟)
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-11 16:17:44 | 显示全部楼层
回复【26楼】trochili:
---------------------------------
要说C++效率低的地方,我现在只想到多态,
普通的继承是不会影响到效率的。
但是如果不是写一个像MFC那样的框架,或者说一个比较大的系统,一般也是用不到多态的。
C++当然是有些特性是不能像PC机上编程那样用的,这个就需要灵活使用了,看需求使用即可,不能为了多态而多态。



PS:刚才简单测试,在已有的结构体上增加成员函数,不会改变对结构体用sizeof求出来的值,这就是说,
直接修改官方的结构体定义的方案还是可行的~其实需要改动的地方不大,只不过是SetMode(GPIOA, in(xxx), ...)
可以这样用 GPIOA->SetMode(Pin(...), ...)而已,没什么的了,也只不过是换了一种表达方式罢了。
https://github.com/roxma
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-12 14:12:29 | 显示全部楼层
刚刚用24楼的方案测试了下,可以的。
只是。。。千万千万不要把编译器的优化等级设置成最低,否则。。。后果将不堪设想,,,700+字节一条语句。。。
https://github.com/roxma
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-3-12 18:39:17 | 显示全部楼层

附件是修改后的代码,只是改成了24楼的方案。直接给GPIO_Typedef结构体增加成员函数。

昨天顺手去ST的官网下载了3.5版的库,把全部文件名改成cpp重新生成了一个lib文件,
因为以后做实验的时候可能会用的到,而且用extern "C"来兼容C++的话有时候还是有些不方便的.
记得都是.c文件的时候生成的lib是8.60M,改成cpp后生成的是8.83M (都是3级优化)
但是这个并不能说明c++的效率是比c低的,我前面有提到过,c++对目标代码的命名
和c是不一样的,因为要支持重载,而库里面肯定是会有关于命名的索引的。

本来想保留原来的那些函数的,但是,由于函数必须是内联的(为了保证效率),
因为原来的函数需要GPIO结构体的定义,所以GPIO结构体需要放在前面,
可是GPIO结构体的成员函数又需要用到这些内容函数,所以这些函数又要放在前面,产生了矛盾。。。
(内联函数必须暴露所有的定义的)

GPIO结构体的成员函数是没办法直接基于这些函数去拓展的,所以我干脆就把它们删了,,,
(现在想想,好像也没必要删。。。我为什么要删???估计当时犯傻了。。。)

修改后的结构体定义被挪到了MYLIB文件夹的GPIO_Typedef.h里面了。

使用方法和上面说的差不多,
只是表达形式变了而已,SetMode名字改成了Config,
因为我发现这个名字比较通用,呵呵~
文档说明木有时间写啊。。。
以后有时间的话我就顺便把如何建立C++版的STM32工程给写了。。。

这里面的代码是C++版的闪烁灯程序。
以后还打算修改官方结构体的定义(只是增加成员函数而已。。。)
不过不打算再在这个帖子上发了,因为继续发一样模式的代码对这个帖子讨论的主题已经没有实质性的意义了。

stm32_cppTest.zip

2.28 MB, 下载次数: 564

https://github.com/roxma
回复 支持 反对

使用道具 举报

36

主题

1263

帖子

1

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1612
金钱
1612
注册时间
2012-6-15
在线时间
39 小时
发表于 2012-6-15 14:35:39 | 显示全部楼层
这是我做的一个工业控制检测的一个项目  有 无线,LCD 键盘 485(Modbus协议)总线等
就是用的C++ 做的, 


后面的类库 也是 自己移植的 只用到 GPIO RCC NVIC



回复 支持 反对

使用道具 举报

36

主题

1263

帖子

1

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1612
金钱
1612
注册时间
2012-6-15
在线时间
39 小时
发表于 2012-6-15 15:01:53 | 显示全部楼层
以前一直用C开发 , 
当时 转 C++ 就是 觉得 c 里面的字符串 处理起来比较麻烦

个人觉得 c++ 的效率,并不比 C低多少,而且 完全兼容C,
在特别注重效率的地方 可以直接用C 或汇编
但是开发效率会提高很多,而且兼容性、安全性、健壮性 都会提升很多
回复 支持 反对

使用道具 举报

36

主题

1263

帖子

1

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1612
金钱
1612
注册时间
2012-6-15
在线时间
39 小时
发表于 2012-6-15 15:09:02 | 显示全部楼层
回头 有时间的话 我也写个帖子,跟大家交流一下 
以前实在没发现 做这方面的, 国外网站看起来又比较费劲 
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-6-15 17:51:25 | 显示全部楼层
嗯,在需要的时候适当利用C++的特性,可以给开发带来很多方便,而且几乎可以说是完全兼容C,在一个团队合作的时候,可以和使用C语言的队友的代码兼容,这一点是很赞的!

对这个感兴趣的人实在少,其实向C++的趋势早就有了,不然ARM的编译器也不会去支持C++的,

我对C++的了解还是比较少的,我比较感兴趣楼上提到的类库是从哪里移植来的?自己写要累死人了。。。

有些特性我一直都不敢用,比如 try catch的,还有 new 操作符,在电脑上编程的时候用说放心,不知道这个在STM32上好用不,以及怎么配置。。。
https://github.com/roxma
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-8-14 20:14:46 | 显示全部楼层
回来补充一下,
前段时间对特去学习了一下C++的多态的机制,我发现以多态认为C++效率低实在是一种肤浅在想法,多态的实现可以说是一种查表法,在速度上比不断的 if else 的机制好得多,多态的最大代价估计只是放弃了内联罢了。
记得以前听别人说过虚函数效率低,原来并不是这样的。
有兴趣的也可以在网上搜索一下C++多态的实现,或者看我上传的这本书,对于深入学习 C++ 很有帮助

Addison Wesley - Inside the C++ Object Model.pdf

1.45 MB, 下载次数: 835

https://github.com/roxma
回复 支持 反对

使用道具 举报

27

主题

147

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
275
金钱
275
注册时间
2012-8-11
在线时间
0 小时
发表于 2012-8-14 20:24:56 | 显示全部楼层
好 NB 的感觉,学习了~~~
回复 支持 反对

使用道具 举报

0

主题

4

帖子

0

精华

新手上路

积分
45
金钱
45
注册时间
2011-4-2
在线时间
2 小时
发表于 2012-8-16 00:57:56 | 显示全部楼层
《Cortex-M3之STM32嵌入式系统设计》
书中就是极度推荐用C++
用Obtain_Studio集成开发环境+GCC ARM编译器
-
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-8-16 01:51:09 | 显示全部楼层
谢谢楼上,有时间去参考一下
https://github.com/roxma
回复 支持 反对

使用道具 举报

27

主题

274

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
472
金钱
472
注册时间
2011-11-2
在线时间
11 小时
发表于 2012-8-30 21:51:06 | 显示全部楼层
实在佩服楼主,我这个半吊子。。。
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
22
金钱
22
注册时间
2011-12-17
在线时间
0 小时
发表于 2012-10-17 16:38:09 | 显示全部楼层
高手,你好啊,能写一下怎么创建一个C++的工程项目吗??????我们也很想用C++,但是总是出错
回复 支持 反对

使用道具 举报

46

主题

1579

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1970
金钱
1970
注册时间
2011-7-17
在线时间
4 小时
发表于 2012-10-17 17:51:14 | 显示全部楼层
C++不给力,弄一个C#开发STM32才给力,或者楼主弄一个STM32 Studio出来。
Time?And?Relative?Dimension?In?Space.
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-10-17 20:17:02 | 显示全部楼层
回复【40楼】Tardis:
---------------------------------

没学过 C#,学过点 JAVA,感觉 JAVA 和 C++ 差不多,很多语句基本上都是一个意思,优点是简单易学。C# 估计也是类似的吧
网上好像有人弄过用 c# 开发STM32的,搜 STM32 .NET 可以搜出来,

C++ 本身是很强大的,不过学好不容易。给不给力还是需要看库的支持,C++ 标准库,STL 库,还有现在的 boost 都是很强大的,不过我对这些库研究不深,所以还没打算在STM32上移植这些。
https://github.com/roxma
回复 支持 反对

使用道具 举报

1

主题

25

帖子

0

精华

新手上路

积分
49
金钱
49
注册时间
2012-9-21
在线时间
0 小时
发表于 2012-10-18 10:14:30 | 显示全部楼层
厉害呀,新手膜拜一下高手。
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-11-12 11:13:13 | 显示全部楼层
昨天看了一网友写的<C++异常机制的实现方式和开销分析>,发现异常处理的开销还是比较小的 
http://baiy.cn/doc/cpp/inside_exception.htm 

异常处理的支持的意义在 《Thinking in C++》 对应的那一节里面说的很详细了,这里就不介绍了 

不过经过我测试发现MDK是把C++的异常对象是在堆上创建的,要是堆被应用程序耗完了,抛出异常就会直接导致死机。。。虽然在C语言的情况下也是经常用死机来处理异常的。。。不过这样总让人觉得不安全 
http://www.keil.com/forum/21809/ 

看了一下 ISO 的C++标准,标准上也没规定异常对象必须要在哪里创建,唉
https://github.com/roxma
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-11-15 21:57:15 | 显示全部楼层
上面的异常处理的问题已经得到解决了,具体可以参考这三个链接 ,感谢 scott 的帮助!

http://www.keil.com/forum/21809/
http://infocenter.arm.com/help/topic/com.arm.doc.dui0378d/CJAFAGBA.html
http://infocenter.arm.com/help/topic/com.arm.doc.dui0378d/CJAGCBHE.html

这个是简单的测试代码:

// To initialize the exceptions system before main is entered,
// we have to include the following function in the link
// __ARM_exceptions_init will be called before main and
// init of any global variables
extern "C" void __cxa_get_globals(void);
extern "C" void __ARM_exceptions_init(void)
{
 output<<"__ARM_exceptions_init()"<<endl;
    __cxa_get_globals();
}

// this function is never called. To make __ARM_exceptions_buffer_init called,
// we must include the symbol __ARM_exceptions_buffer_required
extern "C" void __ARM_exceptions_buffer_required(){
 output<<"__ARM_exceptions_buffer_required()"<<endl;
 return ;
}

static int buf[20];

// simple re-definition, not necessary. I worte it just to trace the call of
// functions
extern "C" void *__ARM_exceptions_buffer_init(){
 output<<"__ARM_exceptions_buffer_init()"<<endl;
 return buf; // just to test the behavior
}
extern "C" void *__ARM_exceptions_buffer_allocate(void *buffer, size_t size){
 output<<"__ARM_exceptions_buffer_allocate()"<<endl;
      // just to test the behavior when heap is exhausted
      // no complicated management is required here!
 return buf;
}
extern "C" void *__ARM_exceptions_buffer_free(void *buffer, void *addr){
 output<<"__ARM_exceptions_buffer_free()"<<endl;
 return addr;
}


int main(void) {
 output<<" in main function "<<endl;
    try{
        try{
            output<<"exhausting the heap"<<endl;
            int* p = new int();
                while(p!=NULL){
                p = new int();
                }
            output<<" heap exhausted"<<endl;
        }
        catch(...){ /* never reach here because I use the --force_new_nothrow */
   output<<"heap exhausted. and received an exception"<<endl;
        }

        output<<"now I throw an int"<<endl;
        throw int();
    }
 catch(char){
  output<<"catch a char"<<endl;
 }
 catch(int ){
  output<<"catch an int"<<endl;
 }
    catch(...){
        // output some debug imformation
        output<<"unkown exception"<<endl;
    }
    output<<"end"<<endl;
    while(1);
}

程序输出的调试信息:
__ARM_exceptions_init() in main function
exhausting the heap heap exhausted
now I throw an int
catch an int
end

如果我使能上面被注释掉的三个函数,输出就是这样的:
__ARM_exceptions_init()
__ARM_exceptions_buffer_init() in main function
exhausting the heap heap exhausted
now I throw an int
__ARM_exceptions_buffer_allocate()
catch an int
__ARM_exceptions_buffer_free()
end

之前的代码是在 --exceptions --force_new_nothorw 下编译的,如果去掉 --force_new_nothrow,输出就变成了
__ARM_exceptions_init()
__ARM_exceptions_buffer_init()
 in main function
exhausting the heap
__ARM_exceptions_buffer_allocate()
heap exhausted. and received an exception
__ARM_exceptions_buffer_free()
now I throw an int
__ARM_exceptions_buffer_allocate()
catch an int
__ARM_exceptions_buffer_free()
end

https://github.com/roxma
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-11-15 22:19:52 | 显示全部楼层
发现帖子老长了
如果以后成功搞完了标准库的 cout  cin 之类的输入输出流的重定义,估计差不多就可以专门写一个总结帖了


经过测试 new 操作符应该是可以安全的使用的,所以不用自己劳烦这一类问题了,只要启动代码的 heap 大小定义的大些,过段时间再探索探索 STL 这个功能强大的模板库
https://github.com/roxma
回复 支持 反对

使用道具 举报

0

主题

3

帖子

0

精华

新手上路

积分
30
金钱
30
注册时间
2013-9-11
在线时间
2 小时
发表于 2013-12-31 17:52:32 | 显示全部楼层
楼主牛人

回复 支持 反对

使用道具 举报

0

主题

3

帖子

0

精华

新手上路

积分
30
金钱
30
注册时间
2013-9-11
在线时间
2 小时
发表于 2013-12-31 17:55:33 | 显示全部楼层
回复【楼主位】Pony279:

注1:以下的内容本来是我在ourdev上发表的帖子。因为昨天在这里发了一个关于宏的帖子,提到一点C++,看到有网友感兴趣
转到这边来了,因为部分内容已经和网友讨论过,所以我对原来的内容也做了一点修改 。
注2:如果有网友只学过C没学习过C++的,没关系,因为C++你已经算是会了一半了,看到不懂的概念,比如C++的函数重载,直接百度,谷歌,你绝对能很快掌握!
因为一开始我自学的就是C++,后来玩单片机以后才使用C语言来开发东西,也写过一些程序了, 
但是我的体会就是,C语言没有C++那么方便,最近才在学STM32,看到ARM编译器能够支持C++,挺爽的,就开始尝试把实验代码的工程改成C++的方式 
出现了一些问题,我不太会查资料,网上讨论这个的也比较少,所以就发个帖子大家一起讨论下 
先说一下,为什么要用C++,(说的可能不太清楚,对没学过C++的哥们就不好意思啊呃。。。
......
---------------------------------
请教楼主一个问题,像IAR或keil这样的新版本,已经支持嵌入式的C++开发了,还有必要重载new吗?为什么?我在用C++开发stm32项目,但是感觉对C++没有一个很好的把握,看了楼主的帖感觉楼主对这块了解的很透彻了。
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2013-12-31 18:55:52 | 显示全部楼层
回复【47楼】liyang121316:
---------------------------------
很久没用MDK了,应该是不需要重载new的,但是有可能需要提供一些初始化的东西,可能STM32的启动脚本已经做了这个事情了。
GCC就是这个样子,要重载一些系统调用函数才能用,至于具体重载哪些函数,可以从GCC的C语言库的文档里面查到。
至于MDK是个什么样子,直接用STM32的启动代码行不行我就不清楚了,也不知道怎么测,以前一直没找到MDK的官方的说明。
https://github.com/roxma
回复 支持 反对

使用道具 举报

4

主题

117

帖子

0

精华

初级会员

Rank: 2

积分
153
金钱
153
注册时间
2013-8-20
在线时间
0 小时
发表于 2013-12-31 21:00:54 | 显示全部楼层
c++不适合单片机,单片机一般来说内存资源少,而C++很多特性要用到RAM以及动态分配RAM,但是你C++的思想是可以用的,特别是C++的封装。还有你个别非常常用的类,你可以使用一个结构对象+一组函数来实现非继承性的类。我就改了原子的SPI/USART函数组来实现同时支持了多组SPI/USART。
回复 支持 反对

使用道具 举报

4

主题

117

帖子

0

精华

初级会员

Rank: 2

积分
153
金钱
153
注册时间
2013-8-20
在线时间
0 小时
发表于 2013-12-31 21:07:22 | 显示全部楼层
try{}catch{}不适合c,不用说c,c++也不完全适合,你申请的内存如何安全释放,不安全释放内存,开玩笑了.
其实c#有时候也不能滥用,有时候效率会很低的。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-19 10:37

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表