5061|2

54

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

【先楫HPM6750测评】裸机移植agile_modbus [复制链接]

  本帖最后由 xiashuang 于 2022-7-19 10:51 编辑

        Modbus是常用的工业通讯协议,本次在HPM上移植Modbus RTU,主要是熟悉uart和定时器。本来想移植freemodbus,但是freemodbus只支持单从机,前段时间在RT-THREAD社区里看到agile_modbus,看了下例程发现和libmodbus一样比较简单,并且支持多主机多从机,正好想试一下HPM6750的uart和定时器,于是使用uart接收和发送中断以及定时器产生超时中断实现modbus rtu。

    移植步骤如下:1.从GitHub上下载agile_modbus文件,在工程中加入相关源文件

        2.增加头文件路径

        3.协议栈初始化

        

/*init modbus stack*/
    uint8_t ctx_send_buf[AGILE_MODBUS_MAX_ADU_LENGTH];
    uint8_t ctx_read_buf[AGILE_MODBUS_MAX_ADU_LENGTH];

    agile_modbus_rtu_t ctx_rtu;
    agile_modbus_t *ctx = &ctx_rtu._ctx;
    agile_modbus_rtu_init(&ctx_rtu, ctx_send_buf, sizeof(ctx_send_buf), ctx_read_buf, sizeof(ctx_read_buf));
    agile_modbus_set_slave(ctx, 1);

        4.串口使用uart13,中断代码如下

void uart_isr(void)
{
    uint8_t c;
    uint8_t uart_irq_state = uart_get_irq_id(TEST_UART1);
        if (uart_irq_state & uart_intr_id_rx_data_avail) 
        {
            if (status_success != uart_receive_byte(TEST_UART1, &c)) {
                while (1) {
                }
            }
            //定时器重置计数
            gptmr_channel_reset_count(MODBUS_CALLBACK_TIMER, MODBUS_CALLBACK_TIMER_CH);
            //printf("R");
            //启动定时器
            if(buff_index == 0)
            {
                gptmr_start_counter(MODBUS_CALLBACK_TIMER, MODBUS_CALLBACK_TIMER_CH);
                uart_rx_outtime = 0;//接收超时状态为0
                //printf("S");
            }

            data_buff[buff_index] = c;
            buff_index++;
            //接收数据过多,重新接收
            if (buff_index >= 260) {
                //uart_disable_irq(TEST_UART1, uart_intr_rx_data_avail_or_timeout);
                //uart_enable_irq(TEST_UART1, uart_intr_tx_slot_avail);
                buff_index = 0;
            }
        

        }

        if (uart_irq_state & uart_intr_id_tx_slot_avail) 
        {
            if (status_success != uart_send_byte(TEST_UART1, data_buff[data_count])) {
                    while (1) {
                    }
            }
            data_count ++;
            if(data_count >= buff_index){
                buff_index = 0;
                data_count = 0;
                uart_rx_outtime = 0;
                uart_flush(TEST_UART1);
                uart_disable_irq(TEST_UART1, uart_intr_tx_slot_avail);
                uart_enable_irq(TEST_UART1, uart_intr_rx_data_avail_or_timeout);
            }
        }
}

SDK_DECLARE_EXT_ISR_M(TEST_UART_IRQ1, uart_isr)

        5.定时器配置

void modbus_timer_create(uint32_t ms, modbus_timer_cb cb)
{
    uint32_t gptmr_freq;
    gptmr_channel_config_t config;
    gptmr_channel_get_default_config(MODBUS_CALLBACK_TIMER, &config);
    clock_add_to_group(MODBUS_CALLBACK_TIMER_CLK_NAME, 0);
    gptmr_freq = clock_get_frequency(MODBUS_CALLBACK_TIMER_CLK_NAME);
    config.reload = gptmr_freq / 1000 * ms;
    gptmr_channel_config(MODBUS_CALLBACK_TIMER, MODBUS_CALLBACK_TIMER_CH, &config, false);
    gptmr_enable_irq(MODBUS_CALLBACK_TIMER, GPTMR_CH_RLD_IRQ_MASK(MODBUS_CALLBACK_TIMER_CH));
    intc_m_enable_irq_with_priority(MODBUS_CALLBACK_TIMER_IRQ, 1);

    //gptmr_start_counter(MODBUS_CALLBACK_TIMER, MODBUS_CALLBACK_TIMER_CH);
}

        6.收到UART第一个接收中断启动定时器,以后每个中断定时器重新计数,超过T3.5后定时器超时更新标志,进行modbus协议栈处理,如果需要发送数据则发送数据

if(uart_rx_outtime == 1)
        {
            //printf("t");
            uart_rx_outtime = 0;
            memcpy(ctx_read_buf,data_buff,buff_index);
            int send_len = agile_modbus_slave_handle(ctx, buff_index, 0, slave_callback, NULL);
            if (send_len > 0)
            {
                data_count = 0;
                buff_index = send_len;
                memcpy(data_buff,ctx_send_buf,buff_index);
                uart_flush(TEST_UART1);
                uart_enable_irq(TEST_UART1, uart_intr_tx_slot_avail);
                uart_disable_irq(TEST_UART1, uart_intr_rx_data_avail_or_timeout);
            }
            else{
                buff_index = 0;
            }             
        }

        7.slave_callback不需要做修改,因为我使用逻辑,所以注释掉互斥访问

 

        总结:HPM官方提供UART中断收发代码中中断状态读取在实际使用中不太合理,发送使用阻塞发送若果不使用阻塞发送将会导致程序卡死在接收中断处理里面的while(1),增加中间变量uint8_t uart_irq_state = uart_get_irq_id(TEST_UART1) 使用中间变量判断状态就OK了,怀疑每次读中断状态将把中断寄存器中断清除。agile_modbus比freemodbus移植和使用点单多了,如果有需要使用modbus的建议试试看看。

最新回复

谢谢非常详尽的测评分享哈!针对最后总结的问题,uart_isr这个是example里面的示例,应用如果有不同需求的时候,可以按照具体的需求编写,谢谢!!  详情 回复 发表于 2022-7-21 14:31
点赞(1) 关注(3)
 
 

回复
举报

7608

帖子

2

TA的资源

五彩晶圆(高级)

沙发
 

看了下这个agile_modbus,谢谢分享,有机会试试

个人签名

默认摸鱼,再摸鱼。2022、9、28

 
 
 

回复

1

帖子

2

TA的资源

一粒金砂(初级)

板凳
 
谢谢非常详尽的测评分享哈!针对最后总结的问题,uart_isr这个是example里面的示例,应用如果有不同需求的时候,可以按照具体的需求编写,谢谢!!
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表