上一篇“stm32L431 串口中断接收和发送(不定长度)”文章写后,想想还是把“stm32F103 串口中断接收和发送(不定长度)”也写一下,想法和做法与上一篇完全一致,只是“stm32L431” 与“stm32F103”串口相关寄存器略有差异。
主导思想是:
1、用STM32CubeMX完成IO口和串口初始化。
2、用串口相关寄存器直接操作替代HAL库(本人不喜欢也不太懂HAL库)调用。
3、支持printf()函数
4、串口中断
接收中断:只负责将接收到的数据存入“接收输入指针”指向的接收缓冲区数组,同时置“接收完成标志”,“接收输入指针”加1。在主程序中从接收缓冲区数组读接收数据时“接收输出指针”加1,当“接收输出指针”等于“接收输入指针”时清“接收完成标志”。
发送中断:如果“发送输出指针”指向的发送缓冲区数组有待发送数据就发送,同时清”接收完成标志“,“发送输出指针”加1 。没有待发送数据(“发送输出指针”等于“发送输入指针”)置“发送完成标志"。在主程序中发送数据时,将待发送数据写入“发送输入指针”指向的发送缓冲区,同时”清”发送完成标志“同时允许发送中断。
具体操作:
1、由STM32CubeMX生成Keil工程“STM32F103_TEST”
2、新建“STM32F103_Uart.H、STM32F103_Uart.C”两个文件,添加“STM32F103_Uart.C"至工程。“STM32F103_Uart.H、STM32F103_Uart.C”两个文件的代码7、代码8(在后边)
3、在STM32CubeMX生成文件中添加代码
***所有添加的代码均放在 /* USER CODE BEGIN ---------- */和/* USER CODE END ---------- */之间,以防止STM32CubeMX生成文件时修改***
在“main.c”中添加代码1、2、3、4、5
代码1 :增加所需的头文件
/* USER CODE BEGIN Includes */
#include "stdio.H"
#include "STM32F103_Uart.H"
/* USER CODE END Includes */
代码2: 变量定义
/* USER CODE BEGIN 1 */
unsigned char Temp_Data;
/* USER CODE END 1 */
代码3:初始化中断收发服务程序所需的收、发缓冲区数组及全局变量
/* USER CODE BEGIN 2 */
Init_Serial_Port();
/* USER CODE END 2 */
代码4:简单的测试程序。收什么发什么,ASC字符、汉字、控制字符均可。
/* USER CODE BEGIN WHILE */
printf("HelloWorld!\n");
while (1)
{
if (Recv_End == 1)
{
Temp_Data = Serial_In();
Serial_Out(Temp_Data);
}
/* USER CODE END WHILE */
代码5:支持printf()函数;
/* USER CODE BEGIN 4 */
int fputc(int ch, FILE *f)
{
Serial_Out(ch);
return ch;
}
int fgetc(FILE *f)
{
unsigned char Temp_Data;
Temp_Data = Serial_In();
return Temp_Data;
}
/* USER CODE END 4 */
在“stm32f1xx_it.c”中添加代码6、7
代码6:增加 包含void USART1_IRQHandler(void)所需”数组及全局变量“的头文件
/* USER CODE BEGIN Includes */
#include "STM32F103_Uart.H"
/* USER CODE END Includes */
代码7:串口1中断收发服务程序。
其中“HAL_UART_IRQHandler(&huart1);”由STM32CubeMX生成,由于在其前面有”return ;"存在,永远不会被调用,会产生本工程编译时唯一的警告“../Core/Src/stm32f1xx_it.c(233): warning: #111-D: statement is unreachable“,不用理会(管也没用,STM32CubeMX还改回来)。
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if(USART1->SR&USART_SR_RXNE)//接收到数据
{
Recv_Buf[Recv_In_Pointer]=USART1->DR;
Recv_In_Pointer=(Recv_In_Pointer+1)%RECV_BUF_LEN;
Recv_End=1; //置串行口接收完成标志
}
if(USART1->SR&USART_SR_TC)// 发送中断
{
USART1->SR&=(~USART_SR_TC); //清中断发送完成中断标志(TC)
Trans_Out_Pointer=(Trans_Out_Pointer+1)%TRANS_BUF_LEN;
if (Trans_In_Pointer==Trans_Out_Pointer) //发送缓冲区中没有数据
{
Trans_End=1; //置串行口发送完成标志
USART1->CR1&=(~USART_CR1_TCIE); //关闭发送完成中断允许(TCIE)
}
else //发送缓冲区中有数据
{
USART1->DR=Trans_Buf[Trans_Out_Pointer]; //发送缓冲区中的数据
Trans_End=0; //清串行口发送完成标志
}
}
return ;
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
新建“STM32F103_Uart.H”
代码8:STM32F103_Uart.H
#ifndef __STM32F103_Uart_H
#define __STM32F103_Uart_H
//***************************用户设置串行口参数开始****************************
#define RECV_BUF_LEN 512 //设置接收缓冲器长度
#define TRANS_BUF_LEN 512 //设置发送缓冲器长度
//***************************用户设置串行口参数结束****************************
//函数定义
extern void Init_Serial_Port(void);
extern unsigned char Serial_In(void);
extern void Serial_Out(unsigned char Serial_Out_Data);
extern unsigned char Recv_Buf[RECV_BUF_LEN]; //串行口1环形接收数据缓冲区
extern unsigned char Trans_Buf[TRANS_BUF_LEN]; //串行口1环形发送数据缓冲区
extern unsigned int Recv_In_Pointer, Recv_Out_Pointer; //串行口1环形接收缓冲区输入、输出指针。全局变量
extern unsigned int Trans_In_Pointer, Trans_Out_Pointer; //串行口1环形发送缓冲区输入、输出指针。全局变量
//串行口工作标志
extern unsigned char Recv_End; //串行口1接收完成标志。全局变量
extern unsigned char Trans_End; //串行口1发送完成标志。全局变量
#endif
新建“STM32F103_Uart.C”
代码9:STM32F103_Uart.C
#include "STM32F103_Uart.H"
#include "main.h"
unsigned char Recv_Buf[RECV_BUF_LEN]; //串行口1环形接收数据缓冲区
unsigned char Trans_Buf[TRANS_BUF_LEN]; //串行口1环形发送数据缓冲区
unsigned int Recv_In_Pointer, Recv_Out_Pointer; //串行口1环形接收缓冲区输入、输出指针。全局变量
unsigned int Trans_In_Pointer, Trans_Out_Pointer; //串行口1环形发送缓冲区输入、输出指针。全局变量
//串行口工作标志
unsigned char Recv_End, Trans_End; //串行口1接收、发送完成标志。全局变量
void Init_Serial_Port(void);
unsigned char Serial_In(void);
void Serial_Out(unsigned char Serial_Out_Data);
//*****************************************************************************
void Init_Serial_Port(void) //串行口初始化函数
{
Trans_End = 1;
Recv_End = 0;
Recv_In_Pointer = 0; //接收缓冲区输入、输出指针
Recv_Out_Pointer = Recv_In_Pointer;
Trans_In_Pointer = 0; //发送缓冲区输入、输出指针
Trans_Out_Pointer = Trans_In_Pointer;
USART1->CR1 |= USART_CR1_RXNEIE; //允许接收中断
USART1->CR1 &= (~USART_CR1_TCIE); //关闭发送中断
USART1->SR |= USART_SR_TC; //置发送完成标志
}
//*****************************************************************************
unsigned char Serial_In(void)
{
unsigned char Temp_Data;
while ( Recv_Out_Pointer == Recv_In_Pointer )
{
}
//没有数据等待。
Temp_Data = Recv_Buf[Recv_Out_Pointer]; //从接收缓冲区中取数据
Recv_Out_Pointer = (Recv_Out_Pointer + 1) % RECV_BUF_LEN; //
if ( Recv_Out_Pointer == Recv_In_Pointer )
{
Recv_End = 0;
}
return Temp_Data;
//返回接收数据
}
//*****************************************************************************
void Serial_Out(unsigned char Serial_Out_Data)
{
while ( ((Trans_In_Pointer + 1) % TRANS_BUF_LEN) == Trans_Out_Pointer )//发送缓冲区满时等待
{
}
if (Trans_End == 1)
{
USART1->DR = Serial_Out_Data;
USART1->CR1 |= USART_CR1_TCIE; //使能发送中断(TCIE)
Trans_Buf[Trans_In_Pointer] = Serial_Out_Data; //发送数据进入发送缓冲区(在中断程序发送数据)
Trans_In_Pointer = (Trans_In_Pointer + 1) % TRANS_BUF_LEN; //发送缓冲区输入指针加1
Trans_End = 0; //清发送结束标志
}
else
{
Trans_Buf[Trans_In_Pointer] = Serial_Out_Data; //发送数据进入发送缓冲区(在中断程序发送数据)
Trans_In_Pointer = (Trans_In_Pointer + 1) % TRANS_BUF_LEN; //发送缓冲区输入指针加1
}
}
编译
4、编译后下载
对不对请您试试,我试是对的,谢谢!!!