Tabla de contenido:

EAL-Industri4.0-RFID Dataopsamling Til Database: 10 pasos (con imágenes)
EAL-Industri4.0-RFID Dataopsamling Til Database: 10 pasos (con imágenes)

Video: EAL-Industri4.0-RFID Dataopsamling Til Database: 10 pasos (con imágenes)

Video: EAL-Industri4.0-RFID Dataopsamling Til Database: 10 pasos (con imágenes)
Video: Индустрия 4.0, Интернет вещей, эволюция технологий и большие данные. Как технологии меняют нашу жизнь 2024, Mes de julio
Anonim
EAL-Industri4.0-RFID Dataopsamling Til Database
EAL-Industri4.0-RFID Dataopsamling Til Database

Dette projekt omhandler opsamling af vægtdata, registrando un identiteter vha. RFID, datos rezagados en base de datos MySQL vha. node-RED, samt fremvisning og behandling af de opsamlede data i et C # program i for en Windows Form Application. Vi forestiller os følgende:

Vi har en produktionslinje som productor leverpostej i 200g foliebakker. Alle færdigbagte leverpostejer udstyres efter afkøling med et RFID tag i plasticlåget / labelen, som indeholder et unikt ID (UID = Unique Identifier, er en 32 bits kode, 8 hexadecimale karakterer) para la identificación entydig af hver enkelt bakke leverpostej. Da færdigvægten af hver enkelt bakke leverpostej kan svinge (afhængig af råvarer, fordampning i ovn mm), og da kunderne hver har et specifikt krav færdigvægten, brujas UID tagget en knytte hver enrettifiktej tillo lagresation en knytte hver enrettifiktej lage lagres leverpostejer til én specifik kunde. Kunderne er supermarkedskæder:

1. Irma. Vægten på Irmas luksus leverpostej skal holde sig inden por +/- 5%, altså mínimo 190g og maksimum 210g.

2. Brugsen. Vægten på Brugsens leverpostej skal holde sig inden por +/- 10%, altså mínimo 180g og maksimum 220g.

3. Aldi. Vægten på Aldis discount leverpostej skal holde sig inden por +/- 15%, altså mínimo 170g og maksimum 230g.

Clasificadora Der er således følgende:

Range0: fuera de rango

Rango 1: mínimo 190 g / máximo 210 g

Rango 2: mínimo 180 g / máximo 220 g

Rango 3: mínimo 170 g / máximo 230 g

Paso 1: Opsamling Af Data for Vægt Samt Registrering Af UID

Opsamling Af Data for Vægt Samt Registrering Af UID
Opsamling Af Data for Vægt Samt Registrering Af UID

Hasta examinar los datos para vægt, registrar las etiquetas RFID y anvendt en Arduino MEGA2560 med en RFID-RC522 reader / writer. Da vi ikke har nogen vægt, datos de simulerer vi para vægten med et potmeter tilsluttet en analog indgang på Arduinoen.

Følgende opstilling er anvendt:

1 stk potenciómetro 25k lineært. Yder-benene er tilsluttet hhv. GND og + 5V, midterbenet er tilsluttet AN0

RFID-RC522 er tilsluttet Arduino boardets SPI port på følgende måde:

SDA -> pin 53

SCK -> pin52

MOSI -> pin51

MISO-> pin50

IRQ -> NC

GND -> GND

RST -> pin5

3,3 V -> 3,3 V

Datos de opsamlede, para hhv. UID og vægten, sendes på den serielle port som en komma-separeret tekstreng videre til node-Red som står para den efterfølgende presentation på et dashboard og lagring en una base de datos.

Paso 2: programa Arduino

I Arduino programmet inkluderes de to biblioteker SPI.h og MFRC522.h for at kunne bruge RFID læseren. Empiezo con una inicialización del programa de una variable anvendte. Der laves en instans af MFRC522. I Setup blokken initialiseres den serielle forbindelse, SPI porten og MFRC522. Derefter escanea las etiquetas RFID. Para ikke en sende det samme UID afsted flere gange efter hinanden, er der lavet en stump kode som tjekker for dette. Når der er scannet et UID tag, carga arary nyUID med det netop læste UID. Hvis array nyUID er forskellig fra oldUID er der tale om et nyt UID som kan sendes på den serielle port. Hvis nyUID og oldUID er ens, er der tale om samme UID tag og UID'et skal ignora. Hvis der er tale om et nyt UID, sendes UID'et på den serielle port sammen med en læst værdi fra den serielle port. Den analoge værdi skaleres til området 150-250. Data sendes som en komma-separeret tekstreng. Som det sidste sættes oldUID = nyUID, således en koden klart hasta læse et nyt etiqueta RFID.. Den sidste funktion i programmet er den funktion som sammenligner 2 arrays. Funktionen retornerer true hvis array'ne er ens, og false hvis array'ne er forskellige.

#incluir

#include // Este programa escanea tarjetas RFID usando la placa lectora / grabadora RDIF-RC522. // Se lee UID, se lee un pin analógico. El valor analógico 0-1023 se escala a 150-250. // El UID y el valor analógico se envían como texto separado por comas en el puerto serie usando 9600, N, 8, 1. // Se ha tenido cuidado de enviar cada UID solo una vez consecutiva, // se debe enviar un nuevo UID presente antes de que se pueda enviar de nuevo el mismo UID. // Esta función se implementa en el código comparando matrices: oldUID nyUID en la función array_cmp (oldUID , nyUID )

constexpr uint8_t RST_PIN = 5;

constexpr uint8_t SS_PIN = 53; int sensorPin = A0; int Valor = 0; String StringValue = "0000"; byte oldUID [4] = {}; byte nyUID [4] = {};

MFRC522 mfrc522 (SS_PIN, RST_PIN); // Cree una instancia de MFRC522.

configuración vacía ()

{Serial.begin (9600); // Iniciar una comunicación en serie SPI.begin (); // Iniciar bus SPI mfrc522. PCD_Init (); // Iniciar MFRC522}

bucle vacío ()

{// Busque nuevas tarjetas if (! Mfrc522. PICC_IsNewCardPresent ()) {return; } // Seleccione una de las tarjetas if (! Mfrc522. PICC_ReadCardSerial ()) {return; } // cargar nyUID con etiqueta UID para (byte i = 0; i <mfrc522.uid.size; i ++) {nyUID = mfrc522.uid.uidByte ; } // if oldUID nyUID if (! array_cmp (oldUID, nyUID)) {// enviar etiqueta UID en el puerto serie para (byte i = 0; i 1000) {Value = 1000; } Valor = (Valor / 10) + 150; // enviar valor analógico escalado Serial.print (Value); // enviar nueva línea Serial.println (); // establece oldUID = nyUID para (byte z = 0; z <4; z ++) oldUID [z] = nyUID [z]; } // esperar 1 segundo de retraso (1000); }

// comparar 2 matrices…

boolean array_cmp (byte a , byte b ) {bool test = true; // prueba que todos los elementos sean iguales. si solo uno no lo es, devuelve falso para (byte n = 0; n <4; n ++) {if (a [n]! = b [n]) test = false; // si el byte no es igual, prueba = falso} si (prueba == verdadero) devuelve verdadero; si no, devuelve falso; }

Paso 3: Nodo-RED, base de datos Lagring Af Data I

Nodo-RED, base de datos de datos de Af Lagring I
Nodo-RED, base de datos de datos de Af Lagring I
Nodo-RED, base de datos de datos de Af Lagring I
Nodo-RED, base de datos de datos de Af Lagring I

Følgende flow er lavet i node-RED:

COM4 er den serielle forbindelse hvor data modtages fra Arduino boardet. Funktionerne "Split and Get value" og "Split and Get UID" splitter teksstrengen ved kommaet og return hhv vægten og UID. Vægten bruges til fremvisning på dashboardet i et linechart og en scale. UID fremvises i et tekstfelt. Funktionen test_sound advarer verbalt med sætningen "Fuera de rango", hvis vægten er menos de 170 g mayor de 230 g, dvs i rango 0.

Dividir y obtener valor:

var salida = msg.payload.split (',');

temp = {payload: (salida [1])}; temperatura de retorno;

Dividir y obtener UID:

var salida = msg.payload.split (",");

temp = {payload: output [0]}; temperatura de retorno;

prueba_sonido:

var number = parseInt (msg.payload);

if (número> 230 || número <170) {newMsg = {payload: "Fuera de rango"}; return newMsg; } else {newMsg = {payload: ""}; return newMsg; }

Funktionen Split string "," indsætter et timestamp, UID og vægten en la base de datos patedb.patelog.

var salida = msg.payload.split (","); // dividir msg.payload por coma en una matriz

UIDTag = salida [0]; // primera parte en la primera posición [0] ValueTag = salida [1]; // segunda parte en segunda posición [1]

var m = {

tema: "INSERT INTO patedb.patelog (marca de tiempo, UID, peso) VALUES ('" + nueva Fecha (). toISOString () + "', '" + UIDTag + "', '" + ValueTag + "');" }; return m;

patelog er es Base de datos MySQL forbindelse som er sat op med følgende parametre:

Anfitrión: localhost

Puerto: 3306

Usuario: root

Base de datos: patedb

Paso 4: diseño de la base de datos

Diseño de base de datos
Diseño de base de datos

Base de datos patedb indeholder 4 tabeller

patelog er dataopsamlingstabellen, tilskrives data af node-RED og C # programmet

ordertable er en tabel som indeholder data om de genemførte ordrer, tilskrives data af C # programmet

customertable er et kunderegister

rangetable er en tabel som indeholder grænseværdierne para las gamas benyttede del programa de i C #.

Paso 5: Patelog

Patelog
Patelog

Tabellen patelog indeholder folgende 6 kolonner:

pateID (int) er clave primaria og inkrementeres automatisk.

Marca de tiempo, UID y vægt er af typen varchar (med forskellig max længde)

rangeNr er af typen tinyint (beregnes og tilføjes af C # programmet)

orderID er af typen int (orderID tilføjes af C # programmet)

Node-RED tilføjer ikke værdier til kolonnerne rangeNr og orderID. rangeNr og orderID tillader NULL værdier, det bruges i C # programmet hasta detektere de rækker som skal tilskrives værdier para rangeNr og orderID

Paso 6: Ordenar

Ordertable
Ordertable

Titular de mesa ordenable 5 kolonner:

orderID (int) er det aktuelle ordrenummer

orderQuant (mediumint) er ordens pålydende antal

quantProduced (mediumint) er antal der rent faktisk er produceret på ordren. (Programa de Tælles af C #)

comment (tinytext) er en eventuel kommentar til ordren.

customerID (int) er det aktuelle kundenummer på ordren.

Paso 7: personalizable

Personalizable
Personalizable

titular de tabla personalizada 6 kolonner:

customerID (int) er clave primaria og auto inc.

nombre, dirección, teléfono, correo electrónico (varchar) med forskellig max længde

rangeNr (int)

Paso 8: tabla de rangos

Rangetable
Rangetable

indeholder rangetable 3 kolonner:

rangeNr (int) er clave primaria og auto inc.

rangeMin (int)

rangeMax (int)

Paso 9: Programa C #

Programa C #
Programa C #

Når der produceres en ordre leverpostej, er Procedureren følgende:

Kundenummer, ordrenummer, ordreantal og en eventuel kommentar indtastes i C # programmet (i praksis overføres det digitalt fra virksomhedens ordresystem. Produktionen startes nu ved tryk på 'start'- knappen. Når en leverpostej er færdigproduceret og låget (på et transportbånd) Samhørende værdier af UID og den aktuelle vægt sendes serielt til node-RED, som viser de opsamlede data på dashboard 'et. Samtidig skrives timestamp, UID og vægt i en ny række i patedb.patelog tabellenv. Da der pårenv. tidspunkt ikke tilskrives værdier til rangeNr og orderID vil de have værdien NULL.

Med et timerinterval undersøger C # programmet patedb.patelogtabellen for nye tilkomne rækker med NULL værdier i rangeNr kolonnen. Når der er detekteret en række med NULL værdi, beregnes rangeNr og det tilføjes sammen med det aktuelle orderID. Når en ordre er produceret, afsluttes ordren ved tryk på”detener” - knappen. Når ordren afsluttes, tilføjes en række til patedb.ordertable med de aktuelle ordredata. Når en ordre er afsluttet, kan kan de opsamlede data i patelog tabellen fremvises ved y trykke på de forskellige knapper i gruppen Update DataGridview. ordertable kan også vises, og der kan søges ordredata på individueller UID'er eller kundedata på individuelle ordrer.

usando System; usando System. Collections. Generic; using System. ComponentModel; utilizando System. Data; usando System. Drawing; utilizando System. Linq; usando System. Text; usando System. Threading. Tasks; usando System. Windows. Forms; usando MySql. Data. MySqlClient;

espacio de nombres show_data_from_database

{Public Part1 class Form1: Form {MySqlConnection connection = new MySqlConnection ("datasource = localhost; username = root; password = ''"); int RowNumber = 0; // Variable para almacenar el valor pateID int RangeNumber = 0; // Variable para almacenar rangenumber int weight = 0; // Variable para almacenar el peso int OrderNr = 0; // Variable para almacenar OrderNR int QuantProduced = 0; // Variable para almacenar la cantidad producida int NumberOfRows = 0; // número de filas con nulos.. bool ProdRunning = false; // Variable que indica si se han activado los botones de inicio y parada int limits = new int [6]; // inicializa la matriz int CustomerID; // Variable para almacenar customerID public Form1 () {InitializeComponent (); load_table (); // llamar a load_table}

vacío tabla_de_carga ()

{Comando MySqlCommand = new MySqlCommand ("SELECT * FROM patedb.patelog ORDER BY timestamp DESC;", conexión); intente {MySqlDataAdapter adapter = new MySqlDataAdapter (); adapter. SelectCommand = comando; DataTable dbdataset = new DataTable (); adaptador. Fill (dbdataset); BindingSource bsource = new BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; SetRowOrder (); adapter. Update (dbdataset); } catch (Exception ex) {MessageBox. Show (ex. Message); }}

privado vacío SetRowOrder ()

{dataGridView1. Columns ["pateID"]. DisplayIndex = 0; // Su kan rækkefølgen af kolonner ændres dataGridView1. Columns ["marca de tiempo"]. DisplayIndex = 1; // Su kan rækkefølgen af kolonner ændres dataGridView1. Columns ["UID"]. DisplayIndex = 2; // Su kan rækkefølgen af kolonner ændres dataGridView1. Columns ["peso"]. DisplayIndex = 3; // Su kan rækkefølgen af kolonner ændres dataGridView1. Columns ["rangeNr"]. DisplayIndex = 4; // Su kan rækkefølgen af kolonner ændres dataGridView1. Columns ["orderID"]. DisplayIndex = 5; // Su kan rækkefølgen af kolonner ændres}

private void GetData_Click (remitente del objeto, EventArgs e) // Lee la tabla de la base de datos y los pedidos por marca de tiempo

{load_table (); }

private void btnRefreshUID_Click (remitente del objeto, EventArgs e) //

{string timeStr = "SELECT * FROM patedb.patelog ORDER BY UID;"; Comando MySqlCommand = new MySqlCommand (timeStr, conexión); intente {Adaptador MySqlDataAdapter = new MySqlDataAdapter (); adapter. SelectCommand = comando; DataTable dbdataset = new DataTable (); adaptador. Fill (dbdataset); BindingSource bsource = new BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; SetRowOrder (); adapter. Update (dbdataset); } catch (Exception ex) {MessageBox. Show (ex. Message); }}

private void btnRefreshValue_Click (remitente del objeto, EventArgs e)

{string weightSort = "SELECT * FROM patedb.patelog ORDER BY CAST (weight AS FIRMADO INTEGER);"; Comando MySqlCommand = new MySqlCommand (weightSort, conexión); intente {MySqlDataAdapter adapter = new MySqlDataAdapter (); adapter. SelectCommand = comando; DataTable dbdataset = new DataTable (); adaptador. Fill (dbdataset); BindingSource bsource = new BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; SetRowOrder (); adapter. Update (dbdataset); } catch (Exception ex) {MessageBox. Show (ex. Message); }}

private void ChkNullBtn_Click (remitente del objeto, EventArgs e)

{if (ProdRunning) {CheckTableForNull (); load_table (); }}

checkTableForNull vacío privado ()

{// Verifica / establece el intervalo de tiempo mínimo 100 ms int i; int. TryParse (textTimer1. Text, out i); if (i <100) {temporizador1. Parar (); i = 100; timer1. Interval = i; MessageBox. Show ("Valor mínimo i 100mS"); timer1. Start (); } else {timer1. Interval = i; } textTimer1. Text = timer1. Interval. ToString (); // Verifica si hay filas con nulo disponibles en la tabla, devuelve el número de filas en la variable: NumberOfRows string weightStr = ""; string chkNull = "SELECT COUNT (*) FROM patedb.patelog DONDE rangeNR ES NULL ORDER BY pateID LIMIT 1;"; Comando MySqlCommand = nuevo MySqlCommand (chkNull, conexión); intente {conexión. Open (); NumberOfRows = Convert. ToInt32 (comando. ExecuteScalar ()); conexión. Cerrar (); } catch (Exception ex) {MessageBox. Show (ex. Message); } finalmente {if (NumberOfRows! = 0) {try {// Selecciona el número pateID más bajo donde rangeNr es NULL string readID = "SELECT pateID FROM patedb.patelog DONDE rangeNR ES NULL ORDER BY pateID ASC LIMIT 1;"; MySqlCommand cmdID = nuevo MySqlCommand (readID, conexión); {conexión. Open (); RowNumber = (int) cmdID. ExecuteScalar (); //¡¡entero!! conexión. Cerrar (); } listPateID. Text = RowNumber. ToString (); // leer el número de PateID seleccionado // Selecciona el peso de la cadena de número de fila seleccionada row = RowNumber. ToString (); string readweight = "SELECCIONE el peso de patedb.patelog DONDE pateID =" + fila; MySqlCommand cmdweight = new MySqlCommand (peso de lectura, conexión); {conexión. Open (); weightStr = (cadena) cmdweight. ExecuteScalar (); //Cuerda !! conexión. Cerrar (); } peso = int. Parse (weightStr); // convertir a int txtWeight. Text = weight. ToString (); // imprimir int RangeNumber = 0; if (peso> = límites [0] && peso = límites [2] && peso = límites [4] && peso <= límites [5]) {RangeNumber = 3; }} txtRange. Text = RangeNumber. ToString (); UpdateLog (); } catch (Exception ex) {MessageBox. Show (ex. Message); } QuantProduced = QuantProduced + 1; }}} private void btnStart_Click (remitente del objeto, EventArgs e) {if (ProdRunning == false) {int valtest; intente {CustomerID = int. Parse (txtCustomerNr. Text); // leer ID de cliente} catch {MessageBox. Show ("Ingrese los datos de producción y presione el botón 'iniciar'."); }

string test = "SELECT COUNT (*) FROM patedb.customertable DONDE customerID =" + CustomerID;

MySqlCommand cmdtestcustomer = new MySqlCommand (prueba, conexión); {conexión. Open (); valtest = Convert. ToInt32 (cmdtestcustomer. ExecuteScalar ()); // devuelve 0 si el cliente no existe connection. Close (); } if (valtest == 1) // si el cliente existe en la base de datos - iniciar la producción {try {OrderNr = int. Parse (txtOrderNumber. Text); ProdRunning = verdadero; timer1. Start (); textTimer1. Text = timer1. Interval. ToString (); ReadLimits (); } catch (Exception ex) {MessageBox. Show ("Ingrese los datos de producción y presione el botón 'iniciar'."); }} else MessageBox. Show ("El cliente no está en la base de datos, inténtelo de nuevo"); } // ReadLimits (); }

ReadLimits vacío privado ()

{// Lee los límites de la tabla de rangos, rango 1 a 3 int contador = 0; for (int rangeNr = 1; rangeNr <4; rangeNr ++) {string readmin = "SELECT rangeMin FROM patedb.rangetable DONDE rangeNr =" + rangeNr; MySqlCommand cmdmin = new MySqlCommand (readmin, conexión); {conexión. Open (); límites [contador] = (int) cmdmin. ExecuteScalar (); contador = contador + 1; conexión. Cerrar (); } // MessageBox. Show (counter. ToString ()); string readmax = "SELECT rangeMax FROM patedb.rangetable DONDE rangeNr =" + rangeNr; MySqlCommand cmdmax = new MySqlCommand (readmax, conexión); {conexión. Open (); límites [contador] = (int) cmdmax. ExecuteScalar (); contador = contador + 1; conexión. Cerrar (); }} // fin del ciclo}

UpdateLog vacío privado ()

{// ACTUALIZAR rangeNR & orderID string Range = RangeNumber. ToString (); string Order = OrderNr. ToString (); string update = "ACTUALIZAR patedb.patelog SET rangeNr =" + Range + ',' + "orderID =" + OrderNr + "WHERE pateID =" + RowNumber; MySqlCommand updatecmd = new MySqlCommand (actualización, conexión); intente {conexión. Open (); updatecmd. ExecuteNonQuery (); conexión. Cerrar (); } catch (Exception ex) {MessageBox. Show (ex. Message); }}

private void btnStop_Click (remitente del objeto, EventArgs e)

{if (ProdRunning == true) {timer1. Stop (); ProdRunning = falso; UpdateOrderTable (); } else {MessageBox. Show ("Aún no ha comenzado la producción. Ingrese los datos y presione el botón 'iniciar'"); }}

UpdateOrderTable vacío privado ()

{string insert = "INSERT INTO patedb.ordertable (orderID, orderQuant, quantProduced, comment, customerID) VALUES ('" + this.txtOrderNumber. Text + "', '" + this.txtOrderQuant. Text + "', '" + QuantProduced. ToString () + "','" + this.txtComment. Text + "','" + this.txtCustomerNr. Text + "');"; MySqlCommand insertcmd = new MySqlCommand (insertar, conectar); intente {conexión. Open (); insertcmd. ExecuteNonQuery (); conexión. Cerrar (); QuantProduced = 0; } catch (Exception ex) {MessageBox. Show (ex. Message); }}

temporizador de vacío privado1_Tick (remitente de objeto, EventArgs e)

{CheckTableForNull (); load_table (); }

btnShowOrderTable_Click vacío privado (remitente del objeto, EventArgs e)

{if (ProdRunning == false) {MySqlCommand command = new MySqlCommand ("SELECT * FROM patedb.ordertable ORDER BY orderID DESC;", conexión); intente {MySqlDataAdapter adapter = new MySqlDataAdapter (); adapter. SelectCommand = comando; DataTable dbdataset = new DataTable (); adaptador. Fill (dbdataset); BindingSource bsource = new BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; adapter. Update (dbdataset); } catch (Exception ex) {MessageBox. Show (ex. Message); }} else {MessageBox. Show ("Presione detener para ver la tabla de pedidos"); }}

private void btnShowOrderDetails_Click (remitente del objeto, EventArgs e)

{if (ProdRunning == false) {string test = ("SELECT patedb.ordertable.orderID, orderQuant, quantProduced, comment, customerID FROM patedb.ordertable INNER JOIN patedb.patelog ON patedb.patelog.orderID = patedb.ordertable.orderID WHERE patedb.patelog. UID = '"+ txtShowOrderDetails. Text +"' "); Comando MySqlCommand = nuevo MySqlCommand (prueba, conexión); intente {conexión. Open (); Adaptador MySqlDataAdapter = nuevo MySqlDataAdapter (); adapter. SelectCommand = comando; DataTable dbdataset = new DataTable (); adaptador. Fill (dbdataset); BindingSource bsource = new BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; adapter. Update (dbdataset); } catch (Exception ex) {MessageBox. Show (ex. Message); } conexión. Cerrar (); } else {MessageBox. Show ("Presione detener para ver los detalles del pedido"); }}

private void btnShowCustomerDetails_Click (remitente del objeto, EventArgs e)

{if (ProdRunning == false) {string test = ("SELECT patedb.customertable.customerID, name, address, phone, email, rangeNr FROM patedb.customertable INNER JOIN patedb.ordertable ON patedb.ordertable.customerID = patedb.customertable. customerID DONDE patedb.ordertable.orderID = '"+ txtShowCustomerDetails. Text +"' "); Comando MySqlCommand = nuevo MySqlCommand (prueba, conexión); intente {MySqlDataAdapter adapter = new MySqlDataAdapter (); adapter. SelectCommand = comando; DataTable dbdataset = new DataTable (); adaptador. Fill (dbdataset); BindingSource bsource = new BindingSource (); bsource. DataSource = dbdataset; dataGridView1. DataSource = bsource; adapter. Update (dbdataset); } catch (Exception ex) {MessageBox. Show (ex. Message); }} else {MessageBox. Show ("Presione detener para ver los detalles del cliente"); }}}

}

Recomendado: