Après avoir écrit « Zigbee Journey (9) » le 3 mars, l’auteur avait initialement prévu de commencer immédiatement à écrire une petite expérience sur un « système de surveillance de température » comme résumé d’une série de points de connaissance dispersés précédents. Cependant, j’ai aussi réalisé que, bien que chacune des petites expériences précédentes ait été décrite en détail, la nature normative et structurelle de son code pouvait être considérée comme insupportable. Puisqu’il s’agit d’un résumé, nous devrions progresser sur la base initiale, plutôt que de reconstituer mécaniquement les petits points de connaissance précédents. J’ai donc mis mon plan initial en pause, pris le temps d’apprendre les techniques générales du développement embarqué, et écrit deux essaisSpécification de programmation intégrée C51« et »Hiérarchie de la structure de code de projet embarquée》。 Ce journal n’est pas seulement un résumé du premier voyage de Zigbee, mais il intègre aussi l’expérience d’apprentissage de l’auteur ces derniers jours, espérant être utile aux débutants en Zigbee.
Le texte intégral est organisé selon le processus de base du développement logiciel : analyse des exigences, conception plan, conception détaillée, mise en œuvre du codage et tests.
1. Analyse de la demandeAprès discussion entre le « client » et le « développeur », la description de la fonction système suivante a été déterminée :
… La température ambiante actuelle est collectée par des nœuds basés sur CC2430, et ses valeurs de température peuvent être surveillées via un PC
… Le nœud CC2430 lui-même doit avoir un certain degré de stabilité et peut automatiquement revenir à l’état normal
… L’intervalle d’échantillonnage et la gestion de la consommation d’énergie du nœud peuvent être contrôlés par un PC
2. Conception de plansSelon l’analyse des exigences ci-dessus, nous pouvons diviser le système en deux modules :Nœud CC2430etPC。
[Nœud CC2430]
… Les paramètres externes peuvent être collectés régulièrement et envoyés au PC
… Réinitialisation automatique lorsque la machine est éteinte
… Les commandes du PC peuvent être reçues et traitées en conséquence : changer l’intervalle d’échantillonnage/la gestion de l’alimentation
[PC]
… La machine C reçoit et affiche les données via l’outil port série
… Les instructions peuvent être envoyées au microcontrôleur via l’outil de port série pour contrôler sa vitesse d’échantillonnage et sa gestion de la puissance
3. Conception détaillée(1) Structure du code
La superposition de la structure de code de ce système a en fait été décrite dans l’essai "Hiérarchie de la structure de code de projet embarquéeet la copie est la suivante :
(1) Couche d’abstraction matérielle
[ioCC2430.h] (Système inclus):Tous les vecteurs SFR et d’interruption du CC2430 sont définis
[hal.h] Inclut des définitions de types courantes, des macros d’affectation courantes et une configuration courante des ressources CC2430 intégrées (E/S, communication série, ADC, minuterie, gestion de l’alimentation, etc.)
(2) Couche fonctionnelle de modules
[module.h] définit les ressources intégrées (minuteries, E/S), les modules d’expansion externes (LED) et les déclarations de fonctions associées
[module.cImplémentez l’initialisation de chaque module (LED).
(3) Couche application
[main.cConsultez hal.h, ioCC2430.h et module.h pour répondre à des exigences spécifiques telles que l’acquisition de température, l’intercommunication avec PC, ainsi que l’arrêt et la réinitialisation
(2) Méthodes d’implémentation de chaque module
Selon les modules divisés selon la conception du contour, le système intrinsèque peut être divisé en deux modules principaux :Nœud CC2430etPC。
Comme il existe des outils de communication par port série sur le PC, ses fonctions peuvent répondre aux exigences, donc nous n’avons pas besoin de faire cette partie du PC, et il n’est pas nécessaire de l’analyser. Parlons ci-dessous de la section CC2430
La méthode d’implémentation de chaque sous-fonction du point :
… Utilisez l’interruption de dépassement de dépassement du compte à rebours du minuteur pour déclencher l’échantillonnage temporisé
… Le mode UART0 avec port série transmet les données de température à un PC
… Le circuit watchdog intégré du CC2430 est utilisé pour réaliser la fonction de réinitialisation automatique du système
… Le port série est utilisé pour recevoir les interruptions afin de capturer et répondre aux commandes de contrôle du PC
1) Si reçu@Le caractère est la commande de contrôle d’intervalle d’échantillonnage, suivie d’un chiffre indiquant l’intervalle d’échantillonnage : 0-0,5s, 1-1s, 2-2s
如:@0,表示每隔0.5秒采样一次。
2) Si reçu$ Le caractère est la commande de contrôle en veille, suivie d’un chiffre indiquant le mode d’alimentation
Par exemple : 3 $, ce qui signifie passer le système en mode alimentation 3.
(3) Organigramme de programme
- Organigramme de programme maître
- Diagramme de flux du programme d’interruption de dépassement du minuteur 1
- Organigramme de la procédure d’interruption de réception de port série
4. Implémentation du codage(1) Couche d’abstraction matérielle
La couche d’abstraction matérielle comprend ioCC2430.h et hal.h. Puisque le système précédent l’accompagne, il ne sera pas listé.
Voici une liste de tout le contenu de hal.h (comme ce fichier est trop long et semble gênant, je vais l’afficher en modules) :
- Tête
- Ports d’E/S
- Interrompu
- Port série
- Gestion de l’alimentation et de l’horloge
- Minuterie
- Chien de garde
- ADC
[url=]
[/url]
/***********************************************************
*Nom du fichier : hal.h
*Auteur : hustlzp
*Date : 8 mars 2011
*Édition : 1.1
*Description de la fonction : couche d’abstraction matérielle
*Records modifiés :
***********************************************************/
#ifndef HAL_H
#defineHAL_H
#include
/***********************************************************
Définitions de type courantes
***********************************************************/
typedef non signéChar BYTE ;
typedef non signéint WORD ;
typedef non signélong DWORD ;
/***********************************************************
Macro-définitions couramment utilisées
***********************************************************/
//8 places plus haut
#defineHIGH_BYTE(a) ((OCTET) (((WORD)(a)) >> 8))
//8 places plus bas
#defineLOW_BYTE(a) ((OCTET) ((MOT)(a)))
//Affectation
#defineSET_WORD(regH,regL,word)
faire{
(regH)=HIGH_BYTE(mot) ;
(regL)=LOW_BYTE(mot) ;
}tandis que(0)
[url=] [/url]
[url=] [/url]
/***********************************************************
Ports d’E/S
***********************************************************/
/*Configurez la direction des ports d’E/S
-----------------------------------------*/
#defineIO_DIR_PORT_PIN(portage, pin, dir)
faire{
si(réal. == IO_OUT)
P##port##DIR |= (0x01<<(épingle)) ;
sinon
P##port##DIR &= ~(0x01<<(épingle)) ;
}tandis que(0)
//La valeur du directeur du paramètre est :
#defineIO_IN 0
#defineIO_OUT 1
/*Configurez le mode d’entrée du port d’E/S
-----------------------------------------*/
#defineIO_IMODE_PORT_PIN(port, broche, imode)
faire{
si(imode == IO_IMODE_TRI)
P##port##INP |= (0x01<<(épingle)) ;
sinon
P##port##INP &= ~(0x01<<(épingle)) ;
}tandis que (0)
#define IO_PUD_PORT(bâbord, pud)
do {
if (pud == IO_PULLDOWN)
P2INP |= (0x01 << (port+5)) ;
sinon
P2INP &= ~(0x01 << (port+5)) ;
} tandis que (0)
La valeur du paramètre PUD est :
#define IO_PULLUP 0 // Tirez vers le haut
#define IO_PULLDOWN 1 // Tirage vers le bas
/*配置I/O口的功能
-----------------------------------------*/
#define IO_FUNC_PORT_PIN(port, broche, fonction)
do {
if((port == 2) & & (pin == 3)){
si (func) {
P2SEL |= 0x02 ;
} else {
P2SEL &= ~0x02 ;
}
}
else if((port == 2) && (pin == 4)){
si (func) {
P2SEL |= 0x04 ;
} else {
P2SEL &= ~0x04 ;
}
}
else{
si (func) {
P##port##SEL |= (0x01<<(épingle)) ;
} else {
P##port##SEL &= ~(0x01<<(épingle)) ;
}
}
} tandis que (0)
La valeur du paramètre func est :
#define IO_FUNC_GIO 0 // E/S générale
#define IO_FUNC_PERIPH 1 // E/S périphérique
Configurez l’emplacement de l’E/S périphérique
#define IO_PER_LOC_TIMER1_AT_PORT0_PIN234() do { PERCFG = (PERCFG&~0x40)|0x00 ; } tandis que (0)
#define IO_PER_LOC_TIMER1_AT_PORT1_PIN012() do { PERCFG = (PERCFG&~0x40)|0x40 ; } tandis que (0)
#define IO_PER_LOC_TIMER3_AT_PORT1_PIN34() do { PERCFG = (PERCFG&~0x20)|0x00 ; } tandis que (0)
#define IO_PER_LOC_TIMER3_AT_PORT1_PIN67() do { PERCFG = (PERCFG&~0x20)|0x20 ; } tandis que (0)
#define IO_PER_LOC_TIMER4_AT_PORT1_PIN01() do { PERCFG = (PERCFG&~0x10)|0x00 ; } tandis que (0)
#define IO_PER_LOC_TIMER4_AT_PORT2_PIN03() do { PERCFG = (PERCFG&~0x10)|0x10 ; } tandis que (0)
#define IO_PER_LOC_SPI1_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x08)|0x00 ; } tandis que (0)
#define IO_PER_LOC_SPI1_AT_PORT1_PIN4567() do { PERCFG = (PERCFG&~0x08)|0x08 ; } tandis que (0)
#define IO_PER_LOC_SPI0_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x04)|0x00 ; } tandis que (0)
#define IO_PER_LOC_SPI0_AT_PORT1_PIN2345() do { PERCFG = (PERCFG&~0x04)|0x04 ; } tandis que (0)
#define IO_PER_LOC_UART1_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x02)|0x00 ; } tandis que (0)
#define IO_PER_LOC_UART1_AT_PORT1_PIN4567() do { PERCFG = (PERCFG&~0x02)|0x02 ; } tandis que (0)
#define IO_PER_LOC_UART0_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x00 ; } tandis que (0)
#define IO_PER_LOC_UART0_AT_PORT1_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x01 ; } tandis que (0)
//La valeur du paramètre imode est :
#defineIO_IMODE_PUD 0 //Tirage vers le haut/vers le bas
#defineIO_IMODE_TRI 1 //Trois États[url=] [/url]
[url=] [/url]
/***********************************************************
Interrompu
***********************************************************/
//Pour les interruptions marche/arrêt
#defineINT_ON 1
#defineINT_OFF 0
//Utilisé pour placer/effacer les drapeaux d’interruption
#defineINT_SET 1
#defineINT_CLR 0
//Paramètres globaux d’interruption
#defineINT_GLOBAL_ENABLE(on) EA=( !! sur)
//Définissez la rupture
#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
#define9 INUM_T1
#defineINUM_T2 10
#define11 INUM_T3
#define12 INUM_T4
#define13 INUM_P0INT
#define14 INUM_UTX1
#defineINUM_P1INT 15
#defineINUM_RF 16
#define17 INUM_WDT
/*Interruptions autorisées
-----------------------------------------*/
#defineINT_ENABLE(inum, on)
faire{
si (inum==INUM_RFERR) { RFERRIE = on ; }
sinon si(inum==INUM_ADC) { ADCIE = on ; }
sinon si(inum==INUM_URX0) { URX0IE = on ; }
sinon si(inum==INUM_URX1) { URX1IE = on ; }
sinon si(inum==INUM_ENC) { ENCIE = on ; }
sinon si(inum==INUM_ST) { STIE = on ; }
sinon si(inum==INUM_P2INT) { (allumé) ? (IEN2 |=0x02) : (IEN2 &= ~0x02); }
sinon si(inum==INUM_UTX0) { (allumé) ? (IEN2 |=0x04) : (IEN2 &= ~0x04); }
sinon si(inum==INUM_DMA) { DMAIE = on ; }
sinon si(inum==INUM_T1) { T1IE = on ; }
sinon si(inum==INUM_T2) { T2IE = on ; }
sinon si(inum==INUM_T3) { T3IE = on ; }
sinon si(inum==INUM_T4) { T4IE = on ; }
sinon si(inum==INUM_P0INT) { P0IE = on ; }
sinon si(inum==INUM_UTX1) { (allumé) ? (IEN2 |=0x08) : (IEN2 &= ~0x08); }
sinon si(inum==INUM_P1INT) { (allumé) ? (IEN2 |=0x10) : (IEN2 &= ~0x10); }
sinon si(inum==INUM_RF) { (allumé) ? (IEN2 |=0x01) : (IEN2 &= ~0x01); }
sinon si(inum==INUM_WDT) { (allumé) ? (IEN2 |=0x20) : (IEN2 &= ~0x20); }
}tandis que (0)
/*Définissez la priorité de coupure
-----------------------------------------*/
#defineINT_PRIORITY(groupe, pris)
faire{
si(pri ==0) { IP0 &= ~group ; IP1 &= ~group ; }
si(pri ==1) { IP0 |= groupe ; IP1 &= ~group ; }
si(pri ==2) { IP0 &= ~group ; IP1 |= groupe ; }
si(pri ==3) { IP0 |= groupe ; IP1 |= groupe ; }
}tandis que (0)
//La valeur du paramètre pri est : 0/1/2/3 (priorité maximale)
//La valeur du groupe de paramètres est :
#defineRFERR_RF_DMA 0x01//Groupe IP0
#defineADC_P2INT_T1 0x02//Groupe IP1
#defineURX0_UTX0_T2 0x04//Groupe IP2
#defineURX1_UTX1_T3 0x08//Groupe IP3
#defineENC_P1INT_T4 0x10//Groupe IP4
#defineST_WDT_P0INT 0x20//Groupe IP5
/*Obtenez le drapeau d’interruption
-----------------------------------------*/
#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) ? T1IF :
(inum==INUM_T2) ? T2IF :
(inum==INUM_T3) ? T3IF :
(inum==INUM_T4) ? T4IF :
(inum==INUM_P0INT) ? P0IF :
(inum==INUM_UTX1) ? UTX1IF :
(inum==INUM_P1INT) ? P1FI :
(inum==INUM_RF) ? S1CON &= ~0x03 :
(inum==INUM_WDT) ? WDTIF :
0
)
/*Définir le drapeau d’interruption
-----------------------------------------*/
#defineINT_SETFLAG(inum, f)
faire{
si (inum==INUM_RFERR) { RFERRIF = f ; }
sinon si(inum==INUM_ADC) { ADCIF = f ; }
sinon si(inum==INUM_URX0) { URX0IF = f ; }
sinon si(inum==INUM_URX1) { URX1IF = f ; }
sinon si(inum==INUM_ENC) { ENCIF_1 = ENCIF_0 = f ; }
sinon si(inum==INUM_ST) { STIF = f ; }
sinon si(inum==INUM_P2INT) { P2IF = f ; }
sinon si(inum==INUM_UTX0) { UTX0IF= f ; }
sinon si(inum==INUM_DMA) { DMAIF = f ; }
sinon si(inum==INUM_T1) { T1IF = f ; }
sinon si(inum==INUM_T2) { T2IF = f ; }
sinon si(inum==INUM_T3) { T3IF = f ; }
sinon si(inum==INUM_T4) { T4IF = f ; }
sinon si(inum==INUM_P0INT) { P0IF = f ; }
sinon si(inum==INUM_UTX1) { UTX1IF= f ; }
sinon si(inum==INUM_P1INT) { P1IF = f ; }
sinon si(inum==INUM_RF) { (f) ? (S1CON |=0x03) : (S1CON &= ~0x03); }
sinon si(inum==INUM_WDT) { WDTIF = f ; }
}tandis que (0)
[url=] [/url]
[url=] [/url]
/***********************************************************
Port série
***********************************************************/
//La valeur de la BAUD_E correspond à différents débits en 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 )
//La valeur de la BAUD_M correspond à différents débits en bauds
#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)
/*Configuration des ports série en mode UART
-----------------------------------------*/
#defineUART_SETUP(uart, receiveEnable, baudRate, options)
faire{
si((uart) ==0){
si(PERCFG &0x01){
P1SEL |=0x30;
}sinon{
P0SEL |=0x0C;
}
}
sinon{
si(PERCFG &0x02){
P1SEL |=0xC0;
}sinon{
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 |= ((options) |0x80);
}tandis que(0)
//La valeur du paramètre receiveEnable :
#defineUART_RECEIVE_ENABLE 0x40 //Obtention de l’autorisation
#defineUART_RECEIVE_DISABLE 0x00
//La valeur des options de paramètres :
#defineFLOW_CONTROL_ENABLE 0x40 //Contrôle de débit
#defineFLOW_CONTROL_DISABLE 0x00
#defineEVEN_PARITY 0x20 //Vérification occasionnelle
#defineODD_PARITY 0x00 //Vérification étrange
#defineNINE_BIT_TRANSFER 0x10 //Transfert de 9 octets
#defineEIGHT_BIT_TRANSFER 0x00 //Transfert de 8 octets
#definePARITY_ENABLE 0x08 //Activation de la vérification de parité
#definePARITY_DISABLE 0x00
#defineTWO_STOP_BITS 0x04 //Position d’arrêt à 2 positions
#defineONE_STOP_BITS 0x00 //1 position d’arrêt
#defineHIGH_STOP 0x02 //Le niveau d’arrêt est élevé
#defineLOW_STOP 0x00 //La position d’arrêt est basse
#defineHIGH_START 0x01 //Le niveau de départ du bit est élevé
#defineLOW_START 0x00 //Le niveau de départ du bit est bas
//Le port série envoie des caractères
#defineUART_SEND(uart,data)
faire{
tandis que(U##uart##CSR &0x01);
U##uart##DBUF = data ;
}tandis que (0)
#defineUART0_SEND(data) UART_SEND(0,data)
#defineUART1_SEND(données) UART_SEND(1,données)
//Le port série reçoit les caractères
#defineUART_RECEIVE(uart,data)
faire{
tandis que(! (U##uart##CSR&0x04));
data=U##uart##DBUF ;
}tandis que(0)
#defineUART0_RECEIVE(data) UART_RECEIVE(0,data)
#defineUART1_RECEIVE(data) UART_RECEIVE(1,data)
[url=] [/url]
[url=] [/url]
/***********************************************************
Gestion de l’alimentation et de l’horloge
***********************************************************/
//Obtenez le crossover horloge
#defineCLKSPD (CLKCON & 0x07)
//Régler le mode d’alimentation
#defineSET_POWER_MODE(mode)
faire{
si(mode ==0) { SOMMEIL &= ~0x03; }
sinon si(mode ==3) { DORS |=0x03; }
sinon{ SOMMEIL &= ~0x03; SOMMEIL |= mode ; }
PCON |=0x01;
asm("NON");
}tandis que (0)
//Le mode paramètre est réglé aux valeurs suivantes :
#definePOWER_MODE_0 0x00
#definePOWER_MODE_1 0x01
#definePOWER_MODE_2 0x02
#definePOWER_MODE_3 0x03
//Utilisé pour détecter la stabilité des oscillateurs RC haute fréquence
#defineHIGH_FREQUENCY_RC_OSC_STABLE (SOMMEIL & 0x20)
//Utilisé pour détecter l’état stable de l’oscillateur à cristal
#defineXOSC_STABLE (SOMMEIL & 0x40)
//Obtenez la valeur de la fréquence de tick du minuteur
#defineTICKSPD ((CLKCON & 0x38) >> 3)
//Réglez la fréquence de l’horloge maîtresse
#defineSET_MAIN_CLOCK_SOURCE(source)
faire{
si(source) {
CLKCON |=0x40;
tandis que(! HIGH_FREQUENCY_RC_OSC_STABLE) ;
si(TICKSPD ==0){
CLKCON |=0x08;
}
SOMMEIL |=0x04;
}
sinon{
SOMMEIL &= ~0x04;
tandis que(! XOSC_STABLE) ;
asm("NON");
CLKCON &= ~0x47;
SOMMEIL |=0x04;
}
}tandis que (0)
//La valeur de la source de paramètre est :
#defineCRISTAL 0x00 //Oscillateur à cristal
#defineRC 0x01 //Oscillateur RC
[url=] [/url]
[url=] [/url]
/***********************************************************
Minuterie 1
***********************************************************/
//Le minuteur 1 permet à l’interruption du débordement de compte
#defineTIMER1_ENABLE_OVERFLOW_INT(Val)
(TIMIF = (val) ? TIMIF |0x40: TIMIF & ~0x40)
//Réglez le drapeau d’interruption de dépassement pour le minuteur 1
#defineTIMER1_OVERFLOW_INT_SETFLAG(f) (T1CTL= ((T1CTL & (~0x10)) | f))
//Démarrage du minuteur 1
#defineTIMER1_RUN(valeur) (T1CTL = (valeur) ? T1CTL|0x02 : T1CTL&~0x03)
//Réglez la division de l’horloge pour le minuteur
#defineSET_TIMER_TICK(valeur) do{ CLKCON = ((CLKCON & (~0x38)) | valeur) ; } tandis que (0)
//La valeur de la valeur est :
#defineTIMER1_TICK_32M 0x00 //32MHz
#defineTIMER1_TICK_16M 0x08 //16 MHz, la valeur par défaut pour la réinitialisation du système
#defineTIMER1_TICK_8M 0x10 //8MHz
#defineTIMER1_TICK_4M 0x18 //4 MHz
#defineTIMER1_TICK_2M 0x20 //2 MHz
#defineTIMER1_TICK_1M 0x28 //1 MHz
#defineTIMER1_TICK_500k 0x30 //500kHz
#defineTIMER1_TICK_250k 0x38 //250kHz
//Réglez le crossover TICK pour le minuteur 1
#defineSET_TIMER1_TICKDIV(valeur)
faire{
T1CTL &= ~0x0c;
T1CTL |= valeur ;
}tandis que (0)
//où la valeur est :
#defineTIMER1_TICKDIV_1 0x00 //1 division
#defineTIMER1_TICKDIV_8 0x04 //Fréquence 8 voies
#defineTIMER1_TICKDIV_32 0x08
#defineTIMER1_TICKDIV_128 0x0c
//Définir la période de dépassement du minuteur
#defineSET_TIMER1_PERIOD(valeur)
faire{
T1CC0H = HIGH_BYTE(valeur) ;
T1CC0L = LOW_BYTE(valeur) ;
}tandis que (0)
//Régler le mode de fonctionnement du minuteur 1
#defineSET_TIMER1_MODE(mode)
faire{
T1CTL = ((T1CTL & (~0x03)) | mode) ;
}tandis que (0)
//La valeur du mode est :
#defineTIMER1_MODE_STOP 0x00
#defineTIMER1_MODE_FREE 0x01
#defineTIMER1_MODE_MODULE 0x02
#defineTIMER1_MODE_UPDOWN 0x03
[url=] [/url]
[url=] [/url]
/***********************************************************
Chien de garde
***********************************************************/
//Régler la période de dépassement pour le minuteur de surveillance
#defineWDT_SET_TIMEOUT_PERIOD(temps mort)
faire{ WDCTL &= ~0x03; WDCTL |= temps mort ; }tandis que (0)
//La valeur du délai d’attente du paramètre est :
#defineSEC_1 0x00 //Après 1 seconde
#defineM_SEC_250 0x01 //Après 250 ms
#defineM_SEC_15 0x02 //Après 15 ms
#defineM_SEC_2 0x03 //Après 2 ms
//Procédures d’alimentation des chiens
#defineWDT_RESET() do {
WDCTL = (WDCTL & ~0xF0) |0xA0;
WDCTL = (WDCTL & ~0xF0) |0x50;
} tandis que (0)
//Démarrer/arrêter le minuteur de surveillance
#defineWDT_ENABLE() WDCTL |= 0x08
#defineWDT_DISABLE() WDCTL &= ~0x08
[url=] [/url]
[url=] [/url]
/***********************************************************
ADC
***********************************************************/
//Configurez un seul ADC
#defineADC_SINGLE_CONVERSION(paramètres)
faire{ ADCCON3 = réglages ; }tandis que(0)
//Le réglage des paramètres est composé des combinaisons suivantes :
//Tension de référence
#defineADC_REF_1_25_V 0x00 //Tension de référence interne 1,25V
#defineADC_REF_P0_7 0x40 //Tension de référence externe sur la broche AIN7
#defineADC_REF_AVDD 0x80 //AVDD_SOC Épingles
#defineADC_REF_P0_6_P0_7 0xC0 //AIN6-AIN7 Tension de référence externe pour les entrées différentielles
//Taux d’échantillonnage
#defineADC_8_BIT 0x00 //8e place
#defineADC_10_BIT 0x10 //10e place
#defineADC_12_BIT 0x20 //12e place
#defineADC_14_BIT 0x30 //14e place
//Entrée dans le 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 //Terres
#defineADC_TEMP_SENS 0x0E //Capteur de température intégré à la puce
#defineADC_VDD_3 0x0F //VDD/3
La conversion ADC est terminée
#define ADC_SAMPLE_READY() (ADCCON1 & 0x80)
#endif
//启动ADC转化
#define ADC_START()
do { ADCCON1 |= 0x40 ; } tandis que (0)//Sélectionnez le mode de déclenchement de l’ADC en mode manuel (c’est-à-dire ADC_SAMPLE_READY)
#defineADC_STOP()
faire{ ADCCON1 |=0x30; }tandis que (0)[url=] [/url]
(2) Couche fonctionnelle de modules
[url=] [/url]
/***********************************************************
*Nom du fichier : module.h
*Auteur : hustlzp
*Date : 6 mars 2011
*Version : 1.0
*Description de la fonction : fichier d’en-tête de couche de module fonctionnel
*Liste des fonctions : void led_init()
Void timer1_init()
vide uart0_init(vide) ;
void Uart0SendString(caractère non signé *s) ;
flotter adc_start(vide)
void get_temperature(caractère non signé *sortie, température flottante) ;
vide watchdog_init(vide) ;
*Records modifiés :
***********************************************************/
#ifndef MODULE_H
#defineMODULE_H
#include"hal.h"
/***********************************************************
LED
***********************************************************/
//Définissez les broches LED
#definemené1 P1_0
#defineLed2 P1_1
#defineLed3 P1_2
#defineLead4 P1_3
//Lumière LED éteinte
#defineLED_OFF 1
#defineLED_ON 0
//Initialisation des LED
videled_init(vide);
/***********************************************************
timer1
***********************************************************/
//Utilisé pour définir la valeur de la période de dépassement pour le minuteur
#defineTIMER1_OVF_2SEC 0xF424 //2
#defineTIMER1_OVF_1SEC 0x7A12 //1
#defineTIMER1_OVF_dot5SEC 0x3D09 //0,5 s
//Le minuteur 1 initialise
vide timer1_init(vide);
/***********************************************************
UART0
***********************************************************/
//Initialisation de l’UART0
vide uart0_init(vide);
//Chaîne de transmission de ports série
vide Uart0SendString(non signéChar*s) ;
/***********************************************************
ADC-14
***********************************************************/
//Utilisé pour convertir les données obtenues par l’ADC en température Celsius
#defineADC_TO_CELSIUS(temp) (température * 0,06229 - 311,43)
//Lancer la conversion ADC
Flotteuradc_start(vide);
//Conversion
vide get_temperature(non signéChar*sortie,Flotteurtemporaire) ;
/***********************************************************
WatchDog
***********************************************************/
//Initialisation du chien de garde
vide watchdog_init(vide);
#endif
[url=] [/url]
[url=] [/url]
/***********************************************************
*Nom du fichier : module.c
*Auteur : hustlzp
*Date : 2011/03/11
*Version : 1.0
*Description de la fonction : Fichier source de la couche fonctionnelle du module
*Liste des fonctions : (omis)
*Records modifiés :
***********************************************************/
#include"module.h"
/***********************************************************
*Nom de la fonction : led_init
*Fonction de fonction : initialisation des LED
*Paramètres d’entrée : Aucun
*Paramètres d’exportation : Aucun
***********************************************************/
videled_init(vide)
{
//Configurez P1.0, P1.1, P1.2 et P1.3 comme ports d’E/S généraux
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) ;
//Configurez P1.0, P1.1, P1.2 et P1.3 comme sorties
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) ;
mené1 = LED_ON ;
mené2 = LED_OFF ;
mené3 = LED_OFF ;
mené4 = LED_OFF ;
}
/***********************************************************
*Nom de la fonction : timer1_init
* Fonction fonction : initialisation du minuteur 1
*Paramètres d’entrée : Aucun
*Paramètres d’exportation : Aucun
***********************************************************/
videtimer1_init(vide)
{
INT_GLOBAL_ENABLE(INT_ON) ; //Ouvrir l’interruption globale
INT_ENABLE(INUM_T1, INT_ON) ; //Interruption T1 ouverte
TIMER1_ENABLE_OVERFLOW_INT(INT_ON) ; //Interruption de débordement à débordement de T1 ouvert
SET_TIMER_TICK(TIMER1_TICK_4M) ; //Réglez le minuteur TICK à 4 MHz
SET_TIMER1_PERIOD(TIMER1_OVF_2SEC) ; //Fixez la période de comptage pour T1 à 2
SET_TIMER1_TICKDIV(TIMER1_TICKDIV_128) ; //Réglez le crossover de l’horloge pour T1 à 128
SET_TIMER1_MODE(TIMER1_MODE_MODULE) ; //Réglez le mode de course de T1 sur module
}
/***********************************************************
*Nom de la fonction : uart0_init
*Fonction fonction : Initialisation du port série UART0
*Paramètres d’entrée : Aucun
*Paramètres d’exportation : Aucun
***********************************************************/
videuart0_init(vide)
{
//Sélectionnez l’emplacement UART
IO_PER_LOC_UART0_AT_PORT0_PIN2345() ;
//Configurer l’UART : Réception autorisée, 115200bps, bit d’arrêt d’un bit, pas de parité
UART_SETUP(0, UART_RECEIVE_ENABLE,115200, ONE_STOP_BITS | PARITY_DISABLE) ;
//Ouvrir l’interruption totale
INT_GLOBAL_ENABLE(INT_ON) ;
//Ouvrir le port série 0 pour recevoir les interruptions
INT_ENABLE(INUM_URX0, INT_ON) ;
}
/***********************************************************
*Nom de la fonction : Uart0SendString
* Fonction fonction : initialisation du minuteur 1
*Paramètre d’entrée : personnage non signé *s
La ficelle que tu veux envoyer
*Paramètres d’exportation : Aucun
***********************************************************/
videUart0SendString(non signéChar*s)
{
tandis que(*s !=0)
UART0_SEND(*s++) ;
}
/***********************************************************
*Nom de la fonction : adc_start
*Fonction fonction : Démarrer la conversion ADC
*Paramètres d’entrée : Aucun
*Paramètre d’exportation : float
La valeur de température dans la tablette
***********************************************************/
Flotteuradc_start(vide)
{
non signéintTemp ;
//La tension de référence est de 1,25V, la précision d’échantillonnage est de 14 bits, et la cible de conversion est le capteur de température intégré à la puce
ADC_SINGLE_CONVERSION(ADC_REF_1_25_V | ADC_14_BIT | ADC_TEMP_SENS) ;
ADC_STOP() ; //Réglez la méthode de déclenchement pour la conversion ADC en manuel
ADC_START() ; //Lancer la conversion ADC
tandis que(! ADC_SAMPLE_READY()) ; //Attendez que la conversion soit terminée
temp = ADCL >>2; //Conserver les résultats de conversion en température
temp |= (((non signéint) ADCH) <<6);
RetourADC_TO_CELSIUS (temporaire) ; //Retourne la valeur réelle de la température après conversion
}
/***********************************************************
*Nom de la fonction : get_temperature
*Fonction fonction : Traiter la valeur de température et la stocker dans le tableau de caractères pour la sortie série
*Paramètre d’entrée : unsigned char *sortie
Utilisé pour stocker la valeur de température convertie
Température de flotteur
Valeur de température Celsius
*Paramètres d’exportation : Aucun
***********************************************************/
videget_temperature(non signéChar*sortie,Flotteurtemp)
{
Sortie[0] = (non signéChar)(temp) /10 + 48; //Dix places
Sortie[1] = (non signéChar(temp) %10 + 48; //Chiffre unique
Sortie[2] ='.'; //Virgule décimale
Sortie[3] = (non signéChar)(temp*10) %10 + 48; //Dixième
Sortie[4] = (non signéChar)(temp*100) %10 + 48; //Percentile
Sortie[5] =''; //Endifeurs de cordes
}
/***********************************************************
*Nom de la fonction : watchdog_init
*Fonction fonction : Initialisation du chien de surveillance
*Paramètres d’entrée : Aucun
*Paramètres d’exportation : Aucun
***********************************************************/
videwatchdog_init(vide)
{
WDT_SET_TIMEOUT_PERIOD(SEC_1) ; //Réglez le temps d’attente à 1 seconde
WDT_ENABLE() ; //Démarrez le chien de garde
}
[url=] [/url]
(3) Couche application
[url=] [/url]
/*******************************************************************
Nom du fichier : main.c
Auteur : hustlzp
Date : 2011/03/11
Version : 1.0
Description de la fonction : Fichier principal du programme
Liste des fonctions : (omis)
Bilan de modifications :
*******************************************************************/
#include
/********************************************************************
Procédures de service d’interruption
********************************************************************/
/* 定时器1溢出中断子程序
-------------------------------------------------------*/
#pragma vecteur = T1_VECTOR
__interrupt vide T1_ISR(vide)
{
EA=0 ; La porte est interrompue
mené2 = LED_ON ;
get_temperature(sortie,adc_start()) ; Convertir la valeur de température en un tableau de caractères à produire
Uart0SendString (sortie) ; Valeur de température de sortie
Uart0SendString(« °C ») ;
led2
/* 串口接收中断子程序
-------------------------------------------------------*/
#pragma vecteur=URX0_VECTOR
__interrupt vide RE_ISR(vide)
{
EA=0 ;
mené3 = LED_ON ;
réception = U0DBUF ;
if(type==1) // type=1, ce qui indique que le caractère reçu est utilisé pour définir la période de dépassement du minuteur
{
type=0 ;
commuter (réception)
{
cas '0' : // La période de dépassement du minuteur est de 0,5 s
{
SET_TIMER1_PERIOD(TIMER1_OVF_dot5SEC) ;
pause ;
}
cas '1' : // La période de dépassement du minuteur est de 1s
{
SET_TIMER1_PERIOD(TIMER1_OVF_1SEC) ;
pause ;
}
cas '2' : // La période de dépassement du minuteur est de 2s
{
SET_TIMER1_PERIOD(TIMER1_OVF_2SEC) ;
pause ;
}
}
}
else if(type==2) // type=2, indiquant que les caractères reçus sont utilisés pour le contrôle du sommeil
{
type=0 ;
mené1 = LED_OFF ;
mené2 = LED_OFF ;
mené3 = LED_OFF ;
commuter (réception)
{
cas '1' : // Entrer en mode alimentation PM1
{
SET_POWER_MODE(1) ;
pause ;
}
cas '2' : // Passer en mode alimentation PM2
{
SET_POWER_MODE(2) ;
pause ;
}
cas '3' : //Entrer en mode alimentation PM3
{
SET_POWER_MODE(3) ;
pause ;
}
}
}
else if(type==0) // type=0, ce qui indique que le caractère reçu est le type de commande de contrôle : @ ou $
{
si(recevoir=='@')
{
type=1 ; '@' est reçu pour indiquer que le caractère suivant est utilisé pour définir la période de dépassement
}
sinon(recevoir=='$')
{
type=2 ; « $ » est reçu, indiquant que le caractère suivant est utilisé pour le contrôle du sommeil système
}
}
mené3 = LED_OFF ;
EA=1 ;
}
=LED_OFF ;
TIMER1_OVERFLOW_INT_SETFLAG(INT_CLR) ; Effacez le panneau d’interruption
EA=1 ; Interruption ouverte
}
/* 主函数
-------------------------------------------------------*/
Void main(void)
{
SET_MAIN_CLOCK_SOURCE(CRISTAL) ; Réglez l’horloge système à un oscillateur à cristal de 32 MHz
led_init() ; Initialisation des LED
uart0_init() ; Initialisation du port série UART0
timer1_init() ; Le minuteur 1 initialise
watchdog_init() ; Initialisation du chien de garde
tandis que (1)
{
WDT_RESET() ; Nourrissez le chien en permanence
}
}/********************************************************************
Programme principal
********************************************************************/
/* 全局变量
-------------------------------------------------------*/
sortie de char non signé[6]={0} ; Les données de température sont stockées pour une sortie série facile
personnage non signé reçoit ; Stocker les caractères reçus
type de caractère non signé=0 ; Le drapeau de type du caractère reçu est fixé à 0/1/2"module.h"[url=] [/url]
5. TestsOh~ Le code est enfin collé, c’est vraiment épuisant, testons ce petit système :
(1) Échantillonnage chronométré
Ouvrez le port série, lancez le débogage IAR, et constatez que le LED1 est activé, que la valeur de température sur l’outil du port série est constamment générée, et que l’intervalle d’échantillonnage est déterminé à 2s :
(2) Contrôle de l’intervalle d’échantillonnage
Entrez « @1 » dans l’outil du port série, puis testez l’intervalle d’échantillonnage, et constatez qu’il est devenu 1s ; Entrez « @0 » et l’intervalle d’échantillonnage est passé à 0,5 s.
(3) Contrôle du sommeil
Entrez « $1 » dans l’outil port série et constatez que toutes les LED sont éteintes et que l’échantillonnage de température s’est arrêté :
Après test, le système fonctionne normalement et de manière stable, et répond essentiellement aux exigences.
Étudiants ayant besoin de code sourceCliquez ici pour télécharger
6. ConclusionCet article prend une expérience relativement complète comme exemple pour montrer comment intégrer les ressources CC2430 embarquées afin d’écrire un système relativement standardisé de petite taille. Dans quelques jours, je prendrai le temps d’écrire un manuel d’utilisation simple pour hal.h afin que moi et tout le monde puissions facilement utiliser le CC2430.
Ensuite, je vais terminer mes recherches sur les ressources embarquées CC2430 et me consacrer à l’apprentissage de la pile de protocoles TI Z-Stack~
L’écriture de billets de blog dans cette série est terminée pour l’instant, mais le parcours de Zigbee va se poursuivre. Le décor à venir est inconnu, mais je crois que l’auteur surmontera les obstacles avec tout le monde, goûtera les hauts et les bas, et il y aura des gains.
Restez à l’écoute : articles de blog « Rejoignez TI Z-Stack » !