STM32F1----USART

1.USART初始化流程
<1>建立GPIO、USART、NVIC初始化结构体

USART_InitTypeDef  USART_InitStructure;
GPIO_InitTypeDef   GPIO_InitStructure;
NVIC_InitTypeDef   NVIC_InitStructure;

<2>打开对应的时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

<3>配置结构体,完成初始化

/*GPIO_InitStructure、NVIC_InitStructure结构体配置 略*/
USART_InitStructure.USART_BaudRate = 115200;                                    //波特率
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_Rx | USART_Mode_Tx;                 //串口模式  
USART_Init(USART1, &USART_InitStructure);                                       //初始化

<4>使能串口接收中断,使能串口

USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);                                  //中断使能

USART_Cmd(USART2, ENABLE);                                                      //定时器使能

2.USART初始化结构体

typedef struct
{
     
  uint32_t USART_BaudRate;            /*此成员配置USART通信波特率*/

  uint16_t USART_WordLength;          /*指定帧中传输或接收的数据位的个数*/
  
  uint16_t USART_StopBits;            /*指定传输的停止位数*/
  
  uint16_t USART_Parity;              /*指定奇偶模式校验模式*/
 
  uint16_t USART_Mode;                /*启用或禁用接收或发送模式*/

  uint16_t USART_HardwareFlowControl; /*是否启用硬件流控制模式*/
} USART_InitTypeDef;

/*传输或接收的数据位的个数宏定义*/
#define USART_WordLength_8b                  ((uint16_t)0x0000)
#define USART_WordLength_9b                  ((uint16_t)0x1000)

/*停止位的宏定义*/
#define USART_StopBits_1                     ((uint16_t)0x0000)
#define USART_StopBits_0_5                   ((uint16_t)0x1000)
#define USART_StopBits_2                     ((uint16_t)0x2000)
#define USART_StopBits_1_5                   ((uint16_t)0x3000)

/*/*奇偶校验位的宏定义*/*/
#define USART_Parity_No                      ((uint16_t)0x0000)
#define USART_Parity_Even                    ((uint16_t)0x0400)
#define USART_Parity_Odd                     ((uint16_t)0x0600)

/*启用或禁用接收或发送的模式*/
#define USART_Mode_Rx                        ((uint16_t)0x0004)
#define USART_Mode_Tx                        ((uint16_t)0x0008)

/*硬件流控制宏定义*/ 
#define USART_HardwareFlowControl_None       ((uint16_t)0x0000)
#define USART_HardwareFlowControl_RTS        ((uint16_t)0x0100)
#define USART_HardwareFlowControl_CTS        ((uint16_t)0x0200)
#define USART_HardwareFlowControl_RTS_CTS    ((uint16_t)0x0300)

一般都是配置为9600或者115200的波特率,8位数据位,1位停止位,不使用硬件流控制,启用发送与接收模式,使能接收中断,使能串口。

3.USART发送与中断接收例程

#include "usart.h"


static void usart_1_config(void);
void usatt_1_init(void);
void usart_SendString(uint8_t *str);


static void usart_1_config(void)
{
     
    USART_InitTypeDef USART_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); 
    
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    USART_InitStructure.USART_BaudRate = 115200;                                    //波特率
    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_Rx | USART_Mode_Tx;                 //串口模式  
    USART_Init(USART1, &USART_InitStructure);                                       //初始化
    
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);                                  //中断使能

    USART_Cmd(USART2, ENABLE);                                                      //串口使能

}


void usatt_1_init(void)
{
     
    usart_1_config();
}

/*发送字符串函数*/
void usart_SendString(u8 *str)
{
     
	u8 i=0;
	do{
     
		USART_SendData( USART2, str[i]);/*库函数,用于发送8位的数据*/
		while(!USART_GetFlagStatus( USART2,  USART_FLAG_TXE));/*等待发送寄存器为空*/
		i++;
	}while(str[i]!=0);  
}


/*串口接收字符串函数*/
void USART2_IRQHandler(void)
{
     
    __IO uint8_t temp;
    
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)/*检测是否接收寄存器是否为空*/
    {
     
		USART_ClearITPendingBit(USART2, USART_IT_RXNE);
    
        temp= USART_ReceiveData(USART2);
    }
}

:1、在串口接收中断中一定要清除中断标志位,不然可能造成串口中断一直被响应,造成程序卡死。
  2、以上程序仅仅是串口最常见的应用。串口作为一种广泛应用的通信协议,有着广泛的用途。

4.4种接串口中断的接收数据的实现方式
<1>最基本串口中断的接收数据的实现方式

void USART1_IRQHandler(u8 GetData)
{
     
    u8 BackData;
  	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //中断产生
  	{
       
	   	USART_ClearITPendingBit(USART1,USART_IT_RXNE);    //清除中断标志.
	   	GetData = UART1_GetByte(BackData); //GetData=USART1->DR;也行   
		USART1_SendByte(GetData);          //发送数据
	   	GPIO_SetBits(GPIOE, GPIO_Pin_8 );  //LED闪烁,接收成功发送完成
	   	delay(100);					       /*此处延时最好不要用SysTick定时器完成,可以用软件延时*/
	   	GPIO_ResetBits(GPIOE, GPIO_Pin_8 );
  	}
}  

最基本串口中断的接收数据的实现方式,将数据接收完成后又发送出去,接收和发送在中断函数里执行,main函数里无其他要处理的。
优点:简单,适合很少量数据传输。
缺点:无缓存区,并且对数据的正确性没有判断,数据量稍大可能导致数据丢失 。

<2>加了校验帧与缓冲区的串口中断的接收数据的实现方式


void USART2_IRQHandler()  
{
     
    if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生
  	{
       
	    USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志
	    Uart2_Buffer[Uart2_Rx_Num] = USART_ReceiveData(USART2);
	    Uart2_Rx_Num++;
  	}
 
 //判断最后接收的数据是否为设定值,确定数据正确性
	if((Uart2_Buffer[0] == 0x5A)&&(Uart2_Buffer[Uart2_Rx_Num-1] == 0xA5)) 
		Uart2_Sta=1;
	/*如果RXEN标志没有被复位,串口有接收到了一个字符就会发生溢出中断,解决方法是清除*/	
	if(USART_GetFlagStatus(USART2,USART_FLAG_ORE) == SET) //溢出
	{
     
	      USART_ClearFlag(USART2,USART_FLAG_ORE);   //读SR
	      USART_ReceiveData(USART2); 				//读DR  
	}     
}
 
if( Uart2_Sta )
{
     
	 for(Uart2_Tx_Num=0;Uart2_Tx_Num < Uart2_Rx_Num;Uart2_Tx_Num++)
	 USART2_SendByte(Uart2_Buffer[Uart2_Tx_Num]); //发送数据
	 Uart2_Rx_Num = 0; //初始化
	 Uart2_Tx_Num = 0;
	 Uart2_Sta = 0;
}

:溢出中断也与死机如影随行,如果出现了溢出中断就意味着百分百丢失了数据。而我们能做的处理无非就是清除标志位防止中断反复触发,从而使整个系统能继续运行下去。至于丢失的数据,已经不可能找回来了。只要接收中断打开,即RXNEIE设置为1,那么ORE中断也自动打开了。

这是加了数据头和数据尾的接收方式,数据头和尾的个数可增加,此处只用于调试之用。中断函数用于接收数据以及判断数据的头尾,第二个函数在main函数里按照查询方式执行。
优点:较简单,采用缓存区接收,对提高数据的正确行有一定的改善 。
缺点:要是第一次数据接收错误,回不到初始化状态,必须复位操作 。

<3>FIFO方式接收串口中断的接收数据的实现方式

void USART2_IRQHandler() 
{
      
     if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生 
     {
      
          USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志. 
          Uart2_Buffer[Uart2_Rx] = USART_ReceiveData(USART2); 
          Uart2_Rx++; 
          Uart2_Rx &= 0x3F; //判断是否计数到最大
     } 
    if(USART_GetFlagStatus(USART2,USART_FLAG_ORE) == SET) //溢出 
    {
      
          USART_ClearFlag(USART2,USART_FLAG_ORE); //读SR 
          USART_ReceiveData(USART2); //读DR 
    } 
}
 
 
if( Uart2_Tx != Uart2_Rx ) 
{
      
    USART2_SendByte(Uart2_Buffer[Uart2_Tx]); //发送数据 
    Uart2_Tx++; 
    Uart2_Tx &= 0x3F; //判断是否计数到最大
}  

采用FIFO方式接收数据,由0x3F可知此处最大接收量为64个,可变,中断函数只负责收,另一函数在main函数里执行,FIFO方式发送。

优点:发送和接收都很自由,中断占用时间少,有利于MCU处理其它。
缺点:对数据的正确性没有判断,一概全部接收。

<4>采用数据包的形式接收串口中断数据的实现方式

void USART2_IRQHandler() 
{
      
     if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生 
     {
      
        USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志
        Uart2_Buffer[Uart2_Rx] = USART_ReceiveData(USART2); 
        Uart2_Rx++; 
        Uart2_Rx &= 0xFF; 
     } 
     if(Uart2_Buffer[Uart2_Rx-1] == 0x5A) //头 
        Uart2_Tx = Uart2_Rx-1; 
     if((Uart2_Buffer[Uart2_Tx] == 0x5A)&&(Uart2_Buffer[Uart2_Rx-1] == 0xA5)) //检测到头的情况下检测到尾 
     {
      
            Uart2_Len = Uart2_Rx-1- Uart2_Tx; //长度 
            Uart2_Sta=1; //标志位 
     } 
     if(USART_GetFlagStatus(USART2,USART_FLAG_ORE) == SET) //溢出 
     {
      
            USART_ClearFlag(USART2,USART_FLAG_ORE); //读SR 
            USART_ReceiveData(USART2); //读DR 
     } 
}
 
 
if( Uart2_Sta ) 
{
      
        for(tx2=0;tx2 <= Uart2_Len;tx2++,Uart2_Tx++) 
        USART2_SendByte(Uart2_Buffer[Uart2_Tx]); //发送数据 
        Uart2_Rx = 0; //初始化 
        Uart2_Tx = 0; 
        Uart2_Sta = 0; 
}

数据采用数据包的形式接收,接收后存放于缓存区,通过判断数据头和数据尾(可变)来判断数据的“包”及有效性,中断函数用于接收数据和判断头尾以及数据包长度,另一函数在main函数里执行,负责发送该段数据。
优点:适合打包传输,稳定性和可靠性很有保证,可随意发送,自动挑选有效数据。
缺点:缓存区数据长度要根据“包裹”长度设定,要是多次接收后无头无尾,到有头有尾的那一段数据恰好跨越缓存区最前和最后位置时,可能导致本次数据丢失,不过这种情况几乎没有可能。

5.关于串口USART的相关函数

  • 常用操作函数
/*串口初始化*/
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);

/*串口使能*/
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);

/*串口中断配置*/
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);

/*串口DMA使能*/
void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState);

/*发送8位的数据*/
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);

/*接收8位的数据*/
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
  • 串口传输数据状态查看函数
/*为获取状态标志位*/
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);

/*清除状态标志位*/
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);

/*获取中断状态标志位*/
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);

/*清除中断状态标志位*/
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);

6.关于串口USART的一些补充
1.注意问题

  • 1.USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);使能了接收中断,那么ORE中断也同时被开启了。

  • 2.ORE中断只能使用USART_GetFlagStatus(USART1, USART_FLAG_ORE) 读到(没有使能USART_IT_ERR中断时)

2.关于printf函数的重定向问题

//加入以下代码,支持printf函数,而不需要选择use MicroLIB	  
//可百度搜索:半主机模式

#if 1 方法1
#pragma import(__use_no_semihosting)  //标准库需要的支持函数 
                
struct __FILE 
{
      
	int handle; 
}; 
 
FILE __stdout;      
 
int _sys_exit(int x) 		//定义_sys_exit()以避免使用半主机模式    
{
      
	x = x; 
} 
 
int fputc(int ch, FILE *f) //重定义fputc函数 
{
           	
	USART1->DR = (u8) ch;  
	while((USART1->SR&0X40)==0){
     };//循环发送,直到发送完毕     
	return ch;
}
 
 
#else
 
/*使用microLib的方法*/ 需要KEIL打钩!!!!
  
int fputc(int ch, FILE *f)
{
     
	 USART_SendData(USART1, (uint8_t) ch);
	 while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {
     }	   
         return ch;
}

你可能感兴趣的:(stm32F1使用简述,单片机,嵌入式,stm32,串口通信)