串口实验

usart 文件

(Universal Synchronous/Asynchronous Receiver/Transmitter)
通用同步/异步串行接/收发送器
SYSTEM 文件夹下

包含 usart.c 和 usart.h
用于串口的初始化和中断接收

默认针对串口 1
使用其他串口时需要修改代码

usart.c

包含两个函数

  1. void USART1_IRQHandler(void);

  2. void uart_init(u32 bound);

一段代码

用于支持 printf 函数,删去不会报错,但STM32无法启动

uart_init 函数

串口1初始化函数 ,调用时 只需要比特率一个参数
但默认设置为 USART1 ,使用其他通用同步/异步串行接/收发送器 或修改波特率以外的设置时 ,要自己修改该文件

void uart_init(u32 bound){
 //GPIO 端口设置
	 GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA
	|RCC_APB2Periph_AFIO, ENABLE); //使能 USART1,GPIOA 时钟
	//以及复用功能时钟
	 //USART1_TX PA.9
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9 复用推挽输出
	 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
	 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.9 发送端
	 
	 //USART1_RX PA.10 浮空输入
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
	 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.10 接收端
	 //Usart1 NVIC 中断配置 配置
	 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //对应中断通道
	 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级 3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级 3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
	NVIC_Init(&NVIC_InitStructure); //中断优先级配置
	 
	 //USART 初始化设置
	USART_InitStructure.USART_BaudRate = bound;//波特率设置;
	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_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx |USART_Mode_Tx;//收发模式
	 USART_Init(USART1, &USART_InitStructure); //初始化串口
	 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
	 USART_Cmd(USART1, ENABLE); //使能串口
} 

1)在使用一个 内置外设 时,首先要使能相应的 GPIO 时钟,然后使能复用功能时钟和内置外设时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA
|RCC_APB2Periph_AFIO, ENABLE); //使能 USART1,GPIOA 时钟,以及复用功能时钟

2)之后要设置要使用的 GPIO 口
查询技术手册——《STM32 中文参考手册 V10》
在这里插入图片描述
可知当要设置全双工模式时
(允许同时在两个方向上传输数据
是两个单工通信方式的结合,要求发送和接收设备都有独立的接收和发送能力)
要把 PA9 设置为推挽输出 ,PA10 设置为浮空输入或带上拉输入

//USART1_TX PA.9
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9 复用推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
 GPIO_Init(GPIOA, &GPIO_InitStructure);
 
 //USART1_RX PA.10 浮空输入
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
 GPIO_Init(GPIOA, &GPIO_InitStructure);

3)因为该实验要用到中断
所以需要初始化 usart1 的中断
设置抢占优先级和响应优先级
并在 main 中设置中断分组

//Usart1 NVIC 中断配置 配置
 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级 3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级 3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化 VIC 寄存器

4)中断后要设置串口1 的初始化参数

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

串口的初始化是通过调用 USART_Init() 实现
调用时需要的参数——结构体指针变量 USART_InitStructure
定义

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;

含有 6 个成员变量

  1. 串口波特率
  2. 字长
  3. 停止位
  4. 奇偶校验位
  5. 串口模式
  6. 是否支持硬件流控制

5)初始化完串口中断优先级和串口后
要开启中断和使能串口
中断的开启在初始化函数内完成
main 中的是设置分组

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
 USART_Cmd(USART1, ENABLE); //使能串口

顺序总结
① 串口时钟使能,GPIO 时钟使能
② 串口复位
③ GPIO 端口模式设置
④ 串口参数初始化
⑤ 初始化 NVIC 并且开启中断
⑥ 使能串口

USART1_IRQHandler 函数

是初始化函数对应串口的 中断响应函数
当串口发生了相应的中断后,会跳到这个函数
中断相应函数的名字不可以随便定
要遵循MDK定义的函数名
从 startup_stm32f10x_hd.s 文件中找名字

函数体👇

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)//接收未完成
			{
			if(USART_RX_STA&0x4000)//接收到了0x0d
				{
				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
				else USART_RX_STA|=0x8000;	//接收完成了 
				}
			else //还没收到0X0D
				{	
				if(Res==0x0d)USART_RX_STA|=0x4000;
				else
					{
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
					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
} 
#endif	

函数通过

if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) 

判断是否接收中断,如果串口接受中断,则读取串口接受到的数据

Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据

定义变量 Res 来储存接收的数据

之后定义了一个接收协议

数组——USART_RX_BUF[]
大小由 USART_REC_LEN 定义
该变量在 usare.c 中有定义
(BUF—— 缓存区)
接收状态寄存器(全局变量,但起到寄存器的作用)——USART_RX_STA
自定义的寄存器定义图👇
在这里插入图片描述
协议思路

  1. 接收到电脑发来的数据
    把接收到的数据保存在 USART_RX_BUF

  2. 在 USART_RX_STA 中计数接收到的有效数据个数
    当接收到回车(回车的表示由 2 个字节组成:0X0D 和 0X0A)的第一个字节时,停止计数器的增加,等待0X0A

  3. 如果 0X0A 没有到来,则认为这次接收失败,重新开始下一次接收

  4. 如果接收到 0X0A ,则标记 USART_RX_STA 的第 15 位,完成一次接收,并等待该位被清除、

  5. 如果一直没有收到 0X0D,当接收数据超过 USART_REC_LEN 的时候,则会丢弃前面的数据,重新接收

EN_USART1_RX 和 USART_REC_LEN 都定义在 usart.h 文件里,使用串口接收时要在 usart.h 里面设置 EN_USART1_RX 为 1
不使用用时设置为 0
其中默认设置 EN_USART1_RX 为 1

SYSTEM_SUPPORT_OS,则是用来判断是否使用 OS
如果使用了 OS,则调用OSIntEnter 和 OSIntExit 函数(用于实现中断嵌套处理),如果没有使用 ucos,则不调用这两个函数

main.c

#include "led.h"//需要使用LED灯
#include "delay.h"//要使用延时函数
#include "sys.h"
#include "usart.h"//需要使用串口

 int main(void)
 {	
	u8 t;
	u8 len;	
	u16 times=0; 
 
	delay_init();	    	 //延时函数初始化	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
	uart_init(9600);	 //串口初始化为9600
	LED_Init();		  	 //初始化与LED连接的硬件接口 
 /*👆初始化设置*/
	while(1)
	{
		if(USART_RX_STA&0x8000)//判断最高位,是否接收完成
		{					   
			len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
			printf("\r\n你发送的消息为:\r\n");
			for(t=0;t<len;t++)
			{
				USART1->DR=USART_RX_BUF[t];
				while((USART1->SR&0X40)==0);//等待发送结束
			}
			printf("\r\n\r\n");//插入换行
			USART_RX_STA=0;//清零,以方便下一次接收
		}else//没有接收的情况
		{
			times++;
			if(times%5000==0)
			{
				printf("请输入数据,以回车键结束\r\n"); 
			}

			if(times%200==0)printf("请输入数据,以回车键结束\r\n");  
			if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
			delay_ms(10);   
		}
	}	 
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值