串口配置使用的一般步骤及实例解读

串口配置的一般步骤

  1. 串口时钟使能,GPIO时钟使能:RCC_APB2PeriphClockCmd();
  2. 串口复位:USART_DeInit(); 这一步不是必须的
  3. GPIO端口模式设置:GPIO_Init(); 模式设置为GPIO_Mode_AF_PP
  4. 串口参数初始化:USART_Init();
  5. 开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
    NVIC_Init();
    USART_ITConfig();
  6. 使能串口:USART_Cmd();
  7. 编写中断处理函数:USARTx_IRQHandler();
  8. 串口数据收发:
    void USART_SendData(); //发送数据到串口,DR
    uint16_t USART_ReceiveData(); //接受数据,从DR读取接受到的数据
  9. 串口传输状态获取:
    FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
    void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
    注:使用中断需要操作5、7、8步骤,否则不需要。
    部分官方库函数的解读在该博客内有说明
    https://blog.csdn.net/DX5618258/article/details/95999557

串口整体初始化函数(非库函数/整合上述步骤1-6)

#define USART_WordLength_8b                  ((uint16_t)0x0000)
#define USART_StopBits_1                      ((uint16_t)0x0000)
#define USART_Parity_No                       ((uint16_t)0x0000)
#define USART_HardwareFlowControl_None        ((uint16_t)0x0000)
#define USART_Mode_Rx                        ((uint16_t)0x0004)
#define USART_Mode_Tx                        ((uint16_t)0x0008)

void uart_init(u32 bound)     //串口整体初始化函数
{
  //各种结构体声明
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  
  //使能USART1,GPIO时钟   对应上述步骤1
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	
  
  //初始化USART1_TX端口对应的GPIOA9    对应上述步骤3
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;   //设置GPIO端口号为PA9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置传输速度为50MHz
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//输出模式为复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);     //初始化GPIOA9
  
  //初始化USART1_RX端口对应的GPIOA10
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;  //设置GPIO端口号为PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  //输入模式为浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);   //初始化GPIOA10
  
  //串口初始化设置    对应上述步骤4
  USART_InitStructure.USART_BaudRate = bound;   //设置串口的波特率为函数的入口参数
  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);    //初始化串口1,该函数的部分内容在上一篇
  
  //串口中断设置     对应上述步骤5
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;       //选定串口1的中断通道
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;  //抢占优先级3
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	     //子优先级3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;	     //IRQ通道使能
  NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);  //开启串口接收中断
  
  //使能串口1        对应上述步骤6
  USART_Cmd(USART1, ENABLE);   //该函数在上文已说明
}

串口中断服务函数

//头文件的定义
#define USART_REC_LEN  	 200  	      //定义最大接收字节数为200
#define EN_USART1_RX 	 1	            //使能(1)/禁止(0)串口1接收
extern u8  USART_RX_BUF[USART_REC_LEN];  //接收缓冲,最大USART_REC_LEN个字节,末尾为换行符
extern u16 USART_RX_STA;         		 //接收状态标记
void uart_init(u32 bound);
typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;  //枚举变量
#define USART_IT_RXNE  ((uint16_t)0x0525)	//10100100101
//源文件的定义
#if EN_USART1_RX   //如果使能了接收
u8  USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节
u16  USART_RX_STA=0;  //接收状态标记   bit15 接收完成标志,接收完成后为1;
           接上一行bit14 接收到0x0d后为1;bit13-bit0 为接收到的有效字节数
    
//串口中断服务函数     对应上述步骤7
void USART1_IRQHandler(void)
{
  u8 Res;
  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
  //获取串口1的当前状态,如果不等于0,则满足条件
  if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)	
  {
    Res =USART_ReceiveData(USART1); //读取接收到的数据(按字节接收)
    //接收状态标记(初始为0)和0x8000进行与运算,若位15不为0,则满足条件
    if((USART_RX_STA&0x8000)==0) //正在接收(未完成接收)
    {
      //接收状态标记变量和0x4000进行与运算,若位14不为0,则满足条件
      if(USART_RX_STA&0x4000) //上一次接收已经接收到了0x0d
      {
        //如果当前接收到的字节不是0x0a,则接收错误,接收状态标记清零
    	if(Res!=0x0a)USART_RX_STA=0;  //接收错误,重新开始
        //如果当前字节是0x0a,则设置USART_RX_STA变量的位15为1
    	else USART_RX_STA|=0x8000;	//接收完成
      }
      else //上一次接收还没有收到0x0d
      {
        //如果该次接收收到了0x0d,设置接收状态标记的位14为1
    	if(Res==0x0d)USART_RX_STA|=0x4000;
    	else //该次接收还没收到0x0d
    	{
          //USART_RX_BUF数组的第 位为接收的字符(存入缓冲区)
    	  USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
    	  USART_RX_STA++;   //接收次数自增(字符数+1)
          //如果接收的字符数超过最大字符数-1个
    	  if(USART_RX_STA>(USART_REC_LEN-1)) 
          {   
            USART_RX_STA=0; //接收数据错误,重新开始接收
          }
    	}		 
      }
    }   		 
  } 
}

串口收发函数(上述函数的应用主函数)

int main(void)    //串口收发函数    对应上述步骤8
{
	u8 t;   u8 len;	 u16 times=0; 
    //初始化延时、中断、串口、LED
	delay_init();	    	 //延时函数初始化
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组
	uart_init(9600);	 //串口初始化为9600
	LED_Init();		  	 //初始化与LED连接的硬件接口
	while(1) 
	{    
        //接收状态标记变量和0x8000进行与运算,若位15为1(接收完成)则进入
		if(USART_RX_STA&0x8000) 
		{					   
			//接收状态标记变量与0x3fff进行与运算,获取位13-0存储的数据长度
            len=USART_RX_STA&0x3fff;
			printf("\r\n您发送的消息为:\r\n");  //打印到串口
			for(t=0;t<len;t++)
			{
                //将DR=USART_RX_BUF中存储的数据按位传输给DR寄存器
				USART1->DR=USART_RX_BUF[t];
                //等待SR寄存器的位6为1时(发送完成时),跳出循环
				while((USART1->SR&0X40)==0);   //等待发送结束
			}
			printf("\r\n\r\n");    //插入换行
			USART_RX_STA=0;    //清空接收状态标记变量
		}
        else   //接收未完成
		{
			times++;  //时间自增
			if(times%5000==0)  //每5000次输出一次
			{  
			  printf("\r\n串口实验\r\n ");
			}
			if(times%200==0)   //每200次输出一次
            {  
              printf("请输入数据,以回车键结束\r\n");  
            }
			if(times%30==0)LED0=!LED0;  //每30次闪烁LED一次,提示系统正在运行
			delay_ms(10);   
		}
	}
}

文中函数和部分内容摘自正点原子stm32资料与官方库函数

自学新手,个人总结,如有出入,请多指教!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值