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

STM32 C++开发

[复制链接]
蓝凌风 发布时间:2016-4-21 20:28
  每次写代码的时候,写外设的初始化都要去复制已经写好的或者是官方的例程,再根据自己的需求来修改,重复性的工作太多,就想到用C++来封装下STM32的库函数,顺便学习下C++,感受下面向对象的强大。
- \* W; x9 |  f6 ~4 N, K8 G    硬件平台:STM32F4-Discovery
; W) V" l9 m0 K* K; P    开发平台:MDK5.14(本来是用VS2013 +VisualGDB的,想到坛友基本都是用MDK的,又改成MDK)5 M6 _7 Q. E4 s+ H
   先看Main+ _. L* Y/ S" F$ T
  1. #include "system.h"( K6 d. [' a/ `% d2 Q6 `6 b
  2. % {4 F' N# s: ]' `; z& m# Z. Y
  3. System *stm32f407;//系统接口指针
    & Y" m$ t- u$ b% y! c( j3 I

  4. ! H0 a& J! o% a3 l8 _/ D
  5. void btnhandle(void *arg)  //按键回调处理函数3 _! m/ V2 b2 ]
  6. {
    - p& Y0 g, U  _: T% }* p& v
  7.          delay->delay_ms(20);+ u: Y( R8 x0 o# N6 r0 B
  8.         if (stm32f407->btn->ReadData() == true)
    ( j2 u! J  W3 J/ M8 g2 C
  9.                 stm32f407->led2->Toggle();
    % ]) Z9 C3 w+ R4 U  s1 Y( n% E1 \
  10. }, s% d/ u' `6 j/ a) w$ _3 ]0 x
  11. 2 w+ x/ P8 P5 t* h$ x5 n+ _
  12. void tim6handle(void *arg)  //定时器中断处理函数( G0 g4 [- r  A6 G6 Z& R
  13. {
      F8 c, ^/ l4 p6 a5 \3 t
  14.         stm32f407->led2->Toggle();
    + @( g& j' [/ D6 _  V! \
  15. }
    7 O1 M: B" K4 _- e" R

  16. ; }, Z# S' K3 J- C- q
  17. int main()
    / @4 h4 n3 [9 s- E1 ?! m; e8 b
  18. {9 a/ }& @5 i( w( u! i9 b/ g( ?' U
  19.         stm32f407 = new System;//构建系统接口类, u# l, X( p1 n
  20.         stm32f407->tim2->startIT((void*)tim6handle, NULL);//调用TIM类的中断启动函数,只要传入中断回调函数实现自己的功能,并不需要知道中断是要怎么处理的. @' G) g  H3 G) Q! a8 M! l
  21.         uint8_t recvdata[100];
    5 }& N# _# x- Y6 _1 @, y* x
  22.   for (;;); W1 G1 T" M6 R. y
  23.   {
    , y) [  |% _5 h2 S2 a; M2 H
  24.           stm32f407->led1->Toggle();//在system中初始化,就可以直接调用类函数
    , f0 z7 P3 o& c  f! F- X5 \
  25.           if (true == stm32f407->Debug->IsGetRecv)//串口自动接收标志
    # M5 v8 |8 `; v/ q2 Y! t
  26.           {
    ( A& G# a  ]+ k1 Y
  27.                   stm32f407->Debug->RecvData(recvdata);//串口接收函数,传入Buffer,得到接收的数据8 T$ y* d4 V' v
  28.                   stm32f407->Debug->SendData(recvdata, stm32f407->Debug->RecvDataLen, 100);
    - z( v9 O1 ~6 d; ^4 R5 I: m
  29.           }2 U0 A0 O3 }1 f9 X  m9 P& M7 Z
  30.           delay->delay_ms(500);9 @3 K9 Y7 ^- Q# e' `1 e- B
  31.   }
    & i6 h. h- R" H, i" w; O
  32. }$ X- |' N5 N/ E$ L+ n# l
复制代码
0 M* l# M' B3 m
    再看System类的初始化
6 i3 N: I0 Q6 Z6 N, U0 h
  1. void System::init()9 f1 ~; W0 Z6 q" y/ J4 U* u
  2. {% J/ b* {  v8 ~1 p) k* I8 z& V
  3.         HAL_Init();4 t. n& ^/ c2 e/ Z
  4.         SystemClock_Config();. x8 `# @4 i6 d8 G* _
  5. //外设初始化" c3 K9 @5 _( z, q( n' }
  6.   delay = new timerdelay;                //系统延时初始
    " [1 @8 K" A4 U$ k' e
  7.         Debug = new Usart(USART3, 115200, Usart::USART_IT, 200); //Debug 串口输出初始化,只要传入用的串口号,跟波特率,传输的模式,还有接收Buffer的大小,就可以完成初始化" C( n6 K2 k! t# W' O
  8.         led1 = new LED(GPIOD, GPIO_PIN_14, true, LED::highlevel);//LED类,继承OutputPort类,只要传入LED对应的GPIO,跟Pin,还有LED电平控制,就可以完成初始化  z2 W' \% h9 F
  9.         led2 = new LED(GPIOD, GPIO_PIN_12, false, LED::highlevel);- a* B7 q( b7 d/ }# w: J% r
  10.         btn = new InputPort(GPIOA, GPIO_PIN_0, GPIO_MODE_IT_RISING, (void*)btnhandle, NULL); //输入类,传入GPIO,PIN,中断触发模式,回调指针,回调参数,完成初始化1 r' y1 M0 x2 [6 |& s% b
  11.         tim2 = new Timer_base(TIM2, 16800, 10000);
    4 n" S) Z  j8 x8 s) D2 b; A7 h3 e
  12.         BoardInfo();' d4 {; V* {( N, a4 q
  13. }
复制代码

4 F% `9 A2 Z6 s" ~# Z3 N% D+ Z" f# `# A+ u
7 K6 ?: {6 G' F. M
OutputPort类:
  1. class OutputPort( N0 x- }9 Z2 U6 o7 o6 X
  2. {; b+ l0 {% A! n: `+ d
  3. public:
    / F4 {. E. U: Z6 e# z
  4.         OutputPort(GPIO_TypeDef* mPORT, uint16_t mGPIO_PIN, bool initialState);//OutputPort类构建函数,简单传入三个参数! m3 j8 Y# u' y' q& C3 E0 N
  5.         OutputPort(GPIO_TypeDef* mPORT, uint16_t mGPIO_PIN, uint32_t GPIO_Speed, uint32_t GPIO_PuPd, bool initialState);//构建函数重载,可以传入更多的参数
    ( [4 d% j0 X2 y, e. p# \
  6.         ~OutputPort();
    % G6 \" c/ g& G7 g
  7.         void H(void);//类函数,构建的类都是调用同函数就可以实现,减少代码的重复/ ]# J; I* F" Y. J
  8.         void L(void);
    4 b( Z& l( C. e* \+ `
  9.         inline void  RegH(){PORT->BSRR |= GPIO_PIN;        }//内联函数,直接代码替换成寄存器操作,提高执行效率4 K8 E$ t: v# }8 x
  10.         inline void  RegL(){ PORT->BSRR |= GPIO_PIN << 16; }1 }6 u! T8 T( D! l
  11.         GPIO_TypeDef* PORT;
    & d0 n$ X' @9 v9 j
  12.         uint16_t GPIO_PIN;8 ~9 K# |+ w" J# ]$ J1 B2 R
  13. private:7 R+ i* R) u1 ^1 Y8 u
  14. protected:
    - D# e( y( O% j- e
  15. 1 @9 K8 F/ b: O9 K7 `9 k
  16. };
    # K! k6 y, z$ S1 l# y/ h5 g

  17. * K" ~, D9 q; k$ C
  18. LED类:
    $ O* u5 s1 s8 N7 Y8 b0 |
  19. class LED :public OutputPort
    " E' M% q; d; h/ ~: x: n' \
  20. {; q9 `# K8 _/ x% }, d7 u7 `, A' {
  21. public:: ?+ m+ }! {% b0 p) V: A/ {1 t* w2 A
  22.         LED(GPIO_TypeDef* mPORT, uint16_t mGPIO_PIN, bool initialState, uint8_t mCtlVolLev) : OutputPort(mPORT, mGPIO_PIN, initialState), CtlVolLev(mCtlVolLev){};//继承OutputPort类,并增加新的参数
    0 f% i$ r: x. o% B& i
  23.          ~LED();
    2 |: [, T3 b- j5 y. v: Z: f' X! F  Y
  24.          void ON();2 c( s# e: _& {5 ?* s2 L
  25.          void OFF();
    5 ~3 U5 [5 W; g% q" g# L4 t5 J
  26.          void Toggle();5 s" k, t% r0 j
  27.          enum{ lowlevel, highlevel };' B& M# \4 O! ]+ R/ k3 j
  28. private:" ^" \. R3 v' G4 `4 l7 ]; E
  29. protected:
    - v$ |; `( S& `+ A3 P
  30.         uint8_t CtlVolLev;    //LED 1为高电平  0为低电平* P: G$ _* V1 w$ ~
  31. };
复制代码

! R2 _9 K& V5 I8 I- j( N
+ D( `+ M: S2 |, I
# w; C3 g3 @. U. L
  UART类:( ?' H; A5 l+ P
  1. extern uint8_t UART_Recv_Timeout[5];//Time Tick
    4 W8 ?8 ~$ b+ j- S8 g* J, a+ W/ x

  2. + Y: U( X9 R0 G: P0 ^6 u4 I
  3. class Usart
    , [% p# r2 c% @4 x: s9 X
  4. {( A9 e0 k2 O! j5 K
  5. public:' Y: R. J! j( ^; \9 _4 Q
  6.         enum tranmode
    ; T/ @9 f; v$ p4 B0 H
  7.         {
    & T! O! C% J+ t7 p
  8.                 USART_Normal, //普通发送
    6 {/ H$ l9 c/ t1 ]9 p
  9.                 USART_IT,    //中断发送接收,接收自动判断超时完成接收- V# }% T9 U: G7 _% Q) A4 z1 U
  10.                 USART_DMA    //DMA发送接收,UART闲时中断自动接收DMA接收完成
    / U2 F" i& \% f  U- `
  11.         };//类构建时传入,类函数根据输入的类别发送接收
    ( \! I  Q' Y) {6 z/ F# D' T
  12.         Usart(USART_TypeDef *USARTx, uint32_t BaudRate, tranmode mmode,uint16_t mRecvBuffSize);
    8 q5 _% `. L% P/ ^0 H4 o; U( n
  13.         void SendData(uint8_t data);* z  ?# B; i4 Y% p8 P+ @
  14.         void SendData(uint8_t *pData, uint16_t Size, uint32_t Timeout);  e  f2 U+ b- l  b" U- o
  15.         uint16_t RecvData(uint8_t *pData);% T* l% _' q' t
  16.         uint16_t RecvDataLen; //接收到数据长度
    + c" X* X! |* o# a
  17.         UART_HandleTypeDef UartHandle;
    , @, H- a9 c  x; d' ~$ X
  18.         uint8_t IsGetRecv;   //接收标志
    9 n7 f2 d. h, A+ g. Z4 Q
  19.         uint8_t isSendOk ;  //发送完成标志: ^0 @- U5 J0 Q1 B3 I, j( i( u
  20.         tranmode mode;
    * I$ e) _2 E5 M5 o  m
  21.         void Printf(const char* fmt, ...);% B  o+ x% C# b0 q
  22.         ~Usart();- |: j) T, Q9 @  U" d) Y* r

  23. 1 L0 L# o. j! y8 e, s- w; ~0 V, X
  24. private:; f* e& ?1 }' \4 b9 I
  25.         uint16_t RecvBuffSize;
    7 C" Y# C6 L- E- a% l
  26.         uint8_t *RecvBuff;( ^. s2 }! [# N/ V8 a6 H1 S* _
  27.         uint8_t SendBuff[100];* o+ M/ C5 _7 }" g
  28.         void USART_DMA_Config(UART_HandleTypeDef *UartHandle);
    - V, z- X" y; o
  29. };
    " X- t+ c- y( |6 w1 V1 R5 p4 G

  30. $ i2 X: U2 |, S
  31. void Do_UART_Recv(uint8_t i);//接收超时处理函数
复制代码

; M$ g% j; T: X7 `0 |% W0 n$ u
3 c: U9 X( B) G     C++面向对象最大的好处是,只要定义一个类,相同的外设只要传入参数构建类,就可以调用类函数来实现功能,不需要为每个外设再重新写代码。而且封装好了类,只需要知道传入什么参数,可以调用什么接口来实现自己的功能就可以了,不需要再去了解类里面是怎么来实现的。目前就封装了GPIO,UART,TIM Base,SPI等几个外设,可以给大家体验下面向对象的强大,提供一些封装函数的思路,更具体的代码可以下载附件的工程。
/ h; F5 W+ v+ z9 g( b# |; @2 w
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,写的程序,都按照“流”执行,思路清晰。9 V/ R$ r. m  y* W9 V
未来的趋势就是单片机会越来越多的支持高级语言的开发,比如C#,ST官网也针对F4有例程,基于.NET MICRO FRAMEWORK的,最近一直研究,有兴趣,可以一起搞。
蓝凌风 回答时间:2016-4-29 09:03:44
auto_ele 发表于 2016-4-28 11:13* G; e( g* V. _) m$ X6 ~9 [
不错,我们好多的项目,已经这么做了,效果不错,就是类和类之间传值有点麻烦,其他的都OK,写的程序,都按 ...

1 z/ C  R0 u& C0 Y; z.NET MICRO FRAMEWORK我去年就有研究,写过一些文章,只能是玩玩,实际上没太多的胜任
auto_ele 回答时间:2016-5-16 21:34:44
蓝凌风 发表于 2016-4-29 09:03
& F: Q9 H) G3 e6 F0 O+ C.NET MICRO FRAMEWORK我去年就有研究,写过一些文章,只能是玩玩,实际上没太多的胜任 ...
/ Z' ]; @& q, E
较LINUX之类的系统,它把硬件层和应用层完全分开,只要写好CLR就可以。
lzts 回答时间:2016-5-17 11:18:08
学习了, 帮顶
# g) I: M" r2 m1 b8 A
HenryChen 回答时间:2016-5-17 11:29:47
学习学习学习学习

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版