|
i.MX6UL RS232串口通信程序
目标:了解i.MX6UL如何使用串口进行数据通信。
功能:使用串口进行自定义的数据收发,并把收发数据实时在显示屏上显示,实现一个嵌入式上运行的,简单的串口调试助手。
RS232是工业控制上用得比较多的一种通信方式,TQ-i.MX6UL底板引出了8个串口(含命令调试口),各个串口的硬件电路图,请查看官方开发资料。
以下是各个串口的描述:
UART1:调试串口,Debug口,三线(RX, TX, GND),RS232电平。
UART2:与RS485复用,默认RS485通信,用作串口时,4线(5V, TXD, RXD, GND)TTL电平。
UART3:无复用,可选3线(RX, TX, GND)RS232电平或4线(5V, TXD, RXD, GND)TTL电平。
UART4:无复用,可选3线(RX, TX, GND)RS232电平或4线(5V, TXD, RXD, GND)TTL电平。
UART5:无复用,可选3线(RX, TX, GND)RS232电平或4线(5V, TXD, RXD, GND)TTL电平。
UART6:无复用,仅支持4线(5V, TXD, RXD, GND)TTL电平。
UART7:与网口2复用,默认为网口2,用作串口时,4线(5V, TXD, RXD, GND)TTL电平。
UART8:与网口2复用,默认为网口2,用作串口时,4线(5V, TXD, RXD, GND)TTL电平。
由此可见,TQ-i.MX6UL某些串口与其他外设接口进行了复用设计,除了调试串口(UART1)外,其他所有串口均支持TTL电平输出(需要更改某些电阻)。
我们选择无复用功能的RS232串口(UART3, UART4, UART5)进行实验。
软件开发篇:
由于 i.MX6UL开发板运行的是QT4.8,不支持QT自带的串口类库,QT5以上才支持自带串口类。
因此,开发QT5以下的串口应用时,需要借助第三方的串口类,可以通过以下的链接下载:https://sourceforge.net/projects/qextserialport/files/
最新的版本为:qextserialport-1.2win-alpha.zip
在Linux下进行串口应用开发,需要用到以下6个文件:
如果在Windows下只需将posix_qextserialport.cpp/posix_qextserialport.h 换为 win_qextserialport.cpp/win_qextserialport.h即可。
1、先用Qt Creator构建一个工程,命名为:004_uart_test,关于如何构建工程,请参考嵌入式Linux应用程序开发-(1)第一个嵌入式QT应用程序
2、双击打开“widget.ui”文件,构建界面,构建后的界面如下图所示:
界面描述:
PORT:指定需要打开的串口,目前提供 ttySAC1 - ttySAC5。表示UART2 - UART6
BAUDRATE:提供 2400/4800/9600/19200/38400/115200 这几种波特率。
【程序默认8位数据位,1位停止位,无校验位,无流控的设置方式(可通过代码修改)。】
OPEN:设置好串口的工作参数后,点击“OPEN”打开串口。
TX_CLEAR按钮和RX_CLEAR按钮:清空接收和发送的显示区域。
send_data按钮:点击一次,则通过串口发送一次固定数据。
3、为了方便配置和操作串口读写,我们可以把串口相关的操作(配置,读/写串口缓冲区)封装成一个类:Uart_Test,这个类包含了打开和关闭串口的方法,读/写串口缓冲区的方法,类的具体内容如下图所示。
- class Uart_Test : public QWidget
- {
- Q_OBJECT
-
- public:
- Uart_Test();
- ~Uart_Test();
-
- bool open_serial_port(QString port,QString baud);
- bool close_serial_port(void);
- void write_serial_port(char *p_data,int len);
- void write_serial_port(QByteArray arr);
-
- signals:
- void read_serial_signals(QByteArray arr);
-
- private slots:
- void slot_read_serial_port();
-
- private:
- QString port_name;
- BaudRateType baudrate;
- QTimer *recv_timeout_timer;
- Posix_QextSerialPort *serial_port;
- QByteArray recv_data;
- BaudRateType get_baudrate(QString baudrate);
- unsigned int serial_port_recv_len;
- };
复制代码
4、串口类中的bool open_serial_port(QString port,QString baud),具体实现如下:
- bool Uart_Test::open_serial_port(QString port,QString baud)
- {
- this->port_name = QString("/dev/")+port;
- this->baudrate = get_baudrate(baud);
-
- //以查询的方式打开串口
- serial_port = new Posix_QextSerialPort(port_name,QextSerialBase::Polling);
-
- if(serial_port->open(QIODevice::ReadWrite))
- {
- serial_port->setBaudRate(baudrate);
- serial_port->setDataBits(DATA_8);
- serial_port->setParity(PAR_NONE);
- serial_port->setStopBits(STOP_1);
- serial_port->setFlowControl(FLOW_OFF);
- serial_port->setTimeout(1);
-
- recv_timeout_timer = new QTimer();
- //设置100ms的定时器,以查询的方式去读取串口数据
- connect( recv_timeout_timer, SIGNAL(timeout()), this, SLOT(slot_read_serial_port()));
- recv_timeout_timer->start(100);
- return true;
- }
-
- return false;
- }
复制代码
重点:由于第三方的串口类库qextserialport在Linux环境下,不支持以事件方式(EventDriven)去读取串口数据(windows下则同时支持EventDriven和Polling)。
所以,Linux环境下,串口需要配置为Polling的工作方式,并且开启一个周期定时器,去读取串口数据。
(最新的QT5版本添加了串口的操作类QSerialPort,支持事件触发。但目前TQ-i.MX6UL仅支持QT4.8,后续待开发板的QT版本更新后,会同步更新串口通信程序。)
5、串口数据读写函数void slot_read_serial_port() 和 void write_serial_port(QByteArray arr)的具体实现如下所示:
- void Uart_Test::write_serial_port(QByteArray arr)
- {
- if(serial_port->isOpen())
- {
- serial_port->write(arr);
- }
- }
-
- void Uart_Test::slot_read_serial_port()
- {
- if(serial_port->bytesAvailable() > 0)
- {
- recv_data.clear();
- recv_data = serial_port->readAll(); //读取串口缓冲区的所有数据
-
- emit read_serial_signals(recv_data); //发送信号,这个信号会在Widget类的构造函数中,与数据处理函数绑定
- }
- }
复制代码
重点:由于串口数据是通过定时器查询的方式读取,并且一次性读取所有数据。因此,每次串口有数据到达,可能会出现数据粘包或分包的情况。
对于此类情况,建议使用自定义报文的方式,定义数据报文的帧头和帧尾,并使用环形队列处理方式。每次保证接收到完整的数据报文后,再进行数据处理。实验中为了简化工程量,所以并没有采用以上方式。
6、在Widget类的构造函数中,我们定义一个Uart_Test的类对象uart_test。并且通过connect函数把对象uart_test里面的信号void read_serial_signals(QByteArray arr) 与串口数据处理的槽函数void slot_serialport_data_process(QByteArray arr)进行绑定。当串口有数据到达时,可以通过该槽函数进行处理。
- Widget::Widget(QWidget *parent) :
- QWidget(parent),
- ui(new Ui::Widget)
- {
- ui->setupUi(this);
-
- ui->pushButton_open_uart->setCheckable(false);
-
- uart_test = new Uart_Test(); //构建一个uart_test对象
-
- connect(uart_test, SIGNAL(read_serial_signals(QByteArray)), this, SLOT(slot_serialport_data_process(QByteArray))); //绑定串口数据处理的槽函数
- }
复制代码
7、在槽函数void slot_serialport_data_process(QByteArray arr)里,我们把串口接收的数据显示出来,当然,也可以处理其他事务。
- void Widget::slot_serialport_data_process(QByteArray arr)
- {
- char data_out[1024];
-
- memset(data_out,0x00,sizeof(data_out));
- byte_to_str(arr.data(),data_out,arr.length());
-
- display_uart_rx_data(QString(data_out));
- }
复制代码
8、点击send_data按钮,则通过串口发送固定数据,send_data按钮的具体实现如下所示:
- void Widget::on_pushButton_send_data_clicked()
- {
- uart_test->write_serial_port((char*)"helloworld\n",sizeof("helloworld\n"));
-
- display_uart_tx_data(QString("helloworld"));
- }
复制代码
9、所有代码编写完成,下载到TQ-i.MX6UL,运行应用程序,可以看到如下效果。我们使用UART3(ttySAC2)与电脑进行串口数据收发,其他串口操作类似。
点击这里,下载工程源码
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
阿莫论坛20周年了!感谢大家的支持与爱护!!
月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!
|