Actualmente existen una infinidad de dispositivos convertidores TTL/RS232 al protocolo USB, y básicamente emulan la comunicación serie en nuestro ordenador asignando un puerto COMxx(Windows) o ttyUSBxx(Linux).
Desde el punto de vista del diseñador electrónico, para obtener conectividad USB en el microcontrolador sera necesario agregar al circuito un chip convertidor como el CP210x, FT232, CH340, PL230x, etc, y así establecer una comunicación segura y transparente con el ordenador. Otra alternativa es buscar un microcontrolador que incluya el hardware necesario para implementar el protocolo en su memoria.
El objetivo de esta entrada es poder implementar la comunicación serial con el ordenador sin hacer uso de un convertir externo, puesto que existen muchos microcontroladores PIC que poseen los recursos para soportar la pila USB haremos uso de un modelo en particular correspondiente a la serie PIC16F creando un programa para enviar información de estado de una entrada digitale y una analógica al ordenador, en el ordenador veremos estos mensajes utilizando una aplicación terminal. También a manera de complemento crearemos una pequeña aplicación en Qt para visualizar los datos USB.
La programación se realizara utilizando el compilador XC8, el entorno de desarrollo MPLABX y la utilidad MMC(Microchip Code Configurator), todo disponible de forma gratuita en la pagina de microchip. Ahí les paso los links oficiales para la descarga de las versiones que utilizo en el ejemplo:
1. Protocolo USB y la Clase CDC
El protocolo implementa una topologia en estrella con la posibilidad de conectar hasta 127 dispositivos administrados por un solo host, en algunos casos el rol de host se negocia entre dos dispositivos mediante un protocolo conocido como OTG.
El host(Computadora) efectúa la mayor parte de la actividad que requiere el protocolo, normalmente el sistema operativo del ordenador carga los drivers necesarios en forma dinámica cuando se conecta un dispositivo al bus(PIC), y es identificado mediante el par PID(Product ID) / VID(Vendor ID).
USB soporta cuatro modos de transferencia: Control, Interrupción(Interrupt), Masiva(Bulk) e Isócrona(Isochronous), y distribuye la alimentación de 5V a todos los dispositivos sin necesidad de una fuente externa, esto siempre y cuando el dispositivo sea de bajo consumo, aqui la limitacion va de acuerdo a la versión: 500mA(USB2.0) y 900mA(USB3.0).
Los niveles lógicos se representan por la diferencia de al menos 200mV entre las lineas D+ y D-, siendo 1 lógico cuando D- es mayor a D+ y 0 lógico cuando D- es menor a D+. A diferencia de RS‐232 o interfaces serie similares donde el formato de los datos no están definidos, en USB existen varias capas del protocolo que definen el tamaño de los paquetes que se enviaran.
En este punto quiero mencionar que la comprensión de los detalles de este protocolo con respecto a su funcionamiento van mucho mas allá de lo que explica este blog. Si realmente estas interesado en conocer con mayor profundidad este extenso protocolo te recomiendo dar lectura a la documentación oficial de grupo USB-IF que promueve y brinda soporte al estándar.
Como nuestra finalidad es comunicar una computadora(Host) con el PIC(Device), desde el lado del PIC trabajaremos con la utilidad MCC(Mplab Code Configurator) que nos librara de entrar en los detalles que ocurren en niveles inferiores del protocolo.
- CDC(Communication Device Class): Utilizado para establecer una comunicación emulando el comportamiento de un puerto serial(RS232, TTL, etc).
- HID(Human Interface Class): Esta clase permite conectar dispositivos de entrada(ratón, teclado, impresora, etc) a la computadora y simplificar el proceso de instalación.
Optaremos por utilizar CDC y mas propiamente la subclase ACM(Abstract Control Layer) que brinda mejor soporte de dispositivos y la mayoría de los sistemas operativos incorporan su funcionalidad sin necesidad de utilizar archivos(drivers) adicionales. En Windows un dispositivo CDC conectado aparece como un puerto serie COMx, y en linux se crea el vinculo raíz /dev/ttyACMx.
2. Microcontrolador PIC16F145x
Actualmente microchip ofrece un amplio numero de microcontroladores que soportan la comunicación USB, en todas las gamas de 8, 16 y 32 bits. En particular he optado en utilizar el PIC16F1455 que junto al PIC16F1454 son de los microcontroladores que menos componentes externos requieren para funcionar y ademas su disponibilidad en encapsulado de 14-pines me hacen pensar en lo simple y económico que resulta la implementación del protocolo USB.
Veamos un resumen de las características de este PIC que es relativamente nuevo y forma parte de los productos que utilizan la tecnología XLP(Xtreme Low Power).
- Voltaje de operación 2.3V a 5.5V
- Frecuencia máxima 48MHz
- Memoria de programa FLASH 14Kbytes
- Memoria de datos RAM 1Kbytes
- Memoria de datos EEPROM 128bytes
- Puertos USB compatible para V2.0
- Módulos TMR0/1/2, PWM1/2, MSSP, EUSART
Adicionalmente el PIC16F1455 cuenta con:
- Modulo Comparador 2 canales
- Modulo CWG de 4 fuentes
- Modulo FVR de tres ajustes
- Modulo ADC de 10-bits
- Modulo DAC de 5-bits
Como les comentaba son muchas las cualidades que posee este microcontrolador, y si revisas la hoja de datos encontraras aun mas elementos como ser el sensor de temperatura incorporado.
El circuito utilizado para trabajar con el ejemplo de este blog es muy simple y puede montarse en un protoboard pequeño, el único inconveniente dependiendo de tu país sera contar con el microcontrolador PIC, aquí en mi cuidad la única manera de obtener uno es mediante compra de tiendas en linea como Digi-Key o Mouser.
Una vez montado el circuito en el protoboard, conectamos el programador de PIC(Pickit3) y creamos un proyecto MPLABX con el programa del microcontrolador, para conectar y probar la funcionalidad del puerto USB utilice un cable de teléfono cortado a la mitad, un extremo se conectara a la computadora y el otro directo al protoboard tal como como se ve en la siguiente imagen.
3. Configuración MPLABX y MCC
Ahora llego la hora de trabajar en el programa del PIC, y como primer paso crearemos un proyecto nuevo configurando los recursos a utilizar.Recuerda que deberás tener instalado en tu PC la aplicación MPLABX y el compilador XC8, así una vez abierto el IDE seleccionas en el menú principal Tools->Plugins->Available Plugins la utilidad MPLAB Code Configurator para que empiece su instalación, asegurate de estar conectado a internet. Luego finalizada la instalación es probable que te pida reiniciar el IDE, y luego cuando vuelves a arrancar podrás verificar en Tools->Plugins->Installed si la utilidad esta instalada.
Aquí creamos un nuevo proyecto seleccionando como dispositivo el PIC16F1455 y el compilador XC8, luego seleccionamos en el menú Tools->Embedded->MPLAB Code Configurator, que nos abrirá una pantalla de asistencia para realizar la configuración inicial de los recursos que se utilizaran en el PIC, básicamente ajustaremos los fusibles, el oscilador y puertos.
La configuración de los fusibles lo hacemos desde la pestaña System Module->Registers, donde desactivamos el circuito de reinicio Reset MLCR seleccionando el pin como una entrada digital
El oscilador se ajusta también en la mista pestaña, con los valores seleccionados trabajaremos con el oscilador integrado a una frecuencia de 48MHz/3 que son 16MHz y un ciclo de instrucción de 0.25uS.
La configuración de los fusibles lo hacemos desde la pestaña System Module->Registers, donde desactivamos el circuito de reinicio Reset MLCR seleccionando el pin como una entrada digital
Con la pestaña Pin Module, definimos los nombres de cada pin y demas opciones, aquí debemos habilitar la resistencia pull-up del pin RA5 donde se conectara el pulsador BUT1, esta habilitación es individual en cada pin y se necesita también habilitar la opción en todo el puerto con el bit nWPUEN en Module->Register.
Ahora buscamos y agregamos los módulos TMR0, ADC y USB de la ventana Device Resources
El modulo USB se basa en una librería MLA modificada para configurar las opciones de la clase CDC, lo único que cambie aquí fue el String del producto.
Finalmente se procede a generar el código con la pestaña Generate, creando toda la estructura lógica de nuestro proyecto, muchos de estos archivos no se tocaran y solo se trabajara en el archivo main.c
4. Programando la comunicación USB
En la estructura del proyecto trabajamos solo con el archivo main.c, para elaborar un programa que realice lo siguiente:
En la estructura del proyecto trabajamos solo con el archivo main.c, para elaborar un programa que realice lo siguiente:
- Destellar el LED1 cada segundo
- Indicar a través del LED2 si se estableció la conexión USB
- Verificar si el pulsador BUT1 es presionado, en caso de ser así enviar un mensaje vía USB con un valor que indique su estado.
- Leer el voltaje POT1 y si hay una diferencia con un lectura previa, enviar un mensaje vía USB con un valor que indique su magnitud.
El código del programa principal se detalla mas abajo, en el archivo muchas lineas ya fueron insertadas por el configurador MCC cuando se genero el proyecto, por eso adicione unicamente las variables y procedimientos APPTask y USBTask.
- APPTask es responsable de las entradas BUT1, POT1 y el LED1 haciendo control de los cambios conforme a los procedimientos descritos anteriormente.
- USBTask es responsable de la conectividad USB con el Host(PC), y dependiendo del estado enviara como mensaje las variables que fueron registradas en APPTask.
#include "mcc_generated_files/mcc.h"
#include <string.h>
#include <stdio.h>
static uint8_t writeBuffer[64]; //Declaracion del buffer de salida
volatile char adcOK = 0, butOK = 0; //Banderas de control
volatile char butval, adcval; //Variables de lectura
void APPTasks(); //Prototipo del procedimiento APP
void USBTasks(void); //Prototipo del procedimiento USB
void main(void) //Programa principal
{
SYSTEM_Initialize(); //Inicializa Puertos, Perifericos, etc
INTERRUPT_GlobalInterruptEnable(); //Activa las interrupciones
INTERRUPT_PeripheralInterruptEnable();
ADC_SelectChannel(POT1); //Selecciona el canal de captura ADC
TMR0_SetInterruptHandler(APPTasks); //Asigna la tarea ISR cada 1ms
while(1)
{
USBTasks(); //Ajecucion continua del procedimiento USB
}
}
#include <string.h>
#include <stdio.h>
static uint8_t writeBuffer[64]; //Declaracion del buffer de salida
volatile char adcOK = 0, butOK = 0; //Banderas de control
volatile char butval, adcval; //Variables de lectura
void APPTasks(); //Prototipo del procedimiento APP
void USBTasks(void); //Prototipo del procedimiento USB
void main(void) //Programa principal
{
SYSTEM_Initialize(); //Inicializa Puertos, Perifericos, etc
INTERRUPT_GlobalInterruptEnable(); //Activa las interrupciones
INTERRUPT_PeripheralInterruptEnable();
ADC_SelectChannel(POT1); //Selecciona el canal de captura ADC
TMR0_SetInterruptHandler(APPTasks); //Asigna la tarea ISR cada 1ms
while(1)
{
USBTasks(); //Ajecucion continua del procedimiento USB
}
}
void APPTasks() //Procedimiento APP cada 1mS via ISR
{
unsigned int val;
static unsigned int but1cnt = 0, led1cnt = 0, adc1cnt = 0;
//Inicio del Control para LED1
led1cnt ++;
if(led1cnt > 499) //cada 500ms
{
LED1_Toggle(); //Destella led
led1cnt = 0;
}
{
unsigned int val;
static unsigned int but1cnt = 0, led1cnt = 0, adc1cnt = 0;
//Inicio del Control para LED1
led1cnt ++;
if(led1cnt > 499) //cada 500ms
{
LED1_Toggle(); //Destella led
led1cnt = 0;
}
//Inicio del Control para BUT1
val = BUT1_GetValue(); //Lectura del pulsador BUT
if(val != butval) //Solo si BUT cambia de estadoT
{
but1cnt ++;
if(but1cnt > 300) //si mantiene por 300ms
{
butval = !butval; //Actuliza estado BUT
butOK = 1; //Indica cambio de estado BUT
}
}
else but1cnt = 0;
val = BUT1_GetValue(); //Lectura del pulsador BUT
if(val != butval) //Solo si BUT cambia de estadoT
{
but1cnt ++;
if(but1cnt > 300) //si mantiene por 300ms
{
butval = !butval; //Actuliza estado BUT
butOK = 1; //Indica cambio de estado BUT
}
}
else but1cnt = 0;
//Inicio de Control para ADC
adc1cnt ++;
if(adc1cnt == 199) ADC_StartConversion(); //inicia en 200ms
if((adc1cnt > 399) && ADC_IsConversionDone()) //Espera 200ms
{
val = (ADC_GetConversionResult() >> 6) / 10; //Lectura valor
if(val != adcval) //Si valor es diferente
{
adcval = val;
adcOK = 1; //indica cambio de valor POT
}
adc1cnt = 0;
}
}
void USBTasks(void) //Procedimiento que atiende a CDC-USB
{
if( USBGetDeviceState() < CONFIGURED_STATE ) return;
LED2_SetHigh(); //Activa LED1 cuendo USB esta configurado
if(USBUSARTIsTxTrfReady()) //Si el Buffer de salida esta libre
{
if(butOK) //Verifica si hay cambio de estado BUT
{
butOK = 0;
sprintf((char *) writeBuffer, "B:%u\n", butval);
putUSBUSART(writeBuffer,4); //Envia mensaje
}
if(adcOK) //Verifica si hay cambio de estado POT
{
adcOK = 0;
sprintf((char *) writeBuffer, "V:%03u\n", adcval);
putUSBUSART(writeBuffer,6); //Envia mensaje
}
}
CDCTxService(); //Procesa servicio USB
}
{
if( USBGetDeviceState() < CONFIGURED_STATE ) return;
LED2_SetHigh(); //Activa LED1 cuendo USB esta configurado
if(USBUSARTIsTxTrfReady()) //Si el Buffer de salida esta libre
{
if(butOK) //Verifica si hay cambio de estado BUT
{
butOK = 0;
sprintf((char *) writeBuffer, "B:%u\n", butval);
putUSBUSART(writeBuffer,4); //Envia mensaje
}
if(adcOK) //Verifica si hay cambio de estado POT
{
adcOK = 0;
sprintf((char *) writeBuffer, "V:%03u\n", adcval);
putUSBUSART(writeBuffer,6); //Envia mensaje
}
}
CDCTxService(); //Procesa servicio USB
}
Una vez terminada la edición se procede a compilar y cargar el programa al microcontrolador, aquí hago uso de un programador Pickit3
Ya con el programa cargado en el PIC16F1455, vamos a conectarlo a un puerto USB de la computadora, si todo marcha bien el LED1 estaría destellando y el LED2 se mantendrá encendido. Utilizando el comando lsusb de linux podemos ver como el sistema operativo ha reconocido nuestro dispositivo USB, ver imagen:
5. Conectado al puerto USB
6. Recepción del mensaje en QT
Ya con el proyecto creado y configurado adicionare un formulario visual mainwindow.ui en la que insertare los siguientes elementos(objetos visuales):
un checkbox para conectar y desconectar la recepción del puerto, un textEdit para mostrar el valor del BUT y otro textEdit_2 para mostrar el valor del POT, adicional hay unos labels que indican la funcionalidad de cada elemento.
un checkbox para conectar y desconectar la recepción del puerto, un textEdit para mostrar el valor del BUT y otro textEdit_2 para mostrar el valor del POT, adicional hay unos labels que indican la funcionalidad de cada elemento.
QT cuenta con la clase QSerial y la misma se debe agregar al proyecto adicionando QT += serialport en el archivo de proyecto CDC_PICMonitor.pro, y partir de aquí trabajare solo con los archivos del programa principal que son:
mainwindow.h
#include <QMainWindow>
#include <QtSerialPort>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void readSerialPort(); //Procedimiento que atendera la recepcion
void on_checkBox_stateChanged(int arg1);
private:
Ui::MainWindow *ui;
QSerialPort *port;
};
#include <QtSerialPort>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void readSerialPort(); //Procedimiento que atendera la recepcion
void on_checkBox_stateChanged(int arg1);
private:
Ui::MainWindow *ui;
QSerialPort *port;
};
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
port = new QSerialPort(); //Instancia a la clase
connect(port, SIGNAL(readyRead()), this, SLOT(readSerialPort()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::readSerialPort() //Cuerpo del Procedimiento
{
QByteArray databytes;
if(port->canReadLine()) //Si hay mensaje recibido
{
databytes = port->readLine(); //Recibe el mensaje
QString msg(databytes);
if(msg.at(0) == 'B') //Si el mensaje es del BUT
{
ui->lineEdit_2->setText(msg.remove(0,2)); //Actualiza
}
if(msg.at(0) == 'V') //Si el mensaje es del POT
{
ui->lineEdit->setText(msg.remove(0,2)); //Actualiza
}
}
}
void MainWindow::on_checkBox_stateChanged(int arg1)
{
if(ui->checkBox->isChecked())
{
port->setPortName("/dev/ttyACM0");
port->setBaudRate(port->Baud9600, port->Input);
port->setFlowControl(port->NoFlowControl);
if(port->open(QIODevice::ReadOnly)) //Abre el puerto para lectura
ui->statusbar->showMessage("Puerto Conectado", 0);
else
ui->statusbar->showMessage("Error de conexion", 0);
}
else
{
if(port->isOpen())
{
port->close();
ui->statusbar->showMessage("Puerto Desconectado", 5000);
}
}
}
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
port = new QSerialPort(); //Instancia a la clase
connect(port, SIGNAL(readyRead()), this, SLOT(readSerialPort()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::readSerialPort() //Cuerpo del Procedimiento
{
QByteArray databytes;
if(port->canReadLine()) //Si hay mensaje recibido
{
databytes = port->readLine(); //Recibe el mensaje
QString msg(databytes);
if(msg.at(0) == 'B') //Si el mensaje es del BUT
{
ui->lineEdit_2->setText(msg.remove(0,2)); //Actualiza
}
if(msg.at(0) == 'V') //Si el mensaje es del POT
{
ui->lineEdit->setText(msg.remove(0,2)); //Actualiza
}
}
}
void MainWindow::on_checkBox_stateChanged(int arg1)
{
if(ui->checkBox->isChecked())
{
port->setPortName("/dev/ttyACM0");
port->setBaudRate(port->Baud9600, port->Input);
port->setFlowControl(port->NoFlowControl);
if(port->open(QIODevice::ReadOnly)) //Abre el puerto para lectura
ui->statusbar->showMessage("Puerto Conectado", 0);
else
ui->statusbar->showMessage("Error de conexion", 0);
}
else
{
if(port->isOpen())
{
port->close();
ui->statusbar->showMessage("Puerto Desconectado", 5000);
}
}
}
Finalizada la edición y previa compilación de este programa, lo corremos y conectamos nuestro circuito PIC al ordenador, luego hacemos click en conectar para ver como se muestra la información del BUT y POT en las casillas textEdit.
7. Visualización con QML
Agregamos al proyecto un archivo QML con nombre QMView1.qml y en este archivo en la vista de edición escribimos el siguiente código base.
import QtQuick 2.0
import QtQuick.Controls 2.3
import QtQuick.Extras 1.4
Rectangle
{
id: rectangle1
x: 0
y: 0
width: 500
height: 300
color: "#000000"
}
import QtQuick.Controls 2.3
import QtQuick.Extras 1.4
Rectangle
{
id: rectangle1
x: 0
y: 0
width: 500
height: 300
color: "#000000"
}
Esto crea un rectangulo de 500 x 300 pixels con fondo negro, sobre este rectangulo en la vista de diseño agregamos un componente Gauge y un Status Indicator, el primero lo utilizaremos para ver la magnitud del POT y el segundo para el estado del BUT, tambien adicionare un texto de referencia para indicar el nombre del programa.
Ya con esto pasare dar una toque personalizado a cada elemento, agregando las siguientes lineas al archivo QMLView1, dejando como resultado lo siguiente:
import QtQuick 2.0
import QtQuick.Controls 2.3
import QtQuick.Extras 1.4
Rectangle
{
id: rectangle1
x: 0
y: 0
width: 500
height: 300
color: "#000000"
Text {
id: element
x: 156
y: 14
color: "#ffffff"
text: qsTr("CDC PIC MONITOR")
font.bold: false
fontSizeMode: Text.FixedSize
font.pixelSize: 18
}
Gauge {
objectName: "pot1"
id: gauge
x: 4
y: 200
width: 492
height: 74
orientation: 1
maximumValue: 100
value: 50
}
StatusIndicator {
objectName: "but1"
id: statusIndicator
x: 299
y: 84
width: 84
height: 70
color: "#30ff00"
active: false
}
Text {
id: element1
x: 308
y: 63
width: 66
height: 15
color: "#ffffff"
text: qsTr("PULSADOR")
font.pixelSize: 12
}
Text {
id: element2
x: 17
y: 174
color: "#f4f1f1"
text: qsTr("ADC PULSADOR")
font.pixelSize: 12
}
import QtQuick.Controls 2.3
import QtQuick.Extras 1.4
Rectangle
{
id: rectangle1
x: 0
y: 0
width: 500
height: 300
color: "#000000"
Text {
id: element
x: 156
y: 14
color: "#ffffff"
text: qsTr("CDC PIC MONITOR")
font.bold: false
fontSizeMode: Text.FixedSize
font.pixelSize: 18
}
Gauge {
objectName: "pot1"
id: gauge
x: 4
y: 200
width: 492
height: 74
orientation: 1
maximumValue: 100
value: 50
}
StatusIndicator {
objectName: "but1"
id: statusIndicator
x: 299
y: 84
width: 84
height: 70
color: "#30ff00"
active: false
}
Text {
id: element1
x: 308
y: 63
width: 66
height: 15
color: "#ffffff"
text: qsTr("PULSADOR")
font.pixelSize: 12
}
Text {
id: element2
x: 17
y: 174
color: "#f4f1f1"
text: qsTr("ADC PULSADOR")
font.pixelSize: 12
}
}
Con esta plantilla basica pasaremos a enlazar los elementos id:"pot1" y "but1" a nuestro proyecto CDC_PICMonitor, adicionaremos las siguientes lineas a los archivos:
CDC_PICMonitor.pro
QT += core gui serialport quick
mainwindows.h
#include <QQuickView>
private:
QQuickView *qv1;
QObject *pot1, *but1;
QObject *pot1, *but1;
En el archivo mainwindows.cpp modificaremos el constructor principal y el procedimiento readSerialPort quedando en lo siguiente:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
port = new QSerialPort();
connect(port, SIGNAL(readyRead()), this, SLOT(readSerialPort()));
qv1 = new QQuickView();
qv1->setSource(QUrl::fromLocalFile("../CDC_PICMonitor/QMView1.qml"));
qv1->show();
pot1 = qv1->findChild<QObject*>("pot1");
but1 = qv1->findChild<QObject*>("but1");
}
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
port = new QSerialPort();
connect(port, SIGNAL(readyRead()), this, SLOT(readSerialPort()));
qv1 = new QQuickView();
qv1->setSource(QUrl::fromLocalFile("../CDC_PICMonitor/QMView1.qml"));
qv1->show();
pot1 = qv1->findChild<QObject*>("pot1");
but1 = qv1->findChild<QObject*>("but1");
}
void MainWindow::readSerialPort()
{
QByteArray databytes;
if(port->canReadLine())
{
databytes = port->readLine();
QString msg(databytes);
if(msg.at(0) == 'B')
{
ui->lineEdit_2->setText(msg.remove(0,2));
if(msg.at(0) == '1') but1->setProperty("active", false);
else but1->setProperty("active", true);
return;
}
if(msg.at(0) == 'V')
{
ui->lineEdit->setText(msg.remove(0,2));
pot1->setProperty("value", msg.toInt());
}
}
}
{
QByteArray databytes;
if(port->canReadLine())
{
databytes = port->readLine();
QString msg(databytes);
if(msg.at(0) == 'B')
{
ui->lineEdit_2->setText(msg.remove(0,2));
if(msg.at(0) == '1') but1->setProperty("active", false);
else but1->setProperty("active", true);
return;
}
if(msg.at(0) == 'V')
{
ui->lineEdit->setText(msg.remove(0,2));
pot1->setProperty("value", msg.toInt());
}
}
}
Luego compilamos y ejecutamos el codigo. Observaremos los valores en los elementos graficos de la ventana QML.
8. Conclusiones
Dejo un video que resume toda la creacion del proyecto en MPABXAqui dejo los enlaces para que puedas descargar los proyectos creados con MPLAB y QT para en este blog, como usuario de linux comentar que ambos proyectos estan comprimidos en gzip y es probable que necesites modifcar algunas referencias si quieres compilarlos en Windows:
Proyecto MPLABX cdc16f
Proyecto QT5 CDC_PICMonitor
La utilidad MCC al momento de trabajar este ejemplo implementa solo la clase CDC como un lite statck del protocolo USB, si quieres utilizar otras clases como ser HID, MSC, ADC o incluso una personalizada débes utilizar las librerias MLA, hay bastante informacion con ejemplos en la documentacion de microchip.
Algo interesante de trabajar con la subclase ACM es que la codificación de linea es automatica, gracias a esto el protocolo se ajusta a cualquier velocidad(baudios) de la aplicación PC o terminal.
Sin mas que mencionar agradezco tu visita al blog y espero que el ejemplo visto pueda ser útil en tu formación y el proyecto que desarrollas.
Atte. Pablo Zárate Arancibia
email: pablinza@me.com/pablinzte@gmail.com
@pablinzar
Santa Cruz de la Sierra - Bolivia
Hola, excelente post y muy útil. Quisiera saber que métodos usar para que el PIC lea la info recibida por el puerto serial desde el PC. (O sea el proceso inverso). Gracias.
ResponderBorrarGracias, estimado. Veré subir un ejemplo donde el PIC reciba datos de la PC, pero en resumen se utiliza la función numBytes = getsUSBUSAR(*dst,64); que devolverá la cantidad de bytes leidos para luego procesar *dst y tomar acciones.
Borrar