USART使用

USART软件配置

具体步骤如下:(USART 相关库函数在 stm32f10x_usart.c 和 stm32f10x_usart.h 文件中)

(1)使能串口时钟及 GPIO 端口时钟

前面说过 STM32F103C8T6 芯片具有 3 个串口,对应不同的引脚,串口 1 挂接在 APB2 总线上,串口 2-串口 3 挂接在 APB1 总线上,根据自己所用串口使能总线时钟和端口时钟。

例如使用 USART1,其挂接在 APB2 总线上,并且 USART1 对应 STM32 芯片管脚的 PA9 和 PA10,因此使能时钟函数如下:


RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能 GPIOA 时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能 USART1 时钟

(2)GPIO 端口模式设置,设置串口对应的引脚为复用功能

因为使用引脚的串口功能,所以在配置 GPIO 时要将设置为复用功能,这里

把串口的 Tx 引脚配置为复用推挽输出, Rx 引脚为浮空输入,数据完全由外部

输入决定。如下:


GPIO_InitTypeDef GPIO_InitStructure;//定义结构体变量 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; //TX //串口输出 PA9 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化串口输入 IO */ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; //RX //串口输入 PA10 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入 GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化 GPIO */

(3)初始化串口参数,包含波特率、字长、奇偶校验等参数

要使用串口功能,必须对串口通信相关参数初始化,其库函数如下:


void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);

想必不用说,大家也知道第一个参数是什么意思,它是用来选择串口。

第二个参数是一个结构体指针变量,结构体类型是 USART_InitTypeDef,

其内包含了串口初始化的成员变量。下面我们就来看下这个结构体:


typedef struct { uint32_t USART_BaudRate; //波特率 uint16_t USART_WordLength; //字长 uint16_t USART_StopBits; //停止位 uint16_t USART_Parity; //校验位 uint16_t USART_Mode; //USART 模式 uint16_t USART_HardwareFlowControl; //硬件流控制 } USART_InitTypeDef;

USART_BaudRate:

波特率设置。常用的波特率为 4800、9600、115200 等。

标准库 函 数 会 根 据 设 定 值 计 算 得 到 USARTDIV 值 , 并 设 置USART_BRR 寄存器值。

USART_WordLength:

数据帧字长。可以选择为 8 位或者 9 位,

通过 USART_CR1 寄存器的 M 位的值决定。如果没有使能奇偶校验控制,一般使用 8 数据位;

如果使能了奇偶校验则一般设置为 9 数据位。

USART_StopBits:

停止位设置。可选 0.5 个、 1 个、 1.5 个和 2 个停止 位,

它设定 USART_CR2 寄存器的 STOP[1:0]位的值,一般我们选择 1 个停止位。

通常使用1

USART_Parity:

奇偶校验控制选择。可选 USART_Parity_No( 无 校 验 ) 、

USART_Parity_Even( 偶 校 验 ) 以 及 USART_Parity_Odd( 奇 校 验 ) ,

它设 定 USART_CR1 寄存器的 PCE 位和 PS 位的值。

USART_Mode:

USART 模式选择。

可以为 USART_Mode_Rx 和 USART_Mode_Tx, 允许使用逻辑或运算选择两个,

它设定 USART_CR1 寄存器的 RE 位和 TE 位。

USART_HardwareFlowControl:

硬件流控制选择。

只有在硬件流控制模式才 有效,

可以选择无硬件流 USART_HardwareFlowControl_None、

RTS 控制USART_HardwareFlowControl_RTS、

CTS 控制 USART_HardwareFlowControl_CTS、 RTS 和 CTS 控制 USART_HardwareFlowControl_RTS_CTS。 了解结构体成员功能后,就可以进行配置,例如我们配置 USART1,如下:


USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate =115200;//波特率设置 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_No ne;//无硬件数据流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式 USART_Init(USART1, &USART_InitStructure); //初始化串口 1

(4)使能串口

配置好串口后,我们还需要使能它,使能串口库函数如下

void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);

例如我们要使能 USART1,如下:


USART_Cmd(USART1, ENABLE);//使能串口 1

(5)设置串口中断类型并使能


// 第五步:设置串口中断类型并使能 USART_ClearFlag(USART1, USART_FLAG_TC); // 清除中断 USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启接收中断

(6)设置串口中断优先级,使能串口中断通道


// 第六步:设置串口中断优先级,使能串口中断通道 NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; // 中断通道 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 3; // 抢占 NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3; // 响应 NVIC_Init(&NVIC_InitStruct);

(7)编写串口中断服务函数


//编写串口中断服务函数 void USART1_IRQHandler(void) { u8 r =0; if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) // 接受中断 不等于0 就是RESET { r = USART_ReceiveData(USART1); // 接收数据 if((USART1_RX_STA&0x8000)==0) { if((USART1_RX_STA&0x4000)==1) { if(r!=0x0a)USART1_RX_STA = 0; //接收错误,重新开始 else USART1_RX_STA |= 0x80000;//接收完成了 } else //还没收到0X0D { if(r==0x0d)USART1_RX_STA|=0x4000; // 是否为0d 次高位设置 else { USART_RX_BUF[USART1_RX_STA&0x3fff] = r; USART1_RX_STA++; if(USART1_RX_STA>(USART_REC_LEN-1))USART1_RX_STA=0; //接收数据错误,重新开始接收 } } } } }

为了确认 USART1 是否发生接收中断,调用了读取串口中断状态标志位函数

USART_GetITStatus,如果确实产生接收中断事件,那么就会执行 if 内的语句,

将串口接收到的数据保存在变量 r 内,然后有通过串口发送出去,通过

USART_GetFlagStatus 函数读取串口状态标志,如果数据发送完成,则退出 while

循环语句。

这里我们设计了一个小小的接收协议:通过这个函数,配合一个数组

USART1_RX_BUF[],一个接收状态变量 USART1_RX_STA 实现对串口数据的接收管

理。USART1_RX_BUF 的大小由 USART1_REC_LEN 定义,也就是一次接收的数据最

大不能超过 USART1_REC_LEN 个字节。USART1_RX_STA 是一个接收状态变量,其

各的定义如下图所示:

设计思路如下:

当接收到从电脑发过来的数据,把接收到的数据保存在 USART1_RX_BUF 中,同时在接收状态寄存器(USART1_RX_STA)中计数接收到的有效数据个数,

当收到回车(回车的表示由 2 个字节组成:0X0D 和 0X0A)的第一个字节 0X0D 时,计数器将不再增加,等待 0X0A 的到来,而如果 0X0A 没有来到,

则认为这次接收失败,重新开始下一次接收。

如果顺利接收到 0X0A,则标记 USART1_RX_STA 的第 15 位,这样完成一次接收,并等待该位被其他程序清除,从而开始下一次的接收,

而如果迟迟没有收到 0X0D,那么在接收数据超过 USART1_REC_LEN 的时候,则会丢弃前面的数据,重新接收。

软件设计

usart.c

#include "usart.h"


u16 USART1_RX_STA =0;
u8 USART_RX_BUF[USART_REC_LEN];



void USART1_Init(u32 bound)
{
	GPIO_InitTypeDef GPIO_InitStructure;//定义结构体变量
	USART_InitTypeDef USART_InitStruct;
	NVIC_InitTypeDef NVIC_InitStruct;

	
	// 第一步 使能串口时钟及 GPIO 端口时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能 GPIOA 时钟 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能 USART1 时钟
	
	/*  配置GPIO的模式和IO口 */
	// 第二步 GPIO 端口模式设置,设置串口对应的引脚为复用功能
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;        //TX    //串口输出 PA9 
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; 
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;     //复用推挽输出 
	GPIO_Init(GPIOA,&GPIO_InitStructure);         /* 初始化串口输入 IO */
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;            //RX //串口输入 PA10 
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;  //模拟输入
	GPIO_Init(GPIOA,&GPIO_InitStructure);     /* 初始化 GPIO */
	
	
	// 第三步:初始化串口参数,包含波特率、字长、奇偶校验等参数
	USART_InitStruct.USART_BaudRate = bound; // 波特率
	USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 字长
	USART_InitStruct.USART_StopBits = USART_StopBits_1; // 停止位
	USART_InitStruct.USART_Parity = USART_Parity_No; // 奇偶校验位
	USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None; // 不使用硬件流
	USART_InitStruct.USART_Mode =USART_Mode_Rx|USART_Mode_Tx; // //收发模式
	USART_Init(USART1,&USART_InitStruct);
	
	// 第四步:使能串口 可以放到最后
	USART_Cmd(USART1,ENABLE);
	
	
	// 第五步:设置串口中断类型并使能
	USART_ClearFlag(USART1, USART_FLAG_TC); // 清除中断
	
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启接收中断
	
	
	
	// 第六步:设置串口中断优先级,使能串口中断通道
	NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; // 中断通道
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 3; // 抢占
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3; // 响应
	NVIC_Init(&NVIC_InitStruct);

	
	
}





//编写串口中断服务函数
void USART1_IRQHandler(void)
{
	u8 r =0;
	
	if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)  // 接受中断 不等于0 就是RESET
	{
		r = USART_ReceiveData(USART1);  // 接收数据
		
		if((USART1_RX_STA&0x8000)==0)
		{
			if((USART1_RX_STA&0x4000)==1)
			{
				if(r!=0x0a)USART1_RX_STA = 0; //接收错误,重新开始
				else USART1_RX_STA |= 0x80000;//接收完成了
			}
			else   //还没收到0X0D
			{
				if(r==0x0d)USART1_RX_STA|=0x4000;  // 是否为0d 次高位设置
				else
				{
					USART_RX_BUF[USART1_RX_STA&0x3fff] = r;
					USART1_RX_STA++;
					if(USART1_RX_STA>(USART_REC_LEN-1))USART1_RX_STA=0;     //接收数据错误,重新开始接收	
				}
			}				
		}			
	}	
}

usart.h

#ifndef _usart_H
#define _usart_H
#include "system.h"

#define USART_REC_LEN	200

extern u8 USART_RX_BUF[USART_REC_LEN];
extern u16 USART1_RX_STA;	
void USART1_Init(u32 bound);
 

#endif

main.c

#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"


int main()
{
	u8 i =0;
	u16 len;
	u16 t=0;
	
	SysTick_Init(72);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	LED_Init();	
	USART1_Init(115200);
	
	while(1)
	{
		if(USART1_RX_STA&0x8000)
		{
			len =USART1_RX_STA&0x3fff;	//得到此次接收到的数据长度
			for(t=0;t

你可能感兴趣的:(STM32单片机,外设,单片机,stm32,嵌入式硬件)