F407+ESP8266+MQTT+AliIoT(三)——TIM7+USART3的使用

F407+ESP8266+MQTT+AliIoT(三)——TIM7+USART3的使用

簡介

在項目裏,串口3用來和ESP8266進行通訊,使用定時器7來判斷串口3的輸入數據是否一幀結束。
定時器7設置爲100ms中斷,在中斷處理函數中,標記一幀串口3數據結束,並關閉定時器。
串口3用來接收外設ESP8266發過來的數據,在中斷中進行處理,同時參考串口1的代碼,設計了u3_printf函數。
這部分可以參考《STM32F4開發指南-HAL庫版本_V1.2》的第九章串口通信實驗和第十三章定時器中斷實驗。

相關程序源碼

啥也別說,直接上代碼。

timer.c

#include "timer.h"
extern vu16 USART3_RX_STA;
TIM_HandleTypeDef TIM7_Handler; //定時器句柄 

//定時器7配置預裝載週期值
void TIM7_SetARR(u16 period)
{
	 TIM7->CNT = 0;     //計數器清空
	 TIM7->ARR&=0x00;   //先清預裝載週期值爲0
	 TIM7->ARR|= period;//更新預裝載週期值 
}

//通用定時器7中斷初始化
//arr:自動重裝值。
//psc:時鐘預分頻數
//定時器溢出時間計算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定時器工作頻率,單位:Mhz
//這裏使用的是定時器7!(定時器7掛在APB1上,時鐘爲HCLK/2)
void TIM7_Init(u16 arr,u16 psc)
{  
	__HAL_RCC_TIM7_CLK_ENABLE();                           //使能TIM7時鐘
    TIM7_Handler.Instance=TIM7;                            //基本定時器7
    TIM7_Handler.Init.Prescaler=psc;                       //分頻係數
    TIM7_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;      //向上計數器
    TIM7_Handler.Init.Period=arr;                          //自動裝載值
    TIM7_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;//時鐘分頻因子
    HAL_TIM_Base_Init(&TIM7_Handler);    
    HAL_TIM_Base_Start_IT(&TIM7_Handler);                  //使能定時器7和定時器7更新中斷:TIM_IT_UPDATE  

	HAL_NVIC_SetPriority(TIM7_IRQn,0,1);                   //設置中斷優先級,搶佔優先級0,子優先級1
	HAL_NVIC_EnableIRQ(TIM7_IRQn);                         //開啓ITM7中斷  	
}

//定時器7中斷服務函數
void TIM7_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&TIM7_Handler);
}

//回調函數,定時器中斷服務函數調用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{ 
    if(htim==(&TIM7_Handler))//定時器7中斷服務函數調用(GSM調用)
    {
          USART3_RX_STA|=1<<15;	           //標記接收完成
          HAL_TIM_Base_Stop(&TIM7_Handler);//關閉定時器7
    }
}

timer.h

#ifndef _TIMER_H
#define _TIMER_H
#include "sys.h"
extern TIM_HandleTypeDef TIM7_Handler;    //定時器句柄 

void TIM7_Init(u16 arr,u16 psc);
void TIM7_SetARR(u16 period);
#endif

usart.c

#include "usart3.h"
#include "delay.h"
#include "stdarg.h"	 	 
#include "stdio.h"	 	 
#include "string.h"	  
#include "timer.h"

//串口發送緩存區 	
__align(8) u8 USART3_TX_BUF[USART3_MAX_SEND_LEN]; 	      //發送緩衝,最大USART3_MAX_SEND_LEN字節
#ifdef USART3_RX_EN   								      //如果使能了接收   	  
//串口接收緩存區 	
u8 USART3_RX_BUF[USART3_MAX_RECV_LEN]; 				      //接收緩衝,最大USART3_MAX_RECV_LEN個字節.

UART_HandleTypeDef UART3_Handler;                         //UART句柄
u16 USART3_RX_STA=0;  

//初始化IO,串口3
//bound:波特率
void uart3_init(u32 bound)
{	
	//GPIO端口設置
	GPIO_InitTypeDef GPIO_Initure;

	__HAL_RCC_GPIOB_CLK_ENABLE();			              //使能GPIOB時鐘
	__HAL_RCC_USART3_CLK_ENABLE();			              //使能USART1時鐘

	//UART 初始化設置
	UART3_Handler.Instance=USART3;					      //USART3
	UART3_Handler.Init.BaudRate=bound;				      //波特率
	UART3_Handler.Init.WordLength=UART_WORDLENGTH_8B;     //字長爲8位數據格式
	UART3_Handler.Init.StopBits=UART_STOPBITS_1;	      //一個停止位
	UART3_Handler.Init.Parity=UART_PARITY_NONE;		      //無奇偶校驗位
	UART3_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE;     //無硬件流控
	UART3_Handler.Init.Mode=UART_MODE_TX_RX;		      //收發模式
	HAL_UART_Init(&UART3_Handler);					      //HAL_UART_Init()會使能UART3	

	GPIO_Initure.Pin=GPIO_PIN_10|GPIO_PIN_11;			  //PB10、PB11
	GPIO_Initure.Mode=GPIO_MODE_AF_PP;		              //複用推輓輸出
	GPIO_Initure.Pull=GPIO_PULLUP;			              //上拉
	GPIO_Initure.Speed=GPIO_SPEED_FAST;		              //高速
	GPIO_Initure.Alternate=GPIO_AF7_USART3;	              //複用爲USART3
	HAL_GPIO_Init(GPIOB,&GPIO_Initure);	            	  //初始化PB10,和PB11
	
	__HAL_UART_DISABLE_IT(&UART3_Handler,UART_IT_TC);
#if USART3_RX_EN 
	__HAL_UART_ENABLE_IT(&UART3_Handler,UART_IT_RXNE);    //開啓接收中斷
	HAL_NVIC_EnableIRQ(USART3_IRQn);				      //使能USART1中斷通道
	HAL_NVIC_SetPriority(USART3_IRQn,2,3);			      //搶佔優先級2,子優先級3
#endif	
	TIM7_Init(1000-1,9000-1);                             //重新設置爲100ms中斷	
	TIM7->CR1&=~(1<<0);                                   //關閉定時器7
	USART3_RX_STA=0;				                      //清零 
}

//timer=100ms
//通過判斷接收連續2個字符之間的時間差不大於timer來決定是不是一次連續的數據.
//如果2個字符接收間隔超過timer,則認爲不是1次連續數據.也就是超過timer沒有接收到
//任何數據,則表示此次接收完畢.
//接收到的數據狀態
//[15]:0,沒有接收到數據;1,接收到了一批數據.
//[14:0]:接收到的數據長度
//串口3中斷服務程序
void USART3_IRQHandler(void)
{
	  u8 Res;
	  if((__HAL_UART_GET_FLAG(&UART3_Handler,UART_FLAG_RXNE)!=RESET))
	  {
		  HAL_UART_Receive(&UART3_Handler,&Res,1,1000);
		  if((USART3_RX_STA&0x8000)==0)                //接收完的一批數據,還沒有被處理,則不再接收其他數據
		  { 
			 if(USART3_RX_STA<USART3_MAX_RECV_LEN)     //還可以接收數據
			 {
				  TIM7->CNT = 0;                       //計數器清空
				  if(USART3_RX_STA==0)                 //如果沒有接收任何數據
				  {
					 TIM7->CR1|=1<<0;                  //開啓定時器7 
				  }
				  USART3_RX_BUF[USART3_RX_STA++]=Res;  //記錄接收到的值
			 }
			 else
			 {
				  USART3_RX_STA|=1<<15;			       //強制標記接收完成
			 }
		  }
	  }
	  HAL_UART_IRQHandler(&UART3_Handler);	
}

//串口3,printf 函數
//確保一次發送數據不超過USART3_MAX_SEND_LEN字節
void u3_printf(char* fmt,...)  
{  
	u16 i,j;
	va_list ap;
	va_start(ap,fmt);
	vsprintf((char*)USART3_TX_BUF,fmt,ap);
	va_end(ap);
	i=strlen((const char*)USART3_TX_BUF);//此次發送數據的長度
	for(j=0;j<i;j++)                     //循環發送數據
	{
		while((USART3->SR&0X40)==0);     //循環發送,直到發送完畢   
		USART3->DR=USART3_TX_BUF[j];  
	}
}

//串口3,senddata 函數
//確保一次發送數據不超過USART3_MAX_SEND_LEN字節
void u3_send(u8* dat, u16 len)
{
    u16 i,j;
    i = len;
	for(j=0;j<i;j++)                     //循環發送數據
	{
		while((USART3->SR&0X40)==0);     //循環發送,直到發送完畢   
		USART3->DR=dat[j];  
	}
}

#endif

usart.h

#ifndef __USART3_H
#define __USART3_H	 
#include "sys.h"  
#include "stdio.h"

#define USART3_MAX_RECV_LEN		400					//最大接收緩存字節數
#define USART3_MAX_SEND_LEN		400					//最大發送緩存字節數
#define USART3_RX_EN 			1					//0,不接收;1,接收.

extern u8  USART3_RX_BUF[USART3_MAX_RECV_LEN]; 		//接收緩衝,最大USART3_MAX_RECV_LEN字節
extern u8  USART3_TX_BUF[USART3_MAX_SEND_LEN]; 		//發送緩衝,最大USART3_MAX_SEND_LEN字節
extern u16 USART3_RX_STA;   						//接收數據狀態

extern UART_HandleTypeDef UART3_Handler;//UART句柄

void uart3_init(u32 bound);				//串口3初始化 
void u3_printf(char* fmt, ...);
void u3_send(u8* dat, u16 len);

#endif
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章