Dopo aver scritto "Zigbee Journey (9)" il 3 marzo, l'autore aveva inizialmente iniziata a scrivere subito un piccolo esperimento su "sistema di monitoraggio della temperatura" come riassunto di una serie di punti di conoscenza sparsi precedenti. Tuttavia, mi sono anche reso conto che, sebbene ciascuno dei piccoli esperimenti precedenti fosse descritto in dettaglio, la natura normativa e strutturale del suo codice poteva essere considerata insopportabile. Poiché si tratta di un riassunto, dovremmo fare progressi sulla base originale, piuttosto che ricostruire meccanicamente i piccoli punti di conoscenza precedenti. Perciò ho messo in pausa il mio piano originale, ho dedicato tempo a imparare le tecniche generali dello sviluppo embedded e ho scritto due saggiSpecifica di programmazione C51 incorporata" e "Gerarchia della struttura del codice di progetto embedded》。 Questo registro non è solo un riassunto del primo viaggio di Zigbee, ma incorpora anche l'esperienza di apprendimento dell'autore negli ultimi giorni, sperando di essere utile per i principianti dello Zigbee.
Il testo completo è organizzato secondo il processo base dello sviluppo software: analisi dei requisiti, progettazione della scaletta, progettazione dettagliata, implementazione della codifica e test.
1. Analisi della domandaDopo una discussione tra il "cliente" e lo "sviluppatore", è stata determinata la seguente descrizione della funzione di sistema:
… La temperatura ambiente attuale viene raccolta da nodi basati su CC2430, e i suoi valori di temperatura possono essere monitorati tramite un PC
… Il nodo CC2430 stesso deve avere un certo grado di stabilità e può tornare automaticamente allo stato normale
… L'intervallo di campionamento e la gestione dell'alimentazione del nodo possono essere controllati da un PC
2. Progettazione della scalettaSecondo l'analisi dei requisiti sopra, possiamo suddividere il sistema in due moduli:Nodo CC2430ePC。
[Nodo CC2430]
… I parametri esterni possono essere raccolti regolarmente e inviati al PC
… Reset automatico quando la macchina viene spenta
… I comandi dal PC possono essere ricevuti ed elaborati di conseguenza: modificare l'intervallo di campionamento/gestione dell'alimentazione
[PC]
… La macchina C riceve e visualizza i dati tramite lo strumento della porta seriale
… Le istruzioni possono essere inviate al microcontrollore tramite lo strumento della porta seriale per controllare la velocità di campionamento e la gestione dell'alimentazione
3. Progettazione dettagliata(1) Struttura del codice
La stratificazione della struttura del codice di questo sistema è stata effettivamente descritta nel saggio "Gerarchia della struttura del codice di progetto embedded, e la copia è la seguente:
(1) Strato di astrazione hardware
[ioCC2430.h] (Sistema incluso):Tutti i vettori SFR e di interruzione del CC2430 sono definiti
[hal.h] Include definizioni di tipo comuni, macro di assegnazione comuni e configurazione comune delle risorse CC2430 on-chip (I/O, comunicazione seriale, ADC, timer, gestione dell'alimentazione, ecc.)
(2) Livello funzionale del modulo
[module.h] definisce le risorse on-chip (timer, I/O), moduli di espansione off-chip (LED) e dichiarazioni di funzioni correlate
[module.cImplementa l'inizializzazione di ogni modulo (LED).
(3) Livello applicativo
[main.cConsulta hal.h, ioCC2430.h e module.h per soddisfare requisiti specifici come l'acquisizione della temperatura, l'intercomunicazione con PC, e lo spegnimento e il reset
(2) Metodi di implementazione di ogni modulo
Secondo i moduli suddivisi secondo il progetto schematico, il sistema intrinseco può essere suddiviso in due moduli principali:Nodo CC2430ePC。
Poiché sul PC ci sono strumenti di comunicazione con porte seriali, le sue funzioni possono soddisfare i requisiti, quindi non è necessario fare questa parte del PC e non è necessario analizzarla. Parliamo della sezione CC2430 qui sotto
Il metodo di implementazione di ciascuna sotto-funzione del punto:
… Usa l'interruzione di overflow del conteggio del timer per attivare il campionamento temporizzato
… La modalità UART0 con porta seriale trasmette i dati di temperatura a un PC
… Il circuito watchdog integrato del CC2430 viene utilizzato per realizzare la funzione di reset automatico del sistema
… La porta seriale viene utilizzata per ricevere interruzioni per catturare e rispondere ai comandi di controllo dal PC
1) Se ricevuto@Il carattere è il comando di controllo dell'intervallo di campionamento, seguito da un numero che indica l'intervallo di campionamento: 0-0,5s, 1-1s, 2-2s
如:@0,表示每隔0.5秒采样一次。
2) Se ricevuto$ Il carattere è il comando di controllo in sospensione, seguito da un numero che indica la modalità di alimentazione
Ad esempio: $3, che significa mettere il sistema in modalità di alimentazione 3.
(3) Diagramma di flusso del programma
- Diagramma di flusso del programma master
- Timer 1 Diagramma di flusso del programma Overflow Interrupt
- Diagramma di flusso della procedura di ricezione delle interruzioni della porta seriale
4. Implementazione della codifica(1) Strato di astrazione hardware
Il livello di astrazione hardware include ioCC2430.h e hal.h. Poiché il sistema precedente lo include, non sarà elencato.
Di seguito è riportato un elenco di tutti i contenuti di hal.h (poiché questo file è troppo lungo e sembra scomodo, lo mostrerò nei moduli):
- Testa
- Porte I/O
- Interrotta
- Porta seriale
- Gestione di alimentazione e clock
- Timer
- Cane da guardia
- ADC
[url=]
[/url]
/***********************************************************
*Nome file: hal.h
*Autore: hustlzp
*Data: 8 marzo 2011
*Edizione: 1.1
*Descrizione della funzione: Livello di astrazione hardware
*Record modificati:
***********************************************************/
#ifndef HAL_H
#defineHAL_H
#include
/***********************************************************
Definizioni di tipo comuni
***********************************************************/
typedef non segnatoChar BYTE;
typedef non segnatoint PAROLA;
typedef non segnatolunga DWORD;
/***********************************************************
Definizioni macro comunemente usate
***********************************************************/
//8 posti in più
#defineHIGH_BYTE(a) ((BYTE) (((WORD)(a)) >> 8))
//8 posti più in basso
#defineLOW_BYTE(a) ((BYTE) ((WORD)(a)))
//Assegnazione
#defineSET_WORD(regH,regL,word)
fare{
(regH)=HIGH_BYTE(parola);
(regL)=LOW_BYTE(parola);
}mentre(0)
[url=] [/url]
[url=] [/url]
/***********************************************************
Porte I/O
***********************************************************/
/*Configura la direzione della porta I/O
-----------------------------------------*/
#defineIO_DIR_PORT_PIN(porting, pin, dir)
fare{
se(dir: == IO_OUT)
P##port##DIR |= (0x01<<(spilla));
altrimenti
P##port##DIR &= ~(0x01<<(spilla));
}mentre(0)
//Il valore del parametro dir è:
#defineIO_IN 0
#defineIO_OUT 1
/*Configura la modalità di ingresso della porta I/O
-----------------------------------------*/
#defineIO_IMODE_PORT_PIN(porta, pin, imode)
fare{
se(imode == IO_IMODE_TRI)
P##port##INP |= (0x01<<(spilla));
altrimenti
P##port##INP &= ~(0x01<<(spilla));
}mentre (0)
#define IO_PUD_PORT(sinistra, pud)
do {
if (pud == IO_PULLDOWN)
P2INP |= (0x01 << (porta+5));
altrimenti
P2INP &= ~(0x01 << (porta+5));
} mentre (0)
Il valore del parametro PUD è:
#define IO_PULLUP 0 // Ritiro
#define IO_PULLDOWN 1 // Tira verso il basso
/*配置I/O口的功能
-----------------------------------------*/
#define IO_FUNC_PORT_PIN(porta, pin, func)
do {
if((port == 2) & (pin == 3)){
se (func) {
P2SEL |= 0x02;
} altrimenti {
P2SEL &= ~0x02;
}
}
else if((port == 2) && (pin == 4)){
se (func) {
P2SEL |= 0x04;
} altrimenti {
P2SEL &= ~0x04;
}
}
else{
se (func) {
P##port##SEL |= (0x01<<(spillo));
} altrimenti {
P##port##SEL &= ~(0x01<<(spilla));
}
}
} mentre (0)
Il valore del parametro func è:
#define IO_FUNC_GIO 0 // I/O generale
#define IO_FUNC_PERIPH 1 // I/O periferica
Configura la posizione dell'I/O periferico
#define IO_PER_LOC_TIMER1_AT_PORT0_PIN234() do { PERCFG = (PERCFG&~0x40)|0x00; } mentre (0)
#define IO_PER_LOC_TIMER1_AT_PORT1_PIN012() do { PERCFG = (PERCFG&~0x40)|0x40; } mentre (0)
#define IO_PER_LOC_TIMER3_AT_PORT1_PIN34() do { PERCFG = (PERCFG&~0x20)|0x00; } mentre (0)
#define IO_PER_LOC_TIMER3_AT_PORT1_PIN67() do { PERCFG = (PERCFG&~0x20)|0x20; } mentre (0)
#define IO_PER_LOC_TIMER4_AT_PORT1_PIN01() do { PERCFG = (PERCFG&~0x10)|0x00; } mentre (0)
#define IO_PER_LOC_TIMER4_AT_PORT2_PIN03() do { PERCFG = (PERCFG&~0x10)|0x10; } mentre (0)
#define IO_PER_LOC_SPI1_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x08)|0x00; } mentre (0)
#define IO_PER_LOC_SPI1_AT_PORT1_PIN4567() do { PERCFG = (PERCFG&~0x08)|0x08; } mentre (0)
#define IO_PER_LOC_SPI0_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x04)|0x00; } mentre (0)
#define IO_PER_LOC_SPI0_AT_PORT1_PIN2345() do { PERCFG = (PERCFG&~0x04)|0x04; } mentre (0)
#define IO_PER_LOC_UART1_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x02)|0x00; } mentre (0)
#define IO_PER_LOC_UART1_AT_PORT1_PIN4567() do { PERCFG = (PERCFG&~0x02)|0x02; } mentre (0)
#define IO_PER_LOC_UART0_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x00; } mentre (0)
#define IO_PER_LOC_UART0_AT_PORT1_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x01; } mentre (0)
//Il valore del parametro imode è:
#defineIO_IMODE_PUD 0 //Tira su/tira giù
#defineIO_IMODE_TRI 1 //Tre stati[url=] [/url]
[url=] [/url]
/***********************************************************
Interrotta
***********************************************************/
//Per interruzioni on/off
#defineINT_ON 1
#defineINT_OFF 0
//Usato per piazzare/cancellare i flag di interruzione
#defineINT_SET 1
#defineINT_CLR 0
//Impostazioni globali degli interrupt
#defineINT_GLOBAL_ENABLE(on) EA=(!! ON)
//Definisci la rottura
#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
#defineINUM_T3 11
#define12 INUM_T4
#defineINUM_P0INT 13
#define14 INUM_UTX1
#defineINUM_P1INT 15
#defineINUM_RF 16
#define17 INUM_WDT
/*Interruzioni consentite
-----------------------------------------*/
#defineINT_ENABLE(inum, on)
fare{
se (inum==INUM_RFERR) { RFERRIE = on; }
altrimenti se(inum==INUM_ADC) { ADCIE = on; }
altrimenti se(inum==INUM_URX0) { URX0IE = on; }
altrimenti se(inum==INUM_URX1) { URX1IE = on; }
altrimenti se(inum==INUM_ENC) { ENCIE = on; }
altrimenti se(inum==INUM_ST) { STIE = on; }
altrimenti se(inum==INUM_P2INT) { (on)? (IEN2 |=0x02) : (IEN2 &= ~0x02); }
altrimenti se(inum==INUM_UTX0) { (on)? (IEN2 |=0x04) : (IEN2 &= ~0x04); }
altrimenti se(inum==INUM_DMA) { DMAIE = acceso; }
altrimenti se(inum==INUM_T1) { T1IE = on; }
altrimenti se(inum==INUM_T2) { T2IE = on; }
altrimenti se(inum==INUM_T3) { T3IE = on; }
altrimenti se(inum==INUM_T4) { T4IE = on; }
altrimenti se(inum==INUM_P0INT) { P0IE = acceso; }
altrimenti se(inum==INUM_UTX1) { (on)? (IEN2 |=0x08) : (IEN2 &= ~0x08); }
altrimenti se(inum==INUM_P1INT) { (on)? (IEN2 |=0x10) : (IEN2 &= ~0x10); }
altrimenti se(inum==INUM_RF) { (on)? (IEN2 |=0x01) : (IEN2 &= ~0x01); }
altrimenti se(inum==INUM_WDT) { (on)? (IEN2 |=0x20) : (IEN2 &= ~0x20); }
}mentre (0)
/*Imposta la priorità di interruzione
-----------------------------------------*/
#defineINT_PRIORITY(gruppo, pri)
fare{
se(pri ==0) { IP0 &= ~gruppo; IP1 &= ~gruppo; }
se(pri ==1) { IP0 |= gruppo; IP1 &= ~gruppo; }
se(pri ==2) { IP0 &= ~gruppo; IP1 |= gruppo; }
se(pri ==3) { IP0 |= gruppo; IP1 |= gruppo; }
}mentre (0)
//Il valore del parametro pri è: 0/1/2/3 (massima priorità)
//Il valore del gruppo dei parametri è:
#defineRFERR_RF_DMA 0x01//Gruppo IP0
#defineADC_P2INT_T1 0x02//Gruppo IP1
#defineURX0_UTX0_T2 0x04//Gruppo IP2
#defineURX1_UTX1_T3 0x08//Gruppo IP3
#defineENC_P1INT_T4 0x10//Gruppo IP4
#defineST_WDT_P0INT 0x20//Gruppo IP5
/*Prendi il flag di interruzione
-----------------------------------------*/
#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) ? P2IF :
(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) ? P1IF:
(inum==INUM_RF) ? S1CON &= ~0x03 :
(inum==INUM_WDT) ? WDTIF:
0
)
/*Imposta il flag di interrupt
-----------------------------------------*/
#defineINT_SETFLAG(inum, f)
fare{
se (inum==INUM_RFERR) { RFERRIF= f; }
altrimenti se(inum==INUM_ADC) { ADCIF = f; }
altrimenti se(inum==INUM_URX0) { URX0IF = f; }
altrimenti se(inum==INUM_URX1) { URX1IF = f; }
altrimenti se(inum==INUM_ENC) { ENCIF_1 = ENCIF_0 = f; }
altrimenti se(inum==INUM_ST) { STIF = f; }
altrimenti se(inum==INUM_P2INT) { P2IF = f; }
altrimenti se(inum==INUM_UTX0) { UTX0IF= f; }
altrimenti se(inum==INUM_DMA) { DMAIF = f; }
altrimenti se(inum==INUM_T1) { T1IF = f; }
altrimenti se(inum==INUM_T2) { T2IF = f; }
altrimenti se(inum==INUM_T3) { T3IF = f; }
altrimenti se(inum==INUM_T4) { T4IF = f; }
altrimenti se(inum==INUM_P0INT) { P0IF = f; }
altrimenti se(inum==INUM_UTX1) { UTX1IF= f; }
altrimenti se(inum==INUM_P1INT) { P1IF = f; }
altrimenti se(inum==INUM_RF) { (f) ? (S1CON |=0x03) : (S1CON &= ~0x03); }
altrimenti se(inum==INUM_WDT) { WDTIF = f; }
}mentre (0)
[url=] [/url]
[url=] [/url]
/***********************************************************
Porta seriale
***********************************************************/
//Il valore della BAUD_E corrisponde a diversi tassi in baud
#defineBAUD_E(baud, clacDivPow) (
(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 )
//Il valore della BAUD_M corrisponde a diversi tassi di baud
#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)
/*Configurazione della porta seriale in modalità UART
-----------------------------------------*/
#defineUART_SETUP(uart, receiveEnable, baudRate, options)
fare{
se((uart) ==0){
se(PERCFG &0x01){
P1SEL |=0x30;
}altrimenti{
P0SEL |=0x0C;
}
}
altrimenti{
se(PERCFG &0x02){
P1SEL |=0xC0;
}altrimenti{
P0SEL |=0x30;
}
}
U##uart##GCR = BAUD_E((baudRate),CLKSPD);
U##uart##BAUD = BAUD_M(baudRate);
U##uart##CSR |=0x80;
U##uart##CSR |= ricevereAbilitare;
U##uart##UCR |= (opzioni) |0x80);
}mentre(0)
//Il valore del parametro ricevutoEnable:
#defineUART_RECEIVE_ENABLE 0x40 //Ricevimento del permesso
#defineUART_RECEIVE_DISABLE 0x00
//Il valore delle opzioni di parametro:
#defineFLOW_CONTROL_ENABLE 0x40 //Controllo del flusso
#defineFLOW_CONTROL_DISABLE 0x00
#defineEVEN_PARITY 0x20 //Verifiche occasionali
#defineODD_PARITY 0x00 //Verifica strana
#defineNINE_BIT_TRANSFER 0x10 //Trasferimento a 9 byte
#defineEIGHT_BIT_TRANSFER 0x00 //Trasferimento da 8 byte
#definePARITY_ENABLE 0x08 //Abilitazione del controllo di parità
#definePARITY_DISABLE 0x00
#defineTWO_STOP_BITS 0x04 //Posizione di arresto a 2 posizioni
#defineONE_STOP_BITS 0x00 //1 posizione di fermamento
#defineHIGH_STOP 0x02 //Il livello di stop è alto
#defineLOW_STOP 0x00 //La posizione di stop è bassa
#defineHIGH_START 0x01 //Il livello di bit iniziale è alto
#defineLOW_START 0x00 //Il livello del bit iniziale è basso
//La porta seriale invia i caratteri
#defineUART_SEND(uart,data)
fare{
mentre(U##uart##CSR &0x01);
U##uart##DBUF = dati;
}mentre (0)
#defineUART0_SEND(dati) UART_SEND(0,dati)
#defineUART1_SEND(dati) UART_SEND(1,dati)
//La porta seriale riceve i caratteri
#defineUART_RECEIVE(uart,data)
fare{
mentre(! (U##uart##CSR&0x04));
data=U##uart##DBUF;
}mentre(0)
#defineUART0_RECEIVE(dati) UART_RECEIVE(0,dati)
#defineUART1_RECEIVE(dati) UART_RECEIVE(1,dati)
[url=] [/url]
[url=] [/url]
/***********************************************************
Gestione di alimentazione e clock
***********************************************************/
//Prendi il crossover dell'orologio
#defineCLKSPD (CLKCON & 0x07)
//Imposta la modalità di alimentazione
#defineSET_POWER_MODE(modalità)
fare{
se(modalità ==0) { SONNO &= ~0x03; }
altrimenti se(modalità ==3) { SONNO |=0x03; }
altrimenti{ SONNO &= ~0x03; SLEEP |= modalità; }
PCON |=0x01;
asm("No");
}mentre (0)
//La modalità parametro è impostata ai seguenti valori:
#definePOWER_MODE_0 0x00
#definePOWER_MODE_1 0x01
#definePOWER_MODE_2 0x02
#definePOWER_MODE_3 0x03
//Utilizzato per rilevare la stabilità degli oscillatori RC ad alta frequenza
#defineHIGH_FREQUENCY_RC_OSC_STABLE (SONNO & 0x20)
//Utilizzato per rilevare la condizione stabile dell'oscillatore a cristallo
#defineXOSC_STABLE (SONNO & 0x40)
//Ottieni il valore della frequenza dei tick del timer
#defineTICKSPD ((CLKCON & 0x38) >> 3)
//Imposta la frequenza del master clock
#defineSET_MAIN_CLOCK_SOURCE(fonte)
fare{
se(fonte) {
CLKCON |=0x40;
mentre(! HIGH_FREQUENCY_RC_OSC_STABLE);
se(TICKSPD ==0){
CLKCON |=0x08;
}
SONNO |=0x04;
}
altrimenti{
SONNO &= ~0x04;
mentre(! XOSC_STABLE);
asm("No");
CLKCON &= ~0x47;
SONNO |=0x04;
}
}mentre (0)
//Il valore della sorgente dei parametri è:
#defineCRISTALLO 0x00 //Oscillatore a cristallo
#defineRC 0x01 //Oscillatore RC
[url=] [/url]
[url=] [/url]
/***********************************************************
Timer 1
***********************************************************/
//Il timer 1 permette all'overflow di conteggio di interrompere
#defineTIMER1_ENABLE_OVERFLOW_INT(val)
(TIMIF = (valle) ? TIMIF |0x40: TIMIF & ~0x40)
//Imposta il flag di interruzione di overflow per timer 1
#defineTIMER1_OVERFLOW_INT_SETFLAG(f) (T1CTL= ((T1CTL & (~0x10)) | f))
//Parte il timer 1
#defineTIMER1_RUN(valore) (T1CTL = (valore) ? T1CTL|0x02 : T1CTL&~0x03)
//Imposta la divisione dell'orologio per il timer
#defineSET_TIMER_TICK(valore) do{ CLKCON = ((CLKCON & (~0x38)) | valore); } while(0)
//Il valore del valore è:
#defineTIMER1_TICK_32M 0x00 //32MHz
#defineTIMER1_TICK_16M 0x08 //16MHz, il valore predefinito per il reset 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
//Imposta il crossover TICK per timer 1
#defineSET_TIMER1_TICKDIV(valore)
fare{
T1CTL &= ~0x0c;
T1CTL |= valore;
}mentre (0)
//dove il valore è:
#defineTIMER1_TICKDIV_1 0x00 //1 Divisione
#defineTIMER1_TICKDIV_8 0x04 //Frequenza a 8 vie
#defineTIMER1_TICKDIV_32 0x08
#defineTIMER1_TICKDIV_128 0x0c
//Imposta il periodo di overflow del timer
#defineSET_TIMER1_PERIOD(valore)
fare{
T1CC0H = HIGH_BYTE(valore);
T1CC0L = LOW_BYTE(valore);
}mentre (0)
//Imposta la modalità operativa del Timer 1
#defineSET_TIMER1_MODE(mode)
fare{
T1CTL = ((T1CTL & (~0x03)) | modalità);
}mentre (0)
//Il valore della modalità è:
#defineTIMER1_MODE_STOP 0x00
#defineTIMER1_MODE_FREE 0x01
#defineTIMER1_MODE_MODULE 0x02
#defineTIMER1_MODE_UPDOWN 0x03
[url=] [/url]
[url=] [/url]
/***********************************************************
Cane da guardia
***********************************************************/
//Imposta il periodo di overflow per il timer del watchdog
#defineWDT_SET_TIMEOUT_PERIOD(timeout)
fare{ WDCTL &= ~0x03; WDCTL |= timeout; }mentre (0)
//Il valore del timeout del parametro è:
#defineSEC_1 0x00 //dopo 1 secondo
#defineM_SEC_250 0x01 //Dopo 250 ms
#defineM_SEC_15 0x02 //Dopo 15 ms
#defineM_SEC_2 0x03 //Dopo 2 ms
//Procedure di alimentazione per cani
#defineWDT_RESET() do {
WDCTL = (WDCTL & ~0xF0) |0xA0;
WDCTL = (WDCTL & ~0xF0) |0x50;
} mentre (0)
//Avvia/ferma il timer del watchdog
#defineWDT_ENABLE() WDCTL |= 0x08
#defineWDT_DISABLE() WDCTL &= ~0x08
[url=] [/url]
[url=] [/url]
/***********************************************************
ADC
***********************************************************/
//Configura un singolo ADC
#defineADC_SINGLE_CONVERSION(ambientazioni)
fare{ ADCCON3 = impostazioni; }mentre(0)
//L'impostazione dei parametri è composta dalle seguenti combinazioni:
//Tensione di riferimento
#defineADC_REF_1_25_V 0x00 //Tensione di riferimento interna 1,25V
#defineADC_REF_P0_7 0x40 //Tensione di riferimento esterna sul pin AIN7
#defineADC_REF_AVDD 0x80 //AVDD_SOC Spille
#defineADC_REF_P0_6_P0_7 0xC0 //AIN6-AIN7 Tensione di riferimento esterna per ingressi differenziali
//Frequenza di campionamento
#defineADC_8_BIT 0x00 //8° posto
#defineADC_10_BIT 0x10 //10° posto
#defineADC_12_BIT 0x20 //12° posto
#defineADC_14_BIT 0x30 //14° posto
//Entra nel canale
#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 //Terra
#defineADC_TEMP_SENS 0x0E //Sensore di temperatura integrato nel chip
#defineADC_VDD_3 0x0F //VDD/3
La conversione ADC è completata
#define ADC_SAMPLE_READY() (ADCCON1 & 0x80)
#endif
//启动ADC转化
#define ADC_START()
do { ADCCON1 |= 0x40; } mentre (0)//Seleziona la modalità di innesco dell'ADC come manuale (cioè, ADC_SAMPLE_READY)
#defineADC_STOP()
fare{ ADCCON1 |=0x30; }mentre (0)[url=] [/url]
(2) Livello funzionale del modulo
[url=] [/url]
/***********************************************************
*Nome file: module.h
*Autore: hustlzp
*Data: 6 marzo 2011
*Versione: 1.0
*Descrizione funzione: file di intestazione a livello modulo funzionale
*Elenco funzioni: void led_init()
void timer1_init()
vuoto uart0_init(vuoto);
void Uart0SendString(carattere senza segno *s);
galleggiare adc_start(vuoto)
void get_temperature(unsigned char *output, float temp);
vuoto watchdog_init(vuoto);
*Record modificati:
***********************************************************/
#ifndef MODULE_H
#defineMODULE_H
#include"hal.h"
/***********************************************************
LED
***********************************************************/
//Definisci i pin LED
#defineLed1 P1_0
#defineled2 P1_1
#defineled3 P1_2
#defineled4 P1_3
//Luce LED e spente
#defineLED_OFF 1
#defineLED_ON 0
//Inizializzazione LED
Voidled_init(Void);
/***********************************************************
timer1
***********************************************************/
//Usato per impostare il valore del periodo di overflow per il timer
#defineTIMER1_OVF_2SEC 0xF424 //2
#defineTIMER1_OVF_1SEC 0x7A12 //1
#defineTIMER1_OVF_dot5SEC 0x3D09 //0,5 secondi
//Il timer 1 inizializza
Void timer1_init(Void);
/***********************************************************
UART0
***********************************************************/
//Inizializzazione UART0
Void uart0_init(Void);
//Stringa di trasmissione della porta seriale
Void Uart0SendString(non firmatoChar*s);
/***********************************************************
ADC-14
***********************************************************/
//Utilizzato per convertire i dati ottenuti dall'ADC in temperatura Celsius
#defineADC_TO_CELSIUS(temperatura) (temperatura * 0,06229 - 311,43)
//Avviare la conversione ADC
Carroadc_start(Void);
//Conversione
Void get_temperature(non firmatoChar*output,Carrotemp);
/***********************************************************
WatchDog
***********************************************************/
//Inizializzazione del cane da guardia
Void watchdog_init(Void);
#endif
[url=] [/url]
[url=] [/url]
/***********************************************************
*Nome file: module.c
*Autore: hustlzp
*Data: 2011/3/11
*Versione: 1.0
*Descrizione funzione: File sorgente del livello modulo funzionale
*Elenco funzioni: (omesso)
*Record modificati:
***********************************************************/
#include"module.h"
/***********************************************************
*Nome funzione: led_init
*Funzione funzione: inizializzazione LED
*Parametri d'ingresso: Nessuno
*Parametri di esportazione: Nessuno
***********************************************************/
Voidled_init(Void)
{
//Configura P1.0, P1.1, P1.2 e P1.3 come porte I/O generali
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 e P1.3 come uscite
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);
condotto1 = LED_ON;
condotto2 = LED_OFF;
condotta 3 = LED_OFF;
condotta 4 = LED_OFF;
}
/***********************************************************
*Nome funzione: timer1_init
* Funzione funzione: inizializzazione Timer 1
*Parametri d'ingresso: Nessuno
*Parametri di esportazione: Nessuno
***********************************************************/
Voidtimer1_init(Void)
{
INT_GLOBAL_ENABLE(INT_ON); //Apri l'interruzione globale
INT_ENABLE(INUM_T1, INT_ON); //Interrupt T1 aperto
TIMER1_ENABLE_OVERFLOW_INT(INT_ON); //Interrupt di overflow a conteggio T1 aperto
SET_TIMER_TICK(TIMER1_TICK_4M); //Imposta il timer TICK a 4MHz
SET_TIMER1_PERIOD(TIMER1_OVF_2SEC); //Imposta il periodo di conteggio per T1 a 2
SET_TIMER1_TICKDIV(TIMER1_TICKDIV_128); //Imposta il crossover dell'orologio per T1 a 128
SET_TIMER1_MODE(TIMER1_MODE_MODULE); //Imposta la modalità di esecuzione di T1 su modulo
}
/***********************************************************
*Nome funzione: uart0_init
*Funzione funzione: Inizializzazione porta seriale UART0
*Parametri d'ingresso: Nessuno
*Parametri di esportazione: Nessuno
***********************************************************/
Voiduart0_init(Void)
{
//Seleziona la sede UART
IO_PER_LOC_UART0_AT_PORT0_PIN2345();
//Configura UART: Ricezione permessa, 115200bps, bit di stop a un bit, nessuna parità
UART_SETUP(0, UART_RECEIVE_ENABLE,115200, ONE_STOP_BITS | PARITY_DISABLE);
//Apri l'interruzione totale
INT_GLOBAL_ENABLE(INT_ON);
//Porta seriale 0 aperta per ricevere interruzioni
INT_ENABLE(INUM_URX0, INT_ON);
}
/***********************************************************
*Nome funzione: Uart0SendStringa
* Funzione funzione: inizializzazione Timer 1
*Parametro di entrata: carattere senza segno *s
La stringa che vuoi inviare
*Parametri di esportazione: Nessuno
***********************************************************/
VoidUart0SendString(non firmatoChar*s)
{
mentre(*s !=0)
UART0_SEND(*s++);
}
/***********************************************************
*Nome funzione: adc_start
*Funzione funzione: Avvio della conversione ADC
*Parametri d'ingresso: Nessuno
*Parametro di esportazione: float
Il valore della temperatura nella tavoletta
***********************************************************/
Carroadc_start(Void)
{
senza firmaturainttemp;
//La tensione di riferimento è 1,25V, la precisione del campionamento è di 14 bit e il target di conversione è il sensore di temperatura integrato nel chip
ADC_SINGLE_CONVERSION(ADC_REF_1_25_V | ADC_14_BIT | ADC_TEMP_SENS);
ADC_STOP(); //Imposta il metodo di trigger per la conversione ADC in manuale
ADC_START(); //Avviare la conversione ADC
mentre(! ADC_SAMPLE_READY()); //Aspetta che la conversione si completi
temp = ADCL >>2; //Salva i risultati della conversione in temperatura
temp |= (((non segnatoint) ADCH) <<6);
RitornoADC_TO_CELSIUS(temporanea); //Restituisce il valore effettivo della temperatura dopo la conversione
}
/***********************************************************
*Nome funzione: get_temperature
*Funzione funzione: Elaborare il valore della temperatura e memorizzarlo nell'array di caratteri per l'output seriale
*Parametro di entrata: unsigned char *output
Usata per memorizzare il valore di temperatura convertito
Temperatura del galleggiante
Valore della temperatura Celsius
*Parametri di esportazione: Nessuno
***********************************************************/
Voidget_temperature(non firmatoChar*output,Carrotemporanea)
{
Output[0] = (non firmatoChar)(temp) /10 + 48; //Dieci posti
Output[1] = (non firmatoChar(temp) %10 + 48; //Cifra singola
Output[2] ='.'; //Virgola decimale
Output[3] = (non firmatoChar(temp*10) %10 + 48; //Decima
Output[4] = (non firmatoChar(temp*100) %10 + 48; //Percentile
Output[5] =''; //Endifieri di stringa
}
/***********************************************************
*Nome funzione: watchdog_init
*Funzione funzione: inizializzazione del cane di guardia
*Parametri d'ingresso: Nessuno
*Parametri di esportazione: Nessuno
***********************************************************/
Voidwatchdog_init(Void)
{
WDT_SET_TIMEOUT_PERIOD(SEC_1); //Imposta il timeout a 1s
WDT_ENABLE(); //Avvia il cane da guardia
}
[url=] [/url]
(3) Livello applicativo
[url=] [/url]
/*******************************************************************
Nome file: main.c
Autore: hustlzp
Data: 2011/3/11
Versione: 1.0
Descrizione della funzione: File master del programma
Elenco funzioni: (omesso)
Record di modifiche:
*******************************************************************/
#include
/********************************************************************
Procedure di servizio di interruzione
********************************************************************/
/* 定时器1溢出中断子程序
-------------------------------------------------------*/
#pragma vettore=T1_VECTOR
__interrupt vuoto T1_ISR(vuoto)
{
EA=0; Il cancello viene interrotto
condotta 2 = LED_ON;
get_temperature(output,adc_start()); Converti il valore della temperatura in un array di caratteri da produrre
Uart0SendString(output); Valore della temperatura di uscita
Uart0SendString("°C");
led2
/* 串口接收中断子程序
-------------------------------------------------------*/
#pragma vettore=URX0_VECTOR
__interrupt vuoto RE_ISR(vuoto)
{
EA=0;
condott3 = LED_ON;
ricevimento = U0DBUF;
if(type==1) // type=1, che indica che il carattere ricevuto viene usato per impostare il periodo di overflow del timer
{
tipo=0;
commutazione (ricevimento)
{
case '0': // Il periodo di overflow del timer è 0,5s
{
SET_TIMER1_PERIOD(TIMER1_OVF_dot5SEC);
pausa;
}
caso '1': // Il periodo di overflow del timer è 1s
{
SET_TIMER1_PERIOD(TIMER1_OVF_1SEC);
pausa;
}
caso '2': // Il periodo di overflow del timer è 2s
{
SET_TIMER1_PERIOD(TIMER1_OVF_2SEC);
pausa;
}
}
}
else if(type==2) // type=2, indicando che i caratteri ricevuti sono usati per il controllo del sleep
{
tipo=0;
condotto1 = LED_OFF;
condotto2 = LED_OFF;
condotta 3 = LED_OFF;
commutazione (ricevimento)
{
case '1': // Entra in modalità di alimentazione PM1
{
SET_POWER_MODE(1);
pausa;
}
case '2': // Entra in modalità alimentazione PM2
{
SET_POWER_MODE(2);
pausa;
}
caso '3': //Entra in modalità alimentazione PM3
{
SET_POWER_MODE(3);
pausa;
}
}
}
else if(type==0) // type=0, che indica che il carattere ricevuto è il tipo di comando control: @ o $
{
se(ricevere=='@')
{
tipo=1; '@' viene ricevuto per indicare che il carattere successivo viene usato per impostare il periodo di overflow
}
altrimenti se(ricevere=='$')
{
tipo=2; '$' viene ricevuto, indicando che il carattere successivo viene utilizzato per il controllo del sistema in sospensione
}
}
condotta 3 = LED_OFF;
EA=1;
}
=LED_OFF;
TIMER1_OVERFLOW_INT_SETFLAG(INT_CLR); Libera il segnale di interruzione
EA=1; Interruzione aperta
}
/* 主函数
-------------------------------------------------------*/
Void main(void)
{
SET_MAIN_CLOCK_SOURCE(CRISTALLO); Imposta il clock di sistema su oscillatore a cristallo a 32MHz
led_init(); Inizializzazione LED
uart0_init(); Inizializzazione della porta seriale UART0
timer1_init(); Il timer 1 inizializza
watchdog_init(); Inizializzazione del cane da guardia
mentre(1)
{
WDT_RESET(); Dai da mangiare al cane costantemente
}
}/********************************************************************
Programma principale
********************************************************************/
/* 全局变量
-------------------------------------------------------*/
unsigned char output[6]={0}; I dati di temperatura vengono memorizzati per un semplice output seriale
personaggio non firmato riceve; Memorizza i caratteri ricevuti
tipo di carattere senza segno=0; Il flag di tipo del carattere ricevuto è impostato su 0/1/2"module.h"[url=] [/url]
5. TestOh~ Il codice è finalmente stato incollato, è davvero estenuante, testiamo questo piccolo sistema:
(1) Campionamento temporizzato
Apri la porta seriale, avvia il debug IAR e scopri che led1 è acceso, il valore di temperatura sullo strumento della porta seriale viene generato costantemente, e l'intervallo di campionamento è determinato come 2s:
(2) Controllo dell'intervallo di campionamento
Inserisci "@1" nello strumento della porta seriale, poi testa l'intervallo di campionamento e scopri che è diventato 1s; Digita "@0" e l'intervallo di campionamento è cambiato a 0,5s.
(3) Controllo del sonno
Inserisci "$1" nello strumento della porta seriale e scopri che tutti i LED sono spenti e il campionamento di temperatura si è fermato:
Dopo i test, il sistema funziona normalmente e stabilmente, e sostanzialmente soddisfa i requisiti.
Studenti che necessitano di codice sorgenteClicca qui per scaricare
6. ConclusioneQuesto articolo prende come esempio un esperimento leggermente completo per mostrare come integrare le risorse CC2430 sul chip per scrivere un sistema relativamente standardizzato di piccole dimensioni. Tra qualche giorno prenderò il tempo di scrivere un semplice manuale utente per hal.h, così io e tutti potremo usare facilmente il CC2430.
Successivamente, finirò la mia ricerca sulle risorse on-chip del CC2430 e mi dedicherò all'apprendimento dello stack protocollo TI Z-Stack~
La scrittura dei post sul blog in questa serie è giunta al termine per ora, ma il percorso di Zigbee continuerà. Il paesaggio davanti a lui è sconosciuto, ma credo che l'autore supererà gli ostacoli con tutti e assaggerà alti e bassi, e ci saranno guadagni.
Restate sintonizzati: post sul blog "Unisciti a TI Z-Stack"!