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

STM32 C++开发

[复制链接]
蓝凌风 发布时间:2016-4-21 20:28
  每次写代码的时候,写外设的初始化都要去复制已经写好的或者是官方的例程,再根据自己的需求来修改,重复性的工作太多,就想到用C++来封装下STM32的库函数,顺便学习下C++,感受下面向对象的强大。4 N$ t. h4 }! S4 l' `4 G
    硬件平台:STM32F4-Discovery
. \/ [" x% `8 A    开发平台:MDK5.14(本来是用VS2013 +VisualGDB的,想到坛友基本都是用MDK的,又改成MDK)
' ~/ X8 i( H( X2 e8 z" t# z% r: O* e   先看Main, |; M# ?1 T2 q+ X, W
  1. #include "system.h"
    3 R4 N* B7 v6 r: a  x

  2. ; P9 G* N( R$ v2 g( Z5 }3 A
  3. System *stm32f407;//系统接口指针
    ' o' Z" q5 W0 W: n3 r% `
  4. 6 N7 E) k4 ^/ ~1 E
  5. void btnhandle(void *arg)  //按键回调处理函数7 Q2 I/ b) X. g8 f( g- d" F: r5 P
  6. {" L( A% }& a% u& Y' G! i! N
  7.          delay->delay_ms(20);
    2 I9 @  |. }- G: {; w$ |' P4 U* C7 }9 f
  8.         if (stm32f407->btn->ReadData() == true)
    ' b9 i* P# w( v
  9.                 stm32f407->led2->Toggle();$ N4 L3 Q* D0 H" m+ F" L
  10. }) a. {  {7 `4 S
  11. # p8 F  P8 X: ?; a
  12. void tim6handle(void *arg)  //定时器中断处理函数9 \- _' @2 T7 ]- _; N7 I
  13. {/ y5 @5 O1 f4 i* i0 G' _
  14.         stm32f407->led2->Toggle();
    # s# m3 Y2 s( u
  15. }
      p7 e* ]( |1 _( V
  16. - z% C2 B5 _& a0 i, h
  17. int main()/ i9 g! W+ K/ g' I; r9 v( ~
  18. {
    . _' Z7 Q$ E; W5 z9 [( L# `4 [
  19.         stm32f407 = new System;//构建系统接口类- \2 Y' [, \3 F
  20.         stm32f407->tim2->startIT((void*)tim6handle, NULL);//调用TIM类的中断启动函数,只要传入中断回调函数实现自己的功能,并不需要知道中断是要怎么处理的  c  M1 ~; M* j5 T5 k) ^% M$ x- V) Z. c
  21.         uint8_t recvdata[100];
    9 S: o! J! r/ x9 J2 U
  22.   for (;;)! F$ V5 Z2 C; }' p+ w! h
  23.   {$ N5 Q4 E8 A( y
  24.           stm32f407->led1->Toggle();//在system中初始化,就可以直接调用类函数
    * \) I* u3 J" B: L1 f4 p
  25.           if (true == stm32f407->Debug->IsGetRecv)//串口自动接收标志
    ) h- `8 \  ]* I! ?6 p
  26.           {
    " x4 N, x2 j( O/ a5 t4 b7 R& e
  27.                   stm32f407->Debug->RecvData(recvdata);//串口接收函数,传入Buffer,得到接收的数据+ u+ Y) E0 s. ^, I
  28.                   stm32f407->Debug->SendData(recvdata, stm32f407->Debug->RecvDataLen, 100);
    4 ^7 b$ O( c0 p$ n2 q. v
  29.           }4 ?/ s7 @8 U0 f* t2 K  T
  30.           delay->delay_ms(500);5 @- d  a/ j  C) ]3 @' g
  31.   }
    1 d9 p& e+ N' h6 v" K+ U; T. M
  32. }' c- T' D; f2 e! D
复制代码

  [8 ]5 {  \) @# n8 E    再看System类的初始化
. T. l! P( G. x
  1. void System::init()) p7 R" R- Z1 _" _
  2. {
    ) R' G+ |5 A) j
  3.         HAL_Init();# G& v/ m* r' z" `6 h( y
  4.         SystemClock_Config();5 Q! [6 b0 z% p7 R/ X
  5. //外设初始化0 R) p( Z# J4 A4 J; S  `
  6.   delay = new timerdelay;                //系统延时初始
    # e, W9 p+ r7 f5 }  q2 H9 @
  7.         Debug = new Usart(USART3, 115200, Usart::USART_IT, 200); //Debug 串口输出初始化,只要传入用的串口号,跟波特率,传输的模式,还有接收Buffer的大小,就可以完成初始化& y; q8 c. q+ i  w+ {7 z  h  k9 W1 B
  8.         led1 = new LED(GPIOD, GPIO_PIN_14, true, LED::highlevel);//LED类,继承OutputPort类,只要传入LED对应的GPIO,跟Pin,还有LED电平控制,就可以完成初始化) n. X  a5 z0 M& k* T) L
  9.         led2 = new LED(GPIOD, GPIO_PIN_12, false, LED::highlevel);
      L: i5 Q' p6 v/ w( J9 S' h
  10.         btn = new InputPort(GPIOA, GPIO_PIN_0, GPIO_MODE_IT_RISING, (void*)btnhandle, NULL); //输入类,传入GPIO,PIN,中断触发模式,回调指针,回调参数,完成初始化
    $ F8 S* J8 N0 [3 m
  11.         tim2 = new Timer_base(TIM2, 16800, 10000);
    " @& ]! W5 y& Q8 r) K
  12.         BoardInfo();! I) B: [9 A' g9 X! I1 t
  13. }
复制代码

6 y, I4 K. J% a1 N9 V0 n( w
1 F& B4 i4 t" q& @/ n7 C& K* P+ D0 G, w/ H8 M8 g
OutputPort类:
  1. class OutputPort
    # m9 _/ N  r7 v( C; l0 u
  2. {
    - {/ z+ v& I# C2 _% s
  3. public:
    6 _( t' Y! F% x+ f
  4.         OutputPort(GPIO_TypeDef* mPORT, uint16_t mGPIO_PIN, bool initialState);//OutputPort类构建函数,简单传入三个参数
    ! l6 [& f  U( M$ y2 J9 n# ]
  5.         OutputPort(GPIO_TypeDef* mPORT, uint16_t mGPIO_PIN, uint32_t GPIO_Speed, uint32_t GPIO_PuPd, bool initialState);//构建函数重载,可以传入更多的参数
    3 V! {$ g8 [" l- Q' Y3 s5 N4 h; O
  6.         ~OutputPort();1 v1 |5 Q( N7 h; {; u1 U
  7.         void H(void);//类函数,构建的类都是调用同函数就可以实现,减少代码的重复% e4 X4 N# N1 s
  8.         void L(void);: E3 e1 W9 z9 f$ b8 \6 W6 {
  9.         inline void  RegH(){PORT->BSRR |= GPIO_PIN;        }//内联函数,直接代码替换成寄存器操作,提高执行效率: d8 m  z* L2 X5 I
  10.         inline void  RegL(){ PORT->BSRR |= GPIO_PIN << 16; }, v/ v0 s9 C7 ~0 B( w. H
  11.         GPIO_TypeDef* PORT;
    & Z, |2 r8 P/ e0 k
  12.         uint16_t GPIO_PIN;: v6 {/ m0 e/ h" K* i( k
  13. private:5 S& P. h; g4 w; P
  14. protected:
    * V+ _% T  d/ o+ W
  15. / n" O" Y+ [/ X8 d
  16. };* t0 z, t1 `" r5 Q9 F( M

  17. 4 S+ c. s! b' [6 L: Y: Y8 O: Y
  18. LED类:
    9 \* @- E4 y" ^3 s# o8 G
  19. class LED :public OutputPort
    0 l& Y: `# E' N8 F. L
  20. {3 B- G8 I+ o, |: t1 i$ I7 d
  21. public:- n8 s4 `+ x2 G2 I
  22.         LED(GPIO_TypeDef* mPORT, uint16_t mGPIO_PIN, bool initialState, uint8_t mCtlVolLev) : OutputPort(mPORT, mGPIO_PIN, initialState), CtlVolLev(mCtlVolLev){};//继承OutputPort类,并增加新的参数
    + k! w4 t6 C2 k. X
  23.          ~LED();. B  n) j5 b9 ?7 }* [& `9 u
  24.          void ON();8 J% i4 N- {1 y5 l
  25.          void OFF();
      I' S0 O  V) k" E' C. {
  26.          void Toggle();
    : o: Y8 j5 m) ]- e% O
  27.          enum{ lowlevel, highlevel };2 E3 N( w# i2 c/ V2 ^
  28. private:
    , v  [2 {( y. D# b8 ?0 ~  _. j
  29. protected:
    ! x4 S1 w  Q3 r( A9 ?
  30.         uint8_t CtlVolLev;    //LED 1为高电平  0为低电平
    ; c3 q% j9 N/ [5 n1 F7 Y# ]
  31. };
复制代码
; f- U0 w9 t& b5 [, w  P. D
  t5 H/ v3 ?* k2 n

6 f7 y8 o5 R# Z! ~
  UART类:: G8 m4 S" [, q' G  @
  1. extern uint8_t UART_Recv_Timeout[5];//Time Tick
    ) ]. }" b  n& ?6 c3 ?
  2. * x: b' T/ U4 S# s/ C
  3. class Usart& }9 s' Y" J, T7 u8 Y7 T+ }+ ]
  4. {$ k7 o+ o9 s7 R2 G8 R7 E% j* q7 @& I
  5. public:
    ; W0 s2 }7 E) @2 g0 a+ L
  6.         enum tranmode
    6 F( h0 ^4 o9 W7 a* {; s
  7.         {
    2 Z% v* R) W7 {3 h! Y5 n
  8.                 USART_Normal, //普通发送, x2 ^) b  ?$ f4 I* ~* L, c
  9.                 USART_IT,    //中断发送接收,接收自动判断超时完成接收" z3 t6 n; L' }7 r2 L% \
  10.                 USART_DMA    //DMA发送接收,UART闲时中断自动接收DMA接收完成1 k2 o* R5 Q, c+ E$ b
  11.         };//类构建时传入,类函数根据输入的类别发送接收( X  R6 P: G- N, j% t* I
  12.         Usart(USART_TypeDef *USARTx, uint32_t BaudRate, tranmode mmode,uint16_t mRecvBuffSize);. {+ S6 R' ], S4 E3 T0 P% n4 t2 T8 v4 Q
  13.         void SendData(uint8_t data);7 k4 I$ I* D  }8 c5 i
  14.         void SendData(uint8_t *pData, uint16_t Size, uint32_t Timeout);. N. t( O7 P/ O) {6 s( q) p, U# r' Q
  15.         uint16_t RecvData(uint8_t *pData);( u7 P4 _% r1 H5 c
  16.         uint16_t RecvDataLen; //接收到数据长度0 g2 k4 `$ X' `6 Y1 C! a
  17.         UART_HandleTypeDef UartHandle;
    , l# c- {7 S& o3 v2 N4 I
  18.         uint8_t IsGetRecv;   //接收标志
    ! o0 A7 s  w( P3 v( K% g
  19.         uint8_t isSendOk ;  //发送完成标志
    ! J, P  f3 I3 [8 X9 S, |/ h) g
  20.         tranmode mode;
    0 k7 C# n' j/ `; I  d- T# W: A7 z& W
  21.         void Printf(const char* fmt, ...);
    ' ~6 A6 _2 o) t! h
  22.         ~Usart();" F2 x4 J) ^: X8 w3 Y, m+ _
  23. : a- y# C# s! ]8 y
  24. private:
    ! Y: H( Z8 C% W; ^- Q! o8 N& m7 |
  25.         uint16_t RecvBuffSize;
    # I% n2 x3 K4 i. L( d4 B
  26.         uint8_t *RecvBuff;/ B# b* ]5 j2 _, m& r7 e
  27.         uint8_t SendBuff[100];
    % }0 K+ }9 ~% ?3 N- G8 B
  28.         void USART_DMA_Config(UART_HandleTypeDef *UartHandle);
    7 D3 n( q: @, J6 O
  29. };
    0 i/ x/ S% O9 n( v

  30. 9 a& J7 a5 s, ]7 W) C) f* x
  31. void Do_UART_Recv(uint8_t i);//接收超时处理函数
复制代码
, Y- p2 X9 S0 m: g7 f$ j' v
# d1 I* G( W2 J" |
     C++面向对象最大的好处是,只要定义一个类,相同的外设只要传入参数构建类,就可以调用类函数来实现功能,不需要为每个外设再重新写代码。而且封装好了类,只需要知道传入什么参数,可以调用什么接口来实现自己的功能就可以了,不需要再去了解类里面是怎么来实现的。目前就封装了GPIO,UART,TIM Base,SPI等几个外设,可以给大家体验下面向对象的强大,提供一些封装函数的思路,更具体的代码可以下载附件的工程。! L3 C2 |# {- G) J
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,写的程序,都按照“流”执行,思路清晰。
1 B; s) ~4 b$ N未来的趋势就是单片机会越来越多的支持高级语言的开发,比如C#,ST官网也针对F4有例程,基于.NET MICRO FRAMEWORK的,最近一直研究,有兴趣,可以一起搞。
蓝凌风 回答时间:2016-4-29 09:03:44
auto_ele 发表于 2016-4-28 11:13
; v4 Z2 L* E% A9 }不错,我们好多的项目,已经这么做了,效果不错,就是类和类之间传值有点麻烦,其他的都OK,写的程序,都按 ...
0 Y% ]; z: q7 i5 K4 V7 f
.NET MICRO FRAMEWORK我去年就有研究,写过一些文章,只能是玩玩,实际上没太多的胜任
auto_ele 回答时间:2016-5-16 21:34:44
蓝凌风 发表于 2016-4-29 09:037 e- K' @. h: H9 w
.NET MICRO FRAMEWORK我去年就有研究,写过一些文章,只能是玩玩,实际上没太多的胜任 ...

3 c: Q3 y7 i  ^- [9 }6 l较LINUX之类的系统,它把硬件层和应用层完全分开,只要写好CLR就可以。
lzts 回答时间:2016-5-17 11:18:08
学习了, 帮顶+ V: T5 v$ C4 [9 q0 D' y7 M# ]" R- S
HenryChen 回答时间:2016-5-17 11:29:47
学习学习学习学习
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版