STM32与串口(Usart)的通俗介绍与使用(例子:串口控制小灯)

STM32与串口(Usart)的通俗介绍与使用(例子:串口控制小灯)

一、说明

写本文目的是从 对串口知识了解不清或刚接触的朋友 的角度出发,帮助此类朋友了解掌握串口的配置与使用。
前面介绍三组串口的具体配置,文章最后举一个例子:串口控制小灯。

二、串口的简单介绍

什么是串口?
简单来说就是实现printf(""),getchar()等函数,即实现字符或字符串的接收发送,从而实现通讯。
其中串口又分为:USART(同步异步收发器)——全双工数据交换 和 UART(异步收发器)——只有异步传输功能,本文只介绍三个USART的配置与使用。

三、串口中断功能的流程图(从右到左看)

此图用于帮助理解中断执行流程

四、有关管脚的电路原理图介绍

有关管脚的电路原理图
如上图所示:该板子具有三组串口接口(TX为发送引脚,RX为接收引脚),分别对应:
RX1/TX1 ——> PA10/PA9 ——> USART1
RX2/TX2 ——> PA3/PA2 ——> USART2
RX3/TX3 ——> PB11/PB10 ——> USART3

引脚 USART1 USART2 USART3
TX PA9 PA2 PB10
RX PA10 PA3 PB11
时钟线 APB2 APB1 APB1
中断函数名 USART1_IRQHandler(void) USART2_IRQHandler(void) USART3_IRQHandler(void)

五、代码配置

1.USART1
(1)发送、接收管脚配置和串口配置

void USART1_Config(void)  
{
    
      
  	GPIO_InitTypeDef x;
	USART_InitTypeDef y;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);		//开启管脚PA9,PA10对应的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);		//开启串口USART1的时钟,注意:**APB2**
	
	x.GPIO_Pin=GPIO_Pin_9;
	x.GPIO_Mode=GPIO_Mode_AF_PP;
	x.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&x);				//配置发送引脚——选择管脚9,模式为复用推挽输出(因为是发送引脚),频率为50MHz,初始化到GPIOA
	
	x.GPIO_Pin=GPIO_Pin_10;
	x.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA,&x);				//配置接收引脚——选择管脚10,模式为浮空输入(因为是接收引脚),输入模式不用配置频率,初始化到GPIOA
	
	y.USART_BaudRate=9600;											//配置波特率9600/115200等,具体看你的硬件配置要求
	y.USART_WordLength=USART_WordLength_8b;							//配置数据位8位
	y.USART_StopBits=USART_StopBits_1;								//配置停止位为1
	y.USART_Parity=USART_Parity_No;									//奇偶校验位为无校验
	y.USART_HardwareFlowControl=USART_HardwareFlowControl_None;		//配置硬件控制流选择为无
	y.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;						//配置串口模式为接收和发送
	USART_Init(USART1,&y);				//初始化到USART1
	
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);		//开启窗口接收中断(即当发生接收数据或发送数据时将触发对应的中断处理函数)
	USART_Cmd(USART1,ENABLE);			//使能USART1,也就是打开USART1功能
	
	NVIC_Configuration();    			//中断优先级配置
} 

(2)配置中断优先级

优先级分组 主优先级 子优先级
NVIC_ PriorityGroup0(0位用于抢占优先级 4位用于子优先级) 0 0~15
NVIC_ PriorityGroup1(1位用于抢占优先级 3位用于子优先级) 0~1 0~7
NVIC_ PriorityGroup2(2位用于抢占优先级 2位用于子优先级) 0~3 0~3
NVIC_ PriorityGroup3(3位用于抢占优先级 1位用于子优先级) 0~7 0~1
NVIC_ PriorityGroup4(4位用于抢占优先级 0位用于子优先级) 0~15 0
void NVIC_Configuration()
{
    
    
	NVIC_InitTypeDef NVIC_InitStruct;	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置分组为组2
	NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;				//配置中断源为USART1
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;		//配置主优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;				//配置子优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;				//中断使能
	NVIC_Init(&NVIC_InitStruct);		//初始化NVIC
}

(3)中断处理函数

void USART1_IRQHandler(void)  
{
    
      
  	u8 res;  
	if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)  		//若当前USART1的状态为接收
	{
    
     
		res= USART_ReceiveData(USART1);   		//读取此时接收的数据
		USART_SendData(USART1,res);				//将数据重新发回去,用于告诉它接收成功
	}
}

(4)重定向收发函数(在 keil 的 C 标准函数中类似 printf 等函数并没有实现其底层,程序开发者需要重定向其中的 fgets 与 fputs 函数后可使用 printf、scanf、gets、puts 等标准函数,记得加#include "stdio.h"哦)

#include "stdio.h"
int fputc(int ch,FILE *f)
{
    
    
	USART_SendData(USART1,(uint8_t)ch);		//发送一个字符
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);	//直到发送完毕
	return (ch);	
}
int fgetc(FILE *f)
{
    
    
	while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);	//直到接收完毕
	return (int)USART_ReceiveData(USART1);
}

(5)最后主函数

int main(void)  
{
    
      
	USART1_Config();
  	while(1);
} 

这样一个完整的串口配置使用就实现了哦!!!
接下来同样的步骤,来用其他两组串口也实现该功能吧

2.USART2
(1)发送、接收管脚配置和串口配置

void USART2_Config(void)  
{
    
      
  	GPIO_InitTypeDef x;
	USART_InitTypeDef y;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);		//注意**APB1**,**USART2**
	
	x.GPIO_Pin=GPIO_Pin_2;
	x.GPIO_Mode=GPIO_Mode_AF_PP;
	x.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&x);
	
	x.GPIO_Pin=GPIO_Pin_3;
	x.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA,&x);
	
	y.USART_BaudRate=9600;
	y.USART_WordLength=USART_WordLength_8b;
	y.USART_StopBits=USART_StopBits_1;
	y.USART_Parity=USART_Parity_No;
	y.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
	y.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
	USART_Init(USART2,&y);
	
	USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
	USART_Cmd(USART2,ENABLE);
	
	NVIC_Configuration();    
} 

(2)配置中断优先级

void NVIC_Configuration()
{
    
    
	NVIC_InitTypeDef NVIC_InitStruct;	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	
	NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn;		//注意:**USART2_IRQn**
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
}

(3)中断处理函数

void USART2_IRQHandler(void)  		//注意:**USART2_IRQHandler**
{
    
      
  	u8 res;  
	if(USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET)  
	{
    
     
		res= USART_ReceiveData(USART2);   
		USART_SendData(USART2,res);	
  }  
}

(4)重定向收发函数(记得加#include "stdio.h"哦)

#include "stdio.h"
int fputc(int ch,FILE *f)
{
    
    
	USART_SendData(USART2,(uint8_t)ch);
	while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);
	return (ch);
}
int fgetc(FILE *f)
{
    
    
	while(USART_GetFlagStatus(USART2,USART_FLAG_RXNE)==RESET);
	return (int)USART_ReceiveData(USART2);
}

(5)最后主函数

int main(void)  
{
    
      
	USART2_Config();
  	while(1);
} 

2.USART3
(1)发送、接收管脚配置和串口配置

void USART3_Config(void)  
{
    
      
  GPIO_InitTypeDef x;
	USART_InitTypeDef y;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);		//注意:**GPIOB**
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);		//注意:**APB1**,**USART3**
	
	x.GPIO_Pin=GPIO_Pin_10;
	x.GPIO_Mode=GPIO_Mode_AF_PP;
	x.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&x);			//注意:**GPIOB**
	
	x.GPIO_Pin=GPIO_Pin_11;
	x.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOB,&x);			//注意:**GPIOB**
	
	y.USART_BaudRate=9600;
	y.USART_WordLength=USART_WordLength_8b;
	y.USART_StopBits=USART_StopBits_1;
	y.USART_Parity=USART_Parity_No;
	y.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
	y.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
	USART_Init(USART3,&y);
	
	USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
	USART_Cmd(USART3,ENABLE);
	
	NVIC_Configuration();    
} 

(2)配置中断优先级

void NVIC_Configuration()
{
    
    
	NVIC_InitTypeDef NVIC_InitStruct;	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	
	NVIC_InitStruct.NVIC_IRQChannel = USART3_IRQn;		//注意:**USART3_IRQn**
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
}

(3)中断处理函数

void USART3_IRQHandler(void)  		//注意:**USART3_IRQHandler**
{
    
      
 	u8 res;  
	if(USART_GetITStatus(USART3,USART_IT_RXNE)!=RESET)  
	{
    
     
		res= USART_ReceiveData(USART3);   
		USART_SendData(USART3,res);	
  }  
}

(4)重定向收发函数(记得加#include "stdio.h"哦)

#include "stdio.h"
int fputc(int ch,FILE *f)
{
    
    
	USART_SendData(USART3,(uint8_t)ch);
	while(USART_GetFlagStatus(USART3,USART_FLAG_TXE)==RESET);
	return (ch);
}
int fgetc(FILE *f)
{
    
    
	while(USART_GetFlagStatus(USART3,USART_FLAG_RXNE)==RESET);
	return (int)USART_ReceiveData(USART3);
}

(5)最后主函数

int main(void)  
{
    
      
	USART3_Config();
  	while(1);
} 

六、最后来个串口控制小灯例子

(1)配置串口(上面三组随便选一组,这里以组1-PA9,PA10为例)
(2)初始化小灯(我的STM32控制LED灯的管脚为PC13)
LED

void LED_GPIO_Config(void)
{
    
    
    GPIO_InitTypeDef GPIO_InitStruct;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);    
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStruct);
}

(3)小灯控制函数

void LED_G(uint8_t n)                    //LED_G(0): 灯亮            LED_G(1):灯灭
{
    
    
    if(n)
                GPIO_SetBits(GPIOC, GPIO_Pin_13);
    else
                GPIO_ResetBits(GPIOC, GPIO_Pin_13);
}

(4)修改主函数

#include "stm32f10x.h"

int main(void)  
{
    
      
    USART_Config();
    LED_GPIO_Config(); 
    while(1);
} 

(5)修改串口中断函数

void USART1_IRQHandler(void)    //如果串口发送‘0’则灯亮,(若其他数据)否则灯灭
{
    
      
    u8 res;  
    if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)  
    {
    
     
        res= USART_ReceiveData(USART1);   
        USART_SendData(USART1,res);
        if(res=='0')
        {
    
    
            LED_G(0);
        }
        else
        {
    
    
            LED_G(1);
        }        
  }  
}

七、完整工程资源共享

链接:https://pan.baidu.com/s/1UvxMlFSzKVpQfpDA3zxnBA
提取码:o8c7

猜你喜欢

转载自blog.csdn.net/weiybin/article/details/107378505