STM32-基本知识梳理6-USART通讯及使用

一、USART基本简述

1,USART,一般不使用它的同步传输功能,只使用异步传输模式。即没有时钟参与,和UART在使用时相似;

2,数据传递的基本构成,起始位+数据位+校验位(可选)+停止位(可选)

起始位:1bit的低电平

数据位:一般为8bit的数据

校验位:根据校验方式,奇校验、偶校验、无校验,根据具体的校验方式确定

停止位:1bit的高电平

3,USART模块框图解析

①外部接口:其中一般只使用TX ,RX

②数据接受、发送寄存器模块(USART操作最重要的模块),后面库函数的对于数据的读取、发送都是通过这些寄存器实现的

③控制模块

④波特率发生器:主要根据配置的时钟,选择对应波特率,由此处发送时钟信号,从而按照波特率的具体值,发送对应频率的数据;

 二、代码控制应用模块

1,GPIO初始化

USART只是内部模块,与外部模块配合传递数据,是需要GPIO进行数据中转的;

ps:1-所有通过内部模块发送数据,必须配置成复用模块,具体是复用推挽还是复用开漏,根据模块的需求配置;

关键点:①TX:配置成复用推挽输出,RX:浮空输入

②时钟配置:PA时钟开启,USART时钟一并开启(在配置所有模块时,要先开启时钟)

③对应脚位初始化

//时钟开启GPIO USART
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1,ENABLE);
	
	//配置GPIO PA9 TX 复用推挽输出  PA10 RX 浮空输入
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
	GPIO_Init(GPIOA, &GPIO_InitStruct);

2,USART初始化

关键点:USART的初始化,关键是通过结构体在初始化函数中,配置对应寄存器

(本质上所有模块的配置逻辑都是这样的)

①波特率;②传输模式;③数据位长度;④停止位;⑤校验位;⑥硬件流

//初始化USART
	USART_InitTypeDef USART_InitStruct;
	USART_InitStruct.USART_BaudRate=115200;
	USART_InitStruct.USART_Mode=USART_Mode_Rx |USART_Mode_Tx ;
	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_Init( USART1, & USART_InitStruct);

3,USART---NVIC模块初始化

关键点:USART---NVIC的初始化

①优先级分组配置;②中断通道选择(NVIC负责管理所有的中断管理,主要分为两大块,GPIO中断、内部模块中断);③抢占优先级、次优先级(根据优先级分组中状态进行分配)

static void bsp_usart_NVIC_config(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStruct);

}

4,USART 中断使能、模块使能开启

关键点:

①调用NVIC初始化函数

②   调用 USART_ITConfig( USART1, USART_IT_RXNE, ENABLE);

其中,我们只在外部接受到中断时刻,进入中断服务函数 ,进行数据处理

③开启USART

//配置NVIC
	bsp_usart_NVIC_config();
	//开启usart中断
	USART_ITConfig( USART1, USART_IT_RXNE, ENABLE);
	//使能打开
	USART_Cmd( USART1, ENABLE);

以上,已经配置好USART初始化模块


5,发送数据

关键点:

①由于内部寄存器大小的等原因,数据必须是8bit,如果是其他类型的数据,则分成多个8bit传递即可

②调用USART_SendData,等待数据寄存器为空,则说明发送完毕;

//  发送数据
void bsp_usart_senddata(USART_TypeDef* USARTx,uint16_t Data)
{
	USART_SendData( USARTx,  Data);
	while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE)==RESET);
}

6,发送双字节、发送数据、发送字符串的常用模块

发送双字节:数据拆分为高位和地位

//发送16位数据
void bsp_usart_halfword(USART_TypeDef* USARTx,uint16_t Data)
{
	uint8_t mes_h,mes_l;
	mes_h=Data>>8;
	mes_l=Data;
	bsp_usart_senddata( USARTx,mes_h);
	bsp_usart_senddata( USARTx,mes_l);
	
}

发送数据:按照数组的大小,重复调用数据

//发送数组

void bsp_usart_arr(USART_TypeDef* USARTx,uint8_t *arr,uint8_t num)
{
	uint8_t i=0;
	for(i=0;i<num;i++)
	{
		bsp_usart_senddata(USARTx,arr[i]);
	}

}

发送字符串:与发送数组类似,主要是结束标志位为‘\0’

//发送字符串

void bsp_usart_string(USART_TypeDef* USARTx,uint8_t *str)
{
	uint8_t i=0;
	while(str[i]!='\0')
	{
		bsp_usart_senddata(USARTx,str[i]);
		i++;
	}
	
}

7,重定向printf、重定向scanf(复写 fputc、复写fgetc),记住即可(要包含stdio的头文件)

//重定向printf

int fputc(int ch, FILE *f)
{
	bsp_usart_senddata(USART1,(uint16_t)ch);
	
	return (ch);
}
//重定向scanf

int fgetc(FILE *f)
{
	
	while(USART_GetFlagStatus( USART1, USART_FLAG_RXNE)==RESET);
	
	return  (int)USART_ReceiveData(USART1);
}

8,中断服务函数

关键点:在中断服务函数,首先检测标志位(数据位非空,规定动作),然后转数据接受给临时变量TEMP

//中断服务函数
void USART1_IRQHandler(void)
{
	
	//检测
	if(USART_GetFlagStatus( USART1, USART_FLAG_RXNE)==SET)
	{
		temp=USART_ReceiveData(USART1);
		bsp_usart_senddata(USART1,temp);
	}
}

三、示范程序

电脑串口发送数据,控制led点亮

整体逻辑:

1,初始化LED,并配置各种点灯函数

2,初始化usart,按照上述配置即可,关键是在usart头文件中,要将中断函数的temp,用extern引用出来,在主函数中接受,并判断

3,在主函数中,通过switch函数

1,初始化LED,并配置各种点灯函数

#include "led.h"

void LED_config(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0 |GPIO_Pin_1 |GPIO_Pin_5;// |GPIO_Pin_5;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init( GPIOB, &GPIO_InitStruct);
	
	
	
}

void led_red(void)
{
	GPIO_ResetBits(GPIOB,GPIO_Pin_5);
	GPIO_SetBits(GPIOB,GPIO_Pin_0);
	GPIO_SetBits(GPIOB,GPIO_Pin_1);
}

void led_green(void)
{
	GPIO_ResetBits(GPIOB,GPIO_Pin_0);
	GPIO_SetBits(GPIOB,GPIO_Pin_5);
	GPIO_SetBits(GPIOB,GPIO_Pin_1);
}

void led_blue(void)
{
	GPIO_ResetBits(GPIOB,GPIO_Pin_1);
	GPIO_SetBits(GPIOB,GPIO_Pin_5);
	GPIO_SetBits(GPIOB,GPIO_Pin_0);
}

void led_off(void)
{
	GPIO_SetBits(GPIOB,GPIO_Pin_5);
	GPIO_SetBits(GPIOB,GPIO_Pin_0);
	GPIO_SetBits(GPIOB,GPIO_Pin_1);
}

2,初始化usart,按照上述配置即可,关键是在usart头文件中,要将中断函数的temp,用extern引用出来,在主函数中接受,并判断

c文件的配置,和上述相同,H文件如下

#ifndef __BSP_UASRT_H
#define __BSP_UASRT_H
#include "stm32f10x.h"                  // Device header
#include <stdio.h>  

extern uint8_t temp;
void bsp_usart_config(void);
void bsp_usart_senddata(USART_TypeDef* USARTx,uint16_t Data);
void bsp_usart_halfword(USART_TypeDef* USARTx,uint16_t Data);
void bsp_usart_arr(USART_TypeDef* USARTx,uint8_t *arr,uint8_t num);
void bsp_usart_string(USART_TypeDef* USARTx,uint8_t *str);
#endif

3,在主函数中,通过switch函数处理

#include "stm32f10x.h"                  // Device header
#include "LED.H"
#include "BSP_USART.H"
uint8_t arr[10]={1,2,3,4,5,6,7,8,9,12};
int main(void)
{
	
	LED_config();
	bsp_usart_config();
//	bsp_usart_senddata( USART1,0x66);
//	bsp_usart_halfword(USART1,0xff31);
//	bsp_usart_arr(USART1,arr,10);
	bsp_usart_string( USART1,"欢迎来到新世界\n");
	printf("welcome!\n");
 
	while(1)
	{
	  switch(temp)
	  {
	  case 1: 	led_red();break;
	  case 2: 	led_green();break;
	  case 3: 	led_blue();break;
	  default:  led_off();break;
	  }
     
	
	}
}

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是使用USART通信实现STM32与GY-53-L1测距模块进行通信的示例代码: ``` #include "stm32f10x.h" #include <stdio.h> // 定义USART相关的GPIO口 #define USARTx USART1 #define USARTx_CLK RCC_APB2Periph_USART1 #define USARTx_TX_PIN GPIO_Pin_9 #define USARTx_TX_GPIO_PORT GPIOA #define USARTx_TX_GPIO_CLK RCC_APB2Periph_GPIOA #define USARTx_RX_PIN GPIO_Pin_10 #define USARTx_RX_GPIO_PORT GPIOA #define USARTx_RX_GPIO_CLK RCC_APB2Periph_GPIOA // 定义USART接收缓冲区大小 #define USART_RX_BUF_SIZE 100 // 定义发送和接收状态 #define USART_SENDING 0 #define USART_RECEIVING 1 // 定义USART接收缓冲区 uint8_t USART_RX_BUF[USART_RX_BUF_SIZE]; uint16_t USART_RX_STA = 0; uint8_t USART_RX_STATUS = USART_RECEIVING; // USART初始化函数 void USART_Config(void) { USART_InitTypeDef USART_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(USARTx_CLK | USARTx_TX_GPIO_CLK | USARTx_RX_GPIO_CLK, ENABLE); // 配置USARTx_TX的GPIO口 GPIO_InitStructure.GPIO_Pin = USARTx_TX_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStructure); // 配置USARTx_RX的GPIO口 GPIO_InitStructure.GPIO_Pin = USARTx_RX_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStructure); 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_Rx | USART_Mode_Tx; USART_Init(USARTx, &USART_InitStructure); USART_Cmd(USARTx, ENABLE); } // USART发送一个字节 void USART_SendByte(USART_TypeDef *USARTx, uint8_t byte) { while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET); USART_SendData(USARTx, byte); } // USART发送字符串 void USART_SendString(USART_TypeDef *USARTx, char *str) { while (*str) { USART_SendByte(USARTx, *str++); } } // USART接收中断处理函数 void USART1_IRQHandler(void) { uint8_t ch; if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { ch = USART_ReceiveData(USART1); // 如果接收到换行符,则表示一行数据接收完成 if (ch == '\n' || ch == '\r') { USART_RX_BUF[USART_RX_STA++] = ch; USART_RX_STATUS = USART_SENDING; } else { USART_RX_BUF[USART_RX_STA++] = ch; if (USART_RX_STA >= USART_RX_BUF_SIZE) { USART_RX_STATUS = USART_SENDING; } else { USART_RX_STATUS = USART_RECEIVING; } } } } int main(void) { uint32_t distance; USART_Config(); // 使能接收中断 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); while (1) { // 发送获取距离命令 USART_SendString(USART1, "AT+DIST?\r\n"); // 等待接收到距离数据 while (USART_RX_STATUS == USART_RECEIVING); // 解析距离数据 sscanf((const char *)USART_RX_BUF, "+DIST:%ldmm", &distance); printf("Distance: %ldmm\r\n", distance); // 清空接收缓冲区和状态 USART_RX_STA = 0; USART_RX_STATUS = USART_RECEIVING; // 延时一段时间 Delay(1000); } } ``` 在上述代码中,使用USART1与GY-53-L1测距模块进行通信,通过发送"AT+DIST?"命令获取距离数据。当接收到一行数据时,会将数据存储到USART_RX_BUF缓冲区中,直到接收到换行符或缓冲区已满。然后从缓冲区中解析出距离数据,并打印到串口终端上。最后清空接收缓冲区和状态,并延时一段时间再次发送命令。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值