RT-Thread基于AT32单片机的485应用开发(二)

本文介绍了如何在RT-Thread中对基于AT32的RS485应用进行优化,通过使用DMA的非阻塞模式提高收发效率,并根据波特率自动控制延时,降低CPU负载。同时展示了如何实现一个基于ModbusRTU的简化从机示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上篇RT-Thread基于AT32单片机的485应用开发(一)中实现了RS485收发,但总觉得效率不高,函数封装也不完善。考虑到RS485总线应用都是主从式结构,比如工业领域常用的Modbus协议,都是以帧为单位进行收发,本次测试对收发函数进行了封装,并对RS485的收发控制引脚根据波特率进行了自动延时控制,降低了CPU负载。

本例中收发全部采用DMA的NON_BLOCKING方式,把接收一帧数据和发送一帧数据进行了函数封装。

测试代码如下:

#include <rtthread.h>
#include <rtdevice.h>

/* 串口设备句柄 */
static rt_device_t serial;

/* 485控制引脚 */
static rt_base_t rs485_ctrl_pin = -1;

/* timeout receive */
static int serial_read_frame(rt_device_t dev, uint8_t *buf, int max_len, uint32_t idle_ms, int timeout_ms)
{
    int rx_len = 0, rc;
    uint32_t idle_time, timeout_time, cur_tick, last_tick;

    timeout_time = rt_tick_from_millisecond(timeout_ms);
    idle_time = rt_tick_from_millisecond(idle_ms);
    cur_tick = rt_tick_get();

    while((rt_tick_get()-last_tick<idle_time && rx_len<max_len) || rx_len<=0){
        rc = rt_device_read(dev, rx_len, buf, max_len-rx_len);
        if(rc>0){
            rx_len += rc;
            last_tick = rt_tick_get();
        }else{
            rt_thread_mdelay(1);
        }
        if(rt_tick_get()-cur_tick>timeout_time && rx_len<=0)
            break;
    }
    return rx_len;
}
/* transmit with auto 485 pin ctrl */
static void serial_write_frame_rs485(rt_device_t dev, uint8_t *buf, int len, int bitrate, int ctrl_pin)
{
    int ms = len * 10 *1000 / bitrate + 2;

    rt_pin_write(rs485_ctrl_pin,1);
    rt_hw_us_delay(10);
    rt_device_write(dev, 0, buf, len);
    rt_thread_mdelay(ms);
    rt_pin_write(rs485_ctrl_pin,0);
}
static void serial_thread_entry(void *parameter)
{
    rt_uint32_t rx_len;
    static unsigned char rx_buf[256];


    while(1){
        rx_len = serial_read_frame(serial, rx_buf, 255, 10, 1000);
        if(rx_len<=0)
            continue;
        serial_write_frame_rs485(serial, rx_buf, rx_len, 115200, rs485_ctrl_pin);
        /* 打印数据 */
        rx_buf[rx_len] = '\0';
        rt_kprintf("rx_len = %d\n",rx_len);
    }
}

static int uart_485_sample(int argc, char *argv[])
{
    rt_err_t ret = RT_EOK;
    char uart_name[RT_NAME_MAX] = "uart4";

    if (argc == 2)
    {
        rt_strncpy(uart_name, argv[1], RT_NAME_MAX);
    }

    rt_kprintf("uart_name = %s\n",uart_name);
    if(rt_strcmp(uart_name,"uart3")==0){
        rs485_ctrl_pin = rt_pin_get("PE.15");
        rt_pin_mode(rs485_ctrl_pin, PIN_MODE_OUTPUT);
        rt_pin_write(rs485_ctrl_pin,0 );
    }else if(rt_strcmp(uart_name,"uart4")==0){
        rs485_ctrl_pin = rt_pin_get("PA.15");
        rt_pin_mode(rs485_ctrl_pin, PIN_MODE_OUTPUT);
        rt_pin_write(rs485_ctrl_pin,0);
    }else{
        return RT_ERROR;
    }

    /* 查找串口设备 */
    serial = rt_device_find(uart_name);
    if (!serial)
    {
        rt_kprintf("find %s failed!\n", uart_name);
        return RT_ERROR;
    }

    /* 以 DMA 接收及轮询发送方式打开串口设备 */
    rt_device_open(serial, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_NON_BLOCKING);

    /* 创建 serial 线程 */
    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
    /* 创建成功则启动线程 */
    if (thread != RT_NULL)
    {
        rt_thread_startup(thread);
    }
    else
    {
        ret = RT_ERROR;
    }

    return ret;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(uart_485_sample, uart device rs485 sample);

接收函数,返回收到的字节数:

int serial_read_frame(rt_device_t dev, uint8_t *buf, int max_len, uint32_t idle_ms, int timeout_ms)

idle_ms : 收到最后一个字节数据后空闲的毫秒数

timeout_ms : 如果在这个时间内没有收到数据,则返回0;-1代表一直等待直到收到数据。

发送函数

void serial_write_frame_rs485(rt_device_t dev, uint8_t *buf, int len, int bitrate, int ctrl_pin)

bitrate : 波特率,用于计算实际需要发送的时间

ctrl_pin :485收发控制引脚号

实际测试结果:

在编辑文字的约6分钟内,总共收发了31270个字节,没有发生错误。

在此基础上,后续又实现了一个极简ModbusRTU从机,核心代码不到300行,支持01、02、03、04、05、06、15、16功能码。

RT-Thread基于AT32单片机的485应用开发(三)Modbus从机

### 关于 RT-Thread 操作系统与阿里云集成 RT-Thread 是一款适合物联网设备和嵌入式系统的实时操作系统(RTOS)[^1]。其特性使得它能够很好地适应各种硬件平台并提供必要的功能来支持复杂的开发需求,比如线程管理和网络协议栈等。 当涉及到与阿里云的集成时,可以通过不同的方式实现数据传输和服务调用: #### 通过 MQTT 协议连接到阿里云 IoT 平台 一种常见的方法是采用 MQTT (Message Queuing Telemetry Transport) 协议来进行消息传递。具体来说,在串口调试工具中发送特定命令 `ali_mqtt_sample` 可使设备成功建立至阿里云IoT云端的服务端链接,并执行相应的MQTT操作[^2]。这种方式非常适合用于传感器节点或其他小型智能终端向云端上传监测信息或者接收控制指令的应用场景。 #### 利用 BC28 AT 模块进行通信 另一种方案则是借助专门针对移动蜂窝网络优化过的硬件模块——例如移远公司的BC系列(如BC28)。这类产品通常会配备有配套的固件库,允许开发者轻松编写程序以发起HTTP请求或是订阅发布MQTT话题给阿里云服务器。值得注意的是,bc28_mqtt 软件包不仅简化了API的设计还实现了诸如自动重新连接这样的高级特性,从而提高了应用程序稳定性[^3]。 #### Spring Boot 应用中的 RocketMQ 集成案例 虽然这不是直接关联于 RT-Thread 的例子,但对于那些希望构建更大规模分布式架构的企业级解决方案而言,可以考虑将Spring Boot框架同RocketMQ结合起来作为异步消息队列服务的一部分。这需要设置好对应的 Maven 依赖项并将相关参数填入配置文件当中以便正常工作[^4]。 综上所述,无论是简单的单片机项目还是复杂的企业级后台服务,都有现成的技术手段可以帮助完成 RT-Thread 和阿里云之间的高效协作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值