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 p>
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.