Po napisaniu "Zigbee Journey (9)" 3 marca, autor pierwotnie planował od razu rozpocząć krótki eksperyment dotyczący "systemu monitorowania temperatury" jako podsumowanie serii rozproszonych punktów wiedzy wcześniej. Jednak zdałem sobie też sprawę, że choć każdy z poprzednich małych eksperymentów był szczegółowo opisany, normatywny i strukturalny charakter jego kodu można uznać za nie do zniesienia. Ponieważ jest to podsumowanie, powinniśmy robić postępy na podstawie pierwotnej podstawy, zamiast mechanicznie składać w całość wcześniejsze drobne punkty wiedzy. Dlatego odłożyłem pierwotny plan na później, poświęciłem czas na naukę ogólnych technik rozwoju embedded i napisałem dwa esejeSpecyfikacja programowania wbudowanego C51" i "Hierarchia struktury kodu projektu wbudowanego》。 Ten dziennik to nie tylko podsumowanie pierwszej podróży Zigbee, ale także zawiera doświadczenia z ostatnich dni nauki autora, mając nadzieję, że będzie pomocny dla początkujących Zigbee.
Pełny tekst jest zorganizowany według podstawowego procesu tworzenia oprogramowania: analizy wymagań, projektowania konspektu, szczegółowego projektu, implementacji kodowania oraz testowania.
1. Analiza popytuPo dyskusji między "klientem" a "deweloperem" ustalono, że określono następujący opis funkcji systemu:
… Aktualna temperatura pokoju jest zbierana przez węzły oparte na CC2430, a jej wartości temperaturowe można monitorować za pomocą komputera
… Sam węzeł CC2430 musi mieć pewien stopień stabilności i może automatycznie wrócić do stanu normalnego
… Interwał próbkowania i zarządzanie energią węzła mogą być kontrolowane przez komputer PC
2. Projektowanie konspektuZgodnie z powyższą analizą wymagań możemy podzielić układ na dwa moduły:Węzeł CC2430iPC。
[Węzeł CC2430]
… Parametry zewnętrzne mogą być regularnie zbierane i przesyłane do komputera
… Automatyczny reset po wyłączeniu maszyny
… Polecenia z komputera mogą być odpowiednio odbierane i przetwarzane: zmień interwał próbkowania/zarządzanie energią
[PC]
… Maszyna C odbiera i wyświetla dane za pomocą narzędzia do portu szeregowego
… Instrukcje mogą być przesyłane do mikrokontrolera za pomocą narzędzia port szeregowy, aby kontrolować jego prędkość próbkowania i zarządzanie energią
3. Szczegółowy projekt(1) Struktura kodu
Warstwowanie struktury kodu tego systemu zostało opisane w eseju "Hierarchia struktury kodu projektu wbudowanego", a kopia wygląda następująco:
(1) Warstwa sprzętowej abstrakcji
[ioCC2430.h] (System w zestawie):Wszystkie wektory SFR i przerwania CC2430 są zdefiniowane
[hal.h] Zawiera wspólne definicje typów, wspólne makra przypisania oraz wspólną konfigurację zasobów CC2430 na chipie (I/O, komunikacja szeregowa, ADC, timer, zarządzanie zasilaniem itp.)
(2) Warstwa modułu funkcjonalnego
[module.h] definiuje zasoby na chipie (timery, I/O), moduły rozszerzeń poza chipem (diody LED) oraz deklaracje powiązanych funkcji
[module.cZaimplementuj inicjalizację każdego modułu (diody LED).
(3) Warstwa aplikacji
[main.cNależy odwołać się do hal.h, ioCC2430.h oraz module.h, aby osiągnąć specyficzne wymagania aplikacji, takie jak pomiar temperatury, komunikacja z komputerem oraz wyłączanie i reset
(2) Metody implementacji każdego modułu
Zgodnie z modułami podzielonymi według projektu zarysu, układ wewnętrzny można podzielić na dwa główne moduły:Węzeł CC2430iPC。
Ponieważ na PC są narzędzia do komunikacji portem szeregowym, jego funkcje spełniają wymagania, więc nie musimy robić tej części komputera ani jej analizować. Porozmawiajmy poniżej o sekcji CC2430
Metoda implementacji każdej podfunkcji punktu:
… Użyj przerwania przelewu licznika do wywołania próbkowania z czasem
… Tryb UART0 z portem szeregowym przesyła dane temperatury do komputera PC
… Wbudowany układ watchdog w CC2430 służy do realizacji funkcji automatycznego resetu systemu
… Port szeregowy służy do odbierania przerwań do przechwytywania i reagowania na polecenia sterujące z komputera
1) Jeśli otrzyma@Znak to polecenie sterujące przedziałem próbkowania, po którym następuje liczba wskazująca przedział próbkowania: 0-0,5s, 1-1s, 2-2s
如:@0,表示每隔0.5秒采样一次。
2) Jeśli zostanie odebrany$ Znak to polecenie sterowania uśpienia, po którym następuje numer wskazujący tryb zasilania
Na przykład: $3, co oznacza przełączenie systemu w tryb zasilania 3.
(3) Schemat przepływu programu
- Schemat przepływu programu magisterskiego
- Diagram przepływu programu przerw przebiegowych Timer 1
- Schemat przepływu procedury przerwania odbioru portu szeregowego
4. Implementacja kodowania(1) Warstwa sprzętowej abstrakcji
Warstwa apstrakcji sprzętowej obejmuje ioCC2430.h oraz hal.h. Ponieważ pierwszy system jest w nim zawarty, nie zostanie on wymieniony.
Poniżej znajduje się lista wszystkich zawartości hal.h (ponieważ ten plik jest za długi i wygląda niewygodnie, pokażę go w modułach):
- głowa
- Porty I/O
- Przerwane
- Port szeregowy
- Zarządzanie zasilaniem i zegarem
- Timer
- Pies stróżujący
- ADC
[url=]
[/url]
/***********************************************************
*Nazwa pliku: hal.h
*Autor: hustlzp
*Data: 8 marca 2011
*Wydanie: 1.1
*Opis funkcji: Warstwa abstrakcji sprzętowej
*Zmodyfikowane rekordy:
***********************************************************/
#ifndef HAL_H
#defineHAL_H
#include
/***********************************************************
Typowe definicje typów
***********************************************************/
Typedef bez podpisuchar BYTE;
Typedef bez podpisuint WORD;
Typedef bez podpisudługie DWORD;
/***********************************************************
Powszechnie stosowane definicje makro
***********************************************************/
//8 miejsc wyżej
#defineHIGH_BYTE(a) ((BYTE) (((WORD)(a)) >> 8))
//8 miejsc niżej
#defineLOW_BYTE(a) ((BYTE) ((WORD)(a)))
//Przydział
#defineSET_WORD(regH,regL,word)
robić{
(regH)=HIGH_BYTE(słowo);
(regL)=LOW_BYTE(słowo);
}podczas gdy(0)
[url=] [/url]
[url=] [/url]
/***********************************************************
Porty I/O
***********************************************************/
/*Konfiguruj kierunek portu I/O
-----------------------------------------*/
#defineIO_DIR_PORT_PIN(lewa lewa linia, pin, reżyseria)
robić{
jeśli(dir == IO_OUT)
P##port##DIR |= (0x01<<(przypinka));
else
P##port##DIR &= ~(0x01<<(przypinka));
}podczas gdy(0)
//Wartość parametru dir to:
#defineIO_IN 0
#defineIO_OUT 1
/*Konfiguruj tryb wejściowy portu I/O
-----------------------------------------*/
#defineIO_IMODE_PORT_PIN(port, pin, imode)
robić{
jeśli(imode == IO_IMODE_TRI)
P##port##INP |= (0x01<<(przypinka));
else
P##port##INP &= ~(0x01<<(przypinka));
}podczas gdy (0)
#define IO_PUD_PORT(portowo, pud)
do {
if (pud == IO_PULLDOWN)
P2INP |= (0x01 << (port+5));
else
P2INP &= ~(0x01 << (port+5));
} podczas gdy (0)
Wartość parametru PUD to:
#define IO_PULLUP 0 // Podciągnij
#define IO_PULLDOWN 1 // Opuszczaj
/*配置I/O口的功能
-----------------------------------------*/
#define IO_FUNC_PORT_PIN(lewa lewa, pin, funkc)
do {
if((port == 2) && (pin == 3)){
jeśli (func) {
P2SEL |= 0x02;
} else {
P2SEL &= ~0x02;
}
}
else if((port == 2) && (pin == 4)){
jeśli (func) {
P2SEL |= 0x04;
} else {
P2SEL &= ~0x04;
}
}
else{
jeśli (func) {
P##port##SEL |= (0x01<<(pin));
} else {
P##port##SEL &= ~(0x01<<(pin));
}
}
} podczas gdy (0)
Wartość funkcja parametru to:
#define IO_FUNC_GIO 0 // Ogólne I/O
#define IO_FUNC_PERIPH 1 // Obwodowe wejścia/wyjścia
Konfiguruj lokalizację peryferyjnego I/O
#define IO_PER_LOC_TIMER1_AT_PORT0_PIN234() do { PERCFG = (PERCFG&~0x40)|0x00; } podczas gdy (0)
#define IO_PER_LOC_TIMER1_AT_PORT1_PIN012() do { PERCFG = (PERCFG&~0x40)|0x40; } podczas gdy (0)
#define IO_PER_LOC_TIMER3_AT_PORT1_PIN34() do { PERCFG = (PERCFG&~0x20)|0x00; } podczas gdy (0)
#define IO_PER_LOC_TIMER3_AT_PORT1_PIN67() do { PERCFG = (PERCFG&~0x20)|0x20; } podczas gdy (0)
#define IO_PER_LOC_TIMER4_AT_PORT1_PIN01() do { PERCFG = (PERCFG&~0x10)|0x00; } podczas gdy (0)
#define IO_PER_LOC_TIMER4_AT_PORT2_PIN03() do { PERCFG = (PERCFG&~0x10)|0x10; } podczas gdy (0)
#define IO_PER_LOC_SPI1_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x08)|0x00; } podczas gdy (0)
#define IO_PER_LOC_SPI1_AT_PORT1_PIN4567() do { PERCFG = (PERCFG&~0x08)|0x08; } podczas gdy (0)
#define IO_PER_LOC_SPI0_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x04)|0x00; } podczas gdy (0)
#define IO_PER_LOC_SPI0_AT_PORT1_PIN2345() do { PERCFG = (PERCFG&~0x04)|0x04; } podczas gdy (0)
#define IO_PER_LOC_UART1_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x02)|0x00; } podczas gdy (0)
#define IO_PER_LOC_UART1_AT_PORT1_PIN4567() do { PERCFG = (PERCFG&~0x02)|0x02; } podczas gdy (0)
#define IO_PER_LOC_UART0_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x00; } podczas gdy (0)
#define IO_PER_LOC_UART0_AT_PORT1_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x01; } podczas gdy (0)
//Wartość parametru imode to:
#defineIO_IMODE_PUD 0 //Podciągnij/pociągnij w dół
#defineIO_IMODE_TRI 1 //Trzy stany[url=] [/url]
[url=] [/url]
/***********************************************************
Przerwane
***********************************************************/
//Dla przerwań on/off
#defineINT_ON 1
#defineINT_OFF 0
//Używane do ustawiania/usuwania flag przerwań
#defineINT_SET 1
#defineINT_CLR 0
//Globalne ustawienia przerwań
#defineINT_GLOBAL_ENABLE(on) EA=(!! włączone)
//Zdefiniuj przerwanie
#defineINUM_RFERR 0
#defineINUM_ADC 1
#defineINUM_URX0 2
#defineINUM_URX1 3
#defineINUM_ENC 4
#defineINUM_ST 5
#defineINUM_P2INT 6
#defineINUM_UTX0 7
#defineINUM_DMA 8
#define9 INUM_T1
#defineINUM_T2 10
#defineINUM_T3 11
#defineINUM_T4 12
#defineINUM_P0INT 13
#defineINUM_UTX1 14
#defineINUM_P1INT 15
#defineINUM_RF 16
#defineINUM_WDT 17
/*Dozwolone przerwy
-----------------------------------------*/
#defineINT_ENABLE(inum, dalej)
robić{
jeśli (inum==INUM_RFERR) { RFERRIE = włączone; }
else jeśli(inum==INUM_ADC) { ADCIE = on; }
else jeśli(inum==INUM_URX0) { URX0IE = włączone; }
else jeśli(inum==INUM_URX1) { URX1IE = on; }
else jeśli(inum==INUM_ENC) { ENCIE = włączone; }
else jeśli(inum==INUM_ST) { STIE = włączone; }
else jeśli(inum==INUM_P2INT) { (włączone) ? (IEN2 |=0x02) : (IEN2 &= ~0x02); }
else jeśli(inum==INUM_UTX0) { (włączone) ? (IEN2 |=0x04) : (IEN2 &= ~0x04); }
else jeśli(inum==INUM_DMA) { DMAIE = włączone; }
else jeśli(inum==INUM_T1) { T1IE = on; }
else jeśli(inum==INUM_T2) { T2IE = on; }
else jeśli(inum==INUM_T3) { T3IE = on; }
else jeśli(inum==INUM_T4) { T4IE = on; }
else jeśli(inum==INUM_P0INT) { P0IE = on; }
else jeśli(inum==INUM_UTX1) { (włączone) ? (IEN2 |=0x08) : (IEN2 &= ~0x08); }
else jeśli(inum==INUM_P1INT) { (włączone) ? (IEN2 |=0x10) : (IEN2 &= ~0x10); }
else jeśli(inum==INUM_RF) { (włączone) ? (IEN2 |=0x01) : (IEN2 &= ~0x01); }
else jeśli(inum==INUM_WDT) { (włączone) ? (IEN2 |=0x20) : (IEN2 &= ~0x20); }
}podczas gdy (0)
/*Ustaw priorytet awarii
-----------------------------------------*/
#defineINT_PRIORITY(grupa, pri)
robić{
jeśli(pri ==0) { IP0 &= ~grupa; IP1 &= ~grupa; }
jeśli(pri ==1) { IP0 |= grupa; IP1 &= ~grupa; }
jeśli(pri ==2) { IP0 &= ~grupa; IP1 |= grupa; }
jeśli(pri ==3) { IP0 |= grupa; IP1 |= grupa; }
}podczas gdy (0)
//Wartość parametru pri to: 0/1/2/3 (najwyższy priorytet)
//Wartość grupy parametrów to:
#defineRFERR_RF_DMA 0x01//Grupa IP0
#defineADC_P2INT_T1 0x02//Grupa IP1
#defineURX0_UTX0_T2 0x04//Grupa IP2
#defineURX1_UTX1_T3 0x08//Grupa IP3
#defineENC_P1INT_T4 0x10//Grupa IP4
#defineST_WDT_P0INT 0x20//Grupa IP5
/*Zdobądź flagę przerwania
-----------------------------------------*/
#defineINT_GETFLAG(inum) (
(inum==INUM_RFERR) ? NAWRÓĆ :
(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) ? T1IF :
(inum==INUM_T2) ? T2IF :
(inum==INUM_T3) ? T3IF :
(inum==INUM_T4) ? T4IF :
(inum==INUM_P0INT) ? P0IF :
(inum==INUM_UTX1) ? UTX1IF :
(inum==INUM_P1INT) ? P1IF :
(inum==INUM_RF) ? S1CON &= ~0x03 :
(inum==INUM_WDT) ? WDTIF :
0
)
/*Ustaw flagę przerwania
-----------------------------------------*/
#defineINT_SETFLAG(inum, f)
robić{
jeśli (inum==INUM_RFERR) { RFERRIF= f; }
else jeśli(inum==INUM_ADC) { ADCIF = f; }
else jeśli(inum==INUM_URX0) { URX0IF = f; }
else jeśli(inum==INUM_URX1) { URX1IF = f; }
else jeśli(inum==INUM_ENC) { ENCIF_1 = ENCIF_0 = f; }
else jeśli(inum==INUM_ST) { STIF = f; }
else jeśli(inum==INUM_P2INT) { P2IF = f; }
else jeśli(inum==INUM_UTX0) { UTX0IF= f; }
else jeśli(inum==INUM_DMA) { DMAIF = f; }
else jeśli(inum==INUM_T1) { T1IF = f; }
else jeśli(inum==INUM_T2) { T2IF = f; }
else jeśli(inum==INUM_T3) { T3IF = f; }
else jeśli(inum==INUM_T4) { T4IF = f; }
else jeśli(inum==INUM_P0INT) { P0IF = f; }
else jeśli(inum==INUM_UTX1) { UTX1IF= f; }
else jeśli(inum==INUM_P1INT) { P1IF = f; }
else jeśli(inum==INUM_RF) { (f) ? (S1CON |=0x03) : (S1CON &= ~0x03); }
else jeśli(inum==INUM_WDT) { WDTIF = f; }
}podczas gdy (0)
[url=] [/url]
[url=] [/url]
/***********************************************************
Port szeregowy
***********************************************************/
//Wartość BAUD_E odpowiada różnym prędkościom transmisji
#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 )
//Wartość BAUD_M odpowiada różnym prędkościom transmisji
#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)
/*Konfiguracja portu szeregowego w trybie UART
-----------------------------------------*/
#defineUART_SETUP(uart, receiveEnable, baudRate, opcje)
robić{
jeśli((uart) ==0){
jeśli(PERCFG &0x01){
P1SEL |=0x30;
}else{
P0SEL |=0x0C;
}
}
else{
jeśli(PERCFG &0x02){
P1SEL |=0xC0;
}else{
P0SEL |=0x30;
}
}
U##uart##GCR = BAUD_E((baudRate),CLKSPD);
U##uart##BAUD = BAUD_M(baudRate);
U##uart##CSR |=0x80;
U##uart##CSR |= odbierzEnable;
U##uart##UCR |= ((opcje) |0x80);
}podczas gdy(0)
//Wartość parametru receiveEnable:
#defineUART_RECEIVE_ENABLE 0x40 //Uzyskanie zgody
#defineUART_RECEIVE_DISABLE 0x00
//Wartość opcji parametrów:
#defineFLOW_CONTROL_ENABLE 0x40 //Kontrola przepływu
#defineFLOW_CONTROL_DISABLE 0x00
#defineEVEN_PARITY 0x20 //Okazjonalna weryfikacja
#defineODD_PARITY 0x00 //Dziwna weryfikacja
#defineNINE_BIT_TRANSFER 0x10 //Transfer 9-bajtowy
#defineEIGHT_BIT_TRANSFER 0x00 //Transfer 8-bajtowy
#definePARITY_ENABLE 0x08 //Umożliwienie kontroli parzystości
#definePARITY_DISABLE 0x00
#defineTWO_STOP_BITS 0x04 //Pozycja zatrzymania 2 pozycji
#defineONE_STOP_BITS 0x00 //Pozycja 1 stop
#defineHIGH_STOP 0x02 //Poziom zatrzymań jest wysoki
#defineLOW_STOP 0x00 //Pozycja stop jest niska
#defineHIGH_START 0x01 //Początkowy poziom bitu jest wysoki
#defineLOW_START 0x00 //Poziom bitu początkowy jest niski
//Port seryjny wysyła znaki
#defineUART_SEND(uart,data)
robić{
podczas gdy(U##uart##CSR &0x01);
U##uart##DBUF = dane;
}podczas gdy (0)
#defineUART0_SEND(data) UART_SEND(0,data)
#defineUART1_SEND(data) UART_SEND(1,data)
//Port seryjny przyjmuje znaki
#defineUART_RECEIVE(uart,data)
robić{
podczas gdy(! (U##uart##CSR&0x04));
data=U##uart##DBUF;
}podczas gdy(0)
#defineUART0_RECEIVE(data) UART_RECEIVE(0,data)
#defineUART1_RECEIVE(data) UART_RECEIVE(1,data)
[url=] [/url]
[url=] [/url]
/***********************************************************
Zarządzanie zasilaniem i zegarem
***********************************************************/
//Weź crossover zegara
#defineCLKSPD (CLKCON & 0x07)
//Ustaw tryb zasilania
#defineSET_POWER_MODE(tryb)
robić{
jeśli(tryb ==0) { SEN &= ~0x03; }
else jeśli(tryb ==3) { SEN |=0x03; }
else{ ŚP &= ~0x03; SLEEP |= tryb; }
PCON |=0x01;
ASM("NOP");
}podczas gdy (0)
//Tryb parametrów jest ustawiony na następujące wartości:
#definePOWER_MODE_0 0x00
#definePOWER_MODE_1 0x01
#definePOWER_MODE_2 0x02
#definePOWER_MODE_3 0x03
//Wykorzystywane do wykrywania stabilności oscylatorów RC o wysokiej częstotliwości
#defineHIGH_FREQUENCY_RC_OSC_STABLE (SEN I 0x20)
//Używany do wykrywania stabilnego stanu oscylatora kryształowego
#defineXOSC_STABLE (SEN I 0x40)
//Uzyskaj wartość częstotliwości tykania timera
#defineTICKSPD ((CLKCON & 0x38) >> 3)
//Ustaw częstotliwość zegara głównego
#defineSET_MAIN_CLOCK_SOURCE(źródło)
robić{
jeśli(źródło) {
CLKCON |=0x40;
podczas gdy(! HIGH_FREQUENCY_RC_OSC_STABLE);
jeśli(TICKSPD ==0){
CLKCON |=0x08;
}
SEN |=0x04;
}
else{
SEN &= ~0x04;
podczas gdy(! XOSC_STABLE);
ASM("NOP");
CLKCON &= ~0x47;
SEN |=0x04;
}
}podczas gdy (0)
//Wartość źródła parametrów to:
#defineKRYSZTAŁOWA 0x00 //Oscylator krystaliczny
#defineRC 0x01 //Oscylator RC
[url=] [/url]
[url=] [/url]
/***********************************************************
Timer 1
***********************************************************/
//Timer 1 pozwala przerwać przepełnienie liczenia
#defineTIMER1_ENABLE_OVERFLOW_INT(val)
(TIMIF = (val) ? TIMIF |0x40: TIMIF & ~0x40)
//Ustaw flagę przerwania przepełnienia dla timera 1
#defineTIMER1_OVERFLOW_INT_SETFLAG(f) (T1CTL= ((T1CTL & (~0x10)) | f))
//Timer 1 się uruchamia
#defineTIMER1_RUN(wartość) (T1CTL = (wartość) ? T1CTL|0x02 : T1CTL&~0x03)
//Ustaw podział zegara dla timera
#defineSET_TIMER_TICK(value) do{ CLKCON = ((CLKCON & (~0x38)) | value); } while(0)
//Wartość wartości to:
#defineTIMER1_TICK_32M 0x00 //32MHz
#defineTIMER1_TICK_16M 0x08 //16MHz, domyślna wartość resetu systemu
#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
//Ustaw crossover TICK na timer 1
#defineSET_TIMER1_TICKDIV(wartość)
robić{
T1CTL &= ~0x0c;
T1CTL |= wartość;
}podczas gdy (0)
//gdzie wartość jest następująca:
#defineTIMER1_TICKDIV_1 0x00 //1 Dywizja
#defineTIMER1_TICKDIV_8 0x04 //Częstotliwość 8-drogowa
#defineTIMER1_TICKDIV_32 0x08
#defineTIMER1_TICKDIV_128 0x0c
//Ustaw okres przepełnienia timera
#defineSET_TIMER1_PERIOD(wartość)
robić{
T1CC0H = HIGH_BYTE(wartość);
T1CC0L = LOW_BYTE(wartość);
}podczas gdy (0)
//Ustaw tryb pracy Timera 1
#defineSET_TIMER1_MODE(tryb)
robić{
T1CTL = ((T1CTL & (~0x03)) | tryb);
}podczas gdy (0)
//Wartość trybu to:
#defineTIMER1_MODE_STOP 0x00
#defineTIMER1_MODE_FREE 0x01
#defineTIMER1_MODE_MODULE 0x02
#defineTIMER1_MODE_UPDOWN 0x03
[url=] [/url]
[url=] [/url]
/***********************************************************
Pies stróżujący
***********************************************************/
//Ustaw okres przelewu dla timera watchdog
#defineWDT_SET_TIMEOUT_PERIOD(przerwa)
robić{ WDCTL &= ~0x03; WDCTL |= przerwa; }podczas gdy (0)
//Wartość limitu czasu parametru to:
#defineSEC_1 0x00 //po 1 sekundzie
#defineM_SEC_250 0x01 //po 250 ms
#defineM_SEC_15 0x02 //po 15 ms
#defineM_SEC_2 0x03 //Po 2 ms
//Procedury karmienia psów
#defineWDT_RESET() do {
WDCTL = (WDCTL & ~0xF0) |0xA0;
WDCTL = (WDCTL & ~0xF0) |0x50;
} podczas gdy (0)
//Uruchamiaj/wyłączaj timer watchdog
#defineWDT_ENABLE() WDCTL |= 0x08
#defineWDT_DISABLE() WDCTL &= ~0x08
[url=] [/url]
[url=] [/url]
/***********************************************************
ADC
***********************************************************/
//Konfiguruj pojedynczy ADC
#defineADC_SINGLE_CONVERSION(ustawienia)
robić{ ADCCON3 = ustawienia; }podczas gdy(0)
//Ustawienie parametrów składa się z następujących kombinacji:
//Napięcie odniesienia
#defineADC_REF_1_25_V 0x00 //Wewnętrzne napięcie odniesienia 1,25V
#defineADC_REF_P0_7 0x40 //Zewnętrzne napięcie odniesienia na pinie AIN7
#defineADC_REF_AVDD 0x80 //AVDD_SOC Piny
#defineADC_REF_P0_6_P0_7 0xC0 //AIN6-AIN7 Zewnętrzne napięcie odniesienia dla wejść różnicowych
//Częstotliwość próbkowania
#defineADC_8_BIT 0x00 //8. miejsce
#defineADC_10_BIT 0x10 //10. miejsce
#defineADC_12_BIT 0x20 //12. miejsce
#defineADC_14_BIT 0x30 //14. miejsce
//Wejście na kanał
#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 //Ziemia
#defineADC_TEMP_SENS 0x0E //Czujnik temperatury w chipie
#defineADC_VDD_3 0x0F //VDD/3
Konwersja ADC zakończona
#define ADC_SAMPLE_READY() (ADCCON1 & 0x80)
#endif
//启动ADC转化
#define ADC_START()
do { ADCCON1 |= 0x40; } podczas gdy (0)//Wybierz tryb spustu ADC jako ręczny (czyli ADC_SAMPLE_READY)
#defineADC_STOP()
robić{ ADCCON1 |=0x30; }podczas gdy (0)[url=] [/url]
(2) Warstwa modułu funkcjonalnego
[url=] [/url]
/***********************************************************
*Nazwa pliku: module.h
*Autor: hustlzp
*Data: 6 marca 2011
*Wersja: 1.0
*Opis funkcji: plik nagłówka warstwy modułu funkcjonalnego
*Lista funkcji: void led_init()
pustka timer1_init()
pustka uart0_init(pustka);
void Uart0SendString(znak nieznany *s);
Float adc_start(pustka)
void get_temperature(znak nieznany *wyjście, temperatura pływania);
pustka watchdog_init(pustka);
*Zmodyfikowane rekordy:
***********************************************************/
#ifndef MODULE_H
#defineMODULE_H
#include"hal.h"
/***********************************************************
LED
***********************************************************/
//Zdefiniuj piny LED
#defineLED1 P1_0
#defineLED2 P1_1
#defineLED3 P1_2
#defineLED4 P1_3
//Dioda LED i wyłączona
#defineLED_OFF 1
#defineLED_ON 0
//Inicjalizacja LED
pustkaled_init(pustka);
/***********************************************************
timer1
***********************************************************/
//Używany do ustawienia wartości okresu przepełnienia dla timera
#defineTIMER1_OVF_2SEC 0xF424 //Dwójki
#defineTIMER1_OVF_1SEC 0x7A12 //1
#defineTIMER1_OVF_dot5SEC 0x3D09 //0,5 s
//Timer 1 się inicjalizuje
pustka timer1_init(pustka);
/***********************************************************
UART0
***********************************************************/
//Inicjalizacja UART0
pustka uart0_init(pustka);
//Ciąg transmisji z portem szeregowym
pustka Uart0SendString(bez znakuchar*s);
/***********************************************************
ADC-14
***********************************************************/
//Używany do konwersji danych uzyskanych przez ADC na temperaturę Celsjusza
#defineADC_TO_CELSIUS(temperatura) (temperatura * 0.06229 - 311.43)
//Rozpocznij konwersję ADC
Pływanieadc_start(pustka);
//Przebudowa
pustka get_temperature(bez podpisuchar*wyjście,Pływanietymczasowe);
/***********************************************************
WatchDog
***********************************************************/
//Inicjalizacja psa strażniczego
pustka watchdog_init(pustka);
#endif
[url=] [/url]
[url=] [/url]
/***********************************************************
*Nazwa pliku: module.c
*Autor: hustlzp
*Data: 2011/3/11
*Wersja: 1.0
*Opis funkcji: Plik źródłowy na warstwie modułu funkcjonalnego
*Lista funkcji: (pominięta)
*Zmodyfikowane rekordy:
***********************************************************/
#include"module.h"
/***********************************************************
*Nazwa funkcji: led_init
*Funkcja funkcyjna: inicjalizacja LED
*Parametry wejścia: brak
*Parametry eksportu: brak
***********************************************************/
pustkaled_init(pustka)
{
//Konfiguruj P1.0, P1.1, P1.2 i P1.3 jako ogólne porty I/O
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);
//Konfiguruj wyjścia P1.0, P1.1, P1.2 i P1.3
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);
led1 = LED_ON;
led2 = LED_OFF;
led3 = LED_OFF;
led4 = LED_OFF;
}
/***********************************************************
*Nazwa funkcji: timer1_init
* Funkcja funkcjonalna: Timer 1 inicjalizacja
*Parametry wejścia: brak
*Parametry eksportu: brak
***********************************************************/
pustkatimer1_init(pustka)
{
INT_GLOBAL_ENABLE(INT_ON); //Otwórz globalne przerwanie
INT_ENABLE(INUM_T1, INT_ON); //Przerwanie Open T1
TIMER1_ENABLE_OVERFLOW_INT(INT_ON); //Przerwanie przelewowe z otwartym T1
SET_TIMER_TICK(TIMER1_TICK_4M); //Ustaw timer TICK na 4MHz
SET_TIMER1_PERIOD(TIMER1_OVF_2SEC); //Ustaw okres liczenia dla T1 do 2
SET_TIMER1_TICKDIV(TIMER1_TICKDIV_128); //Ustaw crossover zegara na T1 na 128
SET_TIMER1_MODE(TIMER1_MODE_MODULE); //Ustaw tryb działania T1 na moduł
}
/***********************************************************
*Nazwa funkcji: uart0_init
*Funkcja funkcyjna: inicjalizacja portu szeregowego UART0
*Parametry wejścia: brak
*Parametry eksportu: brak
***********************************************************/
pustkauart0_init(pustka)
{
//Wybierz lokalizację UART
IO_PER_LOC_UART0_AT_PORT0_PIN2345();
//Konfiguruj UART: Dozwolony odbier, 115200 bps, jednobitowy bit stop, brak parzystości
UART_SETUP(0, UART_RECEIVE_ENABLE,115200, ONE_STOP_BITS | PARITY_DISABLE);
//Otwórz całkowite przerwanie
INT_GLOBAL_ENABLE(INT_ON);
//Otwórz port szeregowy 0, aby odbierać przerwania
INT_ENABLE(INUM_URX0, INT_ON);
}
/***********************************************************
*Nazwa funkcji: Uart0SendString
* Funkcja funkcjonalna: Timer 1 inicjalizacja
*Parametr wejściowy: znak bez znaku *s
Sznurek, który chcesz wysłać
*Parametry eksportu: brak
***********************************************************/
pustkaUart0SendString(bez znakuchar*s)
{
podczas gdy(*s !=0)
UART0_SEND(*s++);
}
/***********************************************************
*Nazwa funkcji: adc_start
*Funkcja funkcji: Rozpocznij konwersję ADC
*Parametry wejścia: brak
*Parametr eksportowy: float
Wartość temperatury w tablecie
***********************************************************/
Pływanieadc_start(pustka)
{
Niepodpisanyinttemperatura;
//Napięcie referencyjne wynosi 1,25V, dokładność próbkowania to 14 bitów, a celem konwersji jest czujnik temperatury na chipie
ADC_SINGLE_CONVERSION(ADC_REF_1_25_V | ADC_14_BIT | ADC_TEMP_SENS);
ADC_STOP(); //Ustaw metodę wyzwalania konwersji ADC na manualną
ADC_START(); //Rozpocznij konwersję ADC
podczas gdy(! ADC_SAMPLE_READY()); //Czekaj, aż konwersja się zakończy
temp = ADCL >>2; //Zapisz wyniki konwersji w temperaturze
temp |= (((bez znakuint) ADCH) <<6);
powrótADC_TO_CELSIUS(tymczasowy); //Zwraca rzeczywistą wartość temperatury po konwersji
}
/***********************************************************
*Nazwa funkcji: get_temperature
*Funkcja funkcji: przetwarza wartość temperatury i zapisuje ją w tablicy znaków do wyjścia szeregowego
*Parametr wejściowy: znak bez znaku *wyjście
Używany do przechowywania przeliczonej wartości temperatury
Temperatura pływaka
Wartość temperatury Celsjusza
*Parametry eksportu: brak
***********************************************************/
pustkaget_temperature(bez podpisuchar*wyjście,Pływanietymczasowe)
{
Wyjście[0] = (bez podpisuchar(tymczasowa) /10 + 48; //Dziesięć miejsc
Wyjście[1] = (bez podpisuchar(temp) %10 + 48; //Jednocyfrowa liczba
Wyjście[2] ='.'; //Przecinek dziesiętny
Wyjście[3] = (bez podpisuchar(tymczasowa*10) %10 + 48; //Dziesiąty
Wyjście[4] = (bez podpisuchar(tymczasowa*100) %10 + 48; //Percentyl
Wyjście[5] =''; //Endyfikatory strun
}
/***********************************************************
*Nazwa funkcji: watchdog_init
*Funkcja funkcji: inicjalizacja psa zegarka
*Parametry wejścia: brak
*Parametry eksportu: brak
***********************************************************/
pustkawatchdog_init(pustka)
{
WDT_SET_TIMEOUT_PERIOD(SEC_1); //Ustaw czas przerwy na 1 sekundy
WDT_ENABLE(); //Uruchom psa stróżującego
}
[url=] [/url]
(3) Warstwa aplikacji
[url=] [/url]
/*******************************************************************
Nazwa pliku: main.c
Autor: hustlzp
Data: 2011/3/11
Wersja: 1.0
Opis funkcji: Plik programu głównego
Lista funkcji: (pominięta)
Rekord modyfikacji:
*******************************************************************/
#include
/********************************************************************
Procedury obsługi przerwań
********************************************************************/
/* 定时器1溢出中断子程序
-------------------------------------------------------*/
#pragma wektor=T1_VECTOR
__interrupt pustka T1_ISR(pustka)
{
EA=0; Brama jest przerwana
led2 = LED_ON;
get_temperature(wyjście,adc_start()); Przekonwertuj wartość temperatury na tablicę znaków, które mają zostać wygenerowane
Uart0SendString(output); Wartość temperatury wyjściowej
Uart0SendString("°C");
led2
/* 串口接收中断子程序
-------------------------------------------------------*/
#pragma wektor=URX0_VECTOR
__interrupt pustka RE_ISR(pustka)
{
EA=0;
led3 = LED_ON;
receive = U0DBUF;
if(type==1) // type=1, co oznacza, że otrzymany znak służy do ustawienia okresu przepełnienia timera
{
typ=0;
Przełączaj (odbiór)
{
przypadek '0': // Okres przepełnienia timera wynosi 0,5s
{
SET_TIMER1_PERIOD(TIMER1_OVF_dot5SEC);
przerwę;
}
przypadek '1': // Okres przepełnienia timera to 1 s
{
SET_TIMER1_PERIOD(TIMER1_OVF_1SEC);
przerwę;
}
przypadek '2': // Okres przepełnienia timera to 2 sekundy
{
SET_TIMER1_PERIOD(TIMER1_OVF_2SEC);
przerwę;
}
}
}
w przeciwnym razie if(type==2) // type=2, co oznacza, że odebrane znaki są używane do kontroli uśpienia
{
typ=0;
led1 = LED_OFF;
led2 = LED_OFF;
led3 = LED_OFF;
Przełączaj (odbiór)
{
przypadek '1': // Wejście w tryb zasilania PM1
{
SET_POWER_MODE(1);
przerwę;
}
przypadek '2': // Przejdź w tryb zasilania PM2
{
SET_POWER_MODE(2);
przerwę;
}
przypadek '3': //Wprowadź tryb zasilania PM3
{
SET_POWER_MODE(3);
przerwę;
}
}
}
w przeciwnym razie jeśli(type==0) // type=0, co oznacza, że odebrany znak to typ polecenia sterującego: @ lub $
{
if(receive=='@')
{
typ=1; Otrzymuje się '@', aby wskazać, że następny znak jest używany do ustawienia okresu przepełnienia
}
w przeciwnym razie jeśli(otrzymać=='$')
{
typ=2; Otrzymujemy '$', co oznacza, że następny znak jest używany do sterowania uśpieniem systemu
}
}
led3 = LED_OFF;
EA=1;
}
=LED_OFF;
TIMER1_OVERFLOW_INT_SETFLAG(INT_CLR); Usuń znak przerwy
EA=1; Przerwanie otwarte
}
/* 主函数
-------------------------------------------------------*/
void main(void)
{
SET_MAIN_CLOCK_SOURCE(KRYSZTAŁ); Ustaw zegar systemu na oscylator kryształowy 32MHz
led_init(); Inicjalizacja LED
uart0_init(); Inicjalizacja portu szeregowego UART0
timer1_init(); Timer 1 się inicjalizuje
watchdog_init(); Inicjalizacja psa strażniczego
while(1)
{
WDT_RESET(); Karm psa cały czas
}
}/********************************************************************
Program główny
********************************************************************/
/* 全局变量
-------------------------------------------------------*/
niepodpisany wynik char[6]={0}; Dane temperaturowe są przechowywane, co ułatwia szeregowe wydawanie danych
niepodpisany char receive; Zapisz otrzymane znaki
typ znaku = 0; Flaga typu otrzymanego znaku jest ustawiona na 0/1/2"module.h"[url=] [/url]
5. TestowanieOch~ Kod w końcu został wklejony, to naprawdę wyczerpujące, przetestujmy ten mały system:
(1) Próbkowanie na czas
Otwórz port szeregowy, rozpocznij debugowanie IAR i zobacz, że LED1 jest włączone, a wartość temperatury w narzędziu portu szeregowego jest stale generowana, a interwał próbkowania określany jest na 2s:
(2) Kontrola interwału próbkowania
Wprowadź "@1" w narzędziu do portu szeregowego, a następnie przetestuj interwał próbkowania i okazuje się, że stał się on jedynkami; Wpisz "@0" i interwał próbkowania zmienia się na 0,5s.
(3) Kontrola snu
Wpisz "$1" w narzędziu do portu szeregowego i zobaczysz, że wszystkie diody LED są wyłączone, a próbkowanie temperatury się zatrzymało:
Po testach system działa normalnie i stabilnie, zasadniczo spełniając wymagania.
Studenci potrzebujący kodu źródłowegoKliknij tutaj, aby pobrać
6. PodsumowanieNiniejszy artykuł wykorzystuje nieco obszerny eksperyment jako przykład, aby pokazać, jak integrować zasoby CC2430 na chipie, aby napisać stosunkowo ustandaryzowany mały system. Za kilka dni poświęcę czas, by napisać prostą instrukcję obsługi hal.h, aby ja i wszyscy mogli łatwo obsługiwać CC2430.
Następnie dokończę badania nad zasobami CC2430 na chipie i poświęcę się nauce stosu protokołów TI Z-Stack~
Pisanie wpisów na blogu w tej serii na razie dobiegło końca, ale podróż Zigbee będzie kontynuowana. Przyszłość jest nieznana, ale wierzę, że autor pokona przeszkody razem z każdym i poczuje wzloty i upadki, a także będą korzyści.
Bądźcie czujni: wpisy na blogu "Dołącz do TI Z-Stack"!