【极海APM32F407 Tiny Board】4通道MODBUS测试
[复制链接]
本帖最后由 aple0807 于 2023-5-23 21:13 编辑
4通道MODBUS测试
本人从事仪表开发工作,MODBUS是最常用的对外通信协议,主站和从站均经常使用。
APM32共有6个串口,本测试开通4路MODBUS,两路主站和两路从站:
USART2: 主站,9600,8N2
USART3: 主站,115200,8N2
UART4: 从站,9600,8N2
UART6: 从站,115200,8N2
4路串口IO配置如下:
// UART1-PA9:TX-PA10:RX
{GPIOA, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_PUPD_NOPULL, GPIO_AF_USART1, GPIO_SPEED_50MHz, 1, GPIO_PIN_9 | GPIO_PIN_10},
// UART2-PD5-TX:-PD6:RX
{GPIOD, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_PUPD_NOPULL, GPIO_AF_USART2, GPIO_SPEED_50MHz, 1, GPIO_PIN_5 | GPIO_PIN_6},
// UART3-PD8-TX:-PD9:RX
{GPIOD, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_PUPD_NOPULL, GPIO_AF_USART3, GPIO_SPEED_50MHz, 1, GPIO_PIN_8 | GPIO_PIN_9},
// UART4-PC10:TX-PC11:RX
{GPIOC, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_PUPD_NOPULL, GPIO_AF_UART4, GPIO_SPEED_50MHz, 1, GPIO_PIN_10 | GPIO_PIN_11},
// UART6-PC6-TX:-PC7:RX
{GPIOC, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_PUPD_NOPULL, GPIO_AF_USART6, GPIO_SPEED_50MHz, 1, GPIO_PIN_6 | GPIO_PIN_7},
由于APM32完全兼容STM32,寄存器排列一摸一样,知识寄存器名字和位名字有变化,拿STM32上面的程序移植十分方便。仅仅修改创建MODBUS端口的文件即可开始测试。对于串口MODBUS,底层最关键的就是串口初始化和串口中断。代码较多,这里仅贴出最关键的部分(中断)加以说明,感兴趣的小伙伴可以下载贴尾的代码进行测试。
/*****************************************************************************
* @brief UART interrupt routine.
* @param none
* @return none
*****************************************************************************/
void qc_isr()
{
volatile uint32_t IntSt;
volatile uint8_t Data;
IntSt = qc_port->STS;
if (IntSt & (BIT(5) | BIT(3))) // RE ORE
{
Data = UART_RCV_DAT();
if ((IntSt & UART_RX_ERR_FLAG) != 0)
{
if (qc_obj.rx_cnt >= 1)
{
qc_obj.err_hal = 1;
}
UART_RX_ERR_CLR();
}
qc_data_rcv(&qc_obj, Data);
}
else if ((qc_obj.tx_size <= qc_obj.tx_cnt) && (IntSt & BIT(6))) // TC
{
qc_send_end(&qc_obj);
qc_tx1_rx0_enable(0);
UART_TX_TC_CLR();
}
else if (IntSt & BIT(7)) // TE
{
if (qc_data_send(&qc_obj, qc_rtu_byte_send, 1))
{
UART_TX_TC_EN();
}
}
else
{
}
}
中断主要处理三种状态:
a、接受中断:保存数据到BUFF
b、发送空闲中断:继续发送下一个数据
c、发送完成中断:从机结束或主机进入等待。
吐槽一下:APM32的寄存器位操作仅支持位域操作,不像STM32那样有位定义的宏。用官方寄存器定义的话,同一寄存器的多个位也要分开操作,效率较低;并且对于UART状态寄存器中的错误标记位,这些位读自动清除,需要多次使用的话很不方便。上面的程序就很无奈,只好用了BIT(X)宏看着手册编了。好在需要多此判断的地方不多,不然这程序就狗血了。
应用层如下配置,两主两从,主机随意添加两条命令:
void qc_task(const void *argv)
{
qc_cmd_type mcmd;
uu8 bdone;
// master config
qc02_Init(QC_MODE_MASTER, 115200, MB_PAR_NONE);
mb.qc02.os_event_send = mb_os_send;
// master config
qc03_Init(QC_MODE_MASTER, 9600, MB_PAR_NONE);
mb.qc03.os_event_send = mb_os_send;
// slave config
qc04_Init(QC_MODE_SLAVE, 115200, MB_PAR_NONE);
mb.qc04.os_event_send = mb_os_send;
// slave config
qc06_Init(QC_MODE_SLAVE, 9600, MB_PAR_NONE);
mb.qc06.os_event_send = mb_os_send;
// cmd config
mcmd.id = 1;
mcmd.wdat = mb_tst.pv_w;
mcmd.rdat = mb_tst.pv_r;
mcmd.wa = word_make(0xF, 5);
mcmd.wn = 4;
mcmd.ra = word_make(0x00, 0x10);
mcmd.rn = 6;
mcmd.callback = qc_callback;
mcmd.attr = QC_MB_ATTR_HOLD_RW;
mqc_stc_cmd_req(&mb.qc03, 0, &mcmd);
mqc_stc_cmd_req(&mb.qc02, 0, &mcmd);
mqc_stc_cmd_req(&mb.qc04, 0, &mcmd);
mqc_stc_cmd_req(&mb.qc06, 0, &mcmd);
mcmd.wa = word_make(0x10, 12);
mcmd.wn = 0;
mqc_stc_cmd_req(&mb.qc03, 1, &mcmd);
mqc_stc_cmd_req(&mb.qc02, 1, &mcmd);
mqc_stc_cmd_req(&mb.qc04, 1, &mcmd);
mqc_stc_cmd_req(&mb.qc06, 1, &mcmd);
mcmd.wa = word_make(0x0C, 8);
mcmd.wn = 8;
mcmd.ra = word_make(0x0C, 8);
mcmd.rn = 8;
mcmd.wdat = mb_tst.reg_w;
mcmd.rdat = mb_tst.reg_r;
mcmd.attr = QC_MB_ATTR_HOLD_RW;
mb.qc03.fun->stc_cmd_req(2, &mcmd);
mb.qc02.fun->stc_cmd_req(2, &mcmd);
mqc_dyna_cmd_req(&mb.qc03, &mcmd);
mqc_dyna_cmd_req(&mb.qc02, &mcmd);
mqc_dyna_cmd_req(&mb.qc03, &mcmd);
mqc_dyna_cmd_req(&mb.qc02, &mcmd);
loop(32) mb_tst.reg_w[index] = index;
mb_tst.reg_w[0] = 0x5588;
// task handle
for (;;)
{
// wait modbus event
osSemaphoreWait(os_obj.sid_mb, 1000);
qc_mb_poll(&mb.qc03);
qc_mb_poll(&mb.qc02);
qc_mb_poll(&mb.qc04);
qc_mb_poll(&mb.qc06);
}
}
硬件将UART2和UART4相连,UART3和UART6相连,如下图所示:
进入状态观察MODBUS对象结构,观察通信成功次数和失败次数,如下所示,说明MODBUS主从站已通信成功,success_cnt指示执行指令成功次数。
下面进行上位机测试,由于手上仅有一个USB-TLL串口,每次只能测试一个端口,以UART4从站进行说明,串口连接在UART4(PC10,PC11)如下图所示。
打开MODBUS调试工具 Modbus Poll,如下配置:从站ID = 1,波特率115200,帧格式8N2。
从地址0处读取20通道数据,指令周期50ms
配置运行后结果如下:
至此MODBUS移植测试完成,整个过程十分顺利。
测试代码托管在gitee平台:
|