你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32 C++开发

[复制链接]
蓝凌风 发布时间:2016-4-21 20:28
  每次写代码的时候,写外设的初始化都要去复制已经写好的或者是官方的例程,再根据自己的需求来修改,重复性的工作太多,就想到用C++来封装下STM32的库函数,顺便学习下C++,感受下面向对象的强大。
$ Q; v9 t% v' x+ P$ K1 {/ Q    硬件平台:STM32F4-Discovery$ [9 ~; B* H5 Y# `0 M  F" c. e
    开发平台:MDK5.14(本来是用VS2013 +VisualGDB的,想到坛友基本都是用MDK的,又改成MDK)" E. d& m+ ~0 j" H% K
   先看Main
% l# F7 c4 k3 A- ]
  1. #include "system.h"; T  ~7 w. h3 Q  ^3 a- i* r
  2. / e+ R" N3 [9 Y) q6 J2 X6 f
  3. System *stm32f407;//系统接口指针% o$ ]6 i6 U+ Q9 l$ d4 \
  4. : w0 ~& l$ a: }8 y/ C
  5. void btnhandle(void *arg)  //按键回调处理函数
    3 S$ ^  ^+ {! I+ [& G9 F$ x
  6. {! Z9 Z' I- C1 |4 g
  7.          delay->delay_ms(20);- ~8 u4 ]. Z& w1 P
  8.         if (stm32f407->btn->ReadData() == true)2 m- N) }% c: ~; U: h
  9.                 stm32f407->led2->Toggle();5 |' i5 A5 m1 d1 g5 l0 r6 i
  10. }
    6 m( Z! Q2 H' T6 f# |. [
  11. 6 F7 ]; s* a; c" ?8 u6 g4 w
  12. void tim6handle(void *arg)  //定时器中断处理函数
    8 I$ {. F3 @8 E0 \' j: w5 q. w
  13. {
    1 D2 h# S4 w5 @) b7 i2 w4 |5 D
  14.         stm32f407->led2->Toggle();
    5 _4 P( [( {( P/ M0 ^1 f
  15. }: d1 ^$ S& u7 ^) O. A
  16. & Y1 L: i% }  X' a0 B
  17. int main()
    6 y2 i8 c: N+ V/ x$ F# Z1 p7 T0 x
  18. {
    " |7 J9 N4 P2 y3 R) b+ S. f
  19.         stm32f407 = new System;//构建系统接口类; y# R7 g- d- u& o
  20.         stm32f407->tim2->startIT((void*)tim6handle, NULL);//调用TIM类的中断启动函数,只要传入中断回调函数实现自己的功能,并不需要知道中断是要怎么处理的
    9 q; J' U$ Z) m5 X* }6 ?
  21.         uint8_t recvdata[100];* ^2 H( Q4 o$ ~  K  J/ r
  22.   for (;;)  Q0 C5 U) x* e4 @+ z
  23.   {
    3 p0 L" T5 V3 R( s6 y; G) N
  24.           stm32f407->led1->Toggle();//在system中初始化,就可以直接调用类函数
    $ v9 ~. K9 T) }9 p8 Z, V
  25.           if (true == stm32f407->Debug->IsGetRecv)//串口自动接收标志7 H! ^% i" K) z1 H* U5 ^
  26.           {
    3 r; C6 j/ T- ]
  27.                   stm32f407->Debug->RecvData(recvdata);//串口接收函数,传入Buffer,得到接收的数据4 c; ^  p9 n+ v3 k
  28.                   stm32f407->Debug->SendData(recvdata, stm32f407->Debug->RecvDataLen, 100);9 B' Q5 _8 c9 v9 k* Q: _
  29.           }
    0 @" v+ L+ m, @& f5 t
  30.           delay->delay_ms(500);
    ( s/ }- I3 K: N  [$ r
  31.   }6 G* ?2 m/ D- D
  32. }
    $ Q; b* V/ H& B
复制代码

0 N  a: C4 R4 o* s    再看System类的初始化- P1 [6 k0 o9 ?3 t7 u# W
  1. void System::init()
    $ c' W9 y6 w/ o; ?7 ^# n
  2. {0 }0 [3 g1 q* J% I: S8 `
  3.         HAL_Init();' \. d$ e3 v  g
  4.         SystemClock_Config();( r; R, O; ^9 ~- X3 \0 J% P+ P+ A
  5. //外设初始化
    ; s) P6 Y8 j2 }! {9 Q( m
  6.   delay = new timerdelay;                //系统延时初始0 S1 B4 k9 o8 b
  7.         Debug = new Usart(USART3, 115200, Usart::USART_IT, 200); //Debug 串口输出初始化,只要传入用的串口号,跟波特率,传输的模式,还有接收Buffer的大小,就可以完成初始化( ?( l! ]8 E. E6 [2 m7 I: R
  8.         led1 = new LED(GPIOD, GPIO_PIN_14, true, LED::highlevel);//LED类,继承OutputPort类,只要传入LED对应的GPIO,跟Pin,还有LED电平控制,就可以完成初始化
    # b1 L8 L' g: K4 L4 K: I3 s; |
  9.         led2 = new LED(GPIOD, GPIO_PIN_12, false, LED::highlevel);
    3 h) [0 n) p2 C' ]- F
  10.         btn = new InputPort(GPIOA, GPIO_PIN_0, GPIO_MODE_IT_RISING, (void*)btnhandle, NULL); //输入类,传入GPIO,PIN,中断触发模式,回调指针,回调参数,完成初始化
    4 X* p8 K3 n$ e2 O( Y0 Q$ E
  11.         tim2 = new Timer_base(TIM2, 16800, 10000);
    : X- z. V" T0 _1 N& ^& R( f2 r
  12.         BoardInfo();
    * r8 ~  t5 {  F9 {( i6 M7 w
  13. }
复制代码

3 V* E* s0 K/ e+ F, g/ w8 C$ s0 W4 T9 S
1 V) w9 A5 `! z- A
OutputPort类:
  1. class OutputPort4 U) V' U* h! q$ V8 j9 I
  2. {- }  G: k! K4 p/ J' o
  3. public:
    0 [  \6 E  h& @% T* m+ ?
  4.         OutputPort(GPIO_TypeDef* mPORT, uint16_t mGPIO_PIN, bool initialState);//OutputPort类构建函数,简单传入三个参数
    + S2 o6 X2 r* q
  5.         OutputPort(GPIO_TypeDef* mPORT, uint16_t mGPIO_PIN, uint32_t GPIO_Speed, uint32_t GPIO_PuPd, bool initialState);//构建函数重载,可以传入更多的参数
    0 O1 L. W( W2 H# [' s$ @
  6.         ~OutputPort();
    ' I/ l/ u3 c2 M3 t/ G9 ]. C
  7.         void H(void);//类函数,构建的类都是调用同函数就可以实现,减少代码的重复
    - l# g$ l0 D- A9 h
  8.         void L(void);6 R3 U6 h) c, w- w% f1 g' S/ D
  9.         inline void  RegH(){PORT->BSRR |= GPIO_PIN;        }//内联函数,直接代码替换成寄存器操作,提高执行效率' c, ]9 j  ?2 v( Q6 T9 N& k
  10.         inline void  RegL(){ PORT->BSRR |= GPIO_PIN << 16; }
    $ C* p! K, T2 S0 K# d
  11.         GPIO_TypeDef* PORT;3 v8 d# i+ M. g$ L4 r9 g( a
  12.         uint16_t GPIO_PIN;
    2 x/ A6 |( k8 j; N2 U
  13. private:5 V: Q5 J: V. F2 T* j
  14. protected:
    ! @! G% p) S. K. I/ Y
  15. 5 ^8 _- x& }! l% `
  16. };
    1 s9 X# k; q" o+ ~: f) R% H' |
  17. 7 O9 Q# e- e1 U$ Q% W5 r2 }+ O* K
  18. LED类:
    ) U3 y8 c; w( Q, H1 H8 J4 b  L
  19. class LED :public OutputPort
    , t5 \: [# U  A% A
  20. {
    : [: E2 \: l4 c& ?2 m* i0 ]- _
  21. public:' r  d& {$ ^  {3 ]/ ]+ V  v6 h
  22.         LED(GPIO_TypeDef* mPORT, uint16_t mGPIO_PIN, bool initialState, uint8_t mCtlVolLev) : OutputPort(mPORT, mGPIO_PIN, initialState), CtlVolLev(mCtlVolLev){};//继承OutputPort类,并增加新的参数) c1 _) @* r9 O$ ^
  23.          ~LED();2 a; X% I8 X* U8 Q4 x
  24.          void ON();. |4 Z* Q; d: ]' E
  25.          void OFF();
    8 E3 i3 W% N* \3 H+ v$ A
  26.          void Toggle();9 O: C: L1 a$ x/ @6 P
  27.          enum{ lowlevel, highlevel };: [2 W, N4 X8 l1 R6 G$ A
  28. private:% @% P1 Y& ~6 Z
  29. protected:+ W8 ?. E3 l5 `& G5 F
  30.         uint8_t CtlVolLev;    //LED 1为高电平  0为低电平
    : O9 C; c4 I+ w% z
  31. };
复制代码
  F% S% h7 }' x6 d+ P2 g# K8 L
- G# ^: o) T! n' u* U- S
+ b) `  H" U1 ~1 F3 S$ r; t
  UART类:% C4 f+ M+ q( w; A0 Y! w
  1. extern uint8_t UART_Recv_Timeout[5];//Time Tick- U8 b5 S% [! a8 v7 X2 h

  2. 4 N3 ?' k" y. O7 m, `9 z
  3. class Usart
    * S4 [. ]* D: ~" _
  4. {2 z( U9 [: I2 U! q
  5. public:
    7 I6 x+ w4 u" n5 V+ Q6 ~9 d7 r
  6.         enum tranmode8 z& q% r8 g+ q! z
  7.         {
    0 ^' g0 Y9 F! `3 w1 p5 Y
  8.                 USART_Normal, //普通发送
    6 Y: ?- o0 v: B8 a
  9.                 USART_IT,    //中断发送接收,接收自动判断超时完成接收
    0 _0 K. Z& U- Z+ E
  10.                 USART_DMA    //DMA发送接收,UART闲时中断自动接收DMA接收完成2 L* n/ O4 S+ Y4 U8 t: a$ Q& D
  11.         };//类构建时传入,类函数根据输入的类别发送接收* T3 O& h7 f* u+ P5 ]  ]
  12.         Usart(USART_TypeDef *USARTx, uint32_t BaudRate, tranmode mmode,uint16_t mRecvBuffSize);2 i5 D4 F0 I5 [* f
  13.         void SendData(uint8_t data);
    ' u- m: o$ k% w  m1 c& M
  14.         void SendData(uint8_t *pData, uint16_t Size, uint32_t Timeout);7 A% e; H; j9 S. F, w- _
  15.         uint16_t RecvData(uint8_t *pData);/ \! x  [, }; @$ @
  16.         uint16_t RecvDataLen; //接收到数据长度
    2 Z+ i3 q- |5 r- V
  17.         UART_HandleTypeDef UartHandle;+ V# I" z7 y! D8 S& O: i, v" ^
  18.         uint8_t IsGetRecv;   //接收标志
    3 {9 U3 H1 I, Q8 ?2 |
  19.         uint8_t isSendOk ;  //发送完成标志" j6 Q5 g% R. y) j- \0 h
  20.         tranmode mode;7 \0 \" Z1 \& }% ]5 O4 s
  21.         void Printf(const char* fmt, ...);; e8 T, Y: |! R
  22.         ~Usart();6 P, Y; Z/ q9 U. Z0 ]$ e
  23. $ R  I' O1 X8 Z0 k
  24. private:2 e# g# f/ c# ?& s
  25.         uint16_t RecvBuffSize;
    6 Z: l3 z- h; s# b& |; I- f: W
  26.         uint8_t *RecvBuff;/ N9 X" o1 S2 g2 T
  27.         uint8_t SendBuff[100];2 a! l( [0 G! y. ~+ @6 e9 |/ K9 T
  28.         void USART_DMA_Config(UART_HandleTypeDef *UartHandle);
    % H3 R1 S1 C- K: g
  29. };+ k- D3 m7 l; c2 s  Q

  30. ' T" j+ U- m; F* Y* k6 Q
  31. void Do_UART_Recv(uint8_t i);//接收超时处理函数
复制代码

) u4 V* u6 n$ X7 F6 W; [& k! `' N3 `( U+ r8 N6 Z3 I- ~+ {  Q
     C++面向对象最大的好处是,只要定义一个类,相同的外设只要传入参数构建类,就可以调用类函数来实现功能,不需要为每个外设再重新写代码。而且封装好了类,只需要知道传入什么参数,可以调用什么接口来实现自己的功能就可以了,不需要再去了解类里面是怎么来实现的。目前就封装了GPIO,UART,TIM Base,SPI等几个外设,可以给大家体验下面向对象的强大,提供一些封装函数的思路,更具体的代码可以下载附件的工程。, e7 h' v. b- S9 ]
STM32F4_Cpp.zip (3.72 MB, 下载次数: 104)
收藏 8 评论11 发布时间:2016-4-21 20:28

举报

11个回答
harvardx 回答时间:2016-4-22 00:10:44
不错 不过现实的单片机c++应用 怕也只是止步于此了.
power568 回答时间:2016-4-22 09:47:59
最近也有这个想法,但是还没实施,先学习了...
风子 回答时间:2016-4-22 10:23:07
楼主可以参考Mbed的实现
wuzhujian 回答时间:2016-4-22 14:26:30
如果使用模板,生成的代码效率,比用C写的还高。
湉湉 回答时间:2016-4-23 21:10:51
先学习下  谢谢分享
helen9898 回答时间:2016-4-26 17:39:56
高手,现在只能观望了。以后有机会再应用吧
auto_ele 回答时间:2016-4-28 11:13:52
不错,我们好多的项目,已经这么做了,效果不错,就是类和类之间传值有点麻烦,其他的都OK,写的程序,都按照“流”执行,思路清晰。
' I' c% z* f5 T! y) L. {7 q未来的趋势就是单片机会越来越多的支持高级语言的开发,比如C#,ST官网也针对F4有例程,基于.NET MICRO FRAMEWORK的,最近一直研究,有兴趣,可以一起搞。
蓝凌风 回答时间:2016-4-29 09:03:44
auto_ele 发表于 2016-4-28 11:13
8 l% j  u( e+ ?4 j, b3 v( k不错,我们好多的项目,已经这么做了,效果不错,就是类和类之间传值有点麻烦,其他的都OK,写的程序,都按 ...
& x0 z- D  u% k4 P; a
.NET MICRO FRAMEWORK我去年就有研究,写过一些文章,只能是玩玩,实际上没太多的胜任
auto_ele 回答时间:2016-5-16 21:34:44
蓝凌风 发表于 2016-4-29 09:03
5 O* {1 ]7 u$ n) Z8 n" S* _& M.NET MICRO FRAMEWORK我去年就有研究,写过一些文章,只能是玩玩,实际上没太多的胜任 ...

9 P0 }! J3 t9 ~较LINUX之类的系统,它把硬件层和应用层完全分开,只要写好CLR就可以。
lzts 回答时间:2016-5-17 11:18:08
学习了, 帮顶; a) m  C; `3 y8 a% x" }
HenryChen 回答时间:2016-5-17 11:29:47
学习学习学习学习

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版