概述
原来一直用74HC04配合SP3485做RS485输出模块,对SP3485模块的DE/RE#端不控制。线路图如下:
但这次因为线路板尺寸紧张,并且有多余的点可以控制DE/RE#, 就选择了如下的线路:
现在来说一下编程遇到的困惑和解决问题的思路。
编程方法
方法一
当要向外部输出数据数据时,采用delay(10) 的方式,才能让串口的数据输出到外部接口。
比如我使用了RX2,TX2作为RS485的输出模块。程序应该这样,不然不能输出数据。
if ( Serial.available())
{
uint8_t x = Serial.read();
if ( x == 's' )
{
char sendBuff[] = "Send message to RS485";
digitalWrite(DE_485, HIGH);
Serial2.println(sendBuff);
delay(10);
digitalWrite(DE_485, LOW);
Serial.println("Message sneded to RS485");
}
}
程序说明:如果在digitalWrite(DE_485, HIGH)后不延时10ms的话无法在串口2上输出信息。在程序中添加这个delay(10)后可以正常输出了。还没有试,大量的数据可能要延长这个延时时间。
方法二
采用中断的方式。
中断程序:
void IRAM_ATTR isrDown() // edge falling
{
digitalWrite(DE_485, HIGH);
}
void IRAM_ATTR isrRDown() // edge falling
{
digitalWrite(DE_485, LOW);
}
在setup中将中断程序分配给特定的端子:
attachInterrupt(17, isrDown, FALLING);
attachInterrupt(16, isrRDown, RISING);
17是TX2,16是RX2,分别是串口2对应的TX和RX。这时,程序就像RS232或USB普通串口一样发送和接收就可以了。
if ( Serial.available())
{
uint8_t x = Serial.read();
if ( x == 's' )
{
char sendBuff[] = "Send message to RS485";
Serial2.println(sendBuff);
Serial.println("Message sneded to RS485");
}
}
2024年4月21日,看了现在的库,好像是有了变化,过去没有注意到。ESP32的HardwareSerial库。可以实现对RS485的流硬件进行控制,具体方法:
const uint8_t RS485_RX2_PIN = 16; // Serial2 RXD2
const uint8_t RS485_TX2_PIN = 17; // Serial2 TXD2
const uint8_t RS485_RTS2_PIN = 4; // flow control
定义管脚,RX2和TX2是默认的Serial2的管脚。
HardwareSerial RS485(2); //在这里定义第二个串口,名字为RS485
RS485.begin(2073600, SERIAL_8N1, RS485_RX2_PIN, RS485_TX2_PIN);
if ( !RS485.setPins(-1, -1, -1, RS485_RTS2_PIN)) // 用RTS控制DE/RE端
{
Serial.println("Failed to set RS485 pins");
}
if (!RS485.setMode(MODE_RS485_HALF_DUPLEX))
{
Serial.println("Failed to set RS485 mode");
}
RS485.setRxTimeout(10);
RS485.onReceive(OnCallback, true);
这里我们实验波特率,最高能够达到多少的波特率,并用RTS管脚控制DE/RE端。
void OnCallback()
{
uint8_t dLen = RS485.available();
Serial.print("Bytes received = ");
Serial.println(dLen);
if ( dLen == 0 ) return;
RS485.readBytes(rx2Buff, dLen);
printHEX(rx2Buff, dLen);
}
上面是自动接收程序并打印的串口1.
总结
从程序可以看出,Arduino还是有操作系统的特点,在代码上看Serial2.println(sendBuff)在后台是运行的,当我们发送这个指令时,后台按波特率不断的执行,这条语句后面如果直接执行digitalWrite(DE_485, LOW), 会使数据发送不出去。采用中断形式是一种尝试。或许在频繁操作的RS485时会不会健康运行有待于验证,也希望网友提宝贵意见。
现在版本的HardwareSerial库也支持RS485的流控制了。方法是:
Serial2.begin(115200);
// bool setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin = -1, int8_t rtsPin = -1);
Serial2.setPins(-1, -1, -1, DE485);
Serial2.setMode(MODE_RS485_HALF_DUPLEX);
上面的代码可以是程序直接读串口和写串口,不需要考虑流控制。但似乎一切并不那么顺利,在波特率是57600的情况下,情况变得不丝滑了,多了一个字节,0x00. 不停得发送,不能停止。有指导得大咖看一下,哪里不对。2024-4-18, 问题解决。
使用ESP8266的模块发现Arduino编程时在使用SoftwareSerial库时有:
/// Transmit control pin.
void setTransmitEnablePin(int8_t txEnablePin);
可以用这个函数来定义DE485输出点。但在使用过程中发现,当波特率较高时,出错的机率比较高,200ms发送一次,一晚上出现了200多次的收发故障。选用的波特率时57600. 说明在高波特率情况下不稳定。