MODBUS是比较常见的工业设备通信协议,战舰板引出了多路串口,今天测试一下多路MODBUS应用。
测试程序使用调试串口和RS485两路,和单片机串口的对应关系如下:
UART1-调试串口
UART2-RS485
移植MODBUS协议,主要是串口的移植,定时器使用系统1ms心跳计时,调用modbus API就可以了。
硬件上RS485串口默认没有连接,需要手动换一下跳线帽位置。
串口移植的关键是初始化和中断处理:
测试程序采用RTU模式,初始化如下:
static void qc_port_Init(uu8 qcMode, uint32_t ulBaudRate, mb_parity_type eParity)
{
LL_USART_InitTypeDef cfg;
qc_port_hal_cfg();
qc_cb_set();
qc_obj.mode = qcMode;
qc_obj.dat_send = qc_port_send;
qc_byte_send = qc_rtu_byte_send;
cfg.BaudRate = ulBaudRate;
cfg.TransferDirection = LL_USART_DIRECTION_TX_RX;
cfg.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
cfg.OverSampling = LL_USART_OVERSAMPLING_16;
if (MB_PAR_NONE == eParity)
{
cfg.Parity = LL_USART_PARITY_NONE;
cfg.StopBits = LL_USART_STOPBITS_2;
cfg.DataWidth = LL_USART_DATAWIDTH_8B;
}
else if (MB_PAR_NONE_1S == eParity)
{
cfg.Parity = LL_USART_PARITY_NONE;
cfg.StopBits = LL_USART_STOPBITS_1;
cfg.DataWidth = LL_USART_DATAWIDTH_8B;
}
else if (MB_PAR_ODD == eParity)
{
cfg.Parity = LL_USART_PARITY_ODD;
cfg.StopBits = LL_USART_STOPBITS_1;
cfg.DataWidth = LL_USART_DATAWIDTH_9B;
}
else
{
cfg.Parity = LL_USART_PARITY_EVEN;
cfg.StopBits = LL_USART_STOPBITS_1;
cfg.DataWidth = LL_USART_DATAWIDTH_9B;
}
if (ulBaudRate > 19200)
{
qc_obj.tim_sv = 3;
}
else
{
qc_obj.tim_sv = (com_timer_cal(ulBaudRate, (35 * 11 + 9) / 10, 300, 12000) + 99) / 100;
}
LL_USART_Init(qc_port, &cfg);
LL_USART_Enable(qc_port);
nvic_irq_set(qc_uart_irqn, 0x06, 1);
qc_tx1_rx0_enable(0);
UART_TX_EN();
}
// 中断处理
void qc_isr()
{
volatile uint32_t IntSt;
volatile uint8_t Data;
IntSt = qc_port->SR;
if (IntSt & (USART_SR_RXNE | USART_SR_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 & USART_SR_TC))
{
qc_send_end(&qc_obj);
qc_tx1_rx0_enable(0);
UART_TX_TC_CLR();
}
else if (IntSt & USART_SR_TXE)
{
if (qc_data_send(&qc_obj, qc_rtu_byte_send, 1))
{
UART_TX_TC_EN();
}
}
else
{
}
}
应用层创建独立任务处理modbus事件。
mbapp.c为任务处理文件,文件中的如下定义用来配置开启哪一路modbus,两路可以同时开启。
#define MB1_EN 1
#define MB2_EN 1
void qc_task(const void *argv)
{
qc_cmd_type mcmd;
uu8 bdone;
#if MB1_EN > 0
qc01_Init(QC_MODE_SLAVE, 9600, MB_PAR_NONE);
mb.qc01.os_event_send = mb_os_send;
#endif
#if MB2_EN > 0
qc02_Init(QC_MODE_SLAVE, 9600, MB_PAR_NONE);
mb.qc02.os_event_send = mb_os_send;
#endif
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;
#if MB1_EN > 0
mqc_stc_cmd_req(&mb.qc01, 0, &mcmd);
#endif
#if MB1_EN > 0
mqc_stc_cmd_req(&mb.qc02, 0, &mcmd);
#endif
loop(32) mb_tst.reg_w[index] = index;
mb_tst.reg_w[0] = 0x5588;
for (;;)
{
osEvent event;
event = osSignalWait(0, 1000);
(void)event;
#if MB1_EN > 0
qc_mb_poll(&mb.qc01);
#endif
#if MB2_EN > 0
qc_mb_poll(&mb.qc02);
#endif
}
}
程序下载测试如下:
代码托管在GITEE,有兴趣的小伙可以一起测试研究:
https://gitee.com/aple_sun/opendev-f1-v4.git