第七周---STM32串口通信入门

一,了解串口协议和RS-232标准,以及RS232电平与TTL电平的区别;了解"USB/TTL转232"模块(以CH340芯片模块为例)的工作原理。
1.1,何为串口协议
串口通信指两个或两个以上的设备使用串口按位(bit)发送和接收字节。可以在使用一根线发送数据的同时用另一根线接收数据。 串口通信协议就是串口通讯时共同遵循的协议。 协议的内容是每一个bit 所代表的意义。 常用的串口通信协议 有以下几种:
1, RS-232(ANSI/EIA-232标准) 只支持 点对点, 最大距离 50英尺。最大速度为128000bit/s, 距离越远 速度越慢。 支持全双工(发送同时也可接收)。
2,RS-422(EIA RS-422-AStandard),支持点对多一条平衡总线上连接最多10个接收器 将传输速率提高到10Mbps,传输距离延长到4000英尺(约1219米),所以在100kbps速率以内,传输距离最大。支持全双工(发送同时也可接收)。
3,RS-485(EIA-485标准)是RS-422的改进, 支持多对多(2线连接),从10个增加到32个,可以用超过4000英尺的线进行串行通行。速率最大10Mbps。支持全双工(发送同时也可接收)。2线连接时 是半双工状态。
1.2,RS-232标准
在TXD和RXD数据线上:
  (1)逻辑1为-3~-15V的电压
  (2)逻辑0为3~15V的电压
在RTS、CTS、DSR、DTR和DCD等控制线上:
  (1)信号有效(ON状态)为3~15V的电压
  (2)信号无效(OFF状态)为-3~-15V的电压
这是由通信协议RS-232规定的。
RS-232:标准串口,最常用的一种串行通讯接口。有三种类型(A,B和C),它们分别采用不同的电压来表示on和off。最被广泛使用的是RS-232C,它将mark(on)比特的电压定义为-3V到-12V之间,而将space(off)的电压定义到+3V到+12V之间。传送距离最大为约15米,最高速率为20kb/s。RS-232是为点对点(即只用一对收、发设备)通讯而设计的,其驱动器负载为3~7kΩ。所以RS-232适合本地设备之间的通信。

1.3,TTL电平与RS232电平的区别
什么是TTL电平、RS232电平?它们有什么区别呢?
(一)、TTL电平标准
输出 L: <0.8V ; H:>2.4V。
输入 L: <1.2V ; H:>2.0V
TTL器件输出低电平要小于0.8V,高电平要大于2.4V。输入,低于1.2V就认为是0,高于2.0就认为是1。于是TTL电平的输入低电平的噪声容限就只有(0.8-0)/2=0.4V,高电平的噪声容限为(5-2.4)/2=1.3V。
1.4,了解“USB/TTL转232“模块(以CH340芯片模块为例)的工作原理。
CH340 是一个USB 总线的转接芯片,实现USB 转串口、USB 转IrDA 红外或者USB 转打印口。为了增加串口通讯的远距离传输及抗干扰能力,RS-232标准使用-15V 表示逻辑 1, +15V 表示逻辑 0。常常会使用 MH340芯片对 USB/TTL与RS-232电平的信号进行转换。
CH340工作原理图:
在这里插入图片描述
二,、标准库封装配置USART1相关函数
打开工程模板,选择相应的工程文件
在这里插入图片描述
在头文件上给出以下格式

#ifndef __SERIAL_H
#define __SERIAL_H
#include "stm32f10x.h"                 // Device header



#endif

在”Serial.c"函数中写入以下

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Stdio.h"



写入一个“Serial_Init”函数,用于配置基本的USART和GPIO
首先是打开APB使能时钟,

//打开USART1时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	//打开GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

接下来配置GPIO口,打开GPIOA的PA9引脚,作为数据发送。模式设置为复用推挽输出模式

GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 ;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

接下来是配置USART串口通信,我们选择USART1作为串口,同样建立结构体,设置波特率为9600,模式为仅发送,0校验位,1停止位,8数据位。编写如下:

USART_InitTypeDef USART_InitStruture;
	USART_InitStruture.USART_BaudRate=9600;//波特率设置为9600
	USART_InitStruture.USART_HardwareFlowControl=USART_HardwareFlowControl_None ;//设置无硬件流
	USART_InitStruture.USART_Mode=USART_Mode_Tx;//模式设置为仅发送
	USART_InitStruture.USART_Parity=USART_Parity_No ;///不需要校验
	USART_InitStruture.USART_StopBits=USART_StopBits_1 ;//停止位选择1位
	USART_InitStruture.USART_WordLength=USART_WordLength_8b;//数据位选择8位
	USART_Init(USART1,&USART_InitStruture);
	
	USART_Cmd(USART1,ENABLE);//启用USART外设

三、自动发送字符串
3.1 发送函数编写
编写一个发送函数,用于单片机对电脑进行数据传输,在标准库中,给出了发送函数为

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)

3.2 主函数编写
基于利用发送字符串的方式发送数据,我们将主函数编写如下:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Serial.h"
#include "Stdio.h"
int main(void)
{
	Serial_Init();
//	uint8_t Array[]={'H','e','l','l','o',',','W','i','n','d','o','w','s','!','!'};//感兴趣可自行完成数组方式

	while (1)
	{
		Serial_SendString("Hello,Windows!!");
		Serial_SendString("\r\n");
		Delay_ms(1000);
		printf("你好,世界!\r\n");
		Delay_ms(1000);
	}
}


3.3 烧录测试结果
我们将程序烧录到开发板上后,打开我们手上的串口调试助手
在这里插入图片描述
3.4 波形测试观察
keil MDK自带的调试模式可以通过输出波形来观察串口的电平变化情况,这里就把图列出来:
在这里插入图片描述
在这里插入图片描述
在设置观察端口时,我们观察USART1的电平变化情况。
在这里插入图片描述
波形测试结果如下:
在这里插入图片描述
在这里插入图片描述
四、基于中断的可控发送
4.1 配置NVIC控制USART1触发中断
在原有“Serial.c"中Serial_Init()代码的基础上,我们需要进行以下修改
首先开启GPIOA的PA10端口。

//配置GPIO口
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 ;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

打开USART中断,配置NVIC

//开启USART中断
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
	
	//配置NVIC
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//选择分组2
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel= USART1_IRQn;//USART1在NVIC中的通道
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE ;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure);
	
	USART_Cmd(USART1,ENABLE);//启用USART外设

4.2 中断函数编写
编写中断函数

//接下来是中断控制

void USART1_IRQHandler(void)//中断函数
{
	if(USART_GetFlagStatus(USART1,USART_IT_RXNE)==SET)//判断标志位
	{
		Serial_RxData=USART_ReceiveData(USART1);//读取PC发来的数据
		Serial_RxFlag=1;//标志位置1
		
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除中断函数标志位
	}
}
uint8_t Serial_GetRxFlag(void)//读后自动清除
{
	if(Serial_RxFlag==1)
	{
		Serial_RxFlag=0;
		return 1;
	}
	else return 0;
	
}
uint8_t Serial_GetRxData(void)//将中断读取的值返回到主函数中
{
	return Serial_RxData;
	
}


4.3 主函数代码
我们在头文件中加入我们新编写的函数

#ifndef __SERIAL_H
#define __SERIAL_H
#include "stm32f10x.h"                  // Device header

void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array,uint16_t Length);
void Serial_SendString(char *String);
uint8_t Serial_GetRxFlag(void);//读后自动清除
uint8_t Serial_GetRxData(void);//将中断读取的值返回到主函数中
#endif

在主函数中编入以下代码

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

int main(void)
{
//	OLED_Init();
	Serial_Init();
  uint8_t RxData1;//定义接收变量,用于接收从PC端发来的数据
  uint16_t flag=0;//定义标志位,用于打断或开启发送
		while (1)
	{
		if (Serial_GetRxFlag() == 1)
		{
			RxData1 = Serial_GetRxData();//接收数据
		if(RxData1=='*')
		{
				flag=1;//标志位置1
			while(flag==1)//开始发送
			{
				Serial_SendString("Hello,Windows!");
				Serial_SendString("\r\n");
//				OLED_ShowString(1, 1, "Hello,Windows!");
				Delay_ms(1000);
				
				RxData1 = Serial_GetRxData();//再读取一次接收端数据
				if(RxData1=='#')//若为’#‘,跳出循环
				{
					flag=0;//标志位变为0
				}
				
			}	
			
		}
		else if(RxData1=='#')//输入#,单片机停止发送
		{
			Serial_SendString("Stop!!! Press '*' to continue!");
//			OLED_ShowString(1, 1, "                  ");
//			OLED_ShowString(1, 1, "Stop!!!");
			Serial_SendString("\r\n");
		}
		else //输入其他字符,显示错误
		{
			Serial_SendString("Wrong!!!");
//			OLED_ShowString(1, 1, "                  ");
//			OLED_ShowString(1, 1, "Wrong!!!");
			Serial_SendString("\r\n");
		}
		}
	}
}


4.4 烧录调试结果
经过烧录,串口输出情况如下:
在这里插入图片描述
五,总结
本次实验让我对相关软件的应用更加熟悉,让我更加的了解了该门课程,我从中学到了很多,虽然过程中遇到了很多困难,但是在同学们的帮助下都一一解决了,收获很多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值