在本次项目中,限于空间要求我们选用了STM32F030F4作为控制芯片。这款MCU不但封装紧凑,而且自带的Flash空间也非常有限,所以我们选择了LL库实现。本篇将说明基于LL实现USART通讯。

1、概述

  我们想要实现基于RS485的Modbus通讯实际就是基于USART的通讯。USART使用可编程波特率发生器提供非常广泛的波特率范围。根据不同配置可以实现我们不同的串行通讯应用需求。其结构图如下:

  我们在USART基础上实现一个Modbus的从站应用,所以我们对于接收采用中断接收,而对于发送则根据接收到的信息做出反馈。所以我们要根据接收状态和发送状态来确定我们的操作。

2、USART配置

  在实现之前,我们来了解一下满足前述的需求,我们应该做哪些配置。主要有2个寄存器需要注意:控制寄存器1(USART_CR1)和波特率寄存器(USART_BRR)。

  首先我们还是来看一看控制寄存器1(USART_CR1)。其中RXNEIE(RXNE中断使能)、TE(发送使能)、RE(接收使能)、UE(USART使能)等位是需要我们注意的。该寄存器的结构如下:

  在控制寄存器1(USART_CR1)中,RXNEIE(RXNE中断使能)被置位后,只要USART_ISRORE=1或者RXNE=1就会产生该中断。接下来我们看一看波特率寄存器(USART_BRR),其结构如下:

  对于波特率寄存器(USART_BRR),顾名思义就是设置波特率。但波特率的值不是随意设置,有一套计算方法,可以查看STM的手册。

3、软件实现

  接下来我们在软件上实现我们的应用。我们先看USART配置,我们将其配置为我们需要的参数,并将其配置为中断接收模式。具体代码如下:

/*配置上位通讯串口*/

static void Comm_UART_Configuration(void)

{

LL_USART_InitTypeDef USART_InitStruct = {0};

LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

/* 使能相关外设时钟 */

LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_USART1);

LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);

/* USART1 GPIO 配置:PA2   ------> USART1_TX

PA3   ------> USART1_RX  */

GPIO_InitStruct.Pin = LL_GPIO_PIN_2;

GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;

GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;

GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;

GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;

GPIO_InitStruct.Alternate = LL_GPIO_AF_1;

LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

GPIO_InitStruct.Pin = LL_GPIO_PIN_3;

GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;

GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;

GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;

GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;

GPIO_InitStruct.Alternate = LL_GPIO_AF_1;

LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

/* USART1中断初始化 */

NVIC_SetPriority(USART1_IRQn, 1);

NVIC_EnableIRQ(USART1_IRQn);

/* USART1端口配置 */

USART_InitStruct.BaudRate = 115200;

USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;

USART_InitStruct.StopBits = LL_USART_STOPBITS_1;

USART_InitStruct.Parity = LL_USART_PARITY_NONE;

USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;

USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;

USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;

LL_USART_Init(USART1, &USART_InitStruct);

LL_USART_DisableIT_CTS(USART1);

LL_USART_ConfigAsyncMode(USART1);

LL_USART_Enable(USART1);

LL_USART_EnableIT_RXNE(USART1);

}

  大部分配置都可通过初始化函数来实现,有一些需同过专门的LL库函数实现。配置完成后寄存器的状态如下图所示。

  我们配置的波特率是115200,其在寄存器中的配置为1A1,关于波特率的配置问题可以查看相关资料。另外我们还需要编写一个接收中断的服务函数。

/*数据接收中断处理函数,添加到USART1中断响应函数中*/

void USART1_ReceiveDataHandle(void)

{

if(rxLength>=RECEIVEDATALENGTH)

{

rxLength=0;

}

/*接收寄存器为空,等待字节被对应的串口完全接收*/

if(LL_USART_IsActiveFlag_RXNE(USART1))

{

uint8_t rData;

/*获取接收到的字节*/

rData=LL_USART_ReceiveData8(USART1);

rxBuffer[rxLength++] = rData;

}

if(LL_USART_IsActiveFlag_ORE(USART1))

{

LL_USART_ClearFlag_ORE(USART1);

}

}

  需要注意的是需要添加ORE溢出标志的检测,确保每次的接收中断都是有效的。

4、总结

  最后我们来测试一下我们的代码。将相关项目下载到目标板并采用两种监测方式查看结果。首先接到PC机的串口,在上位中使用Modscan来查看,其结果如下:

  然后通过J-Link在线调试监控数据通讯,其结果如下:

  上图中,上部是我们的物理量数据,而下面是接收到的上位下发的读取保持寄存器的Modbus报文。结合前一张图,很明显收发都是正确的。

欢迎关注:

STM32F0使用LL库实现Modbus通讯的更多相关文章

  1. STM32F0使用LL库实现SHT70通讯

    在本次项目中,限于空间要求我们选用了STM32F030F4作为控制芯片.这款MCU不但封装紧凑,而且自带的Flash空间也非常有限,所以我们选择了LL库实现.本篇我们将基于LL库采用模拟I2C接口的方 ...

  2. STM32F0使用LL库实现MS5536C通讯

    在本次项目中,限于空间要求我们选用了STM32F030F4作为控制芯片.这款MCU不但封装紧凑,而且自带的Flash空间也非常有限,所以我们选择了LL库实现.在本文中我们说明一下,使用LL库实现MS5 ...

  3. C/C++ 用libcurl库进行http通讯网络编程

    C/C++ 用libcurl库进行http通讯网络编程 目录索引: 一.LibCurl基本编程框架 二.一些基本的函数 三.curl_easy_setopt函数部分选项介绍 四.curl_easy_p ...

  4. 串口屏Modbus协议,串口屏的modbus协议资料,串口屏modbus通讯协议开发,串口屏之modbus协议使用技巧

    串口屏Modbus协议,串口屏的modbus协议资料,串口屏modbus通讯协议开发,串口屏之modbus协议使用技巧 本例程中用51单片机作为Modbus从机,从机的设备地址为2,从机有4个寄存器, ...

  5. C++ 用libcurl库进行http通讯网络编程 【转】

    http://www.cnblogs.com/moodlxs/archive/2012/10/15/2724318.html C++ 用libcurl库进行http通讯网络编程 目录索引: 一.Lib ...

  6. Modbus通讯协议

    <ignore_js_op> O1CN01P1wxTI1dCdw5nAeMO_!!85243700.jpg (287.43 KB, 下载次数: 0) 下载附件  保存到相册 2019-6- ...

  7. (6)STM32使用HAL库实现modbus的简单通讯

    1.判断地址.校验 2.读取本机数据并校验打包 3.发送数据包 4.本机数据长度比要读取的长度短怎么办 4.校验错误怎么办

  8. 6)STM32使用HAL库实现modbus的简单通讯

    1.判断地址.校验 2.读取本机数据并校验打包 3.发送数据包 4.本机数据长度比要读取的长度短怎么办 4.校验错误怎么办

  9. C++ 用libcurl库进行http通讯网络编程

    使用libcurl完成http通讯,很方便而且是线程安全,转载一篇比较好的入门文章 转载自 http://www.cnblogs.com/moodlxs/archive/2012/10/15/2724 ...

随机推荐

  1. 华硕AC66U_B1救砖或者恢复固件

    手贱,刷了个DD-WRT,然后发现无法还原固件,刷不回原厂固件.网上找不到恢复的方法.还是DD-WRT官网给力,本身就提供了恢复原厂固件的方法,是英文的.但是其中提到的一个工具,现在没有了.ASUS ...

  2. 【Code】numpy、pytorch实现全连接神经网络

    """ 利用numpy实现一个两层的全连接网络 网络结构是:input ->(w1) fc_h -> relu ->(w2) output 数据是随机出 ...

  3. DRF 商城项目 - 用户操作(收藏, 留言, 收货地址)

    个人收藏 整体逻辑类似于 个人中心 ( 个人中心的相关逻辑梳理详情  点击这里 ) 也是两个序列化组价的分流 查看收藏  ( list ) 详情指向 收藏详情 的组价 创建收藏 ( create ) ...

  4. 数据库设计很棒的参考CDM-PDM-LDM-PowerDesigner

    此页面显示了涵盖主题领域的  50 个类别中的行业特定数据模型列表,用于创建企业数据模型. 以下是我们所有 1,700 多种数据模型的字母顺序列表 1. 广告 1. 顾客 1. 派对 1.   广告中 ...

  5. ADRC-active disturbance rejection control-自抗扰控制器

    ADRC自抗扰控制基本思想要点: 1.标准型与总扰动,扩张状态与扰动整体辨识,微分信号生成与安排过渡过程以及扰动的消减与控制量产生. ADRC主要构成: 1)跟踪微分器(TD)---the track ...

  6. consul 剔除node_exporter的脚本

    #!/bin/bash clear echo "node_exporter注销工具" read -p "请输入要踢掉的节点IP,如果有多个IP,请使用英文格式 ',' 隔 ...

  7. 经典面试题-python函数之默认参数

    1.可变的默认参数----list  示例: def add(a, mylist=[]): # print(id(mylist)) mylist.append(a) return mylist pri ...

  8. 简单的makefile

    单一程序 准备一个hello.c #include <stdio.h> int main(void) { printf("Hello World!\n"); } gcc ...

  9. python类方法以及类调用实例方法的理解

    classmethod类方法 1) 在python中.类方法 @classmethod 是一个函数修饰符,它表示接下来的是一个类方法,而对于平常我们见到的则叫做实例方法. 类方法的第一个参数cls,而 ...

  10. Sql查询某个字段是否包含小写字母

    SELECT * from student where username COLLATE Chinese_PRC_CS_AS LIKE '%[abcdefghijklmnopqrstuvwxyz]%'