目录

  • 1 课程简介
    • 1.1 课程简介
    • 1.2 课程标准
    • 1.3 职业证书对接
    • 1.4 课程分工
  • 2 数据采集
    • 2.1 数据采集之数字量传感数据采集
    • 2.2 数据采集之模拟量传感数据采集
    • 2.3 数据采集之模拟量转换为数字量
    • 2.4 数据采集之开关量传感数据采集
  • 3 STM32微控制器基本外设应用开发
    • 3.1 STM32基础知识
    • 3.2 任务1 开发环境搭建和工程建立
    • 3.3 任务2 LED流水灯应用开发
    • 3.4 任务3 按键控制LED灯亮灭
    • 3.5 任务4 串行通信控制LED流水灯应用开发
    • 3.6 任务5 电池电量检测应用开发
  • 4 RS-485总线通信应用
    • 4.1 RS-485基本知识
    • 4.2 RS-485通信协议及网关通信协议
    • 4.3 Modbus通信协议
    • 4.4 任务1 案例分析及工程代码编写
    • 4.5 任务2 系统搭建及云平台项目创建
  • 5 CAN总线通信应用
    • 5.1 CAN总线基本知识
    • 5.2 CAN通信帧
    • 5.3 CAN控制器和收发器
    • 5.4 任务1 案例分析及工程代码编写
    • 5.5 任务2 系统搭建及云平台项目创建
    • 5.6 任务3 CAN通信数据抓包与解析
  • 6 BasicRF的无线通信应用
    • 6.1 BasicRF基础知识
    • 6.2 任务1创建工程项目
    • 6.3 任务2 温湿度节点数据采集
    • 6.4 任务3 火焰节点数据采集
    • 6.5 任务4 传感器节点组网
    • 6.6 任务5 传感数据汇聚
  • 7 WiFi数据通信
    • 7.1 WI-FI基础知识
    • 7.2 使用AT指令配置WI-FI工作模式
    • 7.3 WI-FI接入云平台
  • 8 NB-IoT联网通信
    • 8.1 NB-IoT技术简介
    • 8.2 利尔达NB-IoT模组介绍
    • 8.3 任务1 “智慧路灯”AT指令代码编写
    • 8.4 任务2.烧写智能路灯
    • 8.5 任务3NB-IoT接入云平台
  • 9 LoRa 通信技术
    • 9.1 基础知识
    • 9.2 项目分析与LoRa驱动移植
    • 9.3 任务2 LoRa温湿度传感器节点应用程序开发
    • 9.4 任务3 LoRa光照传感器节点数据采集
    • 9.5 任务4 LoRa网关节点汇聚传感器数据
    • 9.6 讨论
任务4 串行通信控制LED流水灯应用开发
  • 1 知识介绍
  • 2 PPT
  • 3 学习视频
  • 4 国家脊梁

任务要求

设计一个LED流水灯系统,该系统与上位机之间通过串行通信接口相连。

上位机可发送命令对LED流水灯系统进行控制,系统中有8个LED灯,分别是LED1~LED8。系统上电时,8个LED灯默认为熄灭状态。系统运行时,8个LED灯依次点亮。(图 2-48

图片1


2-48LED流水灯系示意图


LED流水灯系模式1(图 2-49):8个LED灯依次点亮,每个LED灯点亮1秒后熄灭,然后切换为另一个,点亮顺序为LED1、LED2、……、LED8,并以此循环往复。

图片3


2-49LED流水灯系模式1


LED流水灯系模式2(图 2-50):8个LED灯依次点亮,每个LED灯点亮1秒后熄灭,然后切换为另一个,点亮顺序为LED8、LED7、……、LED1,并以此循环往复。

图片2


2-50LED流水灯系模式2


案例分析

使用上位机发送串口指令mode_1#、mode_2#、stop#对应流水灯的模式一、模式二以及停止状态(图 2-51)。这里MCU需要对指令进行解析处理,并需要记录状态方便进行模式切换。

1


2-51串口控制流水灯


通过对任务进行分析,得到需要解决的任务点如下:

  1. GPIO口模式设置

  2. 串口参数设置

  3. 如何判断数据是否接收完成

知识储备

(一)串口资源:

STM32 的串口资源相当丰富的,功能也相当强劲。STM32F1系列微控制器有5个收发器外设(俗称“串口”)可用于串行通信,包括3个USART和2个UART(通用异步收发器,Universal  Asynchronous Receiver and Transmitter),如图 2-52所示,它们分别是:USART1、USART2、USART3、UART4、UART5。

UART与USART相比,裁剪了同步通信的功能,只有异步通信功能。同步通信与异步通信的区别在于通信中是否需要发送器输出同步时钟信号USART_CK,实际应用中一般使用异步通信。

2


2-52STM32F1串口资源


图 2-53来看,可以发现任何USART双向通信至少需要两个脚:TXD(数据发送引脚、数据发送)和RXD(数据输入引脚、数据接受)。

3


2-53USART双向通信示意图


当需要发送数据时,MCU内核将待发送的数据写入输出数据发送缓冲器后,串行口会自动地按照软件设定的格式将待发送的数据组成数据帧,发送控制器将适时地自动把数据从数据寄存器加载到串行输出移位寄存器,然后通过引脚TXD,把数据一位一位地发送出去。

当需要接收数据时,通过引脚RXD数据一位一位传到接收位移寄存器中,在传输接收数据寄存器中。

(二)数据格式:

一个数据帧包括:

1个起始位(低电平)

8个数据位

1个校验位

1个停止位(高电平表示结束)

注意:串口空闲时,数据线为高电平,所以起始位是一个周期的低电平做为起始。同理:停止位是一个周期的高电平。

STM32发送一个数据帧(也称为字符帧)需要分为三个部分:起始位+数据位+停止位。起始位是一个位周期的低电平,位周期就是每一位占用的时间;数据位就是要发送的8位或9位数据;停止位是一定时间周期的高电平。如图 2-54所示。

图片4


2-54数据帧(字符帧)结构


STM32接收一个数据帧:开始通信,信号线为空闲,当检测到由1到0的跳变时,开始对接收时钟计数;接收端检测到起始位后,隔16个接收时钟对输入信号检测一次,把对应的值作为D0位数据;再隔16个接收时钟,对输入信号检测一次,把对应的值作为D1位数据,直到全部数据位都输入;接收到规定的数据位个数和校验位之后,通信接口电路希望收到停止位(逻辑1),若此时未收到逻辑1,说明出现了错误,在状态寄存器中置“帧错误”标志;若没有错误,对全部数据位进行奇偶校验,无校验错时,把数据位从移位寄存器中取出送至数据输入寄存器,若校验错,在状态寄存器中置“奇偶错”标志;本帧信息全部接收完,把线路上出现的高电平置为空闲位;接收期间需要先监测 接收数据寄存器不为空(准备好读取接收到的数据),在检测线路是否空闲,最后如果没有错误中断标志位(图 2-55)产生,就能正常的接收完成一帧数据了。

5


2-55STM32F1的USART支持的中断事件


任务实施

(一)工程创建

教学视频建立STM32CubeMX工程并生成初始C代码

1:新建STM32CubeMX工程,2:选择MCU型号(STM32F103VE),3:配置时钟树,先找RCC将图上红色框选1部分选择成外部晶振后,点击红色框选2部分进入时钟树配置界面,将HCLK配置为72MHz,PCLK1配置为36MHz,PCLK2配置为72MHz(可参照视频)。(图 2-56

6


2-56STM32CubeMX工程配置1


配置led灯控制引脚,GPIO模式配置位output模式(输出模式),其余参数如图 2-57所示。

7


2-57STM32CubeMX工程配置2


图 2-58所示,配置USART外设的工作参数,展开“Pinout & Configuration”标签页左侧的①“Connectivity”选择 ②“USART1”,将USART1的模式配置为③“Asynchronous(异步)”。点击④“Parameter Settings(参数配置)”,配置USART1的⑤“Baud Rate(波特率)”为115200 Bits/s,配置“Data Direction(数据方向)”为⑥“Receive and Transmit(接收与发送)”。⑦已配置好功能的引脚显示。选择NVIC选项,设置优先级,勾选“Enabled”复选框,使能USART1的“global interrupt(全局中断)”。其中断优先级保留默认配置:抢占优先级“0”,子优先级“0”。最后生产工程即可。

8


2-58STM32CubeMX工程配置3


(二)编写程序代码

教学视频完善代码

在“usart.h”中输入以下代码,将USART发送函数重定向到printf()函数。

/* USER CODE BEGIN 0 */
int fputc(int ch,FILE *f)
{
  HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xffff);
  return ch;
}

/* USER CODE END 0 */

在main.c中,完成变量、接收缓冲器、指令等的声明及赋值。

/* USER CODE BEGIN PV */
#include "string.h"

const char stringMode1[8] = "mode1#";
const char stringMode2[8] = "mode_2#";
const char stringStop[8] = "stop#";
int8_t ledMode = -1;
uint16_t LED_value = 0;
uint8_t uart1RxState = 0;
uint8_t uart1RxCounter = 0;
uint8_t uart1RxBuff[128] = {0};
/* USER CODE END PV */

在main.c中编写USER_UART_IRQHandler的业务逻辑代码。

/* USER CODE BEGIN 4 */
void USER_UART_IRQHandler()
{
  if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE) != RESET)
  {
    __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
    uart1RxBuff[uart1RxCounter] = (uint8_t)(huart1.Instance->DR&(uint8_t)0x00ff);
    uart1RxCounter++;
    __HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_RXNE);
  }

  if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET)
  {
    __HAL_UART_DISABLE_IT (&huart1,UART_IT_IDLE);
    uart1RxState = 1;
  }
/* USER CODE END 4 */

判断接收到的指令进行对比。并将指令对于的工作模式值存放在ledMode变量中。判断ledMode的值进行模式切换。具体操作可查看视频。

printf("hello word.\r\n");

/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
  /* USER CODE END WHILE */
  if(uart1RxState =1)
  {
    if(strstr((const char *)uart1RxBuff,stringMode1)!=NULL)
    {
      printf("I'm in mode_1!\r\n");
      ledMode = 1;
      LED_value = 0x80;
    }
    else if(strstr((const char *)uart1RxBuff,stringMode2)!=NULL)
    {
      printf("I'm in mode_2!\r\n");
      ledMode = 2;
      LED_value = 0x01;
    }
    else if(strst((const char *)uart1RxBuff,stringStop)!=NULL)
    {
      printf("I'm stop!\r\n");
      ledMode 0;
      LED value 0;
    }
    uartlRxState = 0;
    uartlRxCounter = 0;
    memset(uart1RxBuff,0,128);
  }

  HAL_GPIO_WritePin(GPIOE,0xff,GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIOE,LED_value,GPIO_PIN_RESET);
  HAL_Delay(1000);
  switch(ledMode)
  {
    case 1:
      LED_value = LED_value>>1;
      if(LED_value==0)
        LED_value 0x80;
      break;
    case 2:
      LED_value = LED_value<<1;
      if(LED_value==0x100)
        LED_value=0x01;
      break;
    case 0:
      LED_value = 0;
      break;
  }
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */