STM32玩转物联网实战篇:01.网络通信前准备

1、准备开发板

在前面我们已经讲完了基础部分的例程,接下来我们正式进入网络通信部分,在此之前,我们需要做些准备,来适配我们的网络通信模块。现在市场上最常用的解决方案就是WIFI和NB,还有在某些要求数据量大、传输速度快的场景会用到的4G,所以我们下面会主要着重以上三个解决方案进行。

开发板功能区分布图

在这里插入图片描述

开发板俯视图

在这里插入图片描述

网络通信模块对应的串口

在这里插入图片描述
在这里插入图片描述

    由上面的原理图,我们可以知道小熊派的网络通信模块的接口在LPUART1串口上,这个似乎是STM32L系列特有的,它可以通过AT_Switch进行PC和MCU的切换,当你想要用PC调试时,将拨码拨到PC端,然后就可以用网络调试助手进行调试,反之,就是MCU发送AT指令,从而控制网络通信模块。

2、STM32CubeMX生成代码

搜索并选择芯片型号

在这里插入图片描述
在这里插入图片描述

配置系统时钟

在这里插入图片描述

配置时钟树

STM32L4的最高主频可达到80M,最后使HCLK = 80Mhz即可:

在这里插入图片描述
在这里插入图片描述

配置GPIO引脚

在这里插入图片描述
修改引脚的用户标签(相当于取另一个新名字)

在这里插入图片描述

配置串口

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

配置TIM

计时器更新中断频率计算F: 
F = ( arr + 1 )*( psc + 1 ) / 80M 当设置arr = 79,psc = 999时,F = 1000 Hz = 1 K Hz

在这里插入图片描述
在这里插入图片描述

3、在MDK中编写代码

新建sys.h文件

#ifndef _SYS_H
#define _SYS_H
#include "main.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdarg.h"
#include "stdbool.h"
#include "stm32l4xx.h"
#include "usart.h"
//0,不支持os
//1,支持os
#define SYSTEM_SUPPORT_OS		0		//定义系统文件夹是否支持OS

#define delay_ms(Delay)			HAL_Delay(Delay)

void ClearRAM(u8* ram,u32 n);
void USART_SendChar( USART_TypeDef *huart, uint8_t ch );
void USART_SendBuf( USART_TypeDef *huart, uint8_t *str,uint32_t strlen );
void USART_SendString( USART_TypeDef *huart, uint8_t *str);
void UsartPrintf(USART_TypeDef *huart, char *fmt,...);

新建sys.c文件

//清空字节数组
//ram: 待清空的数组
//n: 待清空数组的长度
void ClearRAM(uint8_t* ram,uint32_t n)
{
  u32 i;
  for (i = 0;i < n;i++)
  {
    ram[i] = 0x00;
  }
}

//串口发送字符
//huart: 串口结构体句柄
//ch: 待发送的字符
void USART_SendChar( USART_TypeDef *huart, uint8_t ch )
{
	while((huart->ISR&0X40)==0);
	huart->TDR = (uint8_t)ch;
}

//串口发送指定长度的字节数组
//huart: 串口结构体句柄
//str: 待发送的字节数组
//strlen: 字节数组长度
void USART_SendBuf( USART_TypeDef *huart, uint8_t *str,uint32_t strlen )
{
	unsigned int k = 0;
	do
	{
		USART_SendChar(huart,*(str + (k++)));
	}while( k < strlen );
	
}

//串口发送字符串数组
//huart: 串口结构体句柄
//str: 待发送的字符串数组
void USART_SendString( USART_TypeDef *huart, uint8_t *str)
{
	unsigned int k = 0;
	do
	{
		USART_SendChar(huart,*(str + (k++)));
	}while(*(str + (k)) != '\0');

}

//串口发送长度的字符串
//huart: 串口结构体句柄
//str: 待发送的字符串数组
void UsartPrintf(USART_TypeDef *huart, char *fmt,...)
{

	unsigned char UsartPrintfBuf[200];
	va_list ap;
	unsigned char *pStr = UsartPrintfBuf;
	
	//RTOS_ENTER_CRITICAL();									//写入多个数据时,进入临界段,放置打断出错
	va_start(ap, fmt);
	vsprintf((char *)UsartPrintfBuf, fmt, ap);							//格式化
	va_end(ap);
	
	while(*pStr != 0)
	{
		USART_SendChar(huart,*pStr++);
	}
	//RTOS_EXIT_CRITICAL();

}

在tim.c下用户区添加以下代码

/* USER CODE BEGIN 0 */
uint32_t time2Count;
/* USER CODE END 0 */
//定时器中断使能
void TIM_Interupt_Enable(void)
{
	
	__HAL_TIM_ENABLE_IT(&htim2,TIM_IT_UPDATE);		//使能定时器更新中断
	HAL_TIM_Base_Start(&htim2);										//启动定时器
	
}
//定时器中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM2)
	{
		if(__HAL_TIM_GET_IT_SOURCE(htim,TIM_IT_UPDATE) != RESET)		//如果触发了更新中断
		{
			if(time2Count++ >= 4294967295UL)						//防止数值溢出
			{
				time2Count = 0;
			}
			__HAL_TIM_CLEAR_IT(htim,TIM_IT_UPDATE);			//清除更新中断标志位
		}
	}
}

在gpio.h中编写以下代码

/* USER CODE BEGIN Private defines */

typedef enum
{
    
	LED_OFF = 0,
	LED_ON,
	LED_Toggle
        
} LED_ENUM;

#define LED_Set(status) status != LED_Toggle ? HAL_GPIO_WritePin( LED_GPIO_Port, LED_Pin, status != LED_ON ? GPIO_PIN_RESET : GPIO_PIN_SET): HAL_GPIO_TogglePin( LED_GPIO_Port, LED_Pin);	//利用define可以美化和简短我们的代码,知识点就用到了三目运算符的嵌套判断。

/* USER CODE END Private defines */

在usart.h下的用户代码区编写以下代码

/* USER CODE BEGIN Includes */
#if defined ( __CC_ARM  )
#pragma anon_unions
#endif
/* USER CODE END Includes */

/* USER CODE BEGIN Private defines */

#define RX_BUF_MAX_LEN 1024		  //最大接收缓存字节数

typedef struct 
{
	
	unsigned short dataLenPre;		//上一次的长度数据,用于比较
	
	union{
		unsigned short InfAll;
		struct 
		{
			unsigned short dataLen : 15;			//接收数据长度
			unsigned short finishFlag : 1;		//接收完成标志
		}InfBit;
	};
	unsigned char rxBuf[RX_BUF_MAX_LEN];			//接收缓存

} USART_INFO_STRUCT;


#define REC_OK		1	//接收完成标志
#define REC_WAIT	0	//接收未完成标志

extern USART_INFO_STRUCT usart1Info;
extern USART_INFO_STRUCT lpuart1Info;

/* USER CODE END Private defines */

/* USER CODE BEGIN Prototypes */

void USART_Interupt_Enable(void);
void USER_UartDMAHandler(UART_HandleTypeDef* huart,USART_INFO_STRUCT* usartInfo);

/* USER CODE END Prototypes */

在usart.c下的用户代码区编写以下代码

/* USER CODE BEGIN 0 */

#include <stdio.h>

USART_INFO_STRUCT usart1Info;
USART_INFO_STRUCT lpuart1Info;

int fputc(int ch, FILE *stream)
{
    /* 堵塞判断串口是否发送完成 */
    while((USART1->ISR & 0X40) == 0);

    /* 串口发送完成,将该字符发送 */
    USART1->TDR = (uint8_t) ch;

    return ch;
}

/* USER CODE END 0 */

/* USER CODE BEGIN 1 */

void USART_Interupt_Enable(void)
{
	
	__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);                //空闲中断使能
	__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE); 							//接收中断使能
	__HAL_UART_CLEAR_IDLEFLAG(&huart1);       //清除串口空闲中断标志位
	
	__HAL_UART_ENABLE_IT(&hlpuart1,UART_IT_IDLE);                //空闲中断使能
	__HAL_UART_ENABLE_IT(&hlpuart1,UART_IT_RXNE); 							//接收中断使能
	__HAL_UART_CLEAR_IDLEFLAG(&hlpuart1);       //清除串口空闲中断标志位
    
}


void USER_UartDMAHandler(UART_HandleTypeDef* huart,USART_INFO_STRUCT* usartInfo)
{
	uint32_t ucCh;
	if(huart->Instance == USART1)
	{
			if(__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET)  //触发空闲中断
			{
					__HAL_UART_CLEAR_IDLEFLAG(huart);       //清除串口2空闲中断标志位
					HAL_UART_DMAStop(huart);                //关闭DMA
					ucCh = huart->Instance->ISR;              //清除SR状态寄存器
					ucCh = huart->Instance->RDR;              //读取DR数据寄存器     用来清除中断
					ucCh = hdma_usart1_rx.Instance->CNDTR;      //获取DMA中未传输的数据个数
					usartInfo->InfBit.dataLen = RX_BUF_MAX_LEN - ucCh;           //总计数减去未传输的数据个数,得到已经接收的数据个数
					usartInfo->InfBit.finishFlag = REC_OK;			//标志接收成功
			}
        	HAL_UART_Receive_DMA(huart,usartInfo->rxBuf,RX_BUF_MAX_LEN);  //使能DMA接收到buf1
	}
		
	
	if(huart->Instance == LPUART1)
	{
			if(__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET)  //触发空闲中断
			{
					__HAL_UART_CLEAR_IDLEFLAG(huart);       //清除串口2空闲中断标志位
					HAL_UART_DMAStop(huart);                //关闭DMA
					ucCh = huart->Instance->ISR;              //清除SR状态寄存器
					ucCh = huart->Instance->RDR;              //读取DR数据寄存器     用来清除中断
					ucCh = hdma_lpuart_rx.Instance->CNDTR;      //获取DMA中未传输的数据个数
					usartInfo->InfBit.dataLen = RX_BUF_MAX_LEN - ucCh;           //总计数减去未传输的数据个数,得到已经接收的数据个数
					usartInfo->InfBit.finishFlag = REC_OK;			//标志接收成功
			}
			HAL_UART_Receive_DMA(huart,usartInfo->rxBuf,RX_BUF_MAX_LEN);  //使能DMA接收到buf1
	}
}


/* USER CODE END 1 */


在stm32l4xx_it.c中的USART1_IRQHandler函数的用户代码区编写以下代码

/**
  * @brief This function handles USART1 global interrupt.
  */
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
  USER_UartDMAHandler(&huart1,&usart1Info);	//用户中断代码
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}
/**
  * @brief This function handles LPUART1 global interrupt.
  */
void LPUART1_IRQHandler(void)
{
  /* USER CODE BEGIN LPUART1_IRQn 0 */
	USER_UartDMAHandler(&hlpuart1,&lpuart1Info);	//用户中断代码
  /* USER CODE END LPUART1_IRQn 0 */
  HAL_UART_IRQHandler(&hlpuart1);
  /* USER CODE BEGIN LPUART1_IRQn 1 */

  /* USER CODE END LPUART1_IRQn 1 */
}
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值