正点原子STM32F103学习笔记(八)——串口

串口通信基本原理

处理器与外部设备通信的两种方式

并行通信

  • 传输原理:数据各个位同时传输。
  • 优点:速度快
  • 缺点:占用引脚资源多

串行通信

  • 传输原理:数据按位顺序传输。

  • 优点:占用引脚资源少

  • 缺点:速度相对较慢

  • 按照数据传送方向,分为:

  1. 单工:数据传输只支持数据在一个方向上传输
  2. 半双工:允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;
  3. 全双工:允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。
    在这里插入图片描述
  • 串行通信的通信方式
  1. 同步通信:带时钟同步信号传输。
    -SPI,IIC通信接口
  2. 异步通信:不带时钟同步信号。
    -UART(通用异步收发器),全双工,单总线,要约定速度(波特率)
    常见的串行通信接口:
    在这里插入图片描述

STM32的串口通信接口

UART: 通用异步收发器
USART: 通用同步异步收发器
大容量STM32F10x系列芯片,包含3个USART和2个UART

UART异步通信方式引脚连接方法:

RXD:数据输入引脚。数据接受。
TXD:数据发送引脚。数据发送。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

UART异步通信方式特点:

  • 全双工异步通信。
  • 分数波特率发生器系统,提供精确的波特率。
    -发送和接受共用的可编程波特率,最高可达4.5Mbits/s
  • 可编程的数据字长度(8位或者9位);
  • 可配置的停止位(支持1或者2位停止位);
  • 可配置的使用DMA多缓冲器通信。
  • 单独的发送器和接收器使能位。
  • 检测标志:① 接受缓冲器 ②发送缓冲器空 ③传输结束标志
  • 多个带标志的中断源。触发中断。
  • 其他:校验控制,四个错误检测标志。
    在这里插入图片描述

STM32串口异步通信需要定义的参数:

  1. 起始位
  2. 数据位(8位或者9位)
  3. 奇偶校验位(第9位)
  4. 停止位(1,15,2位)
  5. 波特率设置
    在这里插入图片描述
    在这里插入图片描述
    发射器控制(发射器时钟)和接收器控制(接收器时钟)受到同一个单元控制。

串口寄存器配置

常用的串口相关寄存器

USART_SR状态寄存器
USART_DR数据寄存器(只用到了位0-8)
USART_BRR波特率寄存器
USART_CR1控制寄存器(使能)

波特率计算方法

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

串口操作相关库函数(省略入口参数):

void USART_Init(); //串口初始化:波特率,数据字长,奇偶校验,硬件流控以及收发使能
void USART_Cmd();//使能串口
void USART_ITConfig();//使能相关中断

//DR寄存器
void USART_SendData();//发送数据到串口,DR
uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据

//SR寄存器
FlagStatus USART_GetFlagStatus();//获取状态标志位
void USART_ClearFlag();//清除状态标志位
ITStatus USART_GetITStatus();//获取中断状态标志位
void USART_ClearITPendingBit();//清除中断状态标志位

USART_Init();

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct)

typedef struct
{
  uint32_t USART_BaudRate;            //波特率
  uint16_t USART_WordLength;          //字长
  uint16_t USART_StopBits;            //停止位
  uint16_t USART_Parity;              //奇偶校验位
  uint16_t USART_Mode;                //发送接收使能
  uint16_t USART_HardwareFlowControl; //硬件流控制
} USART_InitTypeDef;

串口配置的一般步骤

  1. 串口时钟使能,GPIO时钟使能:
RCC_APB2PeriphClockCmd();

  1. 串口复位:这一步不是必须的
USART_DeInit(); 

  1. GPIO端口模式设置:要查表“STM32中文参考手册”8.1.11,模式设置为GPIO_Mode_AF_PP(复用为串口一设置为复用推挽)
GPIO_Init(); 

  1. 串口参数初始化:
USART_Init();

  1. 开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
NVIC_Init();//优先级设置
USART_ITConfig();//确定开启哪个中断

  1. 使能串口:
USART_Cmd();

  1. 编写中断处理函数
USARTx_IRQHandler();

  1. 串口数据收发:
void USART_SendData();//发送数据到串口,DR
uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据

  1. 串口传输状态获取:
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);

程序实践

main.c


void My_USART_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	//使能时钟
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA ,ENABLE);
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1  ,ENABLE);
	
	//GPIOA9模式设置为GPIO_Mode_AF_PP
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//GPIOA10模式设置为GPIO_Mode_AF_PP
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//串口初始化
	USART_InitStructure.USART_BaudRate=115200;
	USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//不使用硬件流
	USART_InitStructure.USART_Mode=USART_Mode_Rx|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);
	
	//使能串口
	USART_Cmd(USART1,ENABLE);
	
	//使能哪个串口中断
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//确定开启哪个中断,并开启接收中断(即接收到数据执行中断服务函数)

	//设置响应中断优先级
	NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;//入口参数,在stm32f10x.h头文件447行
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//是否开启中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//设置抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级
	NVIC_Init(&NVIC_InitStructure);
}

void USART1_IRQHandler(void) //接收到数据执行这个中断
{
	u8 res;
	if(USART_GetITStatus(USART1,USART_IT_RXNE))//判断是否接收到数据
	{
		res=USART_ReceiveData(USART1);//接受到的值赋给变量
		USART_SendData(USART1,res);//发送接收到的数据
	}
		
}

int main(void)
 {	
  //中断设置
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //分组选择为2,两位响应两位抢占
	 My_USART_Init();
	 while(1);//使用中断接收,使用死循环
 }

串口实验讲解

#define USART_REC_LEN   200  	//定义最大接收字节数 200

 u8  USART_RX_BUF[USART_REC_LEN];
              //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
 
 u16 USART_RX_STA;         		//接收状态标记	

在这里插入图片描述
程序要求,发送的字符是以回车换行结束(0x0D,0x0A)
eg:ABCDEFGHI…….(0x0D),(0x0A)
bit15标记为1时候提取USART_RX_BUF中bit13~0个有效数据

串口中断服务函数:

void USART1_IRQHandler(void)                	//串口1中断服务程序
	{
	u8 Res;
#if SYSTEM_SUPPORT_OS 		//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntEnter();    
#endif
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
		{
		Res =USART_ReceiveData(USART1);	//读取接收到的数据
		
		if((USART_RX_STA&0x8000)==0)//最高位如果是0,接收未完成,继续下面的接收
			{
			if(USART_RX_STA&0x4000)//接收到了0x0d 即bit14是否为1
				{
				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
				else USART_RX_STA|=0x8000;	//接收完成了 ,最高位设为1
				}
			else //还没收到0X0D
				{	
				if(Res==0x0d)USART_RX_STA|=0x4000;
				else
					{
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;//只可以用bit13~0
					USART_RX_STA++;
					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
					}		 
				}
			}   		 
     } 
#if SYSTEM_SUPPORT_OS 	//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntExit();  											 
#endif
} 

main();

int main(void)
 {		
 	u16 t;  
	u16 len;	
	u16 times=0;
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 //串口初始化为115200
 	LED_Init();			     //LED端口初始化
	KEY_Init();          //初始化与按键连接的硬件接口
 	while(1)
	{
		if(USART_RX_STA&0x8000) //接收完成返回1
		{					   
			len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
			printf("\r\n您发送的消息为:\r\n\r\n");
			for(t=0;t<len;t++)
			{
				USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据
				while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
			}
			printf("\r\n\r\n");//插入换行
			USART_RX_STA=0;
		}else
		{
			times++;
			if(times%5000==0)
			{
				printf("\r\n精英STM32开发板 串口实验\r\n");
				printf("正点原子@ALIENTEK\r\n\r\n");
			}
			if(times%200==0)printf("请输入数据,以回车键结束\n");  
			if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
			delay_ms(10);   
		}
	}	 
 }

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F103C8T6是一款基于ARM Cortex-M3内核的单片机,它是STMicroelectronics公司推出的一款高性能、低功耗的微控制器。下面是对STM32F103C8T6单片机学习的介绍: 1. 硬件特性:STM32F103C8T6单片机具有64KB的Flash存储器和20KB的SRAM,工作频率可达到72MHz。它还拥有多个通用输入输出引脚、模拟输入输出通道、定时器、串口通信接口等丰富的外设资源。 2. 开发环境:为了学习STM32F103C8T6单片机,你需要准备相应的开发环境。STMicroelectronics提供了免费的集成开发环境(IDE)——STM32CubeIDE,它集成了编译器、调试器和一系列的软件库,方便开发者进行代码编写、调试和下载。 3. 编程语言:STM32F103C8T6单片机可以使用多种编程语言进行开发,包括C语言和汇编语言。C语言是最常用的开发语言,它具有良好的可移植性和易于理解的特点。 4. 学习资源:学习STM32F103C8T6单片机可以参考官方提供的文档和教程,例如官方的参考手册、用户手册和应用笔记。此外,还有许多在线教程、视频教程和开发者社区可以供你参考和交流。 5. 实践项目:为了更好地掌握STM32F103C8T6单片机的应用,建议你进行一些实践项目。例如LED闪烁、按键控制、PWM调光等简单的实验,逐步深入学习各种外设的使用和驱动编程。 希望以上介绍对你有所帮助!如果你还有其他问题,请继续提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值