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

STM32F0系列之在Keil-MDK下编写uart串口打印程序

[复制链接]
STMCU小助手 发布时间:2022-8-25 22:20
一、构建程序目录
7 |( Y- p0 ~) r1 P8 D, O5 V* C新建src文件夹,用来存放c源代码( |1 y' e* I! `3 d% v" j
新建inc文件夹,用来存放头文件- i  ~; u- L1 _- r* f) z! G% [% \
# o6 Y( k3 e+ v8 `! T
二、编写源文件
4 O/ Z$ v6 X, Q7 T在src文件夹下新建uart.c文件如下所示
% J5 G" J% ]# e* u
7 A+ u  M% Z( r6 a* U; ?
  1. #include "uart.h"
      u4 y9 r% {  l) |9 q

  2. # M. k7 `, ~9 y& P# Q
  3. typedef unsigned int uint32_t;9 c$ t0 Q+ A: A/ L# H% X- h# P! X
  4. typedef struct1 c5 r: u9 f+ j
  5. {6 \: D" w. h' i9 K+ ^, v
  6.   volatile uint32_t SR;    /*!< USART Status register, Address offset: 0x00 */
    7 P& v* Y, W& g" F; \
  7.   volatile uint32_t DR;    /*!< USART Data register,   Address offset: 0x04 */- Y: g$ h7 }1 [% {8 J9 o
  8.   volatile uint32_t BRR;   /*!< USART Baud rate register, Address offset: 0x08 */
    5 F5 y+ ]5 `( v
  9.   volatile uint32_t CR1;   /*!< USART Control register 1, Address offset: 0x0C */$ r2 U' S" V$ a) P- }
  10.   volatile uint32_t CR2;   /*!< USART Control register 2, Address offset: 0x10 */. R! N( J( i$ r8 d, e
  11.   volatile uint32_t CR3;   /*!< USART Control register 3, Address offset: 0x14 *// g! A8 {% D! h$ ]. I1 l6 v
  12.   volatile uint32_t GTPR;  /*!< USART Guard time and prescaler register, Address offset: 0x18 */! \! C, C" g- V  M- w
  13. } USART_TypeDef;  ?, E/ w* r6 L6 Z5 F6 q. s

  14. 6 h9 \, D! j2 f% v
  15. / Z6 a& X+ t. X% g7 a3 W; `
  16. void uart_init(void)
    ( J0 t* f' |6 @/ P0 \; a. ]$ _
  17. {
    " G( l9 W% _- V" K% M
  18.         USART_TypeDef *usart1 = (USART_TypeDef *)0x40013800;
    ! V! ^/ Q/ M3 M- S9 u) E; o
  19.         volatile unsigned int *pReg;. C/ ^* H# F0 L2 g2 M
  20.         /* 使能GPIOA/USART1模块 */! b" w# I2 ?3 h$ P7 R: n. H1 ], v
  21.         /* RCC_APB2ENR */
    6 M3 E+ ~# D3 s# e0 b- T' u  A
  22.         pReg = (volatile unsigned int *)(0x40021000 + 0x18);6 \" |& p- H  d* ^# }' q! A5 C
  23.         *pReg |= (1<<2) | (1<<14);
    ( z+ T4 m3 J& I3 W
  24.         
    - [! m  U2 ?- U9 D2 J+ Z
  25.         /* 配置引脚功能: PA9(USART1_TX), PA10(USART1_RX) # d: g/ V0 A2 r, T9 M; W- b
  26.          * GPIOA_CRH = 0x40010800 + 0x048 x" H* V0 C& m, J3 j
  27.          */
    $ {  D$ G/ E+ X% Y& S: X
  28.         pReg = (volatile unsigned int *)(0x40010800 + 0x04);
    2 r% ]# y$ ~$ v* w3 C8 C
  29.         . u. j. j4 d% m4 m
  30.         /* PA9(USART1_TX) */
    & p4 Z# X6 ~& ]0 {
  31.         *pReg &= ~((3<<4) | (3<<6));
    $ w* `5 T+ i& G) p/ Q7 L1 i
  32.         *pReg |= (1<<4) | (2<<6);  /* Output mode, max speed 10 MHz; Alternate function output Push-pull */; g1 M7 `9 l0 j! _! X- @* d
  33. 0 Y( ]; Z" \% s1 q' K9 `
  34.         /* PA10(USART1_RX) */
      L1 e! z! B3 H0 n: ]4 [
  35.         *pReg &= ~((3<<8) | (3<<10));
    ) }4 q8 `; X& b: B
  36.         *pReg |= (0<<8) | (1<<10);  /* Input mode (reset state); Floating input (reset state) */6 i$ w2 P( N. b! T# e9 K9 _1 i% e
  37.         
    4 P- x( D0 S( P& t
  38.         /* 设置波特率2 Z* j) G, c  `1 W# k. c
  39.          * 115200 = 8000000/16/USARTDIV( q9 X( R' S7 R
  40.          * USARTDIV = 4.34
    ; Y7 R& `$ L. K0 C7 y& E/ z# A
  41.          * DIV_Mantissa = 4$ L* u8 d/ Q8 e. U
  42.          * DIV_Fraction / 16 = 0.34" M1 N- }- U8 r
  43.          * DIV_Fraction = 16*0.34 = 50 N3 V5 H5 }) E6 {! k8 X# O
  44.          * 真实波特率:, e5 F6 A' @0 w9 f) C. s2 p2 R$ l
  45.          * DIV_Fraction / 16 = 5/16=0.3125
    # j, H' x5 z) k5 U. B( p; Q9 X
  46.          * USARTDIV = DIV_Mantissa + DIV_Fraction / 16 = 4.3125
    5 {6 X! @; W* D: u8 G' }  ^
  47.          * baudrate = 8000000/16/4.3125 = 115942
    2 _5 Y3 R# [5 V6 v0 V- L3 ~
  48.           */
    6 S2 \4 W5 x0 E1 D
  49. #define DIV_Mantissa 4
    ) p# g2 r# e+ K3 F' X# ^
  50. #define DIV_Fraction 5
    ' o% H& r# p' G  U8 O& _  {) Q
  51.         usart1->BRR = (DIV_Mantissa<<4) | (DIV_Fraction);
    . q6 ?9 [! F: H9 K/ `6 T$ i# S! N
  52.         
    9 u: x0 x+ |6 o2 t- P
  53.         /* 设置数据格式: 8n1 */- i* k* C6 O+ S8 _
  54.         usart1->CR1 = (1<<13) | (0<<12) | (0<<10) | (1<<3) | (1<<2);        
    ; r( v3 ?/ f2 v; u
  55.         usart1->CR2 &= ~(3<<12);
      x- s$ }1 ~' {  E1 ]: G+ i
  56.         
      t  q, a1 [# Q% N+ X9 q7 C8 a
  57.         /* 使能USART1 */
    7 ]/ g( G$ V! p. p5 R' O9 c
  58. }. ~/ R$ }7 _7 I
  59.         * F" i1 ^! ~/ [
  60. int getchar(void)( a/ y: `& N, D% c" L8 G! C
  61. {5 \7 p* k! ?; f4 H- f* U
  62.         USART_TypeDef *usart1 = (USART_TypeDef *)0x40013800;
    ! U$ B( N/ q0 A0 Y0 _) f7 _' k
  63.         while ((usart1->SR & (1<<5)) == 0);/ I: y9 j8 {5 r; m
  64.         return usart1->DR;  {) ~+ t* h# h, y2 X+ h2 Q
  65. }
    ! }2 ^5 ~0 A* C3 f# ]) {

  66. 1 @# B# c  n1 l0 }
  67. int putchar(char c)
    . F8 w. X7 G6 P8 t5 D
  68. {
    ; l- I& d' D$ G! j5 C' D! |
  69.         USART_TypeDef *usart1 = (USART_TypeDef *)0x40013800;
    . {! |7 t0 n" I$ Y/ F, P
  70.         while ((usart1->SR & (1<<7)) == 0);/ @# Y( J! G$ q0 o+ G  \7 b2 N2 x
  71.         usart1->DR = c;
    ' |, o+ F" n$ {' f9 A
  72.         
    5 |8 v, o' {; d9 h" l# P) K) r# `
  73.         return c;
    * {, X6 r: w5 M2 u; E$ w8 P3 P
  74. }
复制代码
: Z0 U; h$ f! ~" ^- R
在inc文件夹下新建uart.h内容如下, w! w9 o  E( b0 W' @  X
- d4 _7 {7 Q4 H" t! R: G% A
  1. #ifndef _UART_H
    % q7 [2 `7 E( r& _: t1 Y
  2. #define _UART_H
    + h8 `* V3 u1 k0 m; N7 w$ h
  3. . p( J% L1 b9 W
  4. void uart_init(void);
    7 Z5 D, g- y! J4 l
  5. int getchar(void);4 x8 Y4 b$ C- z1 g+ B* v5 B
  6. int putchar(char c);
    " ^4 w: E6 O9 |( |% }% K* x& q. y

  7. $ i1 O# U! z# H" K8 o: R8 m9 o
  8. #endif
复制代码
: q: J) A) U8 N' M. R& ?6 H
在src文件夹下新建led.c文件如下所示8 K7 t. B# w" D, {" c

# R, M( _; I, z5 f
  1. #include "led.h"! `: y& m" Q- i3 [( @- y3 R
  2. . z1 F; M0 P( B5 v2 M4 U; n# ]8 A
  3. int delay(int ndelay)
    2 J' t8 h; t' e5 c6 R( U$ i8 R; A
  4. {  F. |5 K; l! [/ ?! e  N: j
  5.         volatile int n = ndelay;2 M, }- m* p1 u5 F; b. P) _- e
  6.         while(n--);
    1 v# b" S, `& Y! ?6 I4 S

  7. & B  Z1 N) Y5 q  t. m8 S- J/ \. e+ f
  8.         return 0;
    % A( u/ d# W7 n8 d
  9. }4 W  s  x5 c0 R5 o. L
  10. : L5 |. O8 I+ E! O
  11. void led_init(void)
    4 W! D& _8 m5 B9 b, P
  12. {
    9 Q. X  s" r1 e) m3 b
  13.         unsigned int *pReg;9 j# L$ y+ r# ]0 K1 B
  14.         
    2 b" [9 k, h5 j  ?
  15.         /* 1、使能GPIOB */! ?+ T, U4 |* M+ V/ C( @1 M
  16.         pReg = (unsigned int *)(0x40021000 + 0x18);
    / ~5 N5 t' u5 i1 j4 c: U8 g- d
  17.         *pReg |= (1<<3);9 T8 v, ^4 N- Z* [1 ~6 C0 s
  18.         : a  F2 |5 Z! |6 @; ^1 h, ~
  19.         /* 2、设置GPIOB5为输出引脚 *// _) I3 ~: a& s7 E+ I* r1 t% a& c. @- R
  20.         pReg = (unsigned int *)(0x40010C00 + 0x00);: _  T1 [3 J5 `3 y% S
  21.         *pReg |= (1<<20);
    / z+ f0 S" l( D# R

  22. % E* L0 A2 c: D* c# u6 `! i& ^' k
  23.         pReg = (unsigned int *)(0x40010C00 + 0x0C);+ |+ V! S7 f* {! u1 c/ b% b% v( Z
  24.     *pReg &= ~(1<<5);# q; @" d- ~1 `! R# \& f5 `
  25. }7 M. w& v% K" P: b

  26. ; h3 J+ H' ]# u7 {+ l2 J/ p( t
  27. void led_on(void)
    : Y0 C: C( M1 x. I3 R3 H7 m, |
  28. {4 _$ C2 I3 P) r; Q( Z4 M
  29.         unsigned int *pReg = (unsigned int *)(0x40010C00 + 0x0C);
    # E5 F5 B5 ?: c
  30.                         . w( O1 K5 I$ O. H% z
  31.         /* 设置GPIOB5输出0 */9 V& Y  ?+ l7 M" x, X
  32.         *pReg &= ~(1<<5);
    2 v& Z, f: T! `. l, q6 ], z
  33. }
    3 ?& @* Z5 Q1 w2 R7 d
  34. % p1 P. f) T# H% q: K
  35. void led_off(void)
    9 G( ]7 m' X# v2 D' ?  G7 J7 @
  36. {9 Z8 y+ Y4 V7 N3 k- Z
  37.         unsigned int *pReg = (unsigned int *)(0x40010C00 + 0x0C);4 p4 P% g! [* V! X( t7 b0 w" l2 k
  38.                         " O4 b; ~4 t6 m' O, T
  39.         /* 设置GPIOB5输出1 */& b" E& e8 G2 X
  40.         *pReg |= (1<<5);
    0 e: X8 Y  Z. s3 M2 g
  41. }
复制代码

4 @; M1 `) T; x+ a在inc文件夹下新建led.h内容如下
0 _3 w. H# @5 E7 e3 @5 T) D0 [( N: c) R
  1. #ifndef __LED_H; [* p  w, B) ~) ~# }& t, n
  2. #define __LED_H
    9 O  L0 j* N5 ?2 _

  3. 2 p  t  G' r$ B$ j& q2 F
  4. int delay(int ndelay);- y8 C, g6 L6 [2 d; D
  5. void led_init(void);, }! K+ ~7 E4 a8 a5 c# }
  6. void led_on(void);
    . g! U. ]! O) Q9 G
  7. void led_off(void);8 Y+ B' P" a8 m% X7 _
  8. 4 B8 `& L& g3 e
  9. #endif
复制代码

& P5 V( P/ v: l$ w然后将led.c、uart.c添加到工程中,并添加inc文件夹为头文件目录
3 s8 \, i2 y7 P3 p. x* r0 z7 U 20210122214736469.png $ l+ D$ u& @1 L& T/ q' K1 P

) E; v* z( `7 Q, u  ?7 ], H
7 p! T" Q( i  Q( e) g' ], s三、修改主函数
& C- D9 M; `- O& S& `' \& n/ L将了原来的led.c修改为main.c如下所示+ p! o/ R$ F6 h$ }. t  N

8 h; P$ Z3 Q. v# s+ N6 E0 \
  1. #include "uart.h"
    ; s! T8 z1 y0 h
  2. #include "led.h"6 x+ R9 s! A& B: `+ G8 l5 W
  3. 7 C/ r5 z/ z' [! U
  4. int main(void)) D( T& d. `) m
  5. {8 L0 ^7 _. ^" N7 p; D1 K
  6.     uart_init();
    " E. K6 p+ }% [. Z: _$ ^2 _2 \
  7.     led_init();& `2 B$ m9 U/ w1 F+ R/ Z0 c
  8.     putchar('s');, z! L( E4 f8 k: w& m
  9.     putchar('t');
    - X7 B. F$ E# N% q3 c& g4 {4 r
  10.     putchar('m');
    / w5 f# D7 \( U
  11.     putchar('3');6 h; z# M9 G$ _3 ^+ T
  12.     putchar('2');
    . C) m9 _! f# k3 @, h* z" n
  13.     putchar('f');
    " ^0 |  |$ ^2 l' ?* ]1 o' E0 \
  14.     putchar('1');
    ( E, i/ |5 n6 k; Q/ J- V: s0 _
  15.         putchar('0');; i. R( G1 ^$ K5 N* ]
  16.         putchar('3');
    " e, k9 V( F: m) z/ R3 E% B) s
  17.     putchar('\r');
    , d5 y' B1 ?6 m6 R& x9 T8 l4 S
  18.     putchar('\n');
    / b3 u6 ]4 ^3 n4 c% O
  19. ! C! W% Z) K( L2 x( A, A
  20.     while(1)
    ) t% P% O; s" u+ B/ E0 P4 U: t2 L
  21.     {
    + k7 \* S% r) P% L
  22.         led_on();* J( ?3 h5 e( l
  23.         delay(1000000);; Z7 P( _9 i+ m0 H
  24.         led_off();
    7 X+ ~) @8 J5 U5 ?. s; D
  25.         delay(1000000);
    4 G7 R; g+ z) N: B2 L
  26.     }
    . E0 G& I4 T3 u
  27. }
复制代码

7 C8 C6 R" \& V' _四、编写汇编程序
, H) y; s0 Z) C8 |& W) z) u汇编程序start.s修改为如下所示
9 o1 U$ g  }, ]6 O' B( H1 |( C  N  D! i
  1. Stack_Size      EQU     0x00000400                                  ;定义堆栈大小为1024byte  v: ^- P) h% Z
  2.                                 AREA    STACK, NOINIT, READWRITE, ALIGN=3  ;定义一个数据段,标记为STACK,即栈,不写入初始值初,对RAM来说,即初始化为0,8字节对齐6 e0 A7 ~, z- {! Z6 `: _
  3. Stack_Mem                SPACE        Stack_Size                                    ;保留Stack_Size大小的栈空间
    + S' K' ^2 ^- J
  4. __initial_sp                                                                                  ;标号,代表堆栈顶部地址,后面有用
    / I* S/ F$ S# h" H
  5. : T' F* a  a1 ]. M" Z
  6.                 PRESERVE8                                                        ;指示编译器8字节对齐# |, Y. V4 Y: E
  7.                 THUMB                                                                ;指示编译器以后的指令为THUMB指令                                                               
    / U! @* \0 f/ e
  8. . Q* y' \; P7 D4 F3 p
  9. $ i. H- w+ I7 [  }1 n1 Z9 o3 l- P4 Z. @
  10. ; Vector Table Mapped to Address 0 at Reset* h7 o: O) H$ k; t0 x
  11.                                 AREA    RESET, CODE, READONLY                ;定义只读数据段,标记为RESET,其实放在CODE区,位于0地址5 O9 V' D( L) M  e0 V" `4 A9 h
  12.                                 EXPORT  __Vectors                                        ;在程序中声明一个全局的标号__Vectors,该标号可在其他的文件中引用
    & @$ o! T: V4 X' s1 q
  13.                                        
    4 i$ P; `' ]! F2 S9 k- k
  14. __Vectors       DCD     __initial_sp                                ;当前地址写入一个字(32bit)数据,值应该为栈顶地址
    ! v; u! I0 P9 l  h; @0 I' d/ D3 j' s
  15.                 DCD     Reset_Handler                      ;当前地址写入一个字(32bit)数据,值为Reset_Handler指向的地址值,即程序入口地址
    ! n. ~& s2 [: e4 W! \6 r

  16. / a1 r, p1 d) N7 u& O" Y8 D3 f
  17.                                 AREA    |.text|, CODE, READONLY                ;定义代码段,标记为.text: ]' v2 l7 x* b8 ^

  18. . f! I, Q0 a' d6 E! C4 T* ^
  19. ; Reset handler        ;利用PROC、ENDP这一对伪指令把程序段分为若干个过程,使程序的结构加清晰
    8 i/ q# I) d2 S4 S" y, x7 B
  20. Reset_Handler   PROC                                                                ;过程的开始
    . R0 C! |6 L% q* Q' x; p/ B8 a
  21.                                 EXPORT  Reset_Handler        [WEAK]                ;[WEAK] 弱定义,意思是如果在别处也定义该标号(函数),在链接时用别处的地址。
    3 X! Q8 x$ \4 A8 J" `
  22.                                 IMPORT  main                                                ;通知编译器要使用的标号在其他文件
    0 J1 }% h3 w) I( z/ r
  23.                                 BL                main                                                 ;跳转去执行main函数5 g( G- A7 b8 `7 \4 M1 R7 Z8 w1 ?
  24.                                 B                .                                                        ;原地跳转,即处于循环状态
    * m" ]9 ^% c$ D- `
  25.                                 ENDP
    6 B9 _- r4 ?9 t* `9 H
  26. 1 m7 E& n' A! u
  27.                 ALIGN                                                                 ;填充字节使地址对齐
    , z7 V% t- N) @/ }' n+ p( m
  28.                 END                                                                        ;整个汇编文件结束
复制代码

0 J: G! U5 o  I' h6 a6 w! m五、运行
- ~4 m& ^3 V5 ?. g0 q- c9 N编译烧录运行可以看到其打印的信息$ O6 D/ v. [/ W1 c9 L

2 Q( Y; j* B4 j# A$ H* D 20210122220055344.png " l" e( ^8 D; b

3 z8 A. r+ k" p; l4 S: G( s9 v六、优化9 C# j  o# u% @6 f0 D
接下来我们在uart.c中添加如下两个函数用来打印字符串和16进制数
+ U! ?' [3 C) Z# C. W' S; u* D! }; y% P# _
  1. int putstring(const char *s)
    4 n9 K3 N8 ?) o5 [
  2. {5 a1 z0 c, @, C, ~, J. ]
  3.         while (*s)* g# r. e8 ^+ G2 |/ F
  4.         {
    ) O& u. p' R" U4 \' u8 T6 W& K  K/ e
  5.                 putchar(*s);
    # m2 ?& M: ]8 J/ \9 ?7 T3 _- ?
  6.                 s++;
    * A7 r8 z! X& W
  7.         }& x9 Z8 t9 L+ |1 v  d: c/ `% Y- |& ?
  8.         return 0;. S( y% E: X3 z; E6 n8 l+ O
  9. }
    - Y9 X, @: w; A
  10. 3 r2 q1 B# V( q3 j0 E7 N
  11. void puthex(unsigned int val)
    $ I8 K0 H& o2 k; j
  12. {
    8 @; f0 j3 H& M. v
  13.         /* 0x76543210 */
    $ N' @" O' g4 B4 I4 ]# M
  14.         int i, j;
    % a. f* k, {/ y
  15. : ^, a3 A! h9 R/ M
  16.         //puts("0x");6 C+ W) a2 J  }- \
  17.         putchar('0');: w, ?9 T- f  P3 Z
  18.         putchar('x');
    4 g, @) d, v6 G5 T
  19.         for (i = 7; i >= 0; i--)  S/ ~' _7 @2 v" U
  20.         {
      g# i0 ], U8 S1 }
  21.                 j = (val >> (i*4)) & 0xf;$ k( V  X* d7 V
  22.                 if ((j >= 0) && (j <= 9))7 T/ k# \" h" X( K% J) j
  23.                         putchar('0' + j);/ d' y. _/ I! k) S1 @1 l
  24.                 else
    # c. a) v0 f: Z% B
  25.                         putchar('A' + j - 0xA);
    : T% a9 o) I, }3 S; X- L! O2 H
  26.         }        
    4 z% |% ]2 c* s% d3 X6 d
  27. }
复制代码

. t& ?4 K% K  b- z5 d& B修改main函数如下所示
! o0 q6 A$ ^3 i) F' p: }$ ^, C$ \2 v4 Y
20210122220347595.png
/ g( k" g+ i' l5 b1 ?, U0 N* ^3 @8 j/ f( U' p
编译烧录运行可以看到其串口打印如下! C" i7 R' M. [( l: h/ Z5 M
20210122220402810.png 7 o6 J9 M7 {" _' G( J. _

/ w2 M) c) U6 C* M9 x+ A" Z————————————————
6 J( L& @% Z0 Y( S0 K转载:Willliam_william, e5 v) F+ E3 l- G1 [
8 ~0 r# g' i1 M* ~/ |
5 y$ M, R3 Q3 M. S* [' {
赞 收藏 评论0 发布时间:2022-8-25 22:20

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版