一般步骤

1) 串口时钟和 和 GPIO 时钟 使能。

串口是挂载在 APB2 下面的外设,所以使能函数为:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能 USART1 时钟**
GPIO 时钟使能,就非常简单,因为我们使用的是串口 1,串口 1 对应着芯片引脚 PA9,PA10,
所以这里我们只需要使能 GPIOA 时钟即可:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能 GPIOA 时钟**

2) 设置引脚复用器映射

GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //PA9 复用为 USART1**
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);//PA10 复用为 USART1**
**

3) GPIO 端口模式设置:PA9 和 PA10 要设置 为复用功能。

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9 与 GPIOA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度 50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化 PA9,PA10
**

4) 串口参数初始化:设置波特率,字长,奇偶校验等参数

串口初始化是调用函数 USART_Init 来实现的,具体设置方法如下:
USART_InitStructure.USART_BaudRate = bound;//一般设置为 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为 8 位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口

5) 使能串口

使能串口调用函数 USART_Cmd 来实现,具体使能串口 1 方法如下:
USART_Cmd(USART1, ENABLE); //使能串口

6) 串口数据发送与接收。

STM32F4 的发送与接收是通过数据寄存器 USART_DR 来实现的,这是一个双寄存器,包
含了 TDR 和 RDR。当向该寄存器写数据的时候,串口就会自动发送,当收到数据的时候,也
是存在该寄存器内。
STM32 库函数操作 USART_DR 寄存器发送数据的函数是:
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
STM32 库函数操作 USART_DR 寄存器读取串口接收到的数据的函数是:
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
**

7) 串口状态

串口的状态可以通过状态寄存器 USART_SR 读取
RXNE(读数据寄存器非空),当该位被置 1 的时候,就是提示已经有数据被接收到了,并
且可以读出来了。这时候我们要做的就是尽快去读取 USART_DR,通过读 USART_DR 可以将
该位清零,也可以向该位写 0,直接清除。
TC(发送完成),当该位被置位的时候,表示 USART_DR 内的数据已经被发送完成了。如
果设置了这个位的中断,则会产生中断。该位也有两种清零方式:1)读 USART_SR,写
USART_DR。2)直接向该位写 0。

读取串口状态的函数是:
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
这个函数的第二个入口参数非常关键,它是标示我们要查看串口的哪种状态,比如上面讲解的
RXNE(读数据寄存器非空)以及 TC(发送完成),
例如我们要判断读寄存器是否非空(RXNE),操作库函数的方法是:
USART_GetFlagStatus(USART1, USART_FLAG_RXNE);
我们要判断发送是否完成(TC),操作库函数的方法是:
USART_GetFlagStatus(USART1, USART_FLAG_TC);

8) 开启中断并且初始化 NVIC ,使能相应中断

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级 3**`**<br />**NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //响应优先级 3**** **<br />**NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能**** **<br />**NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化 VIC 寄存器`**<br />**<br />使能相应中断,使能串口中断的函数是:****void USART_ITConfig(USART_TypeDef* USARTx, uint16_tUSART_IT,FunctionalState NewState) `这个函数的第二个入口参数是标示使能串口的类型,也就是使能哪种中断,因为串口的中断类
型有很多种。

比如在接收到数据的时候(RXNE 读数据寄存器非空),我们要产生中断,那么我们开启中断的方法是:
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断,接收到数据中断我们在发送数据结束的时候(TC,发送完成)要产生中断,那么方法是:
USART_ITConfig(USART1,USART_IT_TC,ENABLE);**

9) 获取相应中断状态

当我们使能了某个中断的时候,当该中断发生了,就会设置状态寄存器中的某个标志位。
经常我们在中断处理函数中,要判断该中断是哪种中断,使用的函数是:
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)
比如我们使能了串口发送完成中断,那么当中断发生了, 我们便可以在中断处理函数中调用这
个函数来判断到底是否是串口发送完成中断,方法是:
USART_GetITStatus(USART1, USART_IT_TC);
**

10) 中断服务函数

串口 1 中断服务函数为:
void USART1_IRQHandler(void);




**
usart.h

  1. #ifndef __USART_H
  2. #define __USART_H
  3. #include "stdio.h"
  4. #include "stm32f4xx_conf.h"
  5. #include "sys.h"
  6. #define USART_REC_LEN 200 //定义最大接收字节数 200
  7. #define EN_USART1_RX 1 //使能(1)/禁止(0)串口1接收
  8. extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
  9. extern u16 USART_RX_STA; //接收状态标记
  10. //如果想串口中断接收,请不要注释以下宏定义
  11. void uart_init(u32 bound);
  12. #endif

usart.c

  1. #include "sys.h"
  2. #include "usart.h"
  3. #if SYSTEM_SUPPORT_OS
  4. #include "includes.h" //ucos 使用
  5. #endif
  6. #if 1
  7. #pragma import(__use_no_semihosting)
  8. //标准库需要的支持函数
  9. struct __FILE
  10. {
  11. int handle;
  12. };
  13. FILE __stdout;
  14. //定义_sys_exit()以避免使用半主机模式
  15. void _sys_exit(int x)
  16. {
  17. x = x;
  18. }
  19. //重定义fputc函数
  20. int fputc(int ch, FILE *f) /* **** **** */
  21. {
  22. while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
  23. USART1->DR = (u8) ch;
  24. return ch;
  25. }
  26. #endif
  27. #if EN_USART1_RX //如果使能了接收
  28. //串口1中断服务程序
  29. //注意,读取USARTx->SR能避免莫名其妙的错误
  30. u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
  31. //接收状态
  32. //bit15, 接收完成标志
  33. //bit14, 接收到0x0d
  34. //bit13~0, 接收到的有效字节数目
  35. u16 USART_RX_STA=0; //接收状态标记
  36. //初始化IO 串口1
  37. //bound:波特率
  38. void uart_init(u32 bound){
  39. //GPIO端口设置
  40. GPIO_InitTypeDef GPIO_InitStructure;
  41. USART_InitTypeDef USART_InitStructure;
  42. NVIC_InitTypeDef NVIC_InitStructure;
  43. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟
  44. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟
  45. //串口1对应引脚复用映射
  46. GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9复用为USART1
  47. GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1
  48. //USART1端口配置
  49. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10
  50. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
  51. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz
  52. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
  53. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
  54. GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10
  55. //USART1 初始化设置
  56. USART_InitStructure.USART_BaudRate = bound;//波特率设置
  57. USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
  58. USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
  59. USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
  60. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
  61. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
  62. USART_Init(USART1, &USART_InitStructure); //初始化串口1
  63. USART_Cmd(USART1, ENABLE); //使能串口1
  64. //USART_ClearFlag(USART1, USART_FLAG_TC);
  65. #if EN_USART1_RX
  66. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断
  67. //Usart1 NVIC 配置
  68. NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
  69. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
  70. NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3
  71. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
  72. NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
  73. #endif
  74. }
  75. void USART1_IRQHandler(void) //串口1中断服务程序
  76. {
  77. u8 Res;
  78. #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
  79. OSIntEnter();
  80. #endif
  81. if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
  82. //接收中断(接收到的数据必须是0x0d 0x0a结尾)
  83. {
  84. Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
  85. if((USART_RX_STA&0x8000)==0)//接收未完成
  86. {
  87. if(USART_RX_STA&0x4000)//接收到了0x0d
  88. {
  89. if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
  90. else USART_RX_STA|=0x8000; //接收完成了
  91. }
  92. else //还没收到0X0D
  93. {
  94. if(Res==0x0d)USART_RX_STA|=0x4000;
  95. else
  96. {
  97. USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
  98. USART_RX_STA++;
  99. if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收
  100. }
  101. }
  102. }
  103. }
  104. #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
  105. OSIntExit();
  106. #endif
  107. }
  108. #endif

好难啊, o(╥﹏╥)o
以后再仔细 ~~_**研究**_~~