本博客的全部原創文章採用創做公用版協議。要求署名、非商業用途和保持一致。要求署名必須包含個人網名(geokai)以及文章來源(選擇博客首地址或者具體博文地址)。html
商業性使用須預先徵得本人贊成(發送Email到 geokai@126.com).vue
3.2 串口的操做之Pyserialpython
Python有本身的專用Serial的庫,沒有仔細閱讀qt的代碼不太清楚pyqt的串口庫是否繼承這個庫。git
說說爲何又忽然轉到了這個庫呢,由於上位機與下位機計劃採用ModBus做爲通訊協議。本覺得PyQt是徹底繼承C++ Qt的所有類,可是不行的是並不這樣。全部的QModbus開頭的類在pyqt文檔中都沒有找到。因此徹底以PyQt作所有上位機功能看來不太容易實現。搜索了一番發現Python有一個Modbus_tk這個庫,封裝了Modbus的相關功能,包括rtu,ascii協議模式,master和slave節點模式。而且這個庫直接繼承了Pyserial庫。OK既然這樣那串口的操做直接使用pyserial庫會更簡單和高效。api
Pyserial的官方文檔地址https://pythonhosted.org/pyserial/框架
3.2.1 列出可用串口dom
import serial.tools.list_ports #相應的函數在這個包下面,直接import serial是沒法使用這個工具包的函數
com_list = serial.tools.list_ports.comports() # 返回一個serial.tools.list_ports.ListPortInfo的列表對象,每一個元素均含有串口的多個屬性工具
for port in com_list:oop
print(port.device) #返回端口號如COM3
print(port.describe) #返回設備名字
print(port.location) #返回設備在計算機上的位置
得到這些比較重要的信息後就能夠打開端口了
3.2.2 打開串口
import serial
ser = serial.Serial(com_list[0].device, baudrate=19200, bytesize=EIGHTBITS, parity=PARITY_NONE, stopbits=STOPBITS_ONE, timeout=None, xonxoff=False) #採用直接給參數的方法配置建立一個Serial實例對象,執行完後會直接打開端口
ser = serial.Serial()
ser.baudrate=19200
ser.port=com_list[0].device
ser.open() #這種方式能夠先配置後打開
ser.close()
3.2.3串口的異常狀態判斷
以前採用QSerialPort()類時,有一個error()方法能夠判斷串口的狀態。可是PySerial彷佛沒有這麼完善的功能。我能力不足沒辦法把這個功能實現,這裏介紹一個本身想的能有基本功能的方法。
串口正常打開後,哪怕拔掉設備,使用ser.is_open判斷串口狀態始終是True。可是經過獲取串口信息則獲得一個空的對象。基於這樣的想法從新寫一下打開串口並經過串口發送數據的代碼。
4.通訊部分
這一部分主要實現上位機軟件與下位機的通訊實現。
4.1上位機modbus master
上位機的modbus實現採用python現有的modbus_tk庫來實現,貼上基本代碼
4.2下位機modbus部分基於Arduino
採用arduino的modbus庫,其中設置一個地址爲4的寄存器。
/**
* Modbus slave example 2:
* The purpose of this example is to link the Arduino digital and analog
* pins to an external device.
*
* Recommended Modbus Master: QModbus
* http://qmodbus.sourceforge.net/
*
* Editado al español por LuxARTS
*/
//Incluye la librería del protocolo Modbus
#include <ModbusRtu.h>
#include <stdlib.h>
#define ID 1
//Crear instancia
Modbus slave(ID, 0, 0); //ID del nodo. 0 para el master, 1-247 para esclavo
//Puerto serie (0 = TX: 1 - RX: 0)
//Protocolo serie. 0 para RS-232 + USB (default), cualquier pin mayor a 1 para RS-485
boolean led;
int8_t state = 0;
unsigned long tempus;
uint16_t au16data[9]; //La tabla de registros que se desea compartir por la red
/*********************************************************
Configuración del programa
*********************************************************/
void setup() {
io_setup(); //configura las entradas y salidas
slave.begin(19200); //Abre la comunicación como esclavo
tempus = millis() + 100; //Guarda el tiempo actual + 100ms
digitalWrite(13, HIGH ); //Prende el led del pin 13 (el de la placa)
au16data[4] = 0x8000;
}
/*********************************************************
Inicio del programa
*********************************************************/
void loop() {
//Comprueba el buffer de entrada
state = slave.poll( au16data, 9 ); //Parámetros: Tabla de registros para el intercambio de info
// Tamaño de la tabla de registros
//Devuelve 0 si no hay pedido de datos
//Devuelve 1 al 4 si hubo error de comunicación
//Devuelve mas de 4 si se procesó correctamente el pedido
if (state > 4) { //Si es mayor a 4 = el pedido fué correcto
tempus = millis() + 50; //Tiempo actual + 50ms
digitalWrite(13, HIGH);//Prende el led
}
if (millis() > tempus) digitalWrite(13, LOW );//Apaga el led 50ms después
//Actualiza los pines de Arduino con la tabla de Modbus
io_poll();
}
/**
* pin maping:
* 2 - digital input
* 3 - digital input
* 4 - digital input
* 5 - digital input
* 6 - digital output
* 7 - digital output
* 8 - digital output
* 9 - digital output
* 10 - analog output
* 11 - analog output
* 14 - analog input
* 15 - analog input
*
* pin 13 reservado para ver el estado de la comunicación
*/
void io_setup() {
pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(4, INPUT);
pinMode(5, INPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(13, OUTPUT);
digitalWrite(6, LOW );
digitalWrite(7, LOW );
digitalWrite(8, LOW );
digitalWrite(9, LOW );
digitalWrite(13, HIGH ); //Led del pin 13 de la placa
analogWrite(10, 0 ); //PWM 0%
analogWrite(11, 0 ); //PWM 0%
}
/*********************************************************
Enlaza la tabla de registros con los pines
*********************************************************/
void io_poll() {
long temp;
// digital inputs -> au16data[0]
// Lee las entradas digitales y las guarda en bits de la primera variable del vector
// (es lo mismo que hacer una máscara)
bitWrite( au16data[0], 0, digitalRead( 2 )); //Lee el pin 2 de Arduino y lo guarda en el bit 0 de la variable au16data[0]
bitWrite( au16data[0], 1, digitalRead( 3 ));
bitWrite( au16data[0], 2, digitalRead( 4 ));
bitWrite( au16data[0], 3, digitalRead( 5 ));
// digital outputs -> au16data[1]
// Lee los bits de la segunda variable y los pone en las salidas digitales
digitalWrite( 6, bitRead( au16data[1], 0 )); //Lee el bit 0 de la variable au16data[1] y lo pone en el pin 6 de Arduino
digitalWrite( 7, bitRead( au16data[1], 1 ));
digitalWrite( 8, bitRead( au16data[1], 2 ));
digitalWrite( 9, bitRead( au16data[1], 3 ));
// Cambia el valor del PWM
analogWrite( 10, au16data[2] ); //El valor de au16data[2] se escribe en la salida de PWM del pin 10 de Arduino. (siendo 0=0% y 255=100%)
analogWrite( 11, au16data[3] );
temp=au16data[4];
// Serial.write(temp>>16);
// Serial.write(temp>>8);
// Serial.write(temp);
// Lee las entradas analógicas (ADC)
temp=(long)temp+(long)(random(-3,4));
//temp=-1;
// Serial.write(temp>>24);
// Serial.write(temp>>16);
// Serial.write(temp>>8);
// Serial.write(temp);
temp=temp<0?0:temp;
temp=temp>65535?65535:temp;
//temp=temp<0?0:temp;
//temp=temp>65535?65535:temp;
au16data[4] = temp;
//au16data[4] = byte(random(65530,65535));//analogRead( 0 ); //El valor anaalógico leido en el pin A0 se guarda en au16data[4]. (siendo 0=0v y 1023=5v)
au16data[5] = 0xffff;
// Diagnóstico de la comunicación (para debug)
au16data[6] = slave.getInCnt(); //Devuelve cuantos mensajes se recibieron
au16data[7] = slave.getOutCnt(); //Devuelve cuantos mensajes se transmitieron
au16data[8] = slave.getErrCnt(); //Devuelve cuantos errores hubieron
}
#至此基本的框架已經搭出來了,上位機與下位機的通信也打通了。硬件上的問題已經基本解決
後面開始專一的GUI的編寫。
做者:geokai
出處: https://www.cnblogs.com/geokai/
本文版權歸做者geokai和博客園全部,歡迎轉載和商用,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利.
若有問題, 可郵件(geokai@126.com)諮詢.