当前位置:   article > 正文

STM32串口通信(发送与接收数据)_stm32串口发送数据

stm32串口发送数据


前言

串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。本文主要接收使用串口发送接收数据,波特率设置,串口的基本时序等。


一、介绍部分

通信接口

在这里插入图片描述

术语解释

在这里插入图片描述

串口通信简介

在这里插入图片描述

硬件电路

在这里插入图片描述

电平标准

在这里插入图片描述

串口参数

在这里插入图片描述

串口时序

在这里插入图片描述

USART简介

在这里插入图片描述

USART框图

在这里插入图片描述

USRAT基本结构

在这里插入图片描述

数据帧

在这里插入图片描述
在这里插入图片描述

起始位检测

在受到噪声影响后,采用2:1策略,选择更多的作为所接收到的数据,并使噪声标志位NE置1

在这里插入图片描述
在这里插入图片描述

波特率发生器

在这里插入图片描述
在这里插入图片描述

CH340G

在这里插入图片描述

二、实例部分

使用USART1来作为例子,根据引脚定义,选择正确的接口
在这里插入图片描述

使用串口发送数据

接线图

在这里插入图片描述

代码实现

配置串口Serial.c

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>

void Serial_Init(void){
	// 开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	// 初始化引脚,发送数据引脚
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		// 复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;	// A9
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	// 初始化串口配置
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = 9600; // 串口波特率
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 不使用流控
	USART_InitStructure.USART_Mode = USART_Mode_Tx; // 串口模式,发送
	USART_InitStructure.USART_Parity = USART_Parity_No; // 无校验
	USART_InitStructure.USART_StopBits = USART_StopBits_1; // 选择一位停止位
	USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 不需要校验位,八位字长
	USART_Init(USART1,&USART_InitStructure);
	
	// USART1使能
	USART_Cmd(USART1,ENABLE);
}

// 发送函数
void USART_SendByte(uint8_t Byte){
	USART_SendData(USART1,Byte);
	// 等待写入完成,写入完成之后会将标志位自动清0
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}

// 发送数组函数
void USART_SendArray(uint8_t *Array,uint16_t Length){
	uint8_t i = 0;
	for(i=0;i<Length;i++){
		USART_SendData(USART1,Array[i]);
		// 等待写入完成,写入完成之后会将标志位自动清0
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
	}
}

// 发送字符串函数
void USART_SendString(uint8_t *String){
	uint8_t i = 0;
	for(i=0;String[i]!='\0';i++){
		USART_SendData(USART1,String[i]);
		// 等待写入完成,写入完成之后会将标志位自动清0
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
	}
}

// 返回X的Y次方
uint32_t Serial_Pow(uint32_t X,uint32_t Y){
	uint32_t Result = 1;
	while(Y--){
		Result *= X;
	}
	return Result;
}
// 发送数字函数
void USART_SendNum(uint32_t Num,uint16_t Length){
	uint8_t i = 0;
	for(i=0;i<Length;i++){
		USART_SendByte(Num / Serial_Pow(10,Length-i-1) % 10 + 0x30);
		// 等待写入完成,写入完成之后会将标志位自动清0
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
	}
}

//重定向fputc函数,fputc是printf函数的底层,printf通过不停的调用fputc来达到输出的效果
//重定向到串口
int fputc(int ch,FILE *f){
	USART_SendByte(ch);
	return ch;
}

// 封装使用sprintf输出到串口
void Serial_Printf(char *format, ...)
{
	char String[100];
	va_list arg;							// 可变参数列表
	va_start(arg, format);		// 从format开始接收可变参数
	vsprintf(String, format, arg);
	va_end(arg);
	USART_SendString((uint8_t*)String);
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94

主函数main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"

int main(void)
{
	OLED_Init();
	Serial_Init();
	//USART_SendByte();
//	uint8_t Array[] = {0x41,0x42,0x43,0x44};
//	USART_SendArray(Array,4);
//	uint8_t String[] = {"hello world"};
//	USART_SendString(String);
//	USART_SendNum((uint32_t)12345,5);
//	printf("Num = %d\r\n",666);
//	char String[100];
//	sprintf(String,"Num = %d\r\n",666);
//	USART_SendString((uint8_t*)String);
	Serial_Printf("一程山水");
	while (1)
	{
		
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

重定向printf需要勾上Use MicroLIB

在这里插入图片描述

中文不乱码方法

  1. 代码与串口都使用utf8格式,并在如下图位置加上–no-multibyte-chars
  2. 使用GB2312支持中文编码格式,串口使用GBK编码格式接收即可。

串口的发送与接收数据

线路连接与上面一致

代码实现

串口配置Serial.c

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>

uint8_t RxData;
uint8_t RxFlag;

void Serial_Init(void){
	// 开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	// 初始化引脚
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		// 复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;	// A9 发送数据
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;		// 上拉输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;	// A10 接收数据
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	// 初始化串口配置
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = 9600; // 串口波特率
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 不使用流控
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 串口模式,发送+接收
	USART_InitStructure.USART_Parity = USART_Parity_No; // 无校验
	USART_InitStructure.USART_StopBits = USART_StopBits_1; // 选择一位停止位
	USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 不需要校验位,八位字长
	USART_Init(USART1,&USART_InitStructure);
	
	// 开启中断
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
	
	//初始化NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	// 分组
	NVIC_InitTypeDef NVIC_InitStructure;
	// 中断通道
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	// 中断通道使能
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	// 抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	// 响应优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);

	
	// USART1使能
	USART_Cmd(USART1,ENABLE);
}

// 发送函数
void USART_SendByte(uint8_t Byte){
	USART_SendData(USART1,Byte);
	// 等待写入完成,写入完成之后会将标志位自动清0
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}

// 发送数组函数
void USART_SendArray(uint8_t *Array,uint16_t Length){
	uint8_t i = 0;
	for(i=0;i<Length;i++){
		USART_SendData(USART1,Array[i]);
		// 等待写入完成,写入完成之后会将标志位自动清0
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
	}
}

// 发送字符串函数
void USART_SendString(uint8_t *String){
	uint8_t i = 0;
	for(i=0;String[i]!='\0';i++){
		USART_SendData(USART1,String[i]);
		// 等待写入完成,写入完成之后会将标志位自动清0
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
	}
}

// 返回X的Y次方
uint32_t Serial_Pow(uint32_t X,uint32_t Y){
	uint32_t Result = 1;
	while(Y--){
		Result *= X;
	}
	return Result;
}
// 发送数字函数
void USART_SendNum(uint32_t Num,uint16_t Length){
	uint8_t i = 0;
	for(i=0;i<Length;i++){
		USART_SendByte(Num / Serial_Pow(10,Length-i-1) % 10 + 0x30);
		// 等待写入完成,写入完成之后会将标志位自动清0
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
	}
}

//重定向fputc函数,fputc是printf函数的底层,printf通过不停的调用fputc来达到输出的效果
//重定向到串口
int fputc(int ch,FILE *f){
	USART_SendByte(ch);
	return ch;
}

// 封装使用sprintf输出到串口
void Serial_Printf(char *format, ...)
{
	char String[100];
	va_list arg;							// 可变参数列表
	va_start(arg, format);		// 从format开始接收可变参数
	vsprintf(String, format, arg);
	va_end(arg);
	USART_SendString((uint8_t*)String);
}

// 获取RxFlag
uint8_t USART_GetRxFlag(void){
	if(RxFlag == 1){
		RxFlag = 0;
		return 1;
	}
	return 0;
}

// 获取RxData
uint8_t USART_GetRxData(void){
	return RxData;
}

//中断函数
void USART1_IRQHandler(void){
	if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET){
		RxData = USART_ReceiveData(USART1);
		RxFlag = 1;
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);
	}
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141

主函数main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"

uint8_t Serial_RxData;

int main(void)
{
	OLED_Init();
	OLED_ShowString(1, 1, "RxData:");
	
	Serial_Init();
	
	while (1)
	{
		if (USART_GetRxFlag() == 1)
		{
			Serial_RxData = USART_GetRxData();
			USART_SendByte(Serial_RxData);
			OLED_ShowHexNum(1, 8, Serial_RxData, 2);
		}
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/399607
推荐阅读
相关标签
  

闽ICP备14008679号