Este artículo es un artículo espejo de traducción automática, por favor haga clic aquí para saltar al artículo original.

Vista: 10835|Respuesta: 1

Zigbee Journey (10): Experimento integral - Sistema de monitorización de temperatura basado en CC2430

[Copiar enlace]
Publicado en 30/10/2014 23:47:44 | | | |
Tras escribir "Zigbee Journey (9)" el 3 de marzo, el autor planeaba comenzar inmediatamente a escribir un pequeño experimento sobre "sistema de monitorización de temperatura" como resumen de una serie de puntos de conocimiento dispersos anteriores. Sin embargo, también me di cuenta de que, aunque cada uno de los pequeños experimentos anteriores se describía en detalle, la naturaleza normativa y estructural de su código podía considerarse insoportable. Dado que es un resumen, deberíamos avanzar sobre la base original, en lugar de reconstruir mecánicamente los pequeños puntos de conocimiento anteriores. Por ello, dejé mi plan original en pausa, me tomé tiempo para aprender las técnicas generales del desarrollo embebido y escribí dos ensayosEspecificación de programación C51 embebida" y "Jerarquía de la estructura de código de proyecto embebida》。 Este registro no solo es un resumen del primer viaje de Zigbee, sino que también incorpora la experiencia de aprendizaje del autor en los últimos días, con la esperanza de ser útil para los principiantes en Zigbee.
El texto completo está organizado según el proceso básico de desarrollo de software: análisis de requisitos, diseño esquematizado, diseño detallado, implementación de codificación y pruebas.
1. Análisis de la demanda
Tras una discusión entre el "cliente" y el "desarrollador", se determinó la siguiente descripción de la función del sistema:
… La temperatura actual de la habitación es recogida por nodos basados en CC2430, y sus valores de temperatura pueden monitorizarse mediante un PC
… El propio nodo CC2430 debe tener cierto grado de estabilidad y puede volver automáticamente al estado normal
… El intervalo de muestreo y la gestión de energía del nodo pueden ser controlados por un PC
2. Diseño de esquemas
Según el análisis de requisitos anterior, podemos dividir el sistema en dos módulos:Nodo CC2430yPC
  [Nodo CC2430]  
… Los parámetros externos pueden recopilarse regularmente y enviarse al PC
… Reinicio automático cuando la máquina se apaga
… Se pueden recibir y procesar comandos del PC en consecuencia: cambiar el intervalo de muestra/gestión de energía
  [PC]  
… La máquina C recibe y muestra datos a través de la herramienta de puerto serial
… Las instrucciones pueden enviarse al microcontrolador a través de la herramienta de puerto serie para controlar su velocidad de muestreo y la gestión de la energía
3. Diseño detallado
(1) Estructura del código
La superposición de la estructura del código de este sistema ha sido descrita en el ensayo "Jerarquía de la estructura de código de proyecto embebida, y la copia es la siguiente:
(1) Capa de abstracción de hardware
      [ioCC2430.h] (Sistema incluido)Todos los vectores SFR y de interrupción del CC2430 están definidos
      [hal.h] Incluye definiciones comunes de tipos, macros de asignación comunes y configuración común de recursos CC2430 en chip (E/S, comunicación serie, ADC, temporizador, gestión de energía, etc.)
  (2) Capa funcional de módulos
      [module.h] define recursos dentro del chip (temporizadores, E/S), módulos de expansión externos (LEDs) y declaraciones de funciones relacionadas
      [module.cImplementa la inicialización de cada módulo (LED).
  (3) Capa de aplicación
      [main.cConsulte hal.h, ioCC2430.h y module.h para cumplir requisitos específicos de aplicación como la adquisición de temperatura, la intercomunicación con PC y el apagado y reinicio
(2) Métodos de implementación de cada módulo
Según los módulos divididos según el diseño de contorno, el sistema intrínseco puede dividirse en dos módulos principales:Nodo CC2430yPC
Como el PC dispone de herramientas de comunicación por puerto serial, sus funciones pueden cumplir con los requisitos, así que no necesitamos hacer esta parte del PC ni analizarla. Hablemos más abajo de la sección CC2430
El método de implementación de cada subfunción del punto:
… Utiliza la interrupción de desbordamiento de conteo del temporizador para activar el muestreo temporizado
… El modo UART0 con puerto serie transmite datos de temperatura a un PC
… El circuito watchdog integrado del CC2430 se utiliza para realizar la función de reinicio automático del sistema
… El puerto serie se utiliza para recibir interrupciones que capturan y responden a comandos de control del PC
1) Si se recibe@El carácter es el comando de control de intervalo de muestreo, seguido de un número que indica el intervalo de muestreo: 0-0,5s, 1-1s, 2-2s
如:@0,表示每隔0.5秒采样一次。
2) Si se recibe$  El carácter es el comando de control de suspensión, seguido de un número que indica el modo de encendido
Por ejemplo: $3, lo que significa poner el sistema en modo de alimentación 3.
(3) Diagrama de flujo del programa
  • Diagrama de flujo del programa maestro
  • Diagrama de flujo del programa de interrupción de desbordamiento del temporizador 1
  • Diagrama de flujo del procedimiento de recepción de interrupciones en puertos seriales




4. Implementación de codificación
(1) Capa de abstracción de hardware
La capa de abstracción de hardware incluye ioCC2430.h y hal.h. Como el sistema anterior lo incluye, no aparecerá en la lista.
A continuación se muestra una lista de todo el contenido de hal.h (como este archivo es demasiado largo y resulta incómodo, lo mostraré en módulos):
  • cabeza
  • Puertos de E/S
  • Interrumpido
  • Puerto serial
  • Gestión de energía y reloj
  • Temporizador
  • Perro guardián
  • ADC
[url=] [/url]
/***********************************************************
*Nombre del archivo: hal.h
*Autor: hustlzp
*Fecha: 8 de marzo de 2011
*Edición: 1.1
*Descripción de la función: Capa de abstracción de hardware
*Récords modificados:
**********************************************************
*/


#ifndef HAL_H
#defineHAL_H


#include


/***********************************************************
                       Definiciones comunes de tipos
**********************************************************
*/
typedef unsignedchar   BYTE;
typedef unsignedint    PARE;
typedef unsignedlargo   DWORD;



/***********************************************************
                       Definiciones macro más utilizadas
**********************************************************
*/

//8 puestos más arriba
#defineHIGH_BYTE(a) ((BYTE) (((WORD)(a)) >> 8))


//8 puestos más abajo
#defineLOW_BYTE(a) ((BYTE) ((WORD)(a)))


//Asignación
#defineSET_WORD(regH,regL,word)  
   hacer{                           
      (regH)=HIGH_BYTE(palabra);     
      (regL)=LOW_BYTE(palabra);      
   }mientras(0)
[url=] [/url]

[url=] [/url]
/***********************************************************
                       Puertos de E/S
**********************************************************
*/
/*Configurar la dirección del puerto de E/S
-----------------------------------------
*/
#defineIO_DIR_PORT_PIN(puerto, pin, dir)  
   hacer{                                 
      si(dir: == IO_OUT)                 
         P##port##DIR |= (0x01<<(pin));  
      si no,                              
         P##port##DIR &= ~(0x01<<(pin));
   }mientras(0)



//El valor del director del parámetro es:
#defineIO_IN 0
#defineIO_OUT 1


/*Configura el modo de entrada del puerto de E/S
-----------------------------------------
*/
#defineIO_IMODE_PORT_PIN(puerto, pin, imode)
   hacer{                                    
      si(imode == IO_IMODE_TRI)            
         P##port##INP |= (0x01<<(pin));     
      si no,                                 
         P##port##INP &= ~(0x01<<(pin));   
   }mientras (0)



#define IO_PUD_PORT(babor, pud)        
   do {                              
      si (pud == IO_PULLDOWN)         
         P2INP |= (0x01 << (puerto+5));
      si no,                           
         P2INP &= ~(0x01 << (puerto+5));
   } mientras (0)


El valor del parámetro PUD es:
#define IO_PULLUP 0 // Tira hacia arriba
#define IO_PULLDOWN 1 // Atirar hacia abajo


/*配置I/O口的功能
-----------------------------------------*/

#define IO_FUNC_PORT_PIN(puerto, pin, función)  
   do {                                    
      if((port == 2) && (pin == 3)){      
         si (función) {                       
            P2SEL |= 0x02;                 
         } else {                          
            P2SEL &= ~0x02;               
         }                                 
      }                                    
      else if((port == 2) & & (pin == 4)){  
         si (función) {                       
            P2SEL |= 0x04;                 
         } else {                          
            P2SEL &= ~0x04;               
         }                                 
      }                                    
      else{                                
         si (función) {                       
            P##port##SEL |= (0x01<<(pine));
         } else {                          
            P##port##SEL &= ~(0x01<<(pine));
        }                                 
      }                                    
   } mientras (0)


El valor de la función del parámetro es:
#define IO_FUNC_GIO 0 // E/S general
#define IO_FUNC_PERIPH 1 // E/S periférica


Configurar la ubicación de la E/S periférica
#define IO_PER_LOC_TIMER1_AT_PORT0_PIN234() do { PERCFG = (PERCFG&~0x40)|0x00; } mientras (0)
#define IO_PER_LOC_TIMER1_AT_PORT1_PIN012() do { PERCFG = (PERCFG&~0x40)|0x40; } mientras (0)

#define IO_PER_LOC_TIMER3_AT_PORT1_PIN34() do { PERCFG = (PERCFG&~0x20)|0x00; } mientras (0)
#define IO_PER_LOC_TIMER3_AT_PORT1_PIN67() do { PERCFG = (PERCFG&~0x20)|0x20; } mientras (0)

#define IO_PER_LOC_TIMER4_AT_PORT1_PIN01() do { PERCFG = (PERCFG&~0x10)|0x00; } mientras (0)
#define IO_PER_LOC_TIMER4_AT_PORT2_PIN03() do { PERCFG = (PERCFG&~0x10)|0x10; } mientras (0)

#define IO_PER_LOC_SPI1_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x08)|0x00; } mientras (0)
#define IO_PER_LOC_SPI1_AT_PORT1_PIN4567() do { PERCFG = (PERCFG&~0x08)|0x08; } mientras (0)

#define IO_PER_LOC_SPI0_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x04)|0x00; } mientras (0)
#define IO_PER_LOC_SPI0_AT_PORT1_PIN2345() do { PERCFG = (PERCFG&~0x04)|0x04; } mientras (0)

#define IO_PER_LOC_UART1_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x02)|0x00; } mientras (0)
#define IO_PER_LOC_UART1_AT_PORT1_PIN4567() do { PERCFG = (PERCFG&~0x02)|0x02; } mientras (0)

#define IO_PER_LOC_UART0_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x00; } mientras (0)
#define IO_PER_LOC_UART0_AT_PORT1_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x01; } mientras (0)

//El valor del parámetro imode es:
#defineIO_IMODE_PUD 0   //Tira hacia arriba/tira hacia abajo
#defineIO_IMODE_TRI 1   //Tres estados[url=] [/url]

[url=] [/url]
/***********************************************************
                       Interrumpido
**********************************************************
*/
//Para interrupciones de encendido/apagado
#defineINT_ON 1
#defineINT_OFF 0


//Se usaba para colocar/borrar banderas de interrupción
#defineINT_SET 1
#defineINT_CLR 0


//Configuración global de interrupciones
#defineINT_GLOBAL_ENABLE(en) EA=(!! en)


//Define la ruptura
#defineINUM_RFERR 0
#defineINUM_ADC 1
#defineINUM_URX0 2
#defineINUM_URX1 3
#defineINUM_ENC 4
#defineINUM_ST 5
#defineINUM_P2INT 6
#define7 INUM_UTX0
#define8 INUM_DMA
#defineINUM_T1 9
#define10 INUM_T2
#define11 INUM_T3
#define12 INUM_T4
#defineINUM_P0INT 13
#define14 INUM_UTX1
#defineINUM_P1INT 15
#define16 INUM_RF
#define17 INUM_WDT


/*Interrupciones permitidas
-----------------------------------------
*/
#defineINT_ENABLE(en el inum, on)                        
   hacer{                                             
      si      (inum==INUM_RFERR) { RFERRIE = encendido; }  
      si no, si(inum==INUM_ADC)   { ADCIE = encendido; }  
      si no, si(inum==INUM_URX0)  { URX0IE = encendido; }  
      si no, si(inum==INUM_URX1)  { URX1IE = encendido; }  
      si no, si(inum==INUM_ENC)   { ENCIE = on; }  
      si no, si(inum==INUM_ST)    { STIE = encendido; }  
      si no, si(inum==INUM_P2INT) { (encendido)? (IEN2 |=0x02) : (IEN2 &= ~0x02); }
      si no, si(inum==INUM_UTX0)  { (encendido)? (IEN2 |=0x04) : (IEN2 &= ~0x04); }
      si no, si(inum==INUM_DMA)   { DMAIE = encendido; }  
      si no, si(inum==INUM_T1)    { T1IE = on; }  
      si no, si(inum==INUM_T2)    { T2IE = encendido; }  
      si no, si(inum==INUM_T3)    { T3IE = on; }  
      si no, si(inum==INUM_T4)    { T4IE = on; }  
      si no, si(inum==INUM_P0INT) { P0IE = encendido; }  
      si no, si(inum==INUM_UTX1)  { (encendido)? (IEN2 |=0x08) : (IEN2 &= ~0x08); }
      si no, si(inum==INUM_P1INT) { (encendido)? (IEN2 |=0x10) : (IEN2 &= ~0x10); }
      si no, si(inum==INUM_RF)    { (encendido)? (IEN2 |=0x01) : (IEN2 &= ~0x01); }
      si no, si(inum==INUM_WDT)   { (encendido)? (IEN2 |=0x20) : (IEN2 &= ~0x20); }
   }mientras (0)


/*Establecer la prioridad de cortes
-----------------------------------------
*/
#defineINT_PRIORITY(grupo, pri)                     
   hacer{                                               
      si(pri ==0) { IP0 &= ~group; IP1 &= ~group; }
      si(pri ==1) { IP0 |= grupo; IP1 &= ~group; }
      si(pri ==2) { IP0 &= ~group; IP1 |= grupo; }
      si(pri ==3) { IP0 |= grupo; IP1 |= grupo; }
   }mientras (0)

//El valor del parámetro pri es: 0/1/2/3 (máxima prioridad)


//El valor del grupo de parámetros es:
#defineRFERR_RF_DMA 0x01//Grupo IP0
#defineADC_P2INT_T1 0x02//Grupo IP1
#defineURX0_UTX0_T2 0x04//Grupo IP2
#defineURX1_UTX1_T3 0x08//Grupo IP3
#defineENC_P1INT_T4 0x10//Grupo IP4
#defineST_WDT_P0INT 0x20//Grupo IP5


/*Obtén la bandera de interrupción
-----------------------------------------
*/
#defineINT_GETFLAG(inum) (                       
   (inum==INUM_RFERR) ? RFERRIF:
   (inum==INUM_ADC) ? ADCIF:
   (inum==INUM_URX0) ? URX0IF :
   (inum==INUM_URX1) ? URX1IF:
   (inum==INUM_ENC) ? ENCIF_0 :
   (inum==INUM_ST) ? STIF :
   (inum==INUM_P2INT) ? P2FI:
   (inum==INUM_UTX0) ? UTX0IF :
   (inum==INUM_DMA) ? DMAIF:
   (inum==INUM_T1) ? T1FI:
   (inum==INUM_T2) ? T2FI:
   (inum==INUM_T3) ? T3FI:
   (inum==INUM_T4) ? T4FI:
   (inum==INUM_P0INT) ? P0IF :
   (inum==INUM_UTX1) ? UTX1IF :
   (inum==INUM_P1INT) ? P1FI:
   (inum==INUM_RF) ? S1CON &= ~0x03    :
   (inum==INUM_WDT) ? WDTIF:
   0                                             
)


/*Establecer la bandera de interrupción
-----------------------------------------
*/
#defineINT_SETFLAG(inum, f)                     
   hacer{                                          
      si      (inum==INUM_RFERR) { RFERRIF = f; }
      si no, si(inum==INUM_ADC)   { ADCIF = f; }
      si no, si(inum==INUM_URX0)  { URX0IF = f; }
      si no, si(inum==INUM_URX1)  { URX1IF = f; }
      si no, si(inum==INUM_ENC)   { ENCIF_1 = ENCIF_0 = f; }
      si no, si(inum==INUM_ST)    { STIF = f;  }
      si no, si(inum==INUM_P2INT) { P2IF = f;  }
      si no, si(inum==INUM_UTX0)  { UTX0IF= f;  }
      si no, si(inum==INUM_DMA)   { DMAIF = f;  }
      si no, si(inum==INUM_T1)    { T1IF = f;  }
      si no, si(inum==INUM_T2)    {T2IF = f;  }
      si no, si(inum==INUM_T3)    { T3IF = f;  }
      si no, si(inum==INUM_T4)    {T4IF = f;  }
      si no, si(inum==INUM_P0INT) { P0IF = f;  }
      si no, si(inum==INUM_UTX1)  { UTX1IF= f;  }
      si no, si(inum==INUM_P1INT) { P1IF = f;  }
      si no, si(inum==INUM_RF)    { (f) ? (S1CON |=0x03) : (S1CON &= ~0x03); }
      si no, si(inum==INUM_WDT)   { WDTIF = f;  }
   }mientras (0)
[url=] [/url]

[url=] [/url]
/***********************************************************
                       Puerto serial
**********************************************************
*/
//El valor de la BAUD_E corresponde a diferentes tasas de bauds
#defineBAUD_E(baud, clkDivPow) (     
    (baud==2400)   ?  6  +clkDivPow :
    (baud==4800)   ?  7  +clkDivPow :
    (baud==9600)   ?  8  +clkDivPow :
    (baud==14400)  ?  8  +clkDivPow :
    (baud==19200)  ?  9  +clkDivPow :
    (baud==28800)  ?  9  +clkDivPow :
    (baud==38400)  ?  10+clkDivPow :
    (baud==57600)  ?  10+clkDivPow :
    (baud==76800)  ?  11+clkDivPow :
    (baud==115200) ?  11+clkDivPow :
    (baud==153600) ?  12+clkDivPow :
    (baud==230400) ?  12+clkDivPow :
    (baud==307200) ?  13+clkDivPow :
    0  )


//El valor de la BAUD_M corresponde a diferentes tasas de baudaje
#defineBAUD_M(baud) (      
    (baud==2400)   ?  59  :
    (baud==4800)   ?  59  :
    (baud==9600)   ?  59  :
    (baud==14400)  ?  216 :
    (baud==19200)  ?  59  :
    (baud==28800)  ?  216 :
    (baud==38400)  ?  59  :
    (baud==57600)  ?  216 :
    (baud==76800)  ?  59  :
    (baud==115200) ?  216 :
    (baud==153600) ?  59  :
    (baud==230400) ?  216 :
    (baud==307200) ?  59  :
  0)


/*Configuración del puerto serie en modo UART
-----------------------------------------
*/
#defineUART_SETUP(uart, receiveEnable, baudRate, options)      
   hacer{                                                         
      si((uart) ==0){                                          
         si(PERCFG &0x01){                                    
            P1SEL |=0x30;                                      
         }si no,{                                               
            P0SEL |=0x0C;                                      
         }                                                      
      }                                                         
      si no,{                                                   
         si(PERCFG &0x02){                                    
            P1SEL |=0xC0;                                      
         }si no,{                                               
            P0SEL |=0x30;                                      
         }                                                      
      }                                                         
                                                               
      U##uart##GCR = BAUD_E((baudRate),CLKSPD);                 
      U##uart##BAUD = BAUD_M(baudRate);                        
                                                               
      U##uart##CSR |=0x80;                                    
                                                               
      U##uart##CSR |= receiveEnable;                           
                                                               
      U##uart##UCR |= ((opciones) |0x80);                       
   }mientras(0)
     
//El valor del parámetro recibiendoEnable:
#defineUART_RECEIVE_ENABLE 0x40   //Recibiendo permiso
#defineUART_RECEIVE_DISABLE 0x00   
     
//El valor de las opciones de parámetros:
#defineFLOW_CONTROL_ENABLE 0x40   //Control de flujo
#defineFLOW_CONTROL_DISABLE 0x00


#defineEVEN_PARITY 0x20   //Verificación ocasional
#defineODD_PARITY 0x00   //Verificación extraña


#defineNINE_BIT_TRANSFER 0x10   //Transferencia de 9 bytes
#defineEIGHT_BIT_TRANSFER 0x00   //Transferencia de 8 bytes


#definePARITY_ENABLE 0x08   //Activación de comprobaciones de paridad
#definePARITY_DISABLE 0x00

#defineTWO_STOP_BITS 0x04   //Posición de tope en 2 posiciones
#defineONE_STOP_BITS 0x00   //1 posición de registro


#defineHIGH_STOP 0x02   //El nivel de tope es alto
#defineLOW_STOP 0x00   //La posición de tope es baja
     
#defineHIGH_START 0x01   //El nivel inicial del bit es alto
#defineLOW_START 0x00   //El nivel inicial del bit es bajo


//El puerto serial envía caracteres
#defineUART_SEND(uart,data)            
   hacer{                                 
     mientras(U##uart##CSR &0x01);        
       U##uart##DBUF = data;            
   }mientras (0)
#defineUART0_SEND(datos) UART_SEND(0,datos)
#defineUART1_SEND(datos) UART_SEND(1,datos)


//El puerto serial recibe caracteres
#defineUART_RECEIVE(uart,data)         
   hacer{                                 
     mientras(! (U##uart##CSR&0x04));      
       data=U##uart##DBUF;              
   }mientras(0)
#defineUART0_RECEIVE(datos) UART_RECEIVE(0,datos)
#defineUART1_RECEIVE(datos) UART_RECEIVE(1,datos)
[url=] [/url]

[url=] [/url]
/***********************************************************
                       Gestión de energía y reloj
**********************************************************
*/
//Consigue el cruce del reloj
#defineCLKSPD (CLKCON y 0x07)


//Configurar el modo de alimentación
#defineSET_POWER_MODE(modo)                  
   hacer{                                       
      si(modo ==0) { DORMIR &= ~0x03; }
      si no, si(modo ==3) { DORMIR |=0x03;  }
      si no,{ DORMIR &= ~0x03; SUSPENSIÓN |= modo;  }
      PCON |=0x01;                           
      asm("NOP");                              
   }mientras (0)


//El modo de parámetros se establece en los siguientes valores:
#definePOWER_MODE_0 0x00  
#definePOWER_MODE_1 0x01
#definePOWER_MODE_2 0x02
#definePOWER_MODE_3 0x03


//Utilizado para detectar la estabilidad de osciladores RC de alta frecuencia
#defineHIGH_FREQUENCY_RC_OSC_STABLE (SUEÑO Y 0x20)


//Utilizado para detectar la estabilidad del oscilador de cristal
#defineXOSC_STABLE (SUEÑO Y 0x40)


//Obtén el valor de la frecuencia de ticks del temporizador
#defineTICKSPD ((CLKCON & 0x38) >> 3)


//Ajusta la frecuencia del reloj maestro
#defineSET_MAIN_CLOCK_SOURCE(fuente)
   hacer{                              
      si(fuente) {                    
        CLKCON |=0x40;               
        mientras(! HIGH_FREQUENCY_RC_OSC_STABLE);
        si(TICKSPD ==0){            
          CLKCON |=0x08;            
        }                             
        SUEÑO |=0x04;               
      }                              
      si no,{                          
        SUEÑO &= ~0x04;               
        mientras(! XOSC_STABLE);         
        asm("NOP");                  
        CLKCON &= ~0x47;              
        SUEÑO |=0x04;               
      }                              
   }mientras (0)


//El valor de la fuente de parámetros es:
#defineCRISTAL 0x00   //Oscilador de cristal
#defineRC 0x01   //Oscilador RC
[url=] [/url]

[url=] [/url]
/***********************************************************
                       Temporizador 1
**********************************************************
*/
//El temporizador 1 permite que el desbordamiento de conteo interrumpa
#defineTIMER1_ENABLE_OVERFLOW_INT(val)
   (TIMIF = (val) ? TIMIF |0x40: TIMIF & ~0x40)


//Configura la bandera de interrupción de desbordamiento para el temporizador 1
#defineTIMER1_OVERFLOW_INT_SETFLAG(f) (T1CTL= ((T1CTL & (~0x10)) | f))


//Comienza el Cronómetro 1
#defineTIMER1_RUN(valor) (T1CTL = (valor) ? T1CTL|0x02 : T1CTL&~0x03)


//Configura la división del reloj para el temporizador
#defineSET_TIMER_TICK(valor) do{ CLKCON = ((CLKCON & (~0x38)) | valor); } while(0)


//El valor del valor es:
#defineTIMER1_TICK_32M 0x00  //32MHz
#defineTIMER1_TICK_16M 0x08  //16MHz, el valor predeterminado para el reinicio del sistema
#defineTIMER1_TICK_8M 0x10  //8MHz
#defineTIMER1_TICK_4M 0x18  //4MHz
#defineTIMER1_TICK_2M 0x20  //2MHz
#defineTIMER1_TICK_1M 0x28  //1MHz
#defineTIMER1_TICK_500k 0x30  //500kHz
#defineTIMER1_TICK_250k 0x38  //250kHz

//Configura el crossover TICK para el temporizador 1
#defineSET_TIMER1_TICKDIV(valor)  
   hacer{                             
     T1CTL &= ~0x0c;               
     T1CTL |= valor;               
   }mientras (0)
      
//donde el valor es:      
#defineTIMER1_TICKDIV_1 0x00   //1 División
#defineTIMER1_TICKDIV_8 0x04   //Frecuencia de 8 vías
#defineTIMER1_TICKDIV_32 0x08
#defineTIMER1_TICKDIV_128 0x0c


//Establecer el periodo de desbordamiento del temporizador
#defineSET_TIMER1_PERIOD(valor)
   hacer{                           
     T1CC0H = HIGH_BYTE(valor);  
     T1CC0L = LOW_BYTE(valor);   
   }mientras (0)
     
//Configura el modo de funcionamiento del Temporizador 1
#defineSET_TIMER1_MODE(modo)  
   hacer{                        
     T1CTL = ((T1CTL & (~0x03)) | modo);           
   }mientras (0)


//El valor del modo es:
#defineTIMER1_MODE_STOP 0x00
#defineTIMER1_MODE_FREE 0x01
#defineTIMER1_MODE_MODULE 0x02
#defineTIMER1_MODE_UPDOWN 0x03
[url=] [/url]

[url=] [/url]
/***********************************************************
                       Perro guardián
**********************************************************
*/
//Establece el periodo de desbordamiento para el temporizador watchdog
#defineWDT_SET_TIMEOUT_PERIOD(tiempo muerto)
   hacer{ WDCTL &= ~0x03; WDCTL |= tiempo muerto; }mientras (0)


//El valor del tiempo límite del parámetro es:
#defineSEC_1 0x00     //después de 1 segundo
#defineM_SEC_250 0x01     //Después de 250 ms
#defineM_SEC_15 0x02     //Después de 15 ms
#defineM_SEC_2 0x03     //Después de 2 ms


//Procedimientos de alimentación para perros
#defineWDT_RESET() do {           
   WDCTL = (WDCTL & ~0xF0) |0xA0;
   WDCTL = (WDCTL & ~0xF0) |0x50;
} mientras (0)


//Iniciar/detener el temporizador watchdog
#defineWDT_ENABLE() WDCTL |= 0x08
#defineWDT_DISABLE() WDCTL &= ~0x08
[url=] [/url]

[url=] [/url]
/***********************************************************
                       ADC
**********************************************************
*/
//Configurar un único ADC
#defineADC_SINGLE_CONVERSION(ajustes)
   hacer{ ADCCON3 = ajustes; }mientras(0)

//La configuración de parámetros está compuesta por las siguientes combinaciones:
//Voltaje de referencia
#defineADC_REF_1_25_V 0x00     //Voltaje de referencia interno de 1,25V
#defineADC_REF_P0_7 0x40     //Voltaje de referencia externo en el pin AIN7
#defineADC_REF_AVDD 0x80     //AVDD_SOC Pins
#defineADC_REF_P0_6_P0_7 0xC0     //AIN6-AIN7 Voltaje de referencia externo para entradas diferenciales


//Frecuencia de muestreo
#defineADC_8_BIT 0x00     //8º puesto
#defineADC_10_BIT 0x10     //10º puesto
#defineADC_12_BIT 0x20     //12º puesto
#defineADC_14_BIT 0x30     //14º puesto


//Entra en el canal
#defineADC_AIN0 0x00     //P0_0
#defineADC_AIN1 0x01     //P0_1
#defineADC_AIN2 0x02     //P0_2
#defineADC_AIN3 0x03     //P0_3
#defineADC_AIN4 0x04     //P0_4
#defineADC_AIN5 0x05     //P0_5
#defineADC_AIN6 0x06     //P0_6
#defineADC_AIN7 0x07     //P0_7
#defineADC_GND 0x0C     //Terreno
#defineADC_TEMP_SENS 0x0E     //Sensor de temperatura integrado en el chip
#defineADC_VDD_3 0x0F     //VDD/3




La conversión al ADC está completa
#define ADC_SAMPLE_READY() (ADCCON1 y 0x80)

#endif
//启动ADC转化
#define ADC_START()
  do { ADCCON1 |= 0x40; } mientras (0)//Selecciona el modo de disparo del ADC como manual (es decir, ADC_SAMPLE_READY)
#defineADC_STOP()  
  hacer{ ADCCON1 |=0x30; }mientras (0)[url=] [/url]


(2) Capa funcional de módulos
  • module.h
  • module.c
[url=] [/url]
/***********************************************************
*Nombre del archivo: module.h
*Autor: hustlzp
*Fecha: 6 de marzo de 2011
*Versión: 1.0
*Descripción de la función: Archivo de cabecera de capa de módulo funcional
*Lista de funciones: void led_init()
            void timer1_init()
            vacío uart0_init(vacío);
            void Uart0SendString(char sin signo *s);
            flotar adc_start(vacío)
            void get_temperature(personaje sin signo *salida, temperatura flotante);
            vacío watchdog_init(vacío);
*Récords modificados:
**********************************************************
*/

#ifndef MODULE_H
#defineMODULE_H


#include"hal.h"


/***********************************************************
                        LED
**********************************************************
*/
//Define los pines del LED
#definelideró1 P1_0         
#defineled2 P1_1         
#defineLed3 P1_2         
#defineled4 P1_3   

//Luz LED y apagado
#defineLED_OFF 1
#defineLED_ON 0

//Inicialización de LED
Vacíoled_init(Vacío);




/***********************************************************
                        timer1
**********************************************************
*/
//Se usa para establecer el valor del periodo de desbordamiento para el temporizador
#defineTIMER1_OVF_2SEC 0xF424   //2s
#defineTIMER1_OVF_1SEC 0x7A12   //1s
#defineTIMER1_OVF_dot5SEC 0x3D09   //0,5 s   

//El temporizador 1 inicializa
Vacío  timer1_init(Vacío);
                  

/***********************************************************
                        UART0
**********************************************************
*/
//Inicialización de UART0
Vacío  uart0_init(Vacío);                    

//Cadena de transmisión por puerto serial
Vacío  Uart0SendString(sin signarchar*s);
   

/***********************************************************
                        ADC-14
**********************************************************
*/
//Utilizado para convertir los datos obtenidos por el ADC a temperatura Celsius
#defineADC_TO_CELSIUS(temperatura) (temperatura * 0,06229 - 311,43)

//Iniciar la conversión de ADC
Flotadoradc_start(Vacío);

//Conversión
Vacío  get_temperature(sin firmarchar*salida,Flotadortemporal);


/***********************************************************
                        WatchDog
**********************************************************
*/
//Inicialización de perro guardián
Vacío  watchdog_init(Vacío);                 

#endif
[url=] [/url]

[url=] [/url]
/***********************************************************
*Nombre del archivo: module.c
*Autor: hustlzp
*Fecha: 2011/3/11
*Versión: 1.0
*Descripción de la función: Archivo fuente de la capa funcional del módulo
*Lista de funciones: (omitido)
*Récords modificados:
**********************************************************
*/


#include"module.h"


/***********************************************************
*Nombre de la función: led_init
*Función funcional: inicialización del LED
*Parámetros de entrada: Ninguno
*Parámetros de exportación: Ninguno
**********************************************************
*/
Vacíoled_init(Vacío)
{
  //Configura P1.0, P1.1, P1.2 y P1.3 como puertos generales de E/S
  IO_FUNC_PORT_PIN(1, 0, IO_FUNC_GIO);
  IO_FUNC_PORT_PIN(1, 1, IO_FUNC_GIO);
  IO_FUNC_PORT_PIN(1, 2, IO_FUNC_GIO);
  IO_FUNC_PORT_PIN(1, 3, IO_FUNC_GIO);
  
  //Configura P1.0, P1.1, P1.2 y P1.3 como salidas
  IO_DIR_PORT_PIN(1, 0, IO_OUT);
  IO_DIR_PORT_PIN(1, 1, IO_OUT);
  IO_DIR_PORT_PIN(1, 2, IO_OUT);
  IO_DIR_PORT_PIN(1, 3, IO_OUT);
  
  lideraba1 = LED_ON;
  liderado2 = LED_OFF;
  liderado3 = LED_OFF;
  liderado4 = LED_OFF;
}


/***********************************************************
*Nombre de la función: timer1_init
* Función función: inicialización del temporizador 1
*Parámetros de entrada: Ninguno
*Parámetros de exportación: Ninguno
**********************************************************
*/
Vacíotimer1_init(Vacío)
{
  INT_GLOBAL_ENABLE(INT_ON);                 //Abre la interrupción global
  
  INT_ENABLE(INUM_T1, INT_ON);               //Interrupción T1 abierta

  TIMER1_ENABLE_OVERFLOW_INT(INT_ON);        //Interrupción de desbordamiento de conteo abierto T1
  
  SET_TIMER_TICK(TIMER1_TICK_4M);            //Pon el temporizador TICK a 4MHz
  
  SET_TIMER1_PERIOD(TIMER1_OVF_2SEC);        //Establece el periodo de conteo para T1 a 2
  
  SET_TIMER1_TICKDIV(TIMER1_TICKDIV_128);   //Configura el cruce del reloj para T1 a 128
  
  SET_TIMER1_MODE(TIMER1_MODE_MODULE);      //Establece el modo de ejecución de T1 en módulo
}


/***********************************************************
*Nombre de la función: uart0_init
*Función función: Inicialización del puerto serial UART0
*Parámetros de entrada: Ninguno
*Parámetros de exportación: Ninguno
**********************************************************
*/
Vacíouart0_init(Vacío)
{
  //Seleccione la ubicación de UART
  IO_PER_LOC_UART0_AT_PORT0_PIN2345();
  
  //Configurar UART: Recepción permitida, 115200bps, bit de parada de un bit, sin paridad
  UART_SETUP(0, UART_RECEIVE_ENABLE,115200, ONE_STOP_BITS | PARITY_DISABLE);

  //Abre la interrupción total
  INT_GLOBAL_ENABLE(INT_ON);      

  //Abrir puerto serie 0 para recibir interrupciones
  INT_ENABLE(INUM_URX0, INT_ON);   
}


/***********************************************************
*Nombre de la función: Uart0SendString
* Función función: inicialización del temporizador 1
*Parámetro de entrada: personaje sin firmar *s
            La cadena que quieres enviar
*Parámetros de exportación: Ninguno
**********************************************************
*/
VacíoUart0SendString(sin signarchar*s)
{
  mientras(*s !=0)         
    UART0_SEND(*s++);
}


/***********************************************************
*Nombre de la función: adc_start
*Función función: Iniciar conversión ADC
*Parámetros de entrada: Ninguno
*Parámetro de exportación: float
            El valor de temperatura en la tableta
**********************************************************
*/
Flotadoradc_start(Vacío)
{
  sin firmarintTemp;
  
  //El voltaje de referencia es de 1,25V, la precisión de muestreo es de 14 bits y el objetivo de conversión es el sensor de temperatura integrado en el chip
  ADC_SINGLE_CONVERSION(ADC_REF_1_25_V | ADC_14_BIT | ADC_TEMP_SENS);
  
  ADC_STOP();                           //Configura el método de disparo para la conversión del ADC a manual
  
  ADC_START();                           //Iniciar la conversión de ADC
  
  mientras(! ADC_SAMPLE_READY());            //Esperar a que termine la conversión
  
  temp = ADCL >>2;                     //Guardar los resultados de conversión en la temperatura
  temp |= (((sin signoint) ADCH) <<6);
  
  devoluciónADC_TO_CELSIUS(temporal);           //Devuelve el valor real de temperatura tras la conversión
}


/***********************************************************
*Nombre de la función: get_temperature
*Función de función: Procesar el valor de temperatura y almacenarlo en el array de caracteres para la salida serial
*Parámetro de entrada: unsigned char *salida
            Usado para almacenar el valor de temperatura convertido
            Temperatura del flotador
            Valor de temperatura Celsius
*Parámetros de exportación: Ninguno
**********************************************************
*/
Vacíoget_temperature(sin firmarchar*salida,Flotadortemp)
{
  Salida[0] = (sin signarchar(temporal) /10 + 48;         //Diez plazas
  Salida[1] = (sin signarchar(temp) %10 + 48;         //Dígitos simples
  Salida[2] ='.';                                      //Punto decimal
  Salida[3] = (sin signarchar(temp*10) %10 + 48;      //Décima
  Salida[4] = (sin signarchar(temp*100) %10 + 48;      //Percentil
  Salida[5] ='';                                    //Endifieres de cuerda
}


/***********************************************************
*Nombre de la función: watchdog_init
*Función funcional: Inicialización del perro vigilante
*Parámetros de entrada: Ninguno
*Parámetros de exportación: Ninguno
**********************************************************
*/
Vacíowatchdog_init(Vacío)
{
  WDT_SET_TIMEOUT_PERIOD(SEC_1);   //Establece el tiempo de espera a 1 segundo
  WDT_ENABLE();                    //Inicia el vigilante
}
[url=] [/url]


(3) Capa de aplicación
  • main.c
[url=] [/url]
/*******************************************************************
Nombre del archivo: main.c
Autor: hustlzp
Fecha: 2011/3/11
Versión: 1.0
Descripción de la función: Archivo maestro del programa
Lista de funciones: (omitido)
Historial de modificaciones:
******************************************************************
*/


#include




/********************************************************************
                             Procedimientos de servicio de interrupción
********************************************************************/
/* 定时器1溢出中断子程序
-------------------------------------------------------*/
#pragma vector=T1_VECTOR
__interrupt vacío T1_ISR(vacío)
{
  EA=0;                                   La puerta se interrumpe
  
  lideraba2 = LED_ON;                          
  
  get_temperature(salida,adc_start());    Convierte el valor de temperatura en un array de caracteres que se generará
   
  Uart0SendString (salida);                Valor de temperatura de salida
  Uart0SendString("°C");  


  led2


/* 串口接收中断子程序
-------------------------------------------------------*/
#pragma vector=URX0_VECTOR
__interrupt vacío RE_ISR(vacío)
{
  EA=0;
  
  lideraba3 = LED_ON;

  recepción = U0DBUF;   
  
  if(type==1) // type=1, lo que indica que el carácter recibido se usa para establecer el periodo de desbordamiento del temporizador
  {
    tipo=0;
    Cambio (recepción)
    {
      caso '0': // El periodo de desbordamiento del temporizador es de 0,5 s
      {
        SET_TIMER1_PERIOD(TIMER1_OVF_dot5SEC);
        pausa;
      }
      caso '1': // El periodo de desbordamiento del temporizador es 1s
      {
        SET_TIMER1_PERIOD(TIMER1_OVF_1SEC);
        pausa;
      }
      caso '2': // El periodo de desbordamiento del temporizador es de 2s
      {
        SET_TIMER1_PERIOD(TIMER1_OVF_2SEC);
        pausa;         
      }
    }
  }
  else if(type==2) // type=2, indicando que los caracteres recibidos se usan para el control de suspensión
  {
    tipo=0;
    liderado1 = LED_OFF;
    liderado2 = LED_OFF;
    liderado3 = LED_OFF;
    Cambio (recepción)
    {
      caso '1': // Entrar en modo de alimentación PM1
      {
        SET_POWER_MODE(1);  
        pausa;
      }
      caso '2': // Entrar en modo de alimentación PM2
      {
        SET_POWER_MODE(2);  
        pausa;
      }
      caso '3': //Entrar en modo de alimentación PM3
      {
        SET_POWER_MODE(3);  
        pausa;
      }
    }
  }
  else if(type==0) // type=0, lo que indica que el carácter recibido es el tipo de comando de control: @ o $
  {
    si(recibir=='@')  
    {
      tipo=1;     '@' se recibe para indicar que el siguiente carácter se usa para establecer el periodo de desbordamiento
    }
    si no(recibir=='$')
    {
      tipo=2;     Se recibe '$', indicando que el siguiente carácter se usa para el control de suspensión del sistema
    }
  }
  
  liderado3 = LED_OFF;
   
  EA=1;
}
=LED_OFF;
  
  TIMER1_OVERFLOW_INT_SETFLAG(INT_CLR);   Despejar el signo de interrupción
  
  EA=1;                                   Interrupción abierta  
}
/* 主函数
-------------------------------------------------------*/
Void principal(void)
{
  SET_MAIN_CLOCK_SOURCE(CRISTAL);  Ajusta el reloj del sistema a oscilador de cristal de 32MHz
  
  led_init();                      Inicialización de LED
  
  uart0_init();                    Inicialización del puerto serial UART0
  
  timer1_init();                   El temporizador 1 inicializa
  
  watchdog_init();                 Inicialización de perro guardián
  
  mientras que (1)
  {
    WDT_RESET();                   Alimenta al perro constantemente
  }
}/********************************************************************
                            Programa principal   
********************************************************************/
/* 全局变量
-------------------------------------------------------*/
salida de char sin signo[6]={0};       Los datos de temperatura se almacenan para facilitar la salida serial
personaje no firmado recibir;             Guardar los caracteres recibidos
tipo de personaje sin signo=0;              La bandera de tipo del carácter recibido se establece en 0/1/2"module.h"[url=] [/url]


5. Pruebas
Oh~ Por fin se pega el código, es realmente agotador, vamos a probar este pequeño sistema:
(1) Muestreo cronometrado
Abre el puerto serie y comienza la depuración IAR, y descubre que el led1 está activado, que el valor de temperatura en la herramienta del puerto serie se genera constantemente, y el intervalo de muestreo se determina en 2s:
(2) Control de intervalos de muestreo
Introduce "@1" en la herramienta de puerto serial, luego prueba el intervalo de muestreo y descubre que se ha convertido en 1s; Introduce "@0" y el intervalo de muestreo cambia a 0,5s.
(3) Control del sueño
Introduce "$1" en la herramienta del puerto serie y verás que todos los LEDs están apagados y que el muestreo de temperatura se ha detenido:
Tras las pruebas, el sistema funciona normalmente y de forma estable, y básicamente cumple con los requisitos.
Estudiantes que necesitan código fuenteHaz clic aquí para descargar
6. Conclusión
Este artículo toma un experimento algo completo como ejemplo para mostrar cómo integrar recursos CC2430 en chip para escribir un sistema pequeño relativamente estandarizado. En unos días, me tomaré el tiempo para escribir un manual de usuario sencillo para hal.h para que tanto yo como todos podamos manejar fácilmente el CC2430.
A continuación, terminaré mi investigación sobre los recursos integrados en el chip CC2430 y me dedicaré a aprender la pila de protocolos TI Z-Stack~
La escritura de entradas en el blog de esta serie ha llegado a su fin por ahora, pero el viaje de Zigbee continuará. El paisaje que se ve por delante es desconocido, pero creo que el autor superará obstáculos con todos y saboreará los altibajos, y habrá ganancias.
¡Estad atentos: entradas del blog "Únete a TI Z-Stack"!















Anterior:Zigbee Journey (9): Varios experimentos básicos importantes con CC2430: sueño sistemático y vigilia interrumpida
Próximo:Hoy es Halloween, ¿cómo vais a entretener?
Publicado en 31/10/2014 8:04:14 |
Perdona que no entienda nada
Renuncia:
Todo el software, materiales de programación o artículos publicados por Code Farmer Network son únicamente para fines de aprendizaje e investigación; El contenido anterior no se utilizará con fines comerciales o ilegales; de lo contrario, los usuarios asumirán todas las consecuencias. La información de este sitio proviene de Internet, y las disputas de derechos de autor no tienen nada que ver con este sitio. Debes eliminar completamente el contenido anterior de tu ordenador en un plazo de 24 horas desde la descarga. Si te gusta el programa, por favor apoya el software genuino, compra el registro y obtén mejores servicios genuinos. Si hay alguna infracción, por favor contáctanos por correo electrónico.

Mail To:help@itsvse.com