{"id":439,"date":"2016-08-30T00:10:59","date_gmt":"2016-08-30T03:10:59","guid":{"rendered":"http:\/\/www.pascalscada.com\/?page_id=439"},"modified":"2026-09-17T09:36:44","modified_gmt":"2026-09-17T12:36:44","slug":"tags","status":"publish","type":"page","link":"https:\/\/www.pascalscada.com\/pb\/tags\/","title":{"rendered":"Tags"},"content":{"rendered":"<h5>Introdu\u00e7\u00e3o<\/h5>\n<p>No PascalSCADA, um <strong>tag<\/strong> \u00e9 o componente que representa uma mem\u00f3ria (ou um conjunto de mem\u00f3rias) de um equipamento: uma <em>holding register<\/em> de um inversor Modbus, um byte de um DB de um CLP Siemens, um controller tag de um CLP Rockwell. O tag fica no meio da cadeia de comunica\u00e7\u00e3o:<\/p>\n<pre><code>Porta de comunica\u00e7\u00e3o  \u2192  Driver de protocolo  \u2192  Tag  \u2192  Controle HMI \/ seu c\u00f3digo\n<\/code><\/pre>\n<p>A porta transporta bytes, o driver sabe falar o protocolo do equipamento, e o <strong>tag diz ao driver o que ler e escrever<\/strong>, guarda o \u00faltimo valor lido e avisa quem depende dele quando esse valor muda. Os controles da biblioteca HMI (<code>THMIEdit<\/code>, <code>THMILabel<\/code>, <code>THMICheckBox<\/code>\u2026) nunca falam com o driver: eles se ligam a um tag pela propriedade <code>PLCTag<\/code> e reagem \u00e0s mudan\u00e7as dele. O mesmo tag pode alimentar quantos controles voc\u00ea quiser.<\/p>\n<p>Todos os tags ficam na paleta <strong>PascalSCADA Tags<\/strong> e descendem de <code>TTag<\/code> \u2192 <code>TPLCTag<\/code>. A partir da\u00ed eles se dividem em dois grupos:<\/p>\n<ul>\n<li><strong>Tags num\u00e9ricos<\/strong> (<code>TPLCNumber<\/code>): exp\u00f5em um \u00fanico valor <code>Double<\/code> nas propriedades <code>Value<\/code> e <code>ValueRaw<\/code>. S\u00e3o eles: <code>TPLCTagNumber<\/code>, <code>TPLCBlockElement<\/code>, <code>TPLCStructItem<\/code>, <code>TTagBit<\/code> e <code>TNumericExprTag<\/code>.<\/li>\n<li><strong>Tags de bloco<\/strong> (<code>TTagBlock<\/code>): mapeiam v\u00e1rias mem\u00f3rias consecutivas em uma \u00fanica requisi\u00e7\u00e3o. S\u00e3o eles: <code>TPLCBlock<\/code>, <code>TPLCStruct<\/code> e <code>TPLCString<\/code>.<\/li>\n<\/ul>\n<p>A tabela abaixo resume quando usar cada um:<\/p>\n<table>\n<thead>\n<tr>\n<th>Componente<\/th>\n<th>Use quando\u2026<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><img decoding=\"async\" alt=\"\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/plctagnumber.png\"> <code>TPLCTagNumber<\/code><\/td>\n<td>precisa de <strong>um<\/strong> valor num\u00e9rico, endere\u00e7ado e lido individualmente.<\/td>\n<\/tr>\n<tr>\n<td><img decoding=\"async\" alt=\"\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/plcblock.png\"> <code>TPLCBlock<\/code> + <img decoding=\"async\" alt=\"\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/plcblockelement.png\"> <code>TPLCBlockElement<\/code><\/td>\n<td>precisa de <strong>v\u00e1rios valores consecutivos do mesmo tipo<\/strong> (ex.: 20 registradores a partir do endere\u00e7o 100). O bloco faz uma requisi\u00e7\u00e3o s\u00f3; cada elemento exp\u00f5e um item do bloco como tag num\u00e9rico.<\/td>\n<\/tr>\n<tr>\n<td><img decoding=\"async\" alt=\"\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/plcstruct.png\"> <code>TPLCStruct<\/code> + <img decoding=\"async\" alt=\"\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/plcstructitem.png\"> <code>TPLCStructItem<\/code> + <img decoding=\"async\" alt=\"\" src=\"https:\/\/www.pascalscada.com\/wp-content\/uploads\/2026\/09\/TPLCStructString.png\"> <code>TPLCStructString<\/code><\/td>\n<td>precisa de <strong>v\u00e1rios valores de tipos diferentes<\/strong> que est\u00e3o juntos na mem\u00f3ria (uma <code>STRUCT<\/code>\/UDT de um CLP, um DB Siemens com bytes, words e reais misturados).<\/td>\n<\/tr>\n<tr>\n<td><img decoding=\"async\" alt=\"\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/plcstring.png\"> <code>TPLCString<\/code><\/td>\n<td>precisa ler ou escrever um <strong>texto<\/strong>.<\/td>\n<\/tr>\n<tr>\n<td><img decoding=\"async\" alt=\"\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/tagbit.png\"> <code>TTagBit<\/code><\/td>\n<td>precisa de <strong>um ou mais bits<\/strong> de outro tag num\u00e9rico, sem gerar nova comunica\u00e7\u00e3o.<\/td>\n<\/tr>\n<tr>\n<td><img decoding=\"async\" alt=\"\" src=\"https:\/\/www.pascalscada.com\/wp-content\/uploads\/2026\/09\/TNumericExprTag.png\"> <code>TNumericExprTag<\/code><\/td>\n<td>precisa de um valor <strong>calculado<\/strong> a partir de outros tags, sem comunica\u00e7\u00e3o pr\u00f3pria.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h5>Como um tag \u00e9 lido e escrito<\/h5>\n<p>Cada tag de comunica\u00e7\u00e3o tem quatro opera\u00e7\u00f5es, dispon\u00edveis em c\u00f3digo:<\/p>\n<table>\n<thead>\n<tr>\n<th>M\u00e9todo<\/th>\n<th>Dire\u00e7\u00e3o<\/th>\n<th>Comportamento<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>ScanRead<\/code><\/td>\n<td>leitura<\/td>\n<td><strong>Ass\u00edncrona.<\/strong> Enfileira uma requisi\u00e7\u00e3o de leitura no driver e retorna imediatamente. O valor chega depois, no evento <code>OnValueChange<\/code>\/<code>OnUpdate<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>Read<\/code><\/td>\n<td>leitura<\/td>\n<td><strong>S\u00edncrona.<\/strong> Bloqueia at\u00e9 o driver responder (ou falhar). Ao retornar, <code>Value<\/code> j\u00e1 est\u00e1 atualizado e <code>LastSyncReadStatus<\/code> diz o resultado.<\/td>\n<\/tr>\n<tr>\n<td><code>ScanWrite<\/code><\/td>\n<td>escrita<\/td>\n<td><strong>Ass\u00edncrona.<\/strong> Enfileira a escrita e retorna. O resultado vai para <code>LastASyncWriteStatus<\/code> e para os eventos <code>OnWriteOk<\/code>\/<code>OnWriteFail<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>Write<\/code><\/td>\n<td>escrita<\/td>\n<td><strong>S\u00edncrona.<\/strong> Bloqueia at\u00e9 a escrita ser confirmada.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Na pr\u00e1tica voc\u00ea raramente chama esses m\u00e9todos. O que controla o comportamento do dia a dia s\u00e3o tr\u00eas propriedades:<\/p>\n<ul>\n<li><strong><code>AutoRead<\/code><\/strong> \u2014 se <code>True<\/code> (padr\u00e3o), o driver inclui o tag no seu ciclo de varredura (<em>scan<\/em>) e o l\u00ea automaticamente a cada <code>RefreshTime<\/code> milissegundos. Se <code>False<\/code>, o tag s\u00f3 \u00e9 lido quando voc\u00ea chamar <code>Read<\/code> ou <code>ScanRead<\/code>.<\/li>\n<li><strong><code>RefreshTime<\/code><\/strong> \u2014 per\u00edodo de atualiza\u00e7\u00e3o do tag em milissegundos (padr\u00e3o 1000). Tags no mesmo driver com o mesmo <code>RefreshTime<\/code> e endere\u00e7os vizinhos s\u00e3o agrupados pelo driver em uma \u00fanica requisi\u00e7\u00e3o sempre que o protocolo permitir, ent\u00e3o <strong>n\u00e3o h\u00e1 penalidade em usar muitos tags pequenos<\/strong>; use <code>TPLCBlock<\/code> quando quiser garantir que os dados cheguem juntos, como um \u00fanico snapshot.<\/li>\n<li><strong><code>AutoWrite<\/code><\/strong> \u2014 se <code>True<\/code> (padr\u00e3o), toda atribui\u00e7\u00e3o a <code>Value<\/code> (por c\u00f3digo ou por um controle HMI) gera uma escrita no equipamento. Se <code>False<\/code>, a atribui\u00e7\u00e3o s\u00f3 muda o valor em mem\u00f3ria; o valor vai para o equipamento quando voc\u00ea chamar <code>WriteDirect<\/code> (bloco) ou <code>Write<\/code>\/<code>ScanWrite<\/code>.<\/li>\n<li><strong><code>SyncWrites<\/code><\/strong> \u2014 se <code>True<\/code>, as escritas geradas por <code>AutoWrite<\/code> s\u00e3o s\u00edncronas (<code>Write<\/code>) em vez de ass\u00edncronas (<code>ScanWrite<\/code>). Deixe <code>False<\/code> a n\u00e3o ser que o c\u00f3digo que atribuiu o valor precise ter certeza de que ele j\u00e1 chegou ao equipamento.<\/li>\n<\/ul>\n<blockquote>\n<p>A regra geral \u00e9: <strong>deixe <code>AutoRead<\/code> e <code>AutoWrite<\/code> em <code>True<\/code> e n\u00e3o chame nada<\/strong> \u2014 o driver cuida de tudo. Desligue <code>AutoRead<\/code> s\u00f3 para tags que precisam ser lidos em um momento espec\u00edfico (por exemplo, uma receita carregada sob demanda), e chame <code>Read<\/code> nesse momento.<\/p>\n<\/blockquote>\n<h5>Endere\u00e7amento<\/h5>\n<p>Todo tag de comunica\u00e7\u00e3o tem o mesmo conjunto de propriedades de endere\u00e7o. <strong>O significado de cada uma depende do driver de protocolo<\/strong>, e a p\u00e1gina de cada protocolo explica como preench\u00ea-las. Como refer\u00eancia r\u00e1pida:<\/p>\n<table>\n<thead>\n<tr>\n<th>Propriedade<\/th>\n<th>Modbus<\/th>\n<th>S7 (ISOTCP)<\/th>\n<th>Melsec<\/th>\n<th>West ASCII \/ IBox<\/th>\n<th>Logix \/ S7CommPlus<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>PLCStation<\/code><\/td>\n<td>Endere\u00e7o do escravo (1\u2013247)<\/td>\n<td>\u2013<\/td>\n<td>N\u00famero da esta\u00e7\u00e3o<\/td>\n<td>Endere\u00e7o do controlador<\/td>\n<td>\u2013<\/td>\n<\/tr>\n<tr>\n<td><code>PLCRack<\/code> \/ <code>PLCSlot<\/code><\/td>\n<td>\u2013<\/td>\n<td>Rack e slot da CPU<\/td>\n<td>\u2013<\/td>\n<td>\u2013<\/td>\n<td>\u2013<\/td>\n<\/tr>\n<tr>\n<td><code>MemFile_DB<\/code><\/td>\n<td>\u2013<\/td>\n<td>N\u00famero do DB (\u00e1rea DB)<\/td>\n<td>\u2013<\/td>\n<td>\u2013<\/td>\n<td>\u2013<\/td>\n<\/tr>\n<tr>\n<td><code>MemReadFunction<\/code><\/td>\n<td>Fun\u00e7\u00e3o Modbus de leitura (1, 2, 3, 4)<\/td>\n<td>\u00c1rea de mem\u00f3ria (1 = I, 2 = Q, 3 = M, 4 = DB\u2026)<\/td>\n<td>Tipo de dispositivo (M, SM, L, X, Y, D\u2026)<\/td>\n<td>\u2013<\/td>\n<td>\u2013<\/td>\n<\/tr>\n<tr>\n<td><code>MemWriteFunction<\/code><\/td>\n<td>Fun\u00e7\u00e3o Modbus de escrita (5, 6, 15, 16)<\/td>\n<td>\u2013<\/td>\n<td>Tipo de dispositivo (mesmo c\u00f3digo da leitura)<\/td>\n<td>\u2013<\/td>\n<td>\u2013<\/td>\n<\/tr>\n<tr>\n<td><code>MemAddress<\/code><\/td>\n<td>Endere\u00e7o do registrador\/coil<\/td>\n<td>Endere\u00e7o do byte<\/td>\n<td>Endere\u00e7o do dispositivo<\/td>\n<td>Par\u00e2metro (West) \/ PID (IBox)<\/td>\n<td>\u2013<\/td>\n<\/tr>\n<tr>\n<td><code>MemSubElement<\/code><\/td>\n<td>\u2013<\/td>\n<td>\u2013 (bits: use <code>TTagBit<\/code>)<\/td>\n<td>\u2013<\/td>\n<td>\u2013<\/td>\n<td>\u2013<\/td>\n<\/tr>\n<tr>\n<td><code>LongAddress<\/code><\/td>\n<td>\u2013<\/td>\n<td>\u2013<\/td>\n<td>\u2013<\/td>\n<td>\u2013<\/td>\n<td>Nome simb\u00f3lico do tag no CLP (<code>Motor1.Speed<\/code>, <code>\"DB10\".Setpoint<\/code>)<\/td>\n<\/tr>\n<tr>\n<td><code>Retries<\/code><\/td>\n<td>Tentativas antes de declarar falha (todos os drivers)<\/td>\n<td><\/td>\n<td><\/td>\n<td><\/td>\n<td><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>A forma mais r\u00e1pida de acertar o endere\u00e7amento \u00e9 o <strong>Tag Builder<\/strong>: clique com o bot\u00e3o direito no componente do driver de protocolo (<code>TModBusTCPDriver<\/code>, <code>TISOTCPDriver<\/code>\u2026) e escolha <em>Tag Builder<\/em>. Ele cria os tags j\u00e1 configurados para aquele protocolo.<\/p>\n<p><code>ProtocolDriver<\/code> \u00e9 a propriedade que liga o tag ao driver. Um tag sem driver n\u00e3o faz nada \u2014 nem gera erro.<\/p>\n<h5>Tipo de dado<\/h5>\n<p>A propriedade <strong><code>TagType<\/code><\/strong> diz como o driver deve interpretar os bytes lidos do equipamento:<\/p>\n<table>\n<thead>\n<tr>\n<th>TagType<\/th>\n<th>Tamanho<\/th>\n<th>Interpreta\u00e7\u00e3o<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>pttDefault<\/code><\/td>\n<td>depende do driver<\/td>\n<td>O &#8220;tamanho natural&#8221; do protocolo: 16 bits no Modbus, 8 bits no S7, etc.<\/td>\n<\/tr>\n<tr>\n<td><code>pttShortInt<\/code> \/ <code>pttByte<\/code><\/td>\n<td>8 bits<\/td>\n<td>Inteiro com \/ sem sinal<\/td>\n<\/tr>\n<tr>\n<td><code>pttSmallInt<\/code> \/ <code>pttWord<\/code><\/td>\n<td>16 bits<\/td>\n<td>Inteiro com \/ sem sinal<\/td>\n<\/tr>\n<tr>\n<td><code>pttLongInt<\/code> \/ <code>pttDWord<\/code><\/td>\n<td>32 bits<\/td>\n<td>Inteiro com \/ sem sinal<\/td>\n<\/tr>\n<tr>\n<td><code>pttFloat<\/code><\/td>\n<td>32 bits<\/td>\n<td>Ponto flutuante IEEE-754 (REAL)<\/td>\n<\/tr>\n<tr>\n<td><code>pttInt64<\/code> \/ <code>pttQWord<\/code><\/td>\n<td>64 bits<\/td>\n<td>Inteiro com \/ sem sinal<\/td>\n<\/tr>\n<tr>\n<td><code>pttDouble<\/code><\/td>\n<td>64 bits<\/td>\n<td>Ponto flutuante IEEE-754 (LREAL)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Quando o tamanho do <code>TagType<\/code> \u00e9 diferente do tamanho natural do protocolo, o tag ocupa mais de uma mem\u00f3ria: um <code>pttFloat<\/code> em Modbus ocupa dois registradores de 16 bits consecutivos. <code>TagSizeOnProtocol<\/code> (somente leitura) informa quantas.<\/p>\n<p>Se o valor chega &#8220;embaralhado&#8221; (um <code>REAL<\/code> que aparece como um n\u00famero absurdo, um <code>DINT<\/code> que troca as metades), o equipamento usa uma ordem de bytes diferente da que o driver assume. Ajuste com:<\/p>\n<ul>\n<li><strong><code>SwapBytes<\/code><\/strong> \u2014 inverte os dois bytes de cada palavra de 16 bits.<\/li>\n<li><strong><code>SwapWords<\/code><\/strong> \u2014 inverte as duas palavras de 16 bits de um valor de 32 bits.<\/li>\n<li><strong><code>SwapDWords<\/code><\/strong> \u2014 inverte as duas palavras de 32 bits de um valor de 64 bits.<\/li>\n<\/ul>\n<p>Para Modbus, a combina\u00e7\u00e3o mais comum para <code>REAL<\/code> em equipamentos que usam a ordem &#8220;CDAB&#8221; \u00e9 <code>SwapWords = True<\/code>.<\/p>\n<h5>Valor, escala e limites<\/h5>\n<p>Tags num\u00e9ricos t\u00eam dois valores:<\/p>\n<ul>\n<li><strong><code>ValueRaw<\/code><\/strong> \u2014 o valor exatamente como veio do equipamento.<\/li>\n<li><strong><code>Value<\/code><\/strong> \u2014 o valor depois de passar pela cadeia de escalas ligada em <code>ScaleProcessor<\/code>. Se n\u00e3o houver escala, <code>Value = ValueRaw<\/code>.<\/li>\n<\/ul>\n<p>Os controles HMI e o seu c\u00f3digo normalmente usam <code>Value<\/code>. Para converter, por exemplo, um inteiro 0\u201327648 de uma entrada anal\u00f3gica Siemens em 0\u2013100 %, ligue um <code>TLinearScaleProcessor<\/code> em <code>ScaleProcessor<\/code> \u2014 veja <a href=\"\/pb\/scale-processors\/\">Processadores de escala<\/a>. A escala funciona nos dois sentidos: escrever <code>50<\/code> em <code>Value<\/code> grava <code>13824<\/code> no equipamento.<\/p>\n<p><strong><code>MinValue<\/code><\/strong> \/ <strong><code>MaxValue<\/code><\/strong>, ativados por <strong><code>EnableMinValue<\/code><\/strong> \/ <strong><code>EnableMaxValue<\/code><\/strong>, limitam o que pode ser <em>escrito<\/em> no tag. Uma atribui\u00e7\u00e3o fora da faixa levanta uma exce\u00e7\u00e3o (&#8220;valor fora dos limites&#8221;), dispara <code>OnWriteFail<\/code> e o valor n\u00e3o vai para o equipamento. Os controles de entrada (<code>THMIEdit<\/code>, <code>THMITrackBar<\/code>, <code>THMIUpDown<\/code>) respeitam esses limites.<\/p>\n<h5>Eventos<\/h5>\n<p>Os eventos abaixo existem em todos os tags de comunica\u00e7\u00e3o. Todos rodam na <em>thread principal<\/em>, ent\u00e3o \u00e9 seguro mexer em controles visuais dentro deles.<\/p>\n<table>\n<thead>\n<tr>\n<th>Evento<\/th>\n<th>Quando dispara<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>OnValueChangeFirst<\/code><\/td>\n<td>O valor mudou, <strong>antes<\/strong> de os controles HMI dependentes serem notificados. Use para preparar algo que os controles v\u00e3o mostrar.<\/td>\n<\/tr>\n<tr>\n<td><code>OnValueChangeLast<\/code> (ou <code>OnValueChange<\/code>)<\/td>\n<td>O valor mudou, <strong>depois<\/strong> de os controles serem notificados. \u00c9 o evento &#8220;normal&#8221; de mudan\u00e7a de valor.<\/td>\n<\/tr>\n<tr>\n<td><code>OnUpdate<\/code><\/td>\n<td>O tag foi lido com sucesso, <strong>mesmo que o valor n\u00e3o tenha mudado<\/strong>. Use para &#8220;sinal de vida&#8221; ou para registrar hist\u00f3ricos em intervalo fixo.<\/td>\n<\/tr>\n<tr>\n<td><code>OnReadOK<\/code> \/ <code>OnReadFail<\/code><\/td>\n<td>Resultado de cada leitura.<\/td>\n<\/tr>\n<tr>\n<td><code>OnWriteOk<\/code> \/ <code>OnWriteFail<\/code><\/td>\n<td>Resultado de cada escrita.<\/td>\n<\/tr>\n<tr>\n<td><code>OnAsyncValueChange<\/code><\/td>\n<td>Vers\u00e3o do <code>OnValueChange<\/code> chamada <strong>na thread do driver<\/strong>, sem sincroniza\u00e7\u00e3o com a thread principal. S\u00f3 use se souber o que est\u00e1 fazendo: \u00e9 mais r\u00e1pida, mas n\u00e3o pode tocar em controles visuais.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Para saber o que aconteceu em uma falha, leia <code>LastSyncReadStatus<\/code>, <code>LastSyncWriteStatus<\/code>, <code>LastASyncReadStatus<\/code> ou <code>LastASyncWriteStatus<\/code> (tipo <code>TProtocolIOResult<\/code>: <code>ioOk<\/code>, <code>ioTimeOut<\/code>, <code>ioIllegalFunction<\/code>, <code>ioIllegalRegAddress<\/code>, <code>ioDriverError<\/code>, <code>ioCommError<\/code>, \u2026).<\/p>\n<h5>Diagn\u00f3stico<\/h5>\n<p>Cada tag mant\u00e9m contadores que aparecem no Object Inspector em tempo de execu\u00e7\u00e3o e ajudam a encontrar problemas de rede: <code>CommReadsOK<\/code>, <code>CommReadErrors<\/code>, <code>CommWritesOk<\/code>, <code>CommWriteErrors<\/code>. <code>AvgUpdateRate<\/code> mostra o intervalo m\u00e9dio real entre atualiza\u00e7\u00f5es \u2014 se ele for muito maior que <code>RefreshTime<\/code>, o driver n\u00e3o est\u00e1 dando conta do volume de tags e voc\u00ea deve aumentar o <code>RefreshTime<\/code> dos tags menos importantes ou agrup\u00e1-los em blocos. <code>ClockMonotonicTimeStamp<\/code> guarda o instante da \u00faltima atualiza\u00e7\u00e3o.<\/p>\n<p><code>TagGUID<\/code> \u00e9 um identificador \u00fanico gerado pelo IDE para cada tag. N\u00e3o edite.<\/p>\n<h5 id=\"TPLCTagNumber\">TPLCTagNumber<\/h5>\n<p><img decoding=\"async\" alt=\"\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/plctagnumber.png\"> \u00c9 o tag mais usado: uma mem\u00f3ria, um valor. Configure <code>ProtocolDriver<\/code>, as propriedades de endere\u00e7o e <code>TagType<\/code>, ligue os controles HMI e pronto.<\/p>\n<p>Em c\u00f3digo:<\/p>\n<pre class=\"brush: delphi; tab-size: 2; title: ; notranslate\" title=\"\">\/\/ Leitura: o valor j\u00e1 est\u00e1 no tag, atualizado pelo scan.\nVelocidade := PLCTagNumber1.Value;\n\n\/\/ Escrita: com AutoWrite = True, a atribui\u00e7\u00e3o j\u00e1 grava no equipamento.\nPLCTagNumber1.Value := 1500;\n\n\/\/ For\u00e7ando uma leitura s\u00edncrona agora, independente do scan.\nPLCTagNumber1.Read;\nif PLCTagNumber1.LastSyncReadStatus = ioOk then\n  ShowMessage(FloatToStr(PLCTagNumber1.Value));<\/pre>\n<h5 id=\"TPLCBlock\">TPLCBlock e TPLCBlockElement<\/h5>\n<p><img decoding=\"async\" alt=\"\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/plcblock.png\"> <code>TPLCBlock<\/code> mapeia <code>Size<\/code> mem\u00f3rias consecutivas do mesmo <code>TagType<\/code>, come\u00e7ando em <code>MemAddress<\/code>. Todas s\u00e3o lidas e escritas em uma \u00fanica requisi\u00e7\u00e3o, o que garante que os valores sejam coerentes entre si (o mesmo instante) e reduz o tr\u00e1fego quando o protocolo tem overhead alto por mensagem.<\/p>\n<p>Os valores ficam em <code>ValueRaw[\u00edndice]<\/code> (de <code>0<\/code> a <code>Size-1<\/code>) ou no array <code>ValuesRaw<\/code>. Um <code>TPLCBlock<\/code> sozinho n\u00e3o pode ser ligado a um controle HMI \u2014 para isso existe o <img decoding=\"async\" alt=\"\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/plcblockelement.png\"> <strong><code>TPLCBlockElement<\/code><\/strong>: um tag num\u00e9rico cuja propriedade <code>PLCBlock<\/code> aponta para o bloco e <code>Index<\/code> diz qual elemento ele representa. O elemento tem tudo que um <code>TPLCTagNumber<\/code> tem (<code>Value<\/code>, <code>ScaleProcessor<\/code>, limites, eventos), mas n\u00e3o tem endere\u00e7o pr\u00f3prio nem <code>RefreshTime<\/code>: quem comunica \u00e9 o bloco.<\/p>\n<p>Para n\u00e3o criar os elementos um a um, clique com o bot\u00e3o direito no bloco e escolha <strong>Map block elements\u2026<\/strong> \u2014 o assistente cria um <code>TPLCBlockElement<\/code> para cada \u00edndice.<\/p>\n<p>Escrita em bloco:<\/p>\n<pre class=\"brush: delphi; tab-size: 2; title: ; notranslate\" title=\"\">\/\/ Com AutoWrite = True, cada atribui\u00e7\u00e3o gera uma escrita de um elemento.\nPLCBlock1.ValueRaw&#x5B;3] := 10;\n\n\/\/ Para escrever o bloco inteiro de uma vez, desligue AutoWrite,\n\/\/ atribua os valores e chame WriteDirect (s\u00edncrono) ou WriteByScan (ass\u00edncrono).\nPLCBlock1.AutoWrite := False;\nPLCBlock1.ValueRaw&#x5B;0] := 1;\nPLCBlock1.ValueRaw&#x5B;1] := 2;\nPLCBlock1.ValueRaw&#x5B;2] := 3;\nPLCBlock1.WriteDirect;<\/pre>\n<h5 id=\"TPLCStruct\">TPLCStruct, TPLCStructItem e TPLCStructString<\/h5>\n<p><img decoding=\"async\" alt=\"\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/plcstruct.png\"> <code>TPLCStruct<\/code> \u00e9 um <code>TPLCBlock<\/code> cujo <code>TagType<\/code> \u00e9 fixo em <code>pttByte<\/code>: ele l\u00ea <code>Size<\/code> <strong>bytes<\/strong> consecutivos e deixa que cada item decida como interpret\u00e1-los. \u00c9 a forma de mapear uma estrutura com campos de tipos diferentes \u2014 um DB Siemens com <code>BOOL<\/code>, <code>INT<\/code>, <code>REAL<\/code> e <code>STRING<\/code> misturados, ou uma UDT.<\/p>\n<p>Os campos s\u00e3o representados por:<\/p>\n<ul>\n<li><img decoding=\"async\" alt=\"\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/plcstructitem.png\"> <strong><code>TPLCStructItem<\/code><\/strong> \u2014 um campo num\u00e9rico. <code>PLCBlock<\/code> aponta para a estrutura, <code>Index<\/code> \u00e9 o <strong>offset em bytes<\/strong> do campo dentro dela e <code>TagType<\/code> diz o tipo do campo (o item ocupa o n\u00famero de bytes correspondente). <code>SwapBytes<\/code>\/<code>SwapWords<\/code>\/<code>SwapDWords<\/code> valem por item.<\/li>\n<li><img decoding=\"async\" alt=\"\" src=\"https:\/\/www.pascalscada.com\/wp-content\/uploads\/2026\/09\/TPLCStructString.png\"> <strong><code>TPLCStructString<\/code><\/strong> \u2014 um campo texto. <code>Index<\/code> \u00e9 o offset, <code>StringSize<\/code> o tamanho m\u00e1ximo em caracteres, <code>StringType<\/code> o formato (<code>stC<\/code> ou <code>stSIEMENS<\/code>, veja <code>TPLCString<\/code> abaixo) e <code>StringEncoding<\/code> a p\u00e1gina de c\u00f3digo do equipamento.<\/li>\n<\/ul>\n<p>Exemplo \u2014 um DB Siemens com esta estrutura:<\/p>\n<table>\n<thead>\n<tr>\n<th>Offset<\/th>\n<th>Tipo<\/th>\n<th>Nome<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>0<\/td>\n<td><code>INT<\/code><\/td>\n<td>Contador<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td><code>REAL<\/code><\/td>\n<td>Temperatura<\/td>\n<\/tr>\n<tr>\n<td>6<\/td>\n<td><code>STRING[20]<\/code><\/td>\n<td>Nome do produto (22 bytes com o cabe\u00e7alho Siemens)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>fica: <code>TPLCStruct<\/code> com <code>Size = 28<\/code>; <code>TPLCStructItem<\/code> com <code>Index = 0, TagType = pttSmallInt<\/code>; outro com <code>Index = 2, TagType = pttFloat<\/code>; e um <code>TPLCStructString<\/code> com <code>Index = 6, StringSize = 20, StringType = stSIEMENS<\/code>.<\/p>\n<p>O assistente <strong>Map structure items\u2026<\/strong> (bot\u00e3o direito na estrutura) cria os itens a partir de uma lista de tipos que voc\u00ea monta na tela, calculando os offsets automaticamente.<\/p>\n<p>Assim como no bloco, <code>AutoWrite = False<\/code> + <code>WriteDirect<\/code> grava a estrutura inteira em uma \u00fanica requisi\u00e7\u00e3o.<\/p>\n<h5 id=\"TPLCString\">TPLCString<\/h5>\n<p><img decoding=\"async\" alt=\"\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/plcstring.png\"> L\u00ea e escreve um texto do equipamento. O valor fica na propriedade <code>Value<\/code> (<code>UTF8String<\/code>) e os controles <code>THMIEdit<\/code>\/<code>THMILabel<\/code> mostram e editam texto quando ligados a um <code>TPLCString<\/code>.<\/p>\n<ul>\n<li><strong><code>StringSize<\/code><\/strong> \u2014 quantidade m\u00e1xima de caracteres.<\/li>\n<li><strong><code>StringType<\/code><\/strong> \u2014 como a string \u00e9 armazenada no equipamento:\n<ul>\n<li><code>stC<\/code> \u2014 os caracteres seguem at\u00e9 encontrar um byte <code>0<\/code> (terminador C). Use para Modbus, Melsec e para CLPs Rockwell (apontando <code>LongAddress<\/code> para o membro <code>DATA<\/code> da <code>STRING<\/code>, ex.: <code>MinhaString.DATA<\/code> \u2014 \u00e9 o que o assistente de importa\u00e7\u00e3o de tags Rockwell faz).<\/li>\n<li><code>stSIEMENS<\/code> \u2014 o formato <code>STRING<\/code> do S7: dois bytes de cabe\u00e7alho (tamanho m\u00e1ximo e tamanho usado) seguidos dos caracteres. O tag ocupa <code>StringSize + 2<\/code> bytes.<\/li>\n<li><code>stROCKWELL<\/code> \u2014 reservado, ainda n\u00e3o implementado; devolve string vazia.<\/li>\n<\/ul>\n<\/li>\n<li><strong><code>StringEncoding<\/code><\/strong> \u2014 p\u00e1gina de c\u00f3digo do equipamento (<code>UTF_8<\/code>, <code>CP1252<\/code>, <code>CP850<\/code>\u2026). O tag converte de\/para UTF-8 automaticamente.<\/li>\n<\/ul>\n<p><code>OnAsyncStringChange<\/code> \u00e9 o equivalente de <code>OnAsyncValueChange<\/code> para strings.<\/p>\n<h5 id=\"TTagBit\">TTagBit<\/h5>\n<p><img decoding=\"async\" alt=\"\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/tagbit.png\"> Extrai um intervalo de bits de outro tag num\u00e9rico (<code>PLCTag<\/code>), sem gerar comunica\u00e7\u00e3o adicional. <code>StartBit<\/code> \u00e9 o bit menos significativo e <code>EndBit<\/code> o mais significativo do intervalo (ambos a partir de 0, m\u00e1ximo 31; <code>EndBit &gt;= StartBit<\/code>). O valor do <code>TTagBit<\/code> \u00e9 o intervalo deslocado para a direita:<\/p>\n<table>\n<thead>\n<tr>\n<th>Valor do tag origem<\/th>\n<th>StartBit<\/th>\n<th>EndBit<\/th>\n<th>Valor do TTagBit<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>5 (<code>101b<\/code>)<\/td>\n<td>0<\/td>\n<td>0<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>5 (<code>101b<\/code>)<\/td>\n<td>0<\/td>\n<td>2<\/td>\n<td>5<\/td>\n<\/tr>\n<tr>\n<td>5 (<code>101b<\/code>)<\/td>\n<td>1<\/td>\n<td>2<\/td>\n<td>2 (<code>10b<\/code>)<\/td>\n<\/tr>\n<tr>\n<td>5 (<code>101b<\/code>)<\/td>\n<td>2<\/td>\n<td>2<\/td>\n<td>1<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Escrever no <code>TTagBit<\/code> funciona: ele l\u00ea o valor atual do tag origem, altera s\u00f3 os bits do intervalo e escreve o resultado de volta \u2014 ent\u00e3o com <code>AutoWrite = True<\/code> o bit vai para o equipamento.<\/p>\n<p><code>UseRawValue<\/code> diz se os bits v\u00eam de <code>ValueRaw<\/code> (<code>True<\/code>) ou de <code>Value<\/code> (<code>False<\/code>, padr\u00e3o). Ligue quando o tag origem tiver escala.<\/p>\n<p>O uso t\u00edpico \u00e9 uma palavra de status ou de comando do CLP em que cada bit tem um significado: um <code>TPLCTagNumber<\/code> l\u00ea a palavra e um <code>TTagBit<\/code> por bit alimenta os <code>THMICheckBox<\/code>. O assistente <strong>Map bits<\/strong> (bot\u00e3o direito em qualquer tag num\u00e9rico) cria os 8, 16 ou 32 <code>TTagBit<\/code> de uma vez. O exemplo <a href=\"https:\/\/github.com\/fluisgirardi\/pascalscada_v0\/tree\/master\/examples\/laz_isotcp_mapping_bits_from_other_tag\"><code>examples\/laz_isotcp_mapping_bits_from_other_tag<\/code><\/a> mostra isso com um byte de DB Siemens.<\/p>\n<h5 id=\"TNumericExprTag\">TNumericExprTag<\/h5>\n<p><img decoding=\"async\" alt=\"\" src=\"https:\/\/www.pascalscada.com\/wp-content\/uploads\/2026\/09\/TNumericExprTag.png\"> Um tag num\u00e9rico virtual: o valor \u00e9 o resultado de <code>Expression<\/code>, avaliada sempre que um dos tags ligados \u00e0s vari\u00e1veis <code>A<\/code> a <code>J<\/code> mudar. N\u00e3o tem driver nem endere\u00e7o.<\/p>\n<pre><code>Expression = 'A * B \/ 100'\nExpression = 'ifthen(A &gt; 80, 1, 0)'\nExpression = 'sqrt(sqr(A) + sqr(B))'\n<\/code><\/pre>\n<p>A sintaxe \u00e9 a do <code>TFPExpressionParser<\/code> do Free Pascal (operadores aritm\u00e9ticos, compara\u00e7\u00e3o, <code>and<\/code>\/<code>or<\/code>\/<code>not<\/code>, fun\u00e7\u00f5es matem\u00e1ticas, e a fun\u00e7\u00e3o <code>ifthen(condi\u00e7\u00e3o, seVerdadeiro, seFalso)<\/code> adicionada pelo PascalSCADA). Um erro na express\u00e3o fica em <code>LastEvalutionError<\/code>. Pode ter <code>ScaleProcessor<\/code>. Veja a p\u00e1gina <a href=\"\/pb\/numeric-expression-tag\/\">Tag de express\u00e3o num\u00e9rica<\/a> para mais exemplos.<\/p>\n<h5>Criando tags em tempo de execu\u00e7\u00e3o<\/h5>\n<p>Tags s\u00e3o <code>TComponent<\/code>, ent\u00e3o podem ser criados por c\u00f3digo \u2014 \u00fatil para aplica\u00e7\u00f5es que carregam a configura\u00e7\u00e3o de um banco de dados:<\/p>\n<pre class=\"brush: delphi; tab-size: 2; title: ; notranslate\" title=\"\">uses PLCTagNumber, ProtocolTypes;\n\nvar\n  t: TPLCTagNumber;\nbegin\n  t := TPLCTagNumber.Create(Self);\n  t.Name := &#039;Nivel_Tanque1&#039;;\n  t.MemReadFunction := 3;    \/\/ Modbus: holding register\n  t.MemWriteFunction := 16;\n  t.MemAddress := 100;\n  t.PLCStation := 1;\n  t.TagType := pttFloat;\n  t.SwapWords := True;\n  t.RefreshTime := 500;\n  t.ProtocolDriver := ModBusTCPDriver1;   \/\/ ligue o driver por \u00faltimo\n  t.OnValueChange := @NivelMudou;\nend;<\/pre>\n<p>Ligue <code>ProtocolDriver<\/code> depois de configurar o endere\u00e7o: ao receber o driver, o tag se registra no scan dele com o endere\u00e7o que tem naquele momento. Para remover, basta <code>t.Free<\/code> \u2014 o tag se desregistra do driver e dos controles ligados a ele.<\/p>\n<h5>Exemplos relacionados<\/h5>\n<ul>\n<li><a href=\"https:\/\/github.com\/fluisgirardi\/pascalscada_v0\/tree\/master\/examples\/TagTypes\"><code>examples\/TagTypes<\/code><\/a> \u2014 o mesmo bloco Modbus lido com todos os <code>TagType<\/code> (<code>pttByte<\/code> a <code>pttDouble<\/code>) e as combina\u00e7\u00f5es de <code>SwapBytes<\/code>\/<code>SwapWords<\/code>, com <code>TPLCBlockElement<\/code> e <code>TPLCStructItem<\/code> lado a lado; o melhor lugar para ver o efeito de cada tipo.<\/li>\n<li><a href=\"https:\/\/github.com\/fluisgirardi\/pascalscada_v0\/tree\/master\/examples\/laz_isotcp_mapping_bits_from_other_tag\"><code>examples\/laz_isotcp_mapping_bits_from_other_tag<\/code><\/a> \u2014 um <code>TPLCTagNumber<\/code> <code>pttByte<\/code> e um <code>TTagBit<\/code> por bit.<\/li>\n<li><a href=\"https:\/\/github.com\/fluisgirardi\/pascalscada_v0\/tree\/master\/examples\/laz_numericexpr\"><code>examples\/laz_numericexpr<\/code><\/a> \u2014 <code>TNumericExprTag<\/code> somando dois tags dirigidos por <code>THMITrackBar<\/code>.<\/li>\n<li><a href=\"https:\/\/github.com\/fluisgirardi\/pascalscada_v0\/tree\/master\/examples\/laz_modbus_tcp_example\"><code>examples\/laz_modbus_tcp_example<\/code><\/a> \u2014 <code>TPLCBlock<\/code> + <code>TPLCBlockElement<\/code>, <code>TPLCTagNumber<\/code> e controles de entrada sobre Modbus TCP.<\/li>\n<li><a href=\"https:\/\/github.com\/fluisgirardi\/pascalscada_v0\/tree\/master\/examples\/laz_console_app\"><code>examples\/laz_console_app<\/code><\/a> \u2014 tags e driver Modbus TCP em uma aplica\u00e7\u00e3o de console, sem LCL (um datamodule sem forms).<\/li>\n<li><a href=\"https:\/\/github.com\/fluisgirardi\/pascalscada_v0\/tree\/master\/examples\/hmi_bandeja\"><code>examples\/hmi_bandeja<\/code><\/a> \u2014 <code>TPLCStruct<\/code> com <code>TPLCStructItem<\/code> e <code>TPLCStructString<\/code> mapeando um DB Siemens.<\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>Introdu\u00e7\u00e3o No PascalSCADA, um tag \u00e9 o componente que representa uma mem\u00f3ria (ou um conjunto de mem\u00f3rias) de um equipamento: uma holding register de um inversor Modbus, um byte de &#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"open","ping_status":"open","template":"","meta":{"footnotes":""},"class_list":["post-439","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.pascalscada.com\/pb\/wp-json\/wp\/v2\/pages\/439","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.pascalscada.com\/pb\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.pascalscada.com\/pb\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.pascalscada.com\/pb\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pascalscada.com\/pb\/wp-json\/wp\/v2\/comments?post=439"}],"version-history":[{"count":17,"href":"https:\/\/www.pascalscada.com\/pb\/wp-json\/wp\/v2\/pages\/439\/revisions"}],"predecessor-version":[{"id":1235,"href":"https:\/\/www.pascalscada.com\/pb\/wp-json\/wp\/v2\/pages\/439\/revisions\/1235"}],"wp:attachment":[{"href":"https:\/\/www.pascalscada.com\/pb\/wp-json\/wp\/v2\/media?parent=439"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}