//usart.h

#ifndef __USART_H__
#define __USART_H__

#include "stm32f10x.h"
#include <stdio.h>

void GPIO_Configuration(void);
void NVIC_Configuration(void);
void USART_Configuration(void);
#endif


//usart.c

#include "usart.h"

//加入以下代码,以支持printf()函数,而不需要选中use MicroLIB 
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要支持的函数               
struct __FILE 
{ 
	int handle; 

}; 

FILE __stdout;       
//定义_sys_exit()函数,以避免使用半主机模式
_sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputs()函数
int fputc(int ch, FILE *f)
{      
	while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET); 
    USART_SendData(USART1,(uint8_t)ch);   
	return ch;
}
#endif 



void GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;  
 	
 	//使能GPIO复用功能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE);	
		
	//TX复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//RX浮空输入
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
}

void NVIC_Configuration(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn ;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

void USART_Configuration(void)
{
	USART_InitTypeDef USART_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	
	USART_DeInit(USART1);
	
	USART_InitStructure.USART_BaudRate = 9600; 
	USART_InitStructure.USART_WordLength = USART_WordLength_8b; 
	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_Tx | USART_Mode_Rx; 
	USART_Init(USART1,&USART_InitStructure);
	
	//???必须先使能USART1,再使能中断。顺序不可调换。因为中断初始后程序直接跳进中断函数里面执行发送命令,故必须先使能USART,才能使发送正常。
	USART_Cmd(USART1,ENABLE);
	USART_ITConfig(USART1,USART_IT_TC,ENABLE);
	
}


//main.c

#include "MyTime.h"
#include "usart.h"
#include <stdbool.h>

 const char arr[] = "Hello stm32,Hello usart!!!";
int main(void)
{
	MySysTick_Init();	
	GPIO_Configuration();
	NVIC_Configuration();
	USART_Configuration();
	
	while(1);
	
}

void USART1_IRQHandler(void)  
{
	static s16 i = 0;
	static s16 nCount = sizeof(arr)/sizeof(arr[0]);
	static bool bFirstIn = true;
	//在发送数据的最开始,需要清除一下USART的标志位
	if(bFirstIn)
	{
		USART_ClearFlag(USART1,USART_IT_TC);
		bFirstIn = false;
	}
	if(USART_GetITStatus(USART1,USART_IT_TC) == SET)
	{				
		printf("%c",arr[i++]);
		MyDelay_ms(1000);
		if(i>=nCount)
		{
			printf("\r\n");
			i=0;
		}
	}
	
	
}

注意在对数据进行发送和接收的时候,要检查USART的状态,只有等到数据发送或接收完毕之后才能进行下一帧数据的发送或接收。采用USART_GetFlagStatus()函数。

同时还要注意的是,在发送数据的最开始,需要清除一下USART的标志位,否则,第1位数据会丢失。因为在硬件复位之后,USART的状态位TC是置位的。当包含有数据的一帧发送完成之后,由硬件将该位置位。只要当USART的状态位TC是置位的时候,就可以进行数据的发送。然后TC位的置零则是通过软件序列来清除的,具体的步骤是“先读USART_SR,然后写入USART_DR”,只有这样才能够清除标志位TC,但是在发送第一帧数据的时候,并没有进行读USART_SR的操作,而是直接进行写操作,因此TC标志位并没有清空,那么,当发送第一帧数据,然后用USART_GetFlagStatus()检测状态时返回的是已经发送完毕(因为TC位是置1的),所以程序会马上发送下一帧数据,那么这样,第一帧数据就被第二帧数据给覆盖了,所以看不到第一帧数据的发送。