STM32(六)库函数串口发送与接收实例(中断)

2023-10-27

STM系列文章目录



前言

本篇用库函数写个简单的串口收发,用的是 STM32F103RCT6 开发板(部分来自正点原子)。
STM32F103RCT6 最多可提供 5 路串口,有分数波特率发生器、支持同步单线通信和半双工
单线通讯、支持 LIN、支持调制解调器操作、智能卡协议和 IrDA SIR ENDEC 规范、具有 DMA
等。

串口设置的一般步骤可以总结为如下几个步骤:

  1. 串口时钟使能,GPIO 时钟使能
  2. 串口复位
  3. GPIO 端口模式设置
  4. 串口参数初始化
  5. 开启中断并且初始化 NVIC(如果需要开启中断才需要这个步骤)
  6. 使能串口
  7. 编写中断处理函数

一、串口配置步骤

函数和定义主要分布在 stm32f10x_usart.hstm32f10x_usart.c 文件中。

1.串口时钟使能 串口是挂载在 APB2 下面的外设,所以使能函数为:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1);

2.串口复位 当外设出现异常的时候可以通过复位设置,实现该外设的复位,然后重新配置
这个外设达到让其重新工作的目的。
复位的是在函数 USART_DeInit()中完成:

void USART_DeInit(USART_TypeDef* USARTx);//串口复位

复位串口 1,方法为:

USART_DeInit(USART1); //复位串口 1

3.串口参数初始化 串口初始化是通过 USART_Init()函数实现的,

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);

第二个入口参数是USART_InitTypeDef 类型的结构体指针,这个结构体指针的成员变量用
来设置串口的一些参数。
一般的实现格式为:

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); //初始化串口

4.数据发送与接收 STM32 的发送与接收是通过数据寄存器 USART_DR 来实现的,这是
一个双寄存器,包含了 TDR 和 RDR。当向该寄存器写数据的时候,串口就会自动发送,当收
到收据的时候,也是存在该寄存器内。
STM32 库函数操作 USART_DR 寄存器发送数据的函数是:

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);

STM32 库函数操作 USART_DR 寄存器读取串口接收到的数据的函数是:

uint16_t USART_ReceiveData(USART_TypeDef* USARTx);

6.串口使能 串口使能是通过函数 USART_Cmd()来实现的

USART_Cmd(USART1, ENABLE); //使能串口

7.开启串口响应中断 使能串口中断的函数是:

void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)

开启其中之一的中断的方法是:

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断,接收到数据中断

发送数据结束的时候要产生中断:

USART_ITConfig(USART1,USART_IT_TC,ENABLE);

8.获取相应中断状态 在中断处理函数中,要判断该中断是哪种中断,使用的函数是:

ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)

判断是否是串口发送完成中断:

USART_GetITStatus(USART1, USART_IT_TC)

返回值是 SET,说明是串口发送完成中断发生。

二、实际编写

1.代码部分

——uart.c 文件

①重定向fputc函数

使用串口1(USART1)输出Printf信息

#if 1  
#pragma import(__use_no_semihosting)               
//标准库需要的支持函数                   
struct __FILE   
{   
    int handle;   
    /* Whatever you require here. If the only file you are using is */   
    /* standard output using printf() for debugging, no file handling */   
    /* is required. */   
};   
/* FILE is typedef’ d in stdio.h. */   
FILE __stdout;         
//定义_sys_exit()以避免使用半主机模式      
void _sys_exit(int x)   
{   
    x = x;   
}   
//重定向fputc函数  
//printf的输出,指向fputc,由fputc输出到串口  
//这里使用串口1(USART1)输出printf信息  
int fputc(int ch, FILE *f)  
{        
    while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch; 
    return ch;  
}  
#endif

②GPIO

u8 USART_RX_BUF[USART_REC_LEN] __attribute__ ((at(0X20001000)));
//接收缓冲,最大USART_REC_LEN个字节,起始地址为0X20001000.
u16 USART_RX_STA=0;       //接收状态标记	 
u16 USART_RX_CNT=0;			//接收的字节数	 
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, ENABLE);	
	//使能USART1,GPIOA时钟
  
	//USART1_TX   GPIOA.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	  GPIOA.10初始化
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
  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);	//根据指定的参数初始化VIC寄存器
  
   //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); //初始化串口1
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
  USART_Cmd(USART1, ENABLE);                    //使能串口1 

}
#if EN_USART1_RX   //如果使能了接收
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);//(USART1->DR);	//读取接收到的数据
		if(USART_RX_CNT<USART_REC_LEN)
		{
			USART_RX_BUF[USART_RX_CNT]=Res;
			USART_RX_CNT++;			 									     
		} 		 
     } 
#if SYSTEM_SUPPORT_OS 	//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntExit();  											 
#endif
} 
#endif	

——uart.h 文件

#define USART_REC_LEN  			41*1024 	//定义最大接收字节数 41K
#define EN_USART1_RX 			1		//使能(1)/禁止(0)串口1接收
	  	
extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART_RX_STA;         		//接收状态标记	
extern u16 USART_RX_CNT;				//接收的字节数	
//如果想串口中断接收,请不要注释以下宏定义

void uart_init(u32 bound);
#endif

——main.c 文件

 int main(void)
 {	
	u8 t;
	u8 len;	
	u16 times=0; 
 
	delay_init();	    	 //延时函数初始化	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
	uart_init(115200);	 //串口初始化为115200
 
	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串口发送与接收\r\n");
				printf("\r\n123456\r\n\r\n");
			}
		
			delay_ms(10);   
		}
	}	 
}


后续补充测试结果

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32(六)库函数串口发送与接收实例(中断) 的相关文章

  • 分布式文件与分布式存储系统学习总结(持续更新)

    存储系统知识 Write Ahead Log 问题引入 存储系统在运行过程中 每时每刻都在发生数据更新 如对文件数据的CRUD 对于中心控制节点来说 这些都会涉及到metadata的更新操作 为了保持元数据和文件数据的状态一致性 系统所有对
  • PLC学习第一篇:PLC程序架构

    前言 PLC资料获取 汇川官网 可以下载汇川PLC相关资料 倍福虚拟学院 西门子工业支持网站 西门子系列PLC的编程手册都可以查到 1 PLC编程语言发展 在PLC发展的早期阶段 由于没有统一的国际标准 各个制造商使用不同的编程语言 对使用
  • 操作系统知识

    操作系统结构 1 MS DOS层次 磁盘操作系统 易受错误程序的伤害导致系统崩溃 原因在于应用程序直接连接底层IO 2 UNIX层次 单一式结构使得UNIX难以增强 3 微内核 保留核心模块 是客户程序和运行在用户控件的各种服务之间通信以消
  • 八大经典排序算法

    目录 插入排序 希尔排序 选择排序 堆排序 快速排序 hoare法 挖坑法 前后指针法 快速排序的优化 非递归实现快排 归并排序 计数排序 常见的八种排序算法 插入排序 希尔排序 选择排序 堆排序 冒泡排序 快速排序 归并排序 插入排序 思
  • 【Linux】记一次系统异常宕机分析过程(内存异常)(业务Kubernetes)

    问题现象 最近遇到不同的业务正常运行时出现了宕机 物理机 虚拟机 查看日志是指向的怀疑是内存问题 业务都是部署的Kubernetes 容器集群管理系统 初步日志排查 message日志信息反馈 下面是虚拟机的日志信息 这些日志重复循环到问题

随机推荐