Red de conocimiento informático - Conocimiento informático - Documento en lenguaje C integrado

Documento en lenguaje C integrado

Transplantación y optimización de operaciones de bits en lenguaje C integrado

La aplicación de microcontroladores está cada vez más extendida y cada vez hay más tipos. Debido a que el lenguaje C incorporado es altamente legible y portátil, en comparación con el lenguaje ensamblador, reduce en gran medida la intensidad de trabajo de los ingenieros de software. Por lo tanto, cada vez más ingenieros de microcontroladores están comenzando a utilizar la programación en lenguaje C. Sin embargo, la portabilidad del lenguaje C se limita a subrutinas independientes del hardware, mientras que las subrutinas relacionadas con hardware específico no se pueden portar. En las aplicaciones de microcontroladores, las operaciones de bits (especialmente las operaciones de bits en pines) son muy comunes, como leer y escribir datos de EEPROM y datos de tarjetas IC, pantallas LCD de campo, etc. Muchos circuitos integrados con puertos serie requieren software de microcontrolador para hacerlo. Programa de lectura y escritura de puertos O. Cómo hacer que estas subrutinas sean versátiles y eficientes en la generación de código es una cuestión que muchos ingenieros de software están considerando. A continuación se presentan dos métodos de trasplante para operaciones de bits en lenguaje C.

1 Utilice operaciones lógicas para implementar operaciones de bits

Mire la siguiente subrutina:

INT8U Card102RdByte(void) {

INT8U Temp8U, n = 8;

hacer{ Temp8U lt;

if( PIN_CARD_SDA_RD() ) Temp8U |=

PIN_CARD_CLK_H( ) ;PIN_CARD_CLK_L();

} while(--n);

devuelve Temp8U;

}

Esto se inicia mediante el microcontrolador Una subrutina que lee un byte de la tarjeta 88SC102. El programa adopta el estilo de escritura en μC/OSII, es decir, las variables y funciones se escriben en "caja de camello", y las constantes y funciones en línea definidas por define se escriben en mayúsculas y subrayadas.

Este programa controla un pin para emitir señales altas y bajas CARD_CLK y lee datos CARD_SDA bit a bit desde otro pin.

1.1 Para microcontroladores de la serie MSP430

Este programa se aplica a los microcontroladores MSP430 (este artículo utiliza microcontroladores MSP430F413. El archivo de encabezado debe tener las siguientes definiciones:

). typedefunsigned charINT8U;

#includelt;msp430x41x.hgt;

#definePIN_CARD_SDA_RD()(P6IN amp; 0x01)

#definePIN_CARD_CLK_H()P6OUT |=0x04

#definePIN_CARD_CLK_L()P6OUT amp;= ~0x04

Los resultados del ensamblaje son los siguientes:

En el segmento CÓDIGO, alinee 2, mantenga?con?siguiente

__código carácter sin firmar Card102RdByte(void)

Card102RdByte:

0000007E42MOV.B#0x8, R14

?Card102RdByte_0:

0000024C5CRLA.BR12

000004D2B33400BIT.B#0x1, amp;0x34

0000080128JNC?Card102RdByte_1

00000A5CD3BIS.B#0x1, R12

?Card102RdByte_1:

00000CE2D23500BIS.B#0x4 y 0x35

000010E2C23500BIC.B#0x4 y 0x35

0000147E53ADD.B#0xff, R14

0000164E93CMP.B#0x0, R14

000018F423 JNE?Card102RdByte_0

00001A3041RET

Esto es casi el mismo que el resultado del manual Programación ensambladora. El código es muy eficiente.

1.2 Para microcontroladores serie 51

Para aplicar este programa en los microcontroladores serie 51 se deben agregar las siguientes definiciones al archivo de encabezado:

#include " Reg932.h" //Microcontrolador Philips LPC932

sbitCradClk=P0^1;

sbitCardSDA=P0^0;

#definePIN_CARD_SDA_RD()CardSDA

#definePIN_CARD_CLK_H()CradClk=1

#definePIN_CARD_CLK_L()CradClk=0

El programa original no realiza ningún cambio y el resultado del ensamblaje es el siguiente:

; FUNCIÓN Tarjeta102RdByte (BEGIN)

;-- Variable 'Temp8U' asignada al Registro 'R7' --

;-- Variable 'n' asignada a Registro 'R6' --

00007E08MOVR6, #08H

0002?C0007:

0002EFMOVA, R7

000325E0ADDA, ACC

0005FFMOVR7, A

p>

0006308003JNBCardSDA,?C0008

0009430701ORLAR7,#01H

000C?C0008:

000CD281SETBCradClk

000EC281CLRCradClk

0010DEF0DJNZR6,?C0007

0012?C0009:

001222RET

; FIN)

Por resultado del ensamblaje Se puede ver que la limpieza y configuración directa de bits ha alcanzado el nivel más simple, pero leer el valor del bit no es lo suficientemente ideal.

1.3 Para microcontroladores de la serie 196/296

En 80C196MC, 80C296SA y otros microcontroladores, los puertos de E/S en chip se pueden asignar en ventana a direcciones de gama baja. De esta manera, el puerto de E/S se puede direccionar directamente, por lo que el código del programa es el más corto y la velocidad de ejecución es la más rápida. Sin embargo, el programa C no se puede trasplantar de esta manera. Si no se utiliza la tecnología de ventanas, los puertos de E/S en el chip tienen direcciones de memoria asignadas y funcionan como direcciones de memoria normales. Agregue la siguiente definición al archivo de encabezado para usar el programa original:

INT8UPOUT, PIN;

#pragmalocate(POUT=0x880)

#pragmalocate(PIN =0x881)//Posicionamiento de la dirección del puerto de E/S de expansión externa

#definePIN_CARD_SDA_RD()(PIN amp; 0x01)

#definePIN_CARD_CLK_H()POUT |=0x04

#definePIN_CARD_CLK_L()POUT amp;= ~0x04

El código ensamblado tiene 56 bytes y la eficiencia del código también es muy alta.

Utilizando operaciones lógicas para implementar operaciones de bits, el programa C es simple y claro, tiene buena portabilidad y es mejor legible. Sin embargo, la MCU de la serie 96 no puede usar instrucciones de operación de bits JBC y JBS, y la MCU de la serie 51 no puede usar sus instrucciones de operación de bits únicas, como JB y JNB, para mejorar la eficiencia del código. La implementación de operaciones de bits utilizando estructuras de segmentos de bits puede compensar esta deficiencia.

2 Utilice la estructura de segmentos de bits para implementar operaciones de bits

Reescriba el programa original de la siguiente manera:

INT8U Card102RdByte(void)①

{ ②

INT8U n = 8; ③

#ifndef C51_ASM④

bdata ACCImg; p > hacer{ ACC lt; = 1; ⑦

GET_CARD_SDA(); ⑧

PIN_CARD_CLK_H(); ( --n); ⑩

return ACC;

}

2.1 Aplicación en microcontroladores de la serie 51

Utilizado en C51 ACC. No es necesario definirlo en cada subrutina, por lo que se debe agregar #define C51_ASM al principio del archivo. De esta forma, se ignorarán las oraciones ④, ⑤ y ⑥. Agregue las siguientes definiciones al archivo de encabezado:

sbitACC_0=ACC^0;

#defineGET_CARD_SDA()ACC_0 = CardSDA

Las definiciones restantes son como en el narra la primera parte de este artículo. Como resultado, el conjunto de la oración ⑧ se convierte en dos oraciones: "MOV C, CardSDA" y "MOV ACC_0, C". frase, la función necesita devolver parámetros a través de R7 y el programa ha alcanzado su forma más simple.

; FUNCIÓN Card102RdByte (BEGIN)

-- Variable 'n' asignada al Registro 'R7'--

00007F08MOVR7, #08H

0002?C0007:

000225E0ADDA, ACC

0004A281MOVC, CardSDA

000692E0MOVACC_0, C

0008D280SETBCardClk

000AC280CLRCardClk

000CDFF4DJNZR7,?C0007

000EFFMOVR7,A

000F?C0008:

000F22RET

; FUNCIÓN Card102RdByte (END)

También puede definir una estructura de segmento de bits como 196/296, utilizando la instrucción JB. Los lectores interesados ​​pueden probarlo ellos mismos.

2.2 Aplicación en microcontroladores serie 196/296

Para aplicar este programa en 196/296 es necesario añadir la definición de una variable local ACCImg, que es la ④ en el anterior programa, ⑤, ⑥ tres oraciones.

Luego agregue la siguiente definición de estructura de segmento de bits al archivo de encabezado:

typedef struct {unsigned Bit0: 1

unsigned Bit1:

unsigned Bit2 : 1;

Bit3 sin firmar: 1;

Bit4 sin firmar: 1;

Bit7 sin firmar: 1;

}Divide_to_bit;

unión typedef {INT8U Byte;

Divide_to_bit DivBit;

}bdata;

La variable de dirección del puerto debe definirse como el siguiente tipo de datos:

bdata PIN

Al mismo tiempo, agregue definiciones de macro; en el archivo de encabezado:

#defineACC ACCImg.Byte

#defineACC_0 ACCImg.DivBit.Bit0

#defineGET_CARD_SDA() if(PIN.DivBit.Bit0) ACC |=0x01 ;

De esta manera, ACCImg se define como un registro de extremo bajo y ACC es su forma de acceso a bytes. La octava oración en el programa fuente lee el pin y el resultado del ensamblaje usa la instrucción JBC. Todo el programa reduce bytes en comparación con no usar segmentos de bits, logrando el propósito de optimizar el código.

cseg

0000Card102RdByte:

; Declaración3

0000B10800Rldbn, #8

;

0003 @ 0004:

0003740101RaddbACCImg,ACCImg

; Declaración8

0006B30181081CldbTmp0,PIN

000B 331C03jbcTmp0,3,@0005

000E 910101 RorbACCImg, #1

0011 @ 0005:

; Declaración9

0011 B30180081CldbTmp0, POUT

0016 91041CorbTmp0, #4

0019 C70180081CstbTmp0, POUT

001E 71FB1C andbTmp0, #0FBH

0021 C70180081C stbTmp0, POUT

; Declaración10

00261500Rdecbn

0028980000RcmpbR0,n

002BD7D6bne @ 0004

; Declaración11

002DB0011C RldbTmp0,ACCImg

00302000 br @ 0001

; Statement12

0032 @ 0001:

0032F0ret

2.3 en microcontrolador serie MSP430 Aplicación

Los microcontroladores de la serie MSP430 no tienen instrucciones de operación de bits, por lo que no es necesario definir la estructura del segmento de bits, simplemente defina ACC como un número de 8 dígitos sin signo. El archivo de encabezado se define así:

#ifndef C51_ASM//Esta oración permite que el archivo de encabezado se use con C51 ***

typedef INT8U bdata;

#define ACC ACCImg

#define GET_CARD_SDA() if(P6IN amp; 0x01) ACC |=0x01;

#endif

El resultado del ensamblaje es lo mismo que las operaciones de bits que utilizan operaciones lógicas son exactamente iguales.

Conclusión

Hay tres tipos de operaciones de bits en pines: configuración o borrado directo, entrada de datos desde el puerto y salida de datos desde el puerto. Los dos primeros se han presentado anteriormente. El programa C para generar datos desde el puerto es el siguiente:

do{

OUT_SIO_DA()

CLK_H(); > ACC lt; = 1; //Cambiar ancho de pulso de reloj extensible

CLK_L();

}mientras

Donde: La primera oración OUT_SIO_DA( ), La serie 51 se puede definir como operación de bits SIO_SDA = ACC_7; las series 196/296 y 430 se pueden definir como una declaración if como se indicó anteriormente.

El nombre ACC se utiliza como variable local en el programa de operación del segmento de bits. En C51, este pasa a ser el acumulador principal, lo cual es muy práctico para programas con dispositivos semidúplex como 2401 y tarjetas IC, pero no es tan conveniente cuando la entrada/salida del bus SPI opera al mismo tiempo.

El uso de operaciones lógicas para implementar operaciones de bits no presenta ningún obstáculo a la portabilidad. Todas las operaciones de bits en μC/OS-II se implementan mediante operaciones lógicas. Puede haber problemas con las definiciones de segmentos de bits debido a los diferentes órdenes de asignación de diferentes compiladores, pero considerando que las CPU de alta velocidad de 32 bits no utilizarán software para simular el funcionamiento de este puerto serie, dicho programa solo se utilizará en 51 , 196/296, MSP430 y otros microcontroladores que no son de chip. En los microcontroladores de velocidad media y baja de Cache, el método de utilizar segmentos de bits para operar pines todavía tiene sentido. El uso de operaciones lógicas o campos de bits para operaciones de bits depende completamente de las preferencias personales. Los compiladores utilizados en el programa de este artículo son Keil C51 V7.03, IAR C430 V2.10A y Tasking C96 V5.0.