当前位置:网站首页>串口實驗——簡單數據收發

串口實驗——簡單數據收發

2022-07-07 08:58:00 一只大喵咪1201

作者:一只大喵咪1201
專欄:《STM32學習》
格言:你只管努力,剩下的交給時間!
請添加圖片描述

描述

串口作為 MCU 的重要外部接口,同時也是軟件開發重要的調試手段,其重要性不言而喻。現在基本上所有的 MCU 都會帶有串口,STM32 自然也不例外。
STM32 的串口資源相當豐富的,功能也相當强勁。本喵使用的STM32F103ZET6 最多可提供 5 路串口,有分數波特率發生器、支持同步單線通信和半雙工單線通訊、支持 LIN、支持調制解調器操作、智能卡協議和 IrDA SIR ENDEC 規範、具有 DMA等。

接收狀態標記

#define USART_REC_LEN 200 //定義最大接收字節數 200
#define EN_USART1_RX 1 //使能(1)/禁止(0)串口1接收
	  	
extern u8  USART_RX_BUF[USART_REC_LEN]; //接收緩沖,最大USART_REC_LEN個字節.末字節為換行符 
extern u16 USART_RX_STA;         		//接收狀態標記 

在官方提供的庫函數usart.h中定義了最大接收字節數,是200個字節,而且創建了一個數組,該數組大小是200個字節,每接收一個字節的數據就放入到這個數組中。
而且使用到了一個變量USART_RX_STA,這是一個體些接收狀態的變量,它的大小是16個比特比特,也就是倆個字節大小。
圖
這是它每一比特代錶的意義。

  • 0到13比特存放的是接收到的有效數據個數,每接收到一個有效數據,就會加1。
  • 第14比特代錶是否接受到0X0D數據,也就是回車字符。我們對該串行通信規定,是以回車(0X0D)換行(0X0A)字符結束通信的。如果接受到的數據是0X0D就將該比特置為1。
  • 第15比特代錶是否完成接收。如果在接收到的數據是0X0D(回車字符)之後的一個數據是0X0A(換行字符),說明接收完成了,就將該比特置為1。

以上規定是我們在通信之前雙方之間約定好的,通信雙方投按照這個約定來。

函數配置

我們這個實驗就僅僅實現簡單的數據收發。5個串口中,我們選擇串口1(UASRT1)實現這個實驗。
在本喵的文章串口寄存器函數配置中曾詳細的講到過如何配置串口,在這裏本喵便直接去配置,不再講述原因。

  1. 使能GPIOA和USART1的時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA時鐘
  1. 配置GPIOA口
GPIO_InitTypeDef GPIO_InitStructure;

//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 

USART_Init(USART1, &USART_InitStructure); //初始化串口1
  1. 配置串口
USART_InitTypeDef USART_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;	//收發模式
  1. 配置中斷優先級
NVIC_InitTypeDef NVIC_InitStructure;

//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寄存器
  1. 開啟接收中斷
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開啟串口接受中斷
  1. 串口使能
USART_Cmd(USART1, ENABLE);                    //使能串口1 
  1. 編寫中斷服務函數
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
} 
  • 在進入到中斷函數後創建一個1個字節大小的一個變量Res,用於存放接收到的數據。
  • 需要判斷一下是否發生的是接收中斷,如過是接收中斷則繼續執行中斷服務程序,如果是別的中斷則不執行中斷服務程序。
  • 判斷一下接收狀態標志中的最高比特是否為1,如果是1則說明已經完成了數據的接收,就不用再接收了,如果是0則說明沒有完成數據接收,需要繼續接收。
  • 判斷第14比特是否為1,是1則說明上一個數據是0X0D也就是回車字符,這時就要接著判斷下一個數據是否是0X0A也就是換行字符,如果不是換行字符,說明這個數據接收錯了,需要重新接收,如果是換行字符就說明數據接收完成了,需要將最高比特置1。
  • 判斷第14比特是0的時候,說明數據仍然在不停的接收,在接收到一個數據時就要判斷一下是否是0X0D也就是回車字符,並且設置相應的標志比特。
  • 當上一個數據和這一個數據都不是0X0D的時候,將接收到的數據放在數組中,數組的下標就是0到13比特中有效數據的個數。

以上的函數配置過程是不需要我們一行代碼一行代碼寫的,在ST官方提供的庫函數usart.c中有這些函數,我們直接使用即可。

  1. 編寫主程序

主程序中的代碼是需要我們親自編寫的

#include "delay.h"
#include "usart.h"
#include "led.h"

int main(void)
{
    
	u8 len = 0;//存放數據個數
	u8 t = 0;//循環控制變量
	LED_Init();//LED0初始化
	delay_init();//延時初始化
	uart_init(115200);//串口初始化,波特率為115200
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//優先級分組使用第二組
	
	while(1)
	{
    
		//數據接收完成時發送
		if(USART_RX_STA&0x8000)
		{
    
			len = USART_RX_STA&0x3fff;//得到數據長度
			printf("\r\n您發送的數據為:\r\n");
			//發送所有數據
			for(t = 0; t < len; t ++)
			{
    
				USART_SendData(USART1,USART_RX_BUF[t]);//發送一個數據
				while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET)
				{
    
					;//一個數據未發送完便一直等待
				}
			}
			printf("\r\n\r\n");
			USART_RX_STA = 0;//數據都發送完後將狀態比特清0
		}
		//數據接收未完成時等待數據接收
		else
		{
    
			printf("\r\n請輸入數據,按回車結束:\r\n");
			while((USART_RX_STA&0x8000)==0)
			{
    
				LED0 = !LED0;
				delay_ms(500);//led燈閃爍,等待數據輸入
			}
		}
	}
	
}

這便是串口實驗的所有代碼。

效果展示

圖
在串口調試助手上,輸入內容後點發送,接收窗口就會顯示輸入的內容。
在沒有輸入時,開發板上的LED燈在不停閃爍,這裏就不拍開發板的照片了。

總結

該實驗主要在於主程序的編寫,因為其他初始化函數都是ST官方提供的庫函數,我們如果需要使用到的是其他串口或者有其他的要求,只需要對庫函數稍作修改即可。

原网站

版权声明
本文为[一只大喵咪1201]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/188/202207070626298468.html