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);                //关闭DMAucCh = 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);                //关闭DMAucCh = 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 */
}

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

  1. STM32玩转物联网实战篇:2.ESP8266 WIFI模块TCP通信示例详解

    1.准备开发板 开发板功能区分布图 开发板俯视图 2.ESP8266简介     ESP8266 WIFI模块内置TCP/IP网络协议,模块支持三种网络模式,AP.STA和AP+STA模式,AP模式: ...

  2. 51单片机怎么显示当前时间_51单片机玩转物联网基础篇06-LCD1602液晶显示器

    前言 本节我们开始学习LCD1602,LCD1602是字符型液晶显示屏,在实际项目中应用非常广泛,学完本节就可以逐步开发一些好玩的应用了. 一.基础知识 1.LCD1602简介 LCD1602是字符型 ...

  3. 51单片机玩转物联网基础篇05-控制继电器

    前言 本节我们开始学习如何使用51单片机控制继电器,有了继电器,我们可以使用单片机输出的低电平控制高电平期间工作,比如继电器接到220V用电器上,可通过单片机智能控制用电器. 一.基础知识 1.继电器 ...

  4. 玩转Docker实战篇!使用Docker搭建Sinatra Web程序,附加介绍容器关联(Docker Networking、Docker链接)

    一.本文目的 前面一篇文章,我们在Docker中搭建了Nginx服务器,并访问了Nginx服务器:https://blog.csdn.net/qq_41453285/article/details/1 ...

  5. Docker JFrog Artifactory 7.27.10 maven私服(IDEA 实战篇01) linux

    文章目录 一.私服配置 1. 账户密码 2. 本地仓库 3. ip/port 二.IntelliJ IDEA 2.1. 创建项目 2.2. 指定配置 2.3. 下载依赖 2.4. 依赖查看 2.5. ...

  6. 玩转Docker实战篇!使用Docker与Jenkins进行持续集成测试,附加介绍Docker-in-Docker

    一.本文目的 在前面的文章中,所有的测试例子都是本地的.围绕着单个开发者的(就是说,如何让本地开发者使用Docker来测试本地网站或者引用程序).现在来看看在多开发者的持续集成测试场景中如何使用Doc ...

  7. OKR之剑·实战篇06:OKR致胜法宝-氛围业绩双轮驱动(下)

    作者:vivo 互联网平台产品研发团队 本文是<OKR 之剑>系列之实战第 6 篇-- 本文介绍团队营造氛围的方法与实践.在业绩方面的探索与输出,在两方面分别总结了一些经验分享给大家. 一 ...

  8. OKR之剑·总结篇01:如何开好一场OKR复盘会

    作者:vivo 互联网平台产品研发团队 本文是<OKR 之剑>系列之总结第 1 篇-- OKR复盘是OKR生命周期中的重要环节,起着承上启下的重要作用.本篇将和你一起探讨什么是OKR复盘. ...

  9. OKR之剑·实战篇05:OKR致胜法宝-氛围业绩双轮驱动(上)

    作者:vivo 互联网平台产品研发团队 本文是<OKR 之剑>系列之实战第 5 篇-- 我们的OKR执行如此顺利,离不开我们的"双轮驱动".类似于亚马逊的"飞 ...

最新文章

  1. 6月27日任务 配置Tomcat监听80端口、配置Tomcat虚拟主机、Tomcat日志
  2. 世界机器人大会|人工智能VS人类
  3. Redis学习笔记(八)——持久化
  4. 转换php script类型,ECMAScript 类型转换
  5. 谈谈R中的乱码(一)
  6. SQL ltrim() 和 rtrim() 函数
  7. 追踪电子邮件行踪的“眼”
  8. MySQL抽稀_Android GPS定位轨迹抽稀之道格拉斯-普克(Douglas-Peuker)算法详解
  9. CrossApp 0.4.2 发布,隆重推出 WebView
  10. 华为交换机端口vlan详解
  11. JAVA打字游戏代码
  12. uni-app h5打包发版到测试和生产环境具体步骤
  13. 在午睡,手机接连振动,是几个朋友用短信微信问我
  14. html5 canvas文字标签云3D旋转动画特效
  15. python中关于命名的例子_利用Python批量重命名文件(给非技术人员的Python实例参考)...
  16. 数据版“吐槽大会”: 国产综艺节目年终盘点
  17. oracle创建Triggers
  18. python 仪表盘 ppt_python+仪表
  19. NJ4X源码阅读分析笔记系列(一)——项目整体分析 1
  20. (48)STM32——图片显示实验

热门文章

  1. Discuz论坛web网页mp3音频播放器源码下载
  2. wow服务器合并信息,《魔兽世界》一区合并服务器正式通告
  3. 交换机、路由器、网关的概念,并知道各自的用途
  4. Android 开源项目库汇总
  5. 推荐几个Python爬虫接单渠道
  6. (Note)HTTP常见状态码(Status Code)
  7. 大明:讲解硬盘ESP分区和MSR分区有什么用?值得收藏
  8. office2007有没有64位的
  9. CSS中的代表的什么
  10. excel求方差和标准差的函数_Excel标准差_计算函数Stdev和StdevP的使用方法