本帖最后由 aple0807 于 2023-10-29 10:38 编辑
今天测试一下基于UART的MODBUS-RTU,AT32F423多大8路UART,做工业仪表是个不错的选择。
本次测试使用两个串口:
USART2配置为从机:9600,8N2, 站号1
USART3配置为主站:9600,8N2, 配置命令访问站号1
IO配置:
// U2
{GPIOA, GPIO_MODE_MUX, GPIO_DRIVE_STRENGTH_STRONGER, GPIO_OUTPUT_PUSH_PULL, GPIO_PULL_NONE, GPIO_MUX_7, GPIO_PINS_2 | GPIO_PINS_3},
// U3
{GPIOB, GPIO_MODE_MUX, GPIO_DRIVE_STRENGTH_STRONGER, GPIO_OUTPUT_PUSH_PULL, GPIO_PULL_NONE, GPIO_MUX_7, GPIO_PINS_10 | GPIO_PINS_11},
串口初始化:
/*****************************************************************************
* [url=home.php?mod=space&uid=247401]@brief[/url] com modle init .
* @param none
* [url=home.php?mod=space&uid=266161]@return[/url] none
* [url=home.php?mod=space&uid=72445]@[/url] Pass/ Fail criteria: none
*****************************************************************************/
static void qc_port_Init(uu8 qcMode, uint32_t ulBaudRate, mb_parity_type eParity)
{
usart_data_bit_num_type dat_bits;
usart_stop_bit_num_type stop_bits;
usart_parity_selection_type parity;
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;
// rtu mode
if (MB_PAR_NONE == eParity)
{
dat_bits = USART_DATA_8BITS;
stop_bits = USART_STOP_2_BIT;
parity = USART_PARITY_NONE;
}
else if (MB_PAR_NONE_1S == eParity)
{
dat_bits = USART_DATA_8BITS;
stop_bits = USART_STOP_1_BIT;
parity = USART_PARITY_NONE;
}
else if (MB_PAR_ODD == eParity)
{
dat_bits = USART_DATA_9BITS;
stop_bits = USART_STOP_1_BIT;
parity = USART_PARITY_ODD;
}
else
{
dat_bits = USART_DATA_9BITS;
stop_bits = USART_STOP_1_BIT;
parity = USART_PARITY_EVEN;
}
// rtu timer
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;
}
usart_init(qc_port, ulBaudRate, dat_bits, stop_bits);
usart_parity_selection_config(qc_port, parity);
usart_enable(qc_port, TRUE);
nvic_irq_set(qc_uart_irqn, 0x00, 1);
qc_tx1_rx0_enable(0);
UART_TX_EN();
}
中断处理:
/*****************************************************************************
* [url=home.php?mod=space&uid=247401]@brief[/url] UART interrupt routine.
* @param none
* [url=home.php?mod=space&uid=266161]@return[/url] none
*****************************************************************************/
void qc_isr()
{
volatile uint32_t IntSt;
volatile uint8_t Data;
IntSt = qc_port->sts;
if (IntSt & USART_RDBF_FLAG)
{
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_TDC_FLAG))
{
qc_send_end(&qc_obj);
qc_tx1_rx0_enable(0);
UART_TX_TC_CLR();
}
else if (IntSt & USART_TDBE_FLAG)
{
if (qc_data_send(&qc_obj, qc_rtu_byte_send, 1))
{
UART_TX_TC_EN();
}
}
else
{
}
}
U3主站命令:
void qc_init(void)
{
// master config
qc03_Init(QC_MODE_MASTER, 9600, MB_PAR_NONE);
mb.qc03.os_event_send = mb_os_send;
mcmd.id = 1;
mcmd.wdat = &mb_input[0].uval;
mcmd.rdat = &mb_input[0].uval;
mcmd.wa = 0;
mcmd.wn = 96;
mcmd.ra = 0x1800;
mcmd.rn = 1;
mcmd.callback = qc_callback;
mcmd.attr = QC_MB_ATTR_HOLD_MW;
mqc_stc_cmd_req(&mb.qc03, 0, &mcmd);
mcmd.wdat = &mb_input[0].uval;
mcmd.wa = 96;
mcmd.wn = 96;
mqc_stc_cmd_req(&mb.qc03, 1, &mcmd);
// slave config
qc02_Init(QC_MODE_SLAVE, 9600, MB_PAR_NONE);
mb.qc02.os_event_send = mb_os_send;
mcmd.id = 1;
mcmd.wdat = &mb_input[0].uval;
mcmd.rdat = &mb_input[0].uval;
mcmd.wa = 16;
mcmd.wn = 16;
mcmd.ra = 0;
mcmd.rn = 8;
mcmd.callback = qc_callback;
mcmd.attr = QC_MB_ATTR_HOLD_MW;
mqc_stc_cmd_req(&mb.qc02, 0, &mcmd);
mqc_stc_cmd_req(&mb.qc02, 1, &mcmd);
}
测试时,将评估板PA2连接PB10, PA3连接PB11可完成两个端口通信,运行结果如下:
为方便运行时观察,可以显示串口通信信息到OLED显示屏,效果如下:
任务资源信息:
至此,modbus移植测试成功,可以用来连接各种modbus接口的传感器和PLC设备了。
下面附上测试代码:
AT32F423_EVAL.rar
(4.59 MB)
编译环境:IAR EW for Arm 9.40
|