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

STM32 C++开发

[复制链接]
蓝凌风 发布时间:2016-4-21 20:28
  每次写代码的时候,写外设的初始化都要去复制已经写好的或者是官方的例程,再根据自己的需求来修改,重复性的工作太多,就想到用C++来封装下STM32的库函数,顺便学习下C++,感受下面向对象的强大。7 |; \7 n2 M. i6 a1 y8 y$ J; p
    硬件平台:STM32F4-Discovery
1 b  i! d( Z( ]; n    开发平台:MDK5.14(本来是用VS2013 +VisualGDB的,想到坛友基本都是用MDK的,又改成MDK). b3 B, I0 r8 L9 x3 j) S. {; F
   先看Main
. y2 Q. Y6 O. @0 X& t5 A
  1. #include "system.h"2 y4 Q, K" D8 t9 H+ B$ O6 c
  2. 1 v, G& s( H/ N' i: R
  3. System *stm32f407;//系统接口指针
    $ x0 p/ F- z' Q* T
  4. 7 a  k7 H. ^0 Z
  5. void btnhandle(void *arg)  //按键回调处理函数" _2 u! M0 [' c  r  ~' s- r# Y0 H- }
  6. {. z7 b! k1 c, ^, b6 a, K
  7.          delay->delay_ms(20);4 w+ W7 L5 C/ P, ^
  8.         if (stm32f407->btn->ReadData() == true)6 ^) f% u! q9 U# Z9 P
  9.                 stm32f407->led2->Toggle();7 \) f- m$ q3 G6 j
  10. }2 e- d( n% W( b& v. ^4 z( c

  11. 2 {- h" S' @+ O* P1 D0 U; C! S
  12. void tim6handle(void *arg)  //定时器中断处理函数
    ' Y  N) R6 p3 l9 G. O+ [
  13. {
    7 ?: N1 e1 v# A
  14.         stm32f407->led2->Toggle();9 b- n8 c# k5 v9 u: q6 b
  15. }) A3 a5 t3 R0 p. |6 Q) a/ F

  16. 8 N% p, |* i6 R) c$ r- q6 T4 m
  17. int main()
    " B4 q; ~% |& |* T% Q7 |& f
  18. {
      i2 _! W2 o* N0 N
  19.         stm32f407 = new System;//构建系统接口类! k5 c. ?& ~/ P6 O, G2 ?
  20.         stm32f407->tim2->startIT((void*)tim6handle, NULL);//调用TIM类的中断启动函数,只要传入中断回调函数实现自己的功能,并不需要知道中断是要怎么处理的6 V4 Q% i6 q, _2 R+ V
  21.         uint8_t recvdata[100];: }3 c4 l3 e! i" ?
  22.   for (;;)
    - ]8 X9 M6 N  i3 c$ _
  23.   {, v$ N6 N+ ^* t; m. O- G
  24.           stm32f407->led1->Toggle();//在system中初始化,就可以直接调用类函数
    ) U& ?2 l% P  K  Q. D' Z9 a7 O
  25.           if (true == stm32f407->Debug->IsGetRecv)//串口自动接收标志, r& F6 `( |6 E* d
  26.           {8 ~/ i0 s+ ^) k* d
  27.                   stm32f407->Debug->RecvData(recvdata);//串口接收函数,传入Buffer,得到接收的数据& H5 Y2 o1 q( g7 \( Z3 i/ J
  28.                   stm32f407->Debug->SendData(recvdata, stm32f407->Debug->RecvDataLen, 100);
    , Y0 q# J( R( D: q$ Y
  29.           }
    3 L1 L5 D5 I2 q6 K
  30.           delay->delay_ms(500);# Z9 {' @9 }( X: j' |
  31.   }
    8 d5 A. p% Y0 o! Y" K( e* i6 N
  32. }5 P0 I: N" q7 i: q" F# Q! _
复制代码

9 C* R7 B: p9 r7 ^; e    再看System类的初始化* @; ^2 U  k: d/ q+ k% q
  1. void System::init()
    " l+ B. t( p' s9 B" w! }
  2. {5 z( e, A0 G+ g/ v% f
  3.         HAL_Init();
    ; p( i; k6 x; O7 |- o8 h
  4.         SystemClock_Config();, ~% q5 l; |" k" O
  5. //外设初始化
    ( A, }& W8 e* Z, ?- j, p0 A9 T
  6.   delay = new timerdelay;                //系统延时初始
    1 c( J) Z+ E4 p
  7.         Debug = new Usart(USART3, 115200, Usart::USART_IT, 200); //Debug 串口输出初始化,只要传入用的串口号,跟波特率,传输的模式,还有接收Buffer的大小,就可以完成初始化3 V' g8 y9 e5 x% W) c$ B( [
  8.         led1 = new LED(GPIOD, GPIO_PIN_14, true, LED::highlevel);//LED类,继承OutputPort类,只要传入LED对应的GPIO,跟Pin,还有LED电平控制,就可以完成初始化' X$ t$ E" |% j( z8 i. X. ^
  9.         led2 = new LED(GPIOD, GPIO_PIN_12, false, LED::highlevel);- L! A/ Y& a# `- P+ m
  10.         btn = new InputPort(GPIOA, GPIO_PIN_0, GPIO_MODE_IT_RISING, (void*)btnhandle, NULL); //输入类,传入GPIO,PIN,中断触发模式,回调指针,回调参数,完成初始化
    5 [- k5 E4 l- X, I9 \& I
  11.         tim2 = new Timer_base(TIM2, 16800, 10000);
    9 G# o4 n3 X/ e7 D% n. M, U" o6 I. B
  12.         BoardInfo();( a3 X0 A$ j7 g! e7 V+ s* P$ P4 I
  13. }
复制代码
3 h; B! @3 K' a- v* C
$ ^1 d  }6 [  E7 j
! v4 F& i' ]7 ~" [) y3 a9 ]/ @
OutputPort类:
  1. class OutputPort
    7 o) j$ }: U4 E% Q. y
  2. {
    ! ]7 R6 B- c0 I+ Y2 i' N3 u
  3. public:: J7 ^" w) B& u
  4.         OutputPort(GPIO_TypeDef* mPORT, uint16_t mGPIO_PIN, bool initialState);//OutputPort类构建函数,简单传入三个参数
    & A  r& _" E  C) S
  5.         OutputPort(GPIO_TypeDef* mPORT, uint16_t mGPIO_PIN, uint32_t GPIO_Speed, uint32_t GPIO_PuPd, bool initialState);//构建函数重载,可以传入更多的参数
    ) P) m' X0 \' D# h9 W3 r
  6.         ~OutputPort();
    ' t8 I0 A6 K; ]* X1 }: r$ w/ X
  7.         void H(void);//类函数,构建的类都是调用同函数就可以实现,减少代码的重复
    3 l+ N4 P: s4 w" C$ C( u7 ]
  8.         void L(void);  s. I0 S! [. y$ ?' c
  9.         inline void  RegH(){PORT->BSRR |= GPIO_PIN;        }//内联函数,直接代码替换成寄存器操作,提高执行效率7 }% f. g' p0 T2 Q
  10.         inline void  RegL(){ PORT->BSRR |= GPIO_PIN << 16; }' n4 x, j6 {2 @! r
  11.         GPIO_TypeDef* PORT;
    . F+ ~) x  Q( n  B! J4 C
  12.         uint16_t GPIO_PIN;
    & C4 Y3 i( y* [
  13. private:
      R9 c% w* X) @+ i0 s1 `
  14. protected:
    + z6 d4 M: L: e  d" l, a; p8 h

  15. 3 n" W1 I1 Y& w9 X( f3 I: u
  16. };- u9 _3 B$ J% l" d& Y0 p' n

  17. 0 ]- V3 d6 }/ z6 `. }& B5 E7 `7 t
  18. LED类:
    & t& C* S6 ]4 w3 a8 c
  19. class LED :public OutputPort
    : ?# @; u+ i/ ^2 F
  20. {
    ) a& o& Z3 i7 i: y7 b+ F+ O6 I
  21. public:# T9 c4 Y. S+ D3 H' \3 r2 d1 y7 S! J
  22.         LED(GPIO_TypeDef* mPORT, uint16_t mGPIO_PIN, bool initialState, uint8_t mCtlVolLev) : OutputPort(mPORT, mGPIO_PIN, initialState), CtlVolLev(mCtlVolLev){};//继承OutputPort类,并增加新的参数' X; y5 U, w+ w- M: b
  23.          ~LED();) B1 e- h# O* m: X, B- ~
  24.          void ON();
    . T) m2 I  g- B& {/ Y, S9 S$ g* E
  25.          void OFF();
    - M' d  [$ \: q  O
  26.          void Toggle();- p4 O5 b4 h0 U
  27.          enum{ lowlevel, highlevel };% F+ q5 r& l, N5 E. y
  28. private:
    % ^& f5 H+ H8 {- \
  29. protected:8 K, L! j. v0 ], F4 L- i* W
  30.         uint8_t CtlVolLev;    //LED 1为高电平  0为低电平
    2 U+ d4 i; v1 ~9 a4 Q9 M& t7 ]
  31. };
复制代码

8 ^4 d  w! J: `# n% [1 k" D  {4 X* ]) [7 Q4 `7 D

" O/ }# h" [/ ^  W; q
  UART类:
# r- L/ Y9 f0 Q5 ?- e" ?! Q4 E
  1. extern uint8_t UART_Recv_Timeout[5];//Time Tick8 Q: ~, E3 v7 A" l

  2. & M" Z4 s1 q2 n5 S) a- v8 y
  3. class Usart8 L: k- f. n. w. Y( t# y( J/ ]- L
  4. {6 [* ]) N6 q& Z+ ^2 X4 B% U
  5. public:
    ; P) h7 e! L+ J6 Q
  6.         enum tranmode
    3 c! V- y9 y1 o% s8 A& D/ {1 k$ y/ w
  7.         {
    " B/ S" y1 W8 j
  8.                 USART_Normal, //普通发送
    " ^% v8 V+ I! l9 L5 x# K* o7 l$ z- V
  9.                 USART_IT,    //中断发送接收,接收自动判断超时完成接收
    ; g( i- f; f* U0 F8 [3 w  }
  10.                 USART_DMA    //DMA发送接收,UART闲时中断自动接收DMA接收完成8 `$ E; {6 t7 H- e' g
  11.         };//类构建时传入,类函数根据输入的类别发送接收! _+ S' l( [# M# a
  12.         Usart(USART_TypeDef *USARTx, uint32_t BaudRate, tranmode mmode,uint16_t mRecvBuffSize);
    3 B! e! \% g9 ?3 |' y  `# Q8 w
  13.         void SendData(uint8_t data);
    1 N1 n: d" k0 `3 L
  14.         void SendData(uint8_t *pData, uint16_t Size, uint32_t Timeout);. e, F4 E- F) b7 T- T
  15.         uint16_t RecvData(uint8_t *pData);7 _7 [) `# y3 o& D5 Q- U
  16.         uint16_t RecvDataLen; //接收到数据长度6 S  Q5 c/ }. `% q! A
  17.         UART_HandleTypeDef UartHandle;$ A0 v# s& N9 s, ?( ]
  18.         uint8_t IsGetRecv;   //接收标志0 u6 @9 W: H6 f& r5 c8 H4 d  d/ }6 C
  19.         uint8_t isSendOk ;  //发送完成标志
    * n% ^& F/ r9 y& a6 A
  20.         tranmode mode;7 W9 ^: m) a2 {  o4 _0 \- B
  21.         void Printf(const char* fmt, ...);
    - X5 k* ?" u! p0 k% {: _4 d
  22.         ~Usart();2 m9 y3 H& }$ K/ q; O5 C
  23. + L0 G! T9 C1 H) K3 F
  24. private:# ~, K; H, }/ g# `; u+ i# c
  25.         uint16_t RecvBuffSize;1 h' `. X# t# U+ B/ a% O4 G5 X' n
  26.         uint8_t *RecvBuff;
    5 s+ C' D: I, l: `$ w' L6 g. w
  27.         uint8_t SendBuff[100];
    , B# @0 A! w* M# ?. U& x
  28.         void USART_DMA_Config(UART_HandleTypeDef *UartHandle);
    6 M+ B6 M6 y5 D: I% y& I7 h
  29. };$ W: e1 [3 J' d; w

  30. 1 u/ `: m) Y$ _) s& W
  31. void Do_UART_Recv(uint8_t i);//接收超时处理函数
复制代码
( @- D$ @5 p! D" @% R! T
" ]  D1 J. U9 j3 y2 J6 f( U9 t% Q
     C++面向对象最大的好处是,只要定义一个类,相同的外设只要传入参数构建类,就可以调用类函数来实现功能,不需要为每个外设再重新写代码。而且封装好了类,只需要知道传入什么参数,可以调用什么接口来实现自己的功能就可以了,不需要再去了解类里面是怎么来实现的。目前就封装了GPIO,UART,TIM Base,SPI等几个外设,可以给大家体验下面向对象的强大,提供一些封装函数的思路,更具体的代码可以下载附件的工程。( \% S) e5 ?. |' n* `* k
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,写的程序,都按照“流”执行,思路清晰。
* ]. q  _7 f. ]# J. g未来的趋势就是单片机会越来越多的支持高级语言的开发,比如C#,ST官网也针对F4有例程,基于.NET MICRO FRAMEWORK的,最近一直研究,有兴趣,可以一起搞。
蓝凌风 回答时间:2016-4-29 09:03:44
auto_ele 发表于 2016-4-28 11:133 F3 @0 S9 z/ a3 X+ l4 r
不错,我们好多的项目,已经这么做了,效果不错,就是类和类之间传值有点麻烦,其他的都OK,写的程序,都按 ...

+ n" t* g, G' b+ s* [  u& V$ ].NET MICRO FRAMEWORK我去年就有研究,写过一些文章,只能是玩玩,实际上没太多的胜任
auto_ele 回答时间:2016-5-16 21:34:44
蓝凌风 发表于 2016-4-29 09:035 N7 K/ z1 y/ V  B, Z! O9 _
.NET MICRO FRAMEWORK我去年就有研究,写过一些文章,只能是玩玩,实际上没太多的胜任 ...
- ~. ]# u1 t) o# J7 r; K
较LINUX之类的系统,它把硬件层和应用层完全分开,只要写好CLR就可以。
lzts 回答时间:2016-5-17 11:18:08
学习了, 帮顶( e4 N, Q3 l' W
HenryChen 回答时间:2016-5-17 11:29:47
学习学习学习学习

所属标签

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